comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HexCodeFile.java @ 21551:5324104ac4f3

moved com.oracle.graal.hotspot.jvmci classes to com.oracle.jvmci.hotspot module (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Tue, 26 May 2015 17:13:37 +0200
parents
children
comparison
equal deleted inserted replaced
21550:f48a6cea31eb 21551:5324104ac4f3
1 /*
2 * Copyright (c) 2009, 2011, 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 com.oracle.jvmci.hotspot;
24
25 import java.io.*;
26 import java.util.*;
27 import java.util.regex.*;
28
29 import com.oracle.graal.api.code.*;
30 import com.oracle.graal.api.code.CompilationResult.CodeAnnotation;
31 import com.oracle.graal.api.code.CompilationResult.CodeComment;
32 import com.oracle.graal.api.code.CompilationResult.JumpTable;
33
34 /**
35 * A HexCodeFile is a textual format for representing a chunk of machine code along with extra
36 * information that can be used to enhance a disassembly of the code.
37 *
38 * A pseudo grammar for a HexCodeFile is given below.
39 *
40 * <pre>
41 * HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
42 *
43 * OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
44 *
45 * Platform ::= "Platform" ISA WordWidth
46 *
47 * HexCode ::= "HexCode" StartAddress HexDigits
48 *
49 * Comment ::= "Comment" Position String
50 *
51 * OperandComment ::= "OperandComment" Position String
52 *
53 * JumpTable ::= "JumpTable" Position EntrySize Low High
54 *
55 * LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
56 *
57 * Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
58 *
59 * Delim := "&lt;||@"
60 * </pre>
61 *
62 * There must be exactly one HexCode and Platform part in a HexCodeFile. The length of HexDigits
63 * must be even as each pair of digits represents a single byte.
64 * <p>
65 * Below is an example of a valid Code input:
66 *
67 * <pre>
68 *
69 * Platform AMD64 64 &lt;||@
70 * HexCode 0 e8000000009090904883ec084889842410d0ffff48893c24e800000000488b3c24488bf0e8000000004883c408c3 &lt;||@
71 * Comment 24 frame-ref-map: +0 {0}
72 * at java.lang.String.toLowerCase(String.java:2496) [bci: 1]
73 * |0
74 * locals: |stack:0:a
75 * stack: |stack:0:a
76 * &lt;||@
77 * OperandComment 24 {java.util.Locale.getDefault()} &lt;||@
78 * Comment 36 frame-ref-map: +0 {0}
79 * at java.lang.String.toLowerCase(String.java:2496) [bci: 4]
80 * |0
81 * locals: |stack:0:a
82 * &lt;||@
83 * OperandComment 36 {java.lang.String.toLowerCase(Locale)} lt;||@
84 *
85 * </pre>
86 */
87 public class HexCodeFile {
88
89 public static final String NEW_LINE = CodeUtil.NEW_LINE;
90 public static final String SECTION_DELIM = " <||@";
91 public static final String COLUMN_END = " <|@";
92 public static final Pattern SECTION = Pattern.compile("(\\S+)\\s+(.*)", Pattern.DOTALL);
93 public static final Pattern COMMENT = Pattern.compile("(\\d+)\\s+(.*)", Pattern.DOTALL);
94 public static final Pattern OPERAND_COMMENT = COMMENT;
95 public static final Pattern JUMP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(-{0,1}\\d+)\\s+(-{0,1}\\d+)\\s*");
96 public static final Pattern LOOKUP_TABLE = Pattern.compile("(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*");
97 public static final Pattern HEX_CODE = Pattern.compile("(\\p{XDigit}+)(?:\\s+(\\p{XDigit}*))?");
98 public static final Pattern PLATFORM = Pattern.compile("(\\S+)\\s+(\\S+)", Pattern.DOTALL);
99
100 /**
101 * Delimiter placed before a HexCodeFile when embedded in a string/stream.
102 */
103 public static final String EMBEDDED_HCF_OPEN = "<<<HexCodeFile";
104
105 /**
106 * Delimiter placed after a HexCodeFile when embedded in a string/stream.
107 */
108 public static final String EMBEDDED_HCF_CLOSE = "HexCodeFile>>>";
109
110 /**
111 * Map from a machine code position to a list of comments for the position.
112 */
113 public final Map<Integer, List<String>> comments = new TreeMap<>();
114
115 /**
116 * Map from a machine code position to a comment for the operands of the instruction at the
117 * position.
118 */
119 public final Map<Integer, String> operandComments = new TreeMap<>();
120
121 public final byte[] code;
122
123 public final ArrayList<JumpTable> jumpTables = new ArrayList<>();
124
125 public final String isa;
126
127 public final int wordWidth;
128
129 public final long startAddress;
130
131 public HexCodeFile(byte[] code, long startAddress, String isa, int wordWidth) {
132 this.code = code;
133 this.startAddress = startAddress;
134 this.isa = isa;
135 this.wordWidth = wordWidth;
136 }
137
138 /**
139 * Parses a string in the format produced by {@link #toString()} to produce a
140 * {@link HexCodeFile} object.
141 */
142 public static HexCodeFile parse(String input, int sourceOffset, String source, String sourceName) {
143 return new Parser(input, sourceOffset, source, sourceName).hcf;
144 }
145
146 /**
147 * Formats this HexCodeFile as a string that can be parsed with
148 * {@link #parse(String, int, String, String)}.
149 */
150 @Override
151 public String toString() {
152 ByteArrayOutputStream baos = new ByteArrayOutputStream();
153 writeTo(baos);
154 return baos.toString();
155 }
156
157 public String toEmbeddedString() {
158 return EMBEDDED_HCF_OPEN + NEW_LINE + toString() + EMBEDDED_HCF_CLOSE;
159 }
160
161 public void writeTo(OutputStream out) {
162 PrintStream ps = out instanceof PrintStream ? (PrintStream) out : new PrintStream(out);
163 ps.printf("Platform %s %d %s%n", isa, wordWidth, SECTION_DELIM);
164 ps.printf("HexCode %x %s %s%n", startAddress, HexCodeFile.hexCodeString(code), SECTION_DELIM);
165
166 for (JumpTable table : jumpTables) {
167 ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM);
168 }
169
170 for (Map.Entry<Integer, List<String>> e : comments.entrySet()) {
171 int pos = e.getKey();
172 for (String comment : e.getValue()) {
173 ps.printf("Comment %d %s %s%n", pos, comment, SECTION_DELIM);
174 }
175 }
176
177 for (Map.Entry<Integer, String> e : operandComments.entrySet()) {
178 ps.printf("OperandComment %d %s %s%n", e.getKey(), e.getValue(), SECTION_DELIM);
179 }
180 ps.flush();
181 }
182
183 /**
184 * Formats a byte array as a string of hex digits.
185 */
186 public static String hexCodeString(byte[] code) {
187 if (code == null) {
188 return "";
189 } else {
190 StringBuilder sb = new StringBuilder(code.length * 2);
191 for (int b : code) {
192 String hex = Integer.toHexString(b & 0xff);
193 if (hex.length() == 1) {
194 sb.append('0');
195 }
196 sb.append(hex);
197 }
198 return sb.toString();
199 }
200 }
201
202 /**
203 * Adds a comment to the list of comments for a given position.
204 */
205 public void addComment(int pos, String comment) {
206 List<String> list = comments.get(pos);
207 if (list == null) {
208 list = new ArrayList<>();
209 comments.put(pos, list);
210 }
211 list.add(encodeString(comment));
212 }
213
214 /**
215 * Sets an operand comment for a given position.
216 *
217 * @return the previous operand comment for {@code pos}
218 */
219 public String addOperandComment(int pos, String comment) {
220 return operandComments.put(pos, encodeString(comment));
221 }
222
223 /**
224 * Adds any jump tables, lookup tables or code comments from a list of code annotations.
225 */
226 public static void addAnnotations(HexCodeFile hcf, List<CodeAnnotation> annotations) {
227 if (annotations == null || annotations.isEmpty()) {
228 return;
229 }
230 for (CodeAnnotation a : annotations) {
231 if (a instanceof JumpTable) {
232 JumpTable table = (JumpTable) a;
233 hcf.jumpTables.add(table);
234 } else if (a instanceof CodeComment) {
235 CodeComment comment = (CodeComment) a;
236 hcf.addComment(comment.position, comment.value);
237 }
238 }
239 }
240
241 /**
242 * Modifies a string to mangle any substrings matching {@link #SECTION_DELIM} and
243 * {@link #COLUMN_END}.
244 */
245 public static String encodeString(String input) {
246 int index;
247 String s = input;
248 while ((index = s.indexOf(SECTION_DELIM)) != -1) {
249 s = s.substring(0, index) + " < |@" + s.substring(index + SECTION_DELIM.length());
250 }
251 while ((index = s.indexOf(COLUMN_END)) != -1) {
252 s = s.substring(0, index) + " < @" + s.substring(index + COLUMN_END.length());
253 }
254 return s;
255 }
256
257 /**
258 * Helper class to parse a string in the format produced by {@link HexCodeFile#toString()} and
259 * produce a {@link HexCodeFile} object.
260 */
261 static class Parser {
262
263 final String input;
264 final String inputSource;
265 String isa;
266 int wordWidth;
267 byte[] code;
268 long startAddress;
269 HexCodeFile hcf;
270
271 Parser(String input, int sourceOffset, String source, String sourceName) {
272 this.input = input;
273 this.inputSource = sourceName;
274 parseSections(sourceOffset, source);
275 }
276
277 void makeHCF() {
278 if (hcf == null) {
279 if (isa != null && wordWidth != 0 && code != null) {
280 hcf = new HexCodeFile(code, startAddress, isa, wordWidth);
281 }
282 }
283 }
284
285 void checkHCF(String section, int offset) {
286 check(hcf != null, offset, section + " section must be after Platform and HexCode section");
287 }
288
289 void check(boolean condition, int offset, String message) {
290 if (!condition) {
291 error(offset, message);
292 }
293 }
294
295 Error error(int offset, String message) {
296 throw new Error(errorMessage(offset, message));
297 }
298
299 void warning(int offset, String message) {
300 PrintStream err = System.err;
301 err.println("Warning: " + errorMessage(offset, message));
302 }
303
304 String errorMessage(int offset, String message) {
305 assert offset < input.length();
306 InputPos inputPos = filePos(offset);
307 int lineEnd = input.indexOf(HexCodeFile.NEW_LINE, offset);
308 int lineStart = offset - inputPos.col;
309 String line = lineEnd == -1 ? input.substring(lineStart) : input.substring(lineStart, lineEnd);
310 return String.format("%s:%d: %s%n%s%n%" + (inputPos.col + 1) + "s", inputSource, inputPos.line, message, line, "^");
311 }
312
313 static class InputPos {
314
315 final int line;
316 final int col;
317
318 public InputPos(int line, int col) {
319 this.line = line;
320 this.col = col;
321 }
322 }
323
324 InputPos filePos(int index) {
325 assert input != null;
326 int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1;
327
328 String l = input.substring(lineStart, lineStart + 10);
329 PrintStream out = System.out;
330 out.println("YYY" + input.substring(index, index + 10) + "...");
331 out.println("XXX" + l + "...");
332
333 int pos = input.indexOf(HexCodeFile.NEW_LINE, 0);
334 int line = 1;
335 while (pos > 0 && pos < index) {
336 line++;
337 pos = input.indexOf(HexCodeFile.NEW_LINE, pos + 1);
338 }
339 return new InputPos(line, index - lineStart);
340 }
341
342 void parseSections(int offset, String source) {
343 assert input.startsWith(source, offset);
344 int index = 0;
345 int endIndex = source.indexOf(SECTION_DELIM);
346 while (endIndex != -1) {
347 while (source.charAt(index) <= ' ') {
348 index++;
349 }
350 String section = source.substring(index, endIndex).trim();
351 parseSection(offset + index, section);
352 index = endIndex + SECTION_DELIM.length();
353 endIndex = source.indexOf(SECTION_DELIM, index);
354 }
355 }
356
357 int parseInt(int offset, String value) {
358 try {
359 return Integer.parseInt(value);
360 } catch (NumberFormatException e) {
361 throw error(offset, "Not a valid integer: " + value);
362 }
363 }
364
365 void parseSection(int offset, String section) {
366 if (section.isEmpty()) {
367 return;
368 }
369 assert input.startsWith(section, offset);
370 Matcher m = HexCodeFile.SECTION.matcher(section);
371 check(m.matches(), offset, "Section does not match pattern " + HexCodeFile.SECTION);
372
373 String header = m.group(1);
374 String body = m.group(2);
375 int headerOffset = offset + m.start(1);
376 int bodyOffset = offset + m.start(2);
377
378 if (header.equals("Platform")) {
379 check(isa == null, bodyOffset, "Duplicate Platform section found");
380 m = HexCodeFile.PLATFORM.matcher(body);
381 check(m.matches(), bodyOffset, "Platform does not match pattern " + HexCodeFile.PLATFORM);
382 isa = m.group(1);
383 wordWidth = parseInt(bodyOffset + m.start(2), m.group(2));
384 makeHCF();
385 } else if (header.equals("HexCode")) {
386 check(code == null, bodyOffset, "Duplicate Code section found");
387 m = HexCodeFile.HEX_CODE.matcher(body);
388 check(m.matches(), bodyOffset, "Code does not match pattern " + HexCodeFile.HEX_CODE);
389 String hexAddress = m.group(1);
390 startAddress = Long.valueOf(hexAddress, 16);
391 String hexCode = m.group(2);
392 if (hexCode == null) {
393 code = new byte[0];
394 } else {
395 check((hexCode.length() % 2) == 0, bodyOffset, "Hex code length must be even");
396 code = new byte[hexCode.length() / 2];
397 for (int i = 0; i < code.length; i++) {
398 String hexByte = hexCode.substring(i * 2, (i + 1) * 2);
399 code[i] = (byte) Integer.parseInt(hexByte, 16);
400 }
401 }
402 makeHCF();
403 } else if (header.equals("Comment")) {
404 checkHCF("Comment", headerOffset);
405 m = HexCodeFile.COMMENT.matcher(body);
406 check(m.matches(), bodyOffset, "Comment does not match pattern " + HexCodeFile.COMMENT);
407 int pos = parseInt(bodyOffset + m.start(1), m.group(1));
408 String comment = m.group(2);
409 hcf.addComment(pos, comment);
410 } else if (header.equals("OperandComment")) {
411 checkHCF("OperandComment", headerOffset);
412 m = HexCodeFile.OPERAND_COMMENT.matcher(body);
413 check(m.matches(), bodyOffset, "OperandComment does not match pattern " + HexCodeFile.OPERAND_COMMENT);
414 int pos = parseInt(bodyOffset + m.start(1), m.group(1));
415 String comment = m.group(2);
416 hcf.addOperandComment(pos, comment);
417 } else if (header.equals("JumpTable")) {
418 checkHCF("JumpTable", headerOffset);
419 m = HexCodeFile.JUMP_TABLE.matcher(body);
420 check(m.matches(), bodyOffset, "JumpTable does not match pattern " + HexCodeFile.JUMP_TABLE);
421 int pos = parseInt(bodyOffset + m.start(1), m.group(1));
422 int entrySize = parseInt(bodyOffset + m.start(2), m.group(2));
423 int low = parseInt(bodyOffset + m.start(3), m.group(3));
424 int high = parseInt(bodyOffset + m.start(4), m.group(4));
425 hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize));
426 } else {
427 error(offset, "Unknown section header: " + header);
428 }
429 }
430 }
431 }