1 /* 2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.code; 24 25 import java.lang.invoke.MethodHandle; 26 import java.lang.invoke.MethodHandles; 27 import java.util.Arrays; 28 29 import jdk.vm.ci.code.CodeCacheProvider; 30 import jdk.vm.ci.code.CodeUtil; 31 import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter; 32 import jdk.vm.ci.code.CodeUtil.RefMapFormatter; 33 import jdk.vm.ci.code.InstalledCode; 34 import jdk.vm.ci.code.Register; 35 import jdk.vm.ci.code.RegisterConfig; 36 import jdk.vm.ci.code.TargetDescription; 37 import jdk.vm.ci.code.site.Call; 38 import jdk.vm.ci.code.site.DataPatch; 39 import jdk.vm.ci.code.site.ExceptionHandler; 40 import jdk.vm.ci.code.site.Infopoint; 41 import jdk.vm.ci.code.site.Mark; 42 43 import org.graalvm.compiler.serviceprovider.ServiceProvider; 44 45 /** 46 * {@link HexCodeFile} based implementation of {@link DisassemblerProvider}. 47 */ 48 @ServiceProvider(DisassemblerProvider.class) 49 public class HexCodeFileDisassemblerProvider implements DisassemblerProvider { 50 51 @Override 52 public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { 53 assert compResult != null; 54 return disassemble(codeCache, compResult, null); 55 } 56 57 @Override 58 public String getName() { 59 return "hcf"; 60 } 61 62 @Override 63 public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { 64 assert installedCode != null; 65 return installedCode.isValid() ? disassemble(codeCache, compResult, installedCode) : null; 66 } 67 68 private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { 69 TargetDescription target = codeCache.getTarget(); 70 RegisterConfig regConfig = codeCache.getRegisterConfig(); 71 byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); 72 if (code == null) { 73 // Method was deoptimized/invalidated 74 return ""; 75 } 76 long start = installedCode == null ? 0L : installedCode.getStart(); 77 HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); 78 if (compResult != null) { 79 HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); 80 addExceptionHandlersComment(compResult, hcf); 81 Register fp = regConfig.getFrameRegister(); 82 RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.wordSize, fp, 0); 83 for (Infopoint infopoint : compResult.getInfopoints()) { 84 if (infopoint instanceof Call) { 85 Call call = (Call) infopoint; 86 if (call.debugInfo != null) { 87 hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); 88 } 89 addOperandComment(hcf, call.pcOffset, "{" + codeCache.getTargetName(call) + "}"); 90 } else { 91 if (infopoint.debugInfo != null) { 92 hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); 93 } 94 addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); 95 } 96 } 97 for (DataPatch site : compResult.getDataPatches()) { 98 hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); 99 } 100 for (Mark mark : compResult.getMarks()) { 101 hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark)); 102 } 103 } 104 String hcfEmbeddedString = hcf.toEmbeddedString(); 105 return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString); 106 } 107 108 private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { 109 if (!compResult.getExceptionHandlers().isEmpty()) { 110 String nl = HexCodeFile.NEW_LINE; 111 StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); 112 for (ExceptionHandler e : compResult.getExceptionHandlers()) { 113 buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); 114 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); 115 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); 116 } 117 hcf.addComment(0, buf.toString()); 118 } 119 } 120 121 private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { 122 hcf.addOperandComment(pos, comment); 123 } 124 125 /** 126 * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} 127 * {@link HexCodeFile}. 128 */ 129 static class HexCodeFileDisTool { 130 static final MethodHandle processMethod; 131 132 static { 133 MethodHandle toolMethod = null; 134 try { 135 Class<?> toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); 136 toolMethod = MethodHandles.lookup().unreflect(toolClass.getDeclaredMethod("processEmbeddedString", String.class)); 137 } catch (Exception e) { 138 // Tool not available on the class path 139 } 140 processMethod = toolMethod; 141 } 142 143 public static String tryDisassemble(String hcfEmbeddedString) { 144 if (processMethod != null) { 145 try { 146 return (String) processMethod.invokeExact(hcfEmbeddedString); 147 } catch (Throwable e) { 148 // If the tool is available, for now let's be noisy when it fails 149 throw new InternalError(e); 150 } 151 } 152 return hcfEmbeddedString; 153 } 154 } 155 156 }