# HG changeset patch # User Doug Simon # Date 1433343161 -7200 # Node ID 4c00096fc415405d93c8e1bcf012d69357e14e9a # Parent 729e6acde6c0c129163fd3b36d4aa2780466e25b moved CodeCacheProvider.disassemble(...) from API to CFGPrinterObserver diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Jun 03 16:23:33 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Jun 03 16:52:41 2015 +0200 @@ -365,10 +365,6 @@ Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); } - if (Debug.isLogEnabled()) { - Debug.log("%s", backend.getProviders().getCodeCache().disassemble(compilationResult, null)); - } - Debug.dump(compilationResult, "After code generation"); } } diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Wed Jun 03 16:23:33 2015 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Wed Jun 03 16:52:41 2015 +0200 @@ -22,12 +22,8 @@ */ package com.oracle.graal.printer; -import com.oracle.jvmci.code.CompilationResult; -import com.oracle.jvmci.code.CodeCacheProvider; -import com.oracle.jvmci.code.InstalledCode; -import com.oracle.jvmci.meta.ResolvedJavaMethod; -import com.oracle.jvmci.meta.JavaMethod; import java.io.*; +import java.lang.reflect.*; import java.util.*; import java.util.concurrent.atomic.*; @@ -40,8 +36,16 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.jvmci.code.*; +import com.oracle.jvmci.code.CodeUtil.DefaultRefMapFormatter; +import com.oracle.jvmci.code.CodeUtil.RefMapFormatter; +import com.oracle.jvmci.code.CompilationResult.Call; +import com.oracle.jvmci.code.CompilationResult.DataPatch; +import com.oracle.jvmci.code.CompilationResult.Infopoint; +import com.oracle.jvmci.code.CompilationResult.Mark; import com.oracle.jvmci.common.*; import com.oracle.jvmci.debug.*; +import com.oracle.jvmci.meta.*; /** * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the @@ -179,10 +183,10 @@ } else if (object instanceof CompilationResult) { final CompilationResult compResult = (CompilationResult) object; - cfgPrinter.printMachineCode(codeCache.disassemble(compResult, null), message); + cfgPrinter.printMachineCode(disassemble(codeCache, compResult, null), message); } else if (isCompilationResultAndInstalledCode(object)) { Object[] tuple = (Object[]) object; - cfgPrinter.printMachineCode(codeCache.disassemble((CompilationResult) tuple[0], (InstalledCode) tuple[1]), message); + cfgPrinter.printMachineCode(disassemble(codeCache, (CompilationResult) tuple[0], (InstalledCode) tuple[1]), message); } else if (object instanceof Interval[]) { cfgPrinter.printIntervals(message, (Interval[]) object); } else if (object instanceof StackInterval[]) { @@ -197,6 +201,101 @@ } + /** + * Returns a disassembly of some compiled code. + * + * @param compResult some compiled code + * @param installedCode the result of installing the code in {@code compResult} or null if the + * code has not yet been installed + */ + private static String disassemble(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode installedCode) { + TargetDescription target = codeCache.getTarget(); + RegisterConfig regConfig = codeCache.getRegisterConfig(); + byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); + if (code == null) { + // Method was deoptimized/invalidated + return ""; + } + long start = installedCode == null ? 0L : installedCode.getStart(); + HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); + if (compResult != null) { + HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); + addExceptionHandlersComment(compResult, hcf); + Register fp = regConfig.getFrameRegister(); + RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.arch, target.wordSize, fp, 0); + for (Infopoint infopoint : compResult.getInfopoints()) { + if (infopoint instanceof Call) { + Call call = (Call) infopoint; + if (call.debugInfo != null) { + hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, call.pcOffset, "{" + codeCache.getTargetName(call) + "}"); + } else { + if (infopoint.debugInfo != null) { + hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); + } + addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); + } + } + for (DataPatch site : compResult.getDataPatches()) { + hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); + } + for (Mark mark : compResult.getMarks()) { + hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark)); + } + } + String hcfEmbeddedString = hcf.toEmbeddedString(); + return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString); + } + + /** + * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} + * {@link HexCodeFile}. + */ + static class HexCodeFileDisTool { + static final Method processMethod; + static { + Method toolMethod = null; + try { + Class toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); + toolMethod = toolClass.getDeclaredMethod("processEmbeddedString", String.class); + } catch (Exception e) { + // Tool not available on the class path + } + processMethod = toolMethod; + } + + public static String tryDisassemble(String hcfEmbeddedString) { + if (processMethod != null) { + try { + return (String) processMethod.invoke(null, hcfEmbeddedString); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // If the tool is available, for now let's be noisy when it fails + throw new JVMCIError(e); + } + } + return hcfEmbeddedString; + } + } + + private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { + if (!compResult.getExceptionHandlers().isEmpty()) { + String nl = HexCodeFile.NEW_LINE; + StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); + for (CompilationResult.ExceptionHandler e : compResult.getExceptionHandlers()) { + buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); + hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); + hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); + } + hcf.addComment(0, buf.toString()); + } + } + + private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { + String oldValue = hcf.addOperandComment(pos, comment); + assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue; + } + private static boolean isCompilationResultAndInstalledCode(Object object) { if (object instanceof Object[]) { Object[] tuple = (Object[]) object; diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Wed Jun 03 16:52:41 2015 +0200 @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.printer; + +import java.io.*; +import java.util.*; +import java.util.regex.*; + +import com.oracle.jvmci.code.*; +import com.oracle.jvmci.code.CompilationResult.CodeAnnotation; +import com.oracle.jvmci.code.CompilationResult.CodeComment; +import com.oracle.jvmci.code.CompilationResult.JumpTable; + +/** + * A HexCodeFile is a textual format for representing a chunk of machine code along with extra + * information that can be used to enhance a disassembly of the code. + * + * A pseudo grammar for a HexCodeFile is given below. + * + *
+ *     HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
+ *
+ *     OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
+ *
+ *     Platform ::= "Platform" ISA WordWidth
+ *
+ *     HexCode ::= "HexCode" StartAddress HexDigits
+ *
+ *     Comment ::= "Comment" Position String
+ *
+ *     OperandComment ::= "OperandComment" Position String
+ *
+ *     JumpTable ::= "JumpTable" Position EntrySize Low High
+ *
+ *     LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
+ *
+ *     Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
+ *
+ *     Delim := "<||@"
+ * 
+ * + * There must be exactly one HexCode and Platform part in a HexCodeFile. The length of HexDigits + * must be even as each pair of digits represents a single byte. + *

+ * Below is an example of a valid Code input: + * + *

+ *
+ *  Platform AMD64 64  <||@
+ *  HexCode 0 e8000000009090904883ec084889842410d0ffff48893c24e800000000488b3c24488bf0e8000000004883c408c3  <||@
+ *  Comment 24 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 1]
+ *              |0
+ *     locals:  |stack:0:a
+ *     stack:   |stack:0:a
+ *    <||@
+ *  OperandComment 24 {java.util.Locale.getDefault()}  <||@
+ *  Comment 36 frame-ref-map: +0 {0}
+ *  at java.lang.String.toLowerCase(String.java:2496) [bci: 4]
+ *              |0
+ *     locals:  |stack:0:a
+ *    <||@
+ *  OperandComment 36 {java.lang.String.toLowerCase(Locale)}  lt;||@
+ *
+ * 
+ */ +public class HexCodeFile { + + public static final String NEW_LINE = CodeUtil.NEW_LINE; + public static final String SECTION_DELIM = " <||@"; + public static final String COLUMN_END = " <|@"; + public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL); + public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL); + public static final Pattern OPERAND_COMMENT = COMMENT; + public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*"); + public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*"); + public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?"); + public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL); + + /** + * Delimiter placed before a HexCodeFile when embedded in a string/stream. + */ + public static final String EMBEDDED_HCF_OPEN = "<<> comments = new TreeMap<>(); + + /** + * Map from a machine code position to a comment for the operands of the instruction at the + * position. + */ + public final Map operandComments = new TreeMap<>(); + + public final byte[] code; + + public final ArrayList jumpTables = new ArrayList<>(); + + public final String isa; + + public final int wordWidth; + + public final long startAddress; + + public HexCodeFile(byte[] code, long startAddress, String isa, int wordWidth) { + this.code = code; + this.startAddress = startAddress; + this.isa = isa; + this.wordWidth = wordWidth; + } + + /** + * Parses a string in the format produced by {@link #toString()} to produce a + * {@link HexCodeFile} object. + */ + public static HexCodeFile parse(String input, int sourceOffset, String source, String sourceName) { + return new Parser(input, sourceOffset, source, sourceName).hcf; + } + + /** + * Formats this HexCodeFile as a string that can be parsed with + * {@link #parse(String, int, String, String)}. + */ + @Override + public String toString() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writeTo(baos); + return baos.toString(); + } + + public String toEmbeddedString() { + return EMBEDDED_HCF_OPEN + NEW_LINE + toString() + EMBEDDED_HCF_CLOSE; + } + + public void writeTo(OutputStream out) { + PrintStream ps = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out); + ps.printf("Platform %s %d %s%n", isa, wordWidth, SECTION_DELIM); + ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM); + + for (JumpTable table : jumpTables) { + ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM); + } + + for (Map.Entry> e : comments.entrySet()) { + int pos = e.getKey(); + for (String comment : e.getValue()) { + ps.printf("Comment %d %s %s%n", pos, comment, SECTION_DELIM); + } + } + + for (Map.Entry e : operandComments.entrySet()) { + ps.printf("OperandComment %d %s %s%n", e.getKey(), e.getValue(), SECTION_DELIM); + } + ps.flush(); + } + + /** + * Formats a byte array as a string of hex digits. + */ + public static String hexCodeString(byte[] code) { + if (code == null) { + return ""; + } else { + StringBuilder sb = new StringBuilder(code.length * 2); + for (int b : code) { + String hex = Integer.toHexString(b & 0xff); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } + } + + /** + * Adds a comment to the list of comments for a given position. + */ + public void addComment(int pos, String comment) { + List list = comments.get(pos); + if (list == null) { + list = new ArrayList<>(); + comments.put(pos, list); + } + list.add(encodeString(comment)); + } + + /** + * Sets an operand comment for a given position. + * + * @return the previous operand comment for {@code pos} + */ + public String addOperandComment(int pos, String comment) { + return operandComments.put(pos, encodeString(comment)); + } + + /** + * Adds any jump tables, lookup tables or code comments from a list of code annotations. + */ + public static void addAnnotations(HexCodeFile hcf, List annotations) { + if (annotations == null || annotations.isEmpty()) { + return; + } + for (CodeAnnotation a : annotations) { + if (a instanceof JumpTable) { + JumpTable table = (JumpTable) a; + hcf.jumpTables.add(table); + } else if (a instanceof CodeComment) { + CodeComment comment = (CodeComment) a; + hcf.addComment(comment.position, comment.value); + } + } + } + + /** + * Modifies a string to mangle any substrings matching {@link #SECTION_DELIM} and + * {@link #COLUMN_END}. + */ + public static String encodeString(String input) { + int index; + String s = input; + while ((index = s.indexOf(SECTION_DELIM)) != -1) { + s = s.substring(0, index) + " < |@" + s.substring(index + SECTION_DELIM.length()); + } + while ((index = s.indexOf(COLUMN_END)) != -1) { + s = s.substring(0, index) + " < @" + s.substring(index + COLUMN_END.length()); + } + return s; + } + + /** + * Helper class to parse a string in the format produced by {@link HexCodeFile#toString()} and + * produce a {@link HexCodeFile} object. + */ + static class Parser { + + final String input; + final String inputSource; + String isa; + int wordWidth; + byte[] code; + long startAddress; + HexCodeFile hcf; + + Parser(String input, int sourceOffset, String source, String sourceName) { + this.input = input; + this.inputSource = sourceName; + parseSections(sourceOffset, source); + } + + void makeHCF() { + if (hcf == null) { + if (isa != null && wordWidth != 0 && code != null) { + hcf = new HexCodeFile(code, startAddress, isa, wordWidth); + } + } + } + + void checkHCF(String section, int offset) { + check(hcf != null, offset, section + " section must be after Platform and HexCode section"); + } + + void check(boolean condition, int offset, String message) { + if (!condition) { + error(offset, message); + } + } + + Error error(int offset, String message) { + throw new Error(errorMessage(offset, message)); + } + + void warning(int offset, String message) { + PrintStream err = System.err; + err.println("Warning: " + errorMessage(offset, message)); + } + + String errorMessage(int offset, String message) { + assert offset < input.length(); + InputPos inputPos = filePos(offset); + int lineEnd = input.indexOf(HexCodeFile.NEW_LINE, offset); + int lineStart = offset - inputPos.col; + String line = lineEnd == -1 ? input.substring(lineStart) : input.substring(lineStart, lineEnd); + return String.format("%s:%d: %s%n%s%n%" + (inputPos.col + 1) + "s", inputSource, inputPos.line, message, line, "^"); + } + + static class InputPos { + + final int line; + final int col; + + public InputPos(int line, int col) { + this.line = line; + this.col = col; + } + } + + InputPos filePos(int index) { + assert input != null; + int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1; + + String l = input.substring(lineStart, lineStart + 10); + PrintStream out = System.out; + out.println("YYY" + input.substring(index, index + 10) + "..."); + out.println("XXX" + l + "..."); + + int pos = input.indexOf(HexCodeFile.NEW_LINE, 0); + int line = 1; + while (pos > 0 && pos < index) { + line++; + pos = input.indexOf(HexCodeFile.NEW_LINE, pos + 1); + } + return new InputPos(line, index - lineStart); + } + + void parseSections(int offset, String source) { + assert input.startsWith(source, offset); + int index = 0; + int endIndex = source.indexOf(SECTION_DELIM); + while (endIndex != -1) { + while (source.charAt(index) <= ' ') { + index++; + } + String section = source.substring(index, endIndex).trim(); + parseSection(offset + index, section); + index = endIndex + SECTION_DELIM.length(); + endIndex = source.indexOf(SECTION_DELIM, index); + } + } + + int parseInt(int offset, String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + throw error(offset, "Not a valid integer: " + value); + } + } + + void parseSection(int offset, String section) { + if (section.isEmpty()) { + return; + } + assert input.startsWith(section, offset); + Matcher m = HexCodeFile.SECTION.matcher(section); + check(m.matches(), offset, "Section does not match pattern " + HexCodeFile.SECTION); + + String header = m.group(1); + String body = m.group(2); + int headerOffset = offset + m.start(1); + int bodyOffset = offset + m.start(2); + + if (header.equals("Platform")) { + check(isa == null, bodyOffset, "Duplicate Platform section found"); + m = HexCodeFile.PLATFORM.matcher(body); + check(m.matches(), bodyOffset, "Platform does not match pattern " + HexCodeFile.PLATFORM); + isa = m.group(1); + wordWidth = parseInt(bodyOffset + m.start(2), m.group(2)); + makeHCF(); + } else if (header.equals("HexCode")) { + check(code == null, bodyOffset, "Duplicate Code section found"); + m = HexCodeFile.HEX_CODE.matcher(body); + check(m.matches(), bodyOffset, "Code does not match pattern " + HexCodeFile.HEX_CODE); + String hexAddress = m.group(1); + startAddress = Long.valueOf(hexAddress, 16); + String hexCode = m.group(2); + if (hexCode == null) { + code = new byte[0]; + } else { + check((hexCode.length() % 2) == 0, bodyOffset, "Hex code length must be even"); + code = new byte[hexCode.length() / 2]; + for (int i = 0; i < code.length; i++) { + String hexByte = hexCode.substring(i * 2, (i + 1) * 2); + code[i] = (byte) Integer.parseInt(hexByte, 16); + } + } + makeHCF(); + } else if (header.equals("Comment")) { + checkHCF("Comment", headerOffset); + m = HexCodeFile.COMMENT.matcher(body); + check(m.matches(), bodyOffset, "Comment does not match pattern " + HexCodeFile.COMMENT); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + String comment = m.group(2); + hcf.addComment(pos, comment); + } else if (header.equals("OperandComment")) { + checkHCF("OperandComment", headerOffset); + m = HexCodeFile.OPERAND_COMMENT.matcher(body); + check(m.matches(), bodyOffset, "OperandComment does not match pattern " + HexCodeFile.OPERAND_COMMENT); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + String comment = m.group(2); + hcf.addOperandComment(pos, comment); + } else if (header.equals("JumpTable")) { + checkHCF("JumpTable", headerOffset); + m = HexCodeFile.JUMP_TABLE.matcher(body); + check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE); + int pos = parseInt(bodyOffset + m.start(1), m.group(1)); + int entrySize = parseInt(bodyOffset + m.start(2), m.group(2)); + int low = parseInt(bodyOffset + m.start(3), m.group(3)); + int high = parseInt(bodyOffset + m.start(4), m.group(4)); + hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize)); + } else { + error(offset, "Unknown section header: " + header); + } + } + } +} diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Wed Jun 03 16:23:33 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Wed Jun 03 16:52:41 2015 +0200 @@ -198,9 +198,6 @@ a.getAssumption().registerInstalledCode(installedCode); } - if (Debug.isLogEnabled()) { - Debug.log(providers.getCodeCache().disassemble(result, installedCode)); - } return result; } diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/CodeCacheProvider.java --- a/graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/CodeCacheProvider.java Wed Jun 03 16:23:33 2015 +0200 +++ b/graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/CodeCacheProvider.java Wed Jun 03 16:52:41 2015 +0200 @@ -22,9 +22,11 @@ */ package com.oracle.jvmci.code; -import com.oracle.jvmci.meta.*; +import com.oracle.jvmci.code.CompilationResult.Call; import com.oracle.jvmci.code.CompilationResult.DataPatch; +import com.oracle.jvmci.code.CompilationResult.Mark; import com.oracle.jvmci.code.DataSection.Data; +import com.oracle.jvmci.meta.*; /** * Access to code cache related details and requirements. @@ -54,16 +56,18 @@ InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult); /** - * Returns a disassembly of some compiled code. - * - * @param compResult some compiled code - * @param installedCode the result of installing the code in {@code compResult} or null if the - * code has not yet been installed - * - * @return a disassembly. This will be of length 0 if the runtime does not support - * disassembling. + * Gets a name for a {@link Mark} mark. */ - String disassemble(CompilationResult compResult, InstalledCode installedCode); + default String getMarkName(Mark mark) { + return String.valueOf(mark.id); + } + + /** + * Gets a name for the {@linkplain Call#target target} of a {@link Call}. + */ + default String getTargetName(Call call) { + return String.valueOf(call.target); + } /** * Gets the register configuration to use when compiling a given method. diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HexCodeFile.java --- a/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HexCodeFile.java Wed Jun 03 16:23:33 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,431 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.jvmci.hotspot; - -import java.io.*; -import java.util.*; -import java.util.regex.*; - -import com.oracle.jvmci.code.*; -import com.oracle.jvmci.code.CompilationResult.CodeAnnotation; -import com.oracle.jvmci.code.CompilationResult.CodeComment; -import com.oracle.jvmci.code.CompilationResult.JumpTable; - -/** - * A HexCodeFile is a textual format for representing a chunk of machine code along with extra - * information that can be used to enhance a disassembly of the code. - * - * A pseudo grammar for a HexCodeFile is given below. - * - *
- *     HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
- *
- *     OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
- *
- *     Platform ::= "Platform" ISA WordWidth
- *
- *     HexCode ::= "HexCode" StartAddress HexDigits
- *
- *     Comment ::= "Comment" Position String
- *
- *     OperandComment ::= "OperandComment" Position String
- *
- *     JumpTable ::= "JumpTable" Position EntrySize Low High
- *
- *     LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
- *
- *     Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
- *
- *     Delim := "<||@"
- * 
- * - * There must be exactly one HexCode and Platform part in a HexCodeFile. The length of HexDigits - * must be even as each pair of digits represents a single byte. - *

- * Below is an example of a valid Code input: - * - *

- *
- *  Platform AMD64 64  <||@
- *  HexCode 0 e8000000009090904883ec084889842410d0ffff48893c24e800000000488b3c24488bf0e8000000004883c408c3  <||@
- *  Comment 24 frame-ref-map: +0 {0}
- *  at java.lang.String.toLowerCase(String.java:2496) [bci: 1]
- *              |0
- *     locals:  |stack:0:a
- *     stack:   |stack:0:a
- *    <||@
- *  OperandComment 24 {java.util.Locale.getDefault()}  <||@
- *  Comment 36 frame-ref-map: +0 {0}
- *  at java.lang.String.toLowerCase(String.java:2496) [bci: 4]
- *              |0
- *     locals:  |stack:0:a
- *    <||@
- *  OperandComment 36 {java.lang.String.toLowerCase(Locale)}  lt;||@
- *
- * 
- */ -public class HexCodeFile { - - public static final String NEW_LINE = CodeUtil.NEW_LINE; - public static final String SECTION_DELIM = " <||@"; - public static final String COLUMN_END = " <|@"; - public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL); - public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL); - public static final Pattern OPERAND_COMMENT = COMMENT; - public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*"); - public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*"); - public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?"); - public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL); - - /** - * Delimiter placed before a HexCodeFile when embedded in a string/stream. - */ - public static final String EMBEDDED_HCF_OPEN = "<<> comments = new TreeMap<>(); - - /** - * Map from a machine code position to a comment for the operands of the instruction at the - * position. - */ - public final Map operandComments = new TreeMap<>(); - - public final byte[] code; - - public final ArrayList jumpTables = new ArrayList<>(); - - public final String isa; - - public final int wordWidth; - - public final long startAddress; - - public HexCodeFile(byte[] code, long startAddress, String isa, int wordWidth) { - this.code = code; - this.startAddress = startAddress; - this.isa = isa; - this.wordWidth = wordWidth; - } - - /** - * Parses a string in the format produced by {@link #toString()} to produce a - * {@link HexCodeFile} object. - */ - public static HexCodeFile parse(String input, int sourceOffset, String source, String sourceName) { - return new Parser(input, sourceOffset, source, sourceName).hcf; - } - - /** - * Formats this HexCodeFile as a string that can be parsed with - * {@link #parse(String, int, String, String)}. - */ - @Override - public String toString() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - writeTo(baos); - return baos.toString(); - } - - public String toEmbeddedString() { - return EMBEDDED_HCF_OPEN + NEW_LINE + toString() + EMBEDDED_HCF_CLOSE; - } - - public void writeTo(OutputStream out) { - PrintStream ps = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out); - ps.printf("Platform %s %d %s%n", isa, wordWidth, SECTION_DELIM); - ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM); - - for (JumpTable table : jumpTables) { - ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM); - } - - for (Map.Entry> e : comments.entrySet()) { - int pos = e.getKey(); - for (String comment : e.getValue()) { - ps.printf("Comment %d %s %s%n", pos, comment, SECTION_DELIM); - } - } - - for (Map.Entry e : operandComments.entrySet()) { - ps.printf("OperandComment %d %s %s%n", e.getKey(), e.getValue(), SECTION_DELIM); - } - ps.flush(); - } - - /** - * Formats a byte array as a string of hex digits. - */ - public static String hexCodeString(byte[] code) { - if (code == null) { - return ""; - } else { - StringBuilder sb = new StringBuilder(code.length * 2); - for (int b : code) { - String hex = Integer.toHexString(b & 0xff); - if (hex.length() == 1) { - sb.append('0'); - } - sb.append(hex); - } - return sb.toString(); - } - } - - /** - * Adds a comment to the list of comments for a given position. - */ - public void addComment(int pos, String comment) { - List list = comments.get(pos); - if (list == null) { - list = new ArrayList<>(); - comments.put(pos, list); - } - list.add(encodeString(comment)); - } - - /** - * Sets an operand comment for a given position. - * - * @return the previous operand comment for {@code pos} - */ - public String addOperandComment(int pos, String comment) { - return operandComments.put(pos, encodeString(comment)); - } - - /** - * Adds any jump tables, lookup tables or code comments from a list of code annotations. - */ - public static void addAnnotations(HexCodeFile hcf, List annotations) { - if (annotations == null || annotations.isEmpty()) { - return; - } - for (CodeAnnotation a : annotations) { - if (a instanceof JumpTable) { - JumpTable table = (JumpTable) a; - hcf.jumpTables.add(table); - } else if (a instanceof CodeComment) { - CodeComment comment = (CodeComment) a; - hcf.addComment(comment.position, comment.value); - } - } - } - - /** - * Modifies a string to mangle any substrings matching {@link #SECTION_DELIM} and - * {@link #COLUMN_END}. - */ - public static String encodeString(String input) { - int index; - String s = input; - while ((index = s.indexOf(SECTION_DELIM)) != -1) { - s = s.substring(0, index) + " < |@" + s.substring(index + SECTION_DELIM.length()); - } - while ((index = s.indexOf(COLUMN_END)) != -1) { - s = s.substring(0, index) + " < @" + s.substring(index + COLUMN_END.length()); - } - return s; - } - - /** - * Helper class to parse a string in the format produced by {@link HexCodeFile#toString()} and - * produce a {@link HexCodeFile} object. - */ - static class Parser { - - final String input; - final String inputSource; - String isa; - int wordWidth; - byte[] code; - long startAddress; - HexCodeFile hcf; - - Parser(String input, int sourceOffset, String source, String sourceName) { - this.input = input; - this.inputSource = sourceName; - parseSections(sourceOffset, source); - } - - void makeHCF() { - if (hcf == null) { - if (isa != null && wordWidth != 0 && code != null) { - hcf = new HexCodeFile(code, startAddress, isa, wordWidth); - } - } - } - - void checkHCF(String section, int offset) { - check(hcf != null, offset, section + " section must be after Platform and HexCode section"); - } - - void check(boolean condition, int offset, String message) { - if (!condition) { - error(offset, message); - } - } - - Error error(int offset, String message) { - throw new Error(errorMessage(offset, message)); - } - - void warning(int offset, String message) { - PrintStream err = System.err; - err.println("Warning: " + errorMessage(offset, message)); - } - - String errorMessage(int offset, String message) { - assert offset < input.length(); - InputPos inputPos = filePos(offset); - int lineEnd = input.indexOf(HexCodeFile.NEW_LINE, offset); - int lineStart = offset - inputPos.col; - String line = lineEnd == -1 ? input.substring(lineStart) : input.substring(lineStart, lineEnd); - return String.format("%s:%d: %s%n%s%n%" + (inputPos.col + 1) + "s", inputSource, inputPos.line, message, line, "^"); - } - - static class InputPos { - - final int line; - final int col; - - public InputPos(int line, int col) { - this.line = line; - this.col = col; - } - } - - InputPos filePos(int index) { - assert input != null; - int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1; - - String l = input.substring(lineStart, lineStart + 10); - PrintStream out = System.out; - out.println("YYY" + input.substring(index, index + 10) + "..."); - out.println("XXX" + l + "..."); - - int pos = input.indexOf(HexCodeFile.NEW_LINE, 0); - int line = 1; - while (pos > 0 && pos < index) { - line++; - pos = input.indexOf(HexCodeFile.NEW_LINE, pos + 1); - } - return new InputPos(line, index - lineStart); - } - - void parseSections(int offset, String source) { - assert input.startsWith(source, offset); - int index = 0; - int endIndex = source.indexOf(SECTION_DELIM); - while (endIndex != -1) { - while (source.charAt(index) <= ' ') { - index++; - } - String section = source.substring(index, endIndex).trim(); - parseSection(offset + index, section); - index = endIndex + SECTION_DELIM.length(); - endIndex = source.indexOf(SECTION_DELIM, index); - } - } - - int parseInt(int offset, String value) { - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - throw error(offset, "Not a valid integer: " + value); - } - } - - void parseSection(int offset, String section) { - if (section.isEmpty()) { - return; - } - assert input.startsWith(section, offset); - Matcher m = HexCodeFile.SECTION.matcher(section); - check(m.matches(), offset, "Section does not match pattern " + HexCodeFile.SECTION); - - String header = m.group(1); - String body = m.group(2); - int headerOffset = offset + m.start(1); - int bodyOffset = offset + m.start(2); - - if (header.equals("Platform")) { - check(isa == null, bodyOffset, "Duplicate Platform section found"); - m = HexCodeFile.PLATFORM.matcher(body); - check(m.matches(), bodyOffset, "Platform does not match pattern " + HexCodeFile.PLATFORM); - isa = m.group(1); - wordWidth = parseInt(bodyOffset + m.start(2), m.group(2)); - makeHCF(); - } else if (header.equals("HexCode")) { - check(code == null, bodyOffset, "Duplicate Code section found"); - m = HexCodeFile.HEX_CODE.matcher(body); - check(m.matches(), bodyOffset, "Code does not match pattern " + HexCodeFile.HEX_CODE); - String hexAddress = m.group(1); - startAddress = Long.valueOf(hexAddress, 16); - String hexCode = m.group(2); - if (hexCode == null) { - code = new byte[0]; - } else { - check((hexCode.length() % 2) == 0, bodyOffset, "Hex code length must be even"); - code = new byte[hexCode.length() / 2]; - for (int i = 0; i < code.length; i++) { - String hexByte = hexCode.substring(i * 2, (i + 1) * 2); - code[i] = (byte) Integer.parseInt(hexByte, 16); - } - } - makeHCF(); - } else if (header.equals("Comment")) { - checkHCF("Comment", headerOffset); - m = HexCodeFile.COMMENT.matcher(body); - check(m.matches(), bodyOffset, "Comment does not match pattern " + HexCodeFile.COMMENT); - int pos = parseInt(bodyOffset + m.start(1), m.group(1)); - String comment = m.group(2); - hcf.addComment(pos, comment); - } else if (header.equals("OperandComment")) { - checkHCF("OperandComment", headerOffset); - m = HexCodeFile.OPERAND_COMMENT.matcher(body); - check(m.matches(), bodyOffset, "OperandComment does not match pattern " + HexCodeFile.OPERAND_COMMENT); - int pos = parseInt(bodyOffset + m.start(1), m.group(1)); - String comment = m.group(2); - hcf.addOperandComment(pos, comment); - } else if (header.equals("JumpTable")) { - checkHCF("JumpTable", headerOffset); - m = HexCodeFile.JUMP_TABLE.matcher(body); - check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE); - int pos = parseInt(bodyOffset + m.start(1), m.group(1)); - int entrySize = parseInt(bodyOffset + m.start(2), m.group(2)); - int low = parseInt(bodyOffset + m.start(3), m.group(3)); - int high = parseInt(bodyOffset + m.start(4), m.group(4)); - hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize)); - } else { - error(offset, "Unknown section header: " + header); - } - } - } -} diff -r 729e6acde6c0 -r 4c00096fc415 graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotCodeCacheProvider.java --- a/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotCodeCacheProvider.java Wed Jun 03 16:23:33 2015 +0200 +++ b/graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotCodeCacheProvider.java Wed Jun 03 16:52:41 2015 +0200 @@ -25,15 +25,11 @@ import static com.oracle.jvmci.hotspot.HotSpotCompressedNullConstant.*; import java.lang.reflect.*; -import java.util.*; import com.oracle.jvmci.code.*; -import com.oracle.jvmci.code.CodeUtil.DefaultRefMapFormatter; -import com.oracle.jvmci.code.CodeUtil.RefMapFormatter; import com.oracle.jvmci.code.CompilationResult.Call; import com.oracle.jvmci.code.CompilationResult.ConstantReference; import com.oracle.jvmci.code.CompilationResult.DataPatch; -import com.oracle.jvmci.code.CompilationResult.Infopoint; import com.oracle.jvmci.code.CompilationResult.Mark; import com.oracle.jvmci.code.DataSection.Data; import com.oracle.jvmci.code.DataSection.DataBuilder; @@ -59,75 +55,8 @@ } @Override - public String disassemble(CompilationResult compResult, InstalledCode installedCode) { - byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); - if (code == null) { - // Method was deoptimized/invalidated - return ""; - } - long start = installedCode == null ? 0L : installedCode.getStart(); - HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); - if (compResult != null) { - HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); - addExceptionHandlersComment(compResult, hcf); - Register fp = regConfig.getFrameRegister(); - RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.arch, target.wordSize, fp, 0); - for (Infopoint infopoint : compResult.getInfopoints()) { - if (infopoint instanceof Call) { - Call call = (Call) infopoint; - if (call.debugInfo != null) { - hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); - } - addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); - } else { - if (infopoint.debugInfo != null) { - hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); - } - addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); - } - } - for (DataPatch site : compResult.getDataPatches()) { - hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}"); - } - for (Mark mark : compResult.getMarks()) { - hcf.addComment(mark.pcOffset, getMarkIdName((int) mark.id)); - } - } - String hcfEmbeddedString = hcf.toEmbeddedString(); - return HexCodeFileDisTool.tryDisassemble(hcfEmbeddedString); - } - - /** - * Interface to the tool for disassembling an {@link HexCodeFile#toEmbeddedString() embedded} - * {@link HexCodeFile}. - */ - static class HexCodeFileDisTool { - static final Method processMethod; - static { - Method toolMethod = null; - try { - Class toolClass = Class.forName("com.oracle.max.hcfdis.HexCodeFileDis", true, ClassLoader.getSystemClassLoader()); - toolMethod = toolClass.getDeclaredMethod("processEmbeddedString", String.class); - } catch (Exception e) { - // Tool not available on the class path - } - processMethod = toolMethod; - } - - public static String tryDisassemble(String hcfEmbeddedString) { - if (processMethod != null) { - try { - return (String) processMethod.invoke(null, hcfEmbeddedString); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - // If the tool is available, for now let's be noisy when it fails - throw new JVMCIError(e); - } - } - return hcfEmbeddedString; - } - } - - private String getMarkIdName(int markId) { + public String getMarkName(Mark mark) { + int markId = (int) mark.id; Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); for (Field f : fields) { if (f.getName().startsWith("MARKID_")) { @@ -140,13 +69,14 @@ } } } - return String.valueOf(markId); + return CodeCacheProvider.super.getMarkName(mark); } /** * Decodes a call target to a mnemonic if possible. */ - private String getTargetName(Call call) { + @Override + public String getTargetName(Call call) { Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); for (Field f : fields) { if (f.getName().endsWith("Stub")) { @@ -160,25 +90,7 @@ } } } - return String.valueOf(call.target); - } - - private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) { - if (!compResult.getExceptionHandlers().isEmpty()) { - String nl = HexCodeFile.NEW_LINE; - StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl); - for (CompilationResult.ExceptionHandler e : compResult.getExceptionHandlers()) { - buf.append(" ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl); - hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]"); - hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]"); - } - hcf.addComment(0, buf.toString()); - } - } - - private static void addOperandComment(HexCodeFile hcf, int pos, String comment) { - String oldValue = hcf.addOperandComment(pos, comment); - assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue; + return CodeCacheProvider.super.getTargetName(call); } @Override