comparison graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/CodeUtil.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java@93215cb4a2f9
children f5b549811bac
comparison
equal deleted inserted replaced
21555:d12eaef9af72 21556:48c1ebd24120
1 /*
2 * Copyright (c) 2010, 2013, 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.code;
24
25 import com.oracle.jvmci.meta.Signature;
26 import com.oracle.jvmci.meta.ResolvedJavaMethod;
27 import com.oracle.jvmci.meta.JavaType;
28 import com.oracle.jvmci.meta.MetaUtil;
29 import java.util.*;
30
31
32 /**
33 * Miscellaneous collection of utility methods used by {@code com.oracle.jvmci.code} and its
34 * clients.
35 */
36 public class CodeUtil {
37
38 public static final String NEW_LINE = String.format("%n");
39
40 public static final int K = 1024;
41 public static final int M = 1024 * 1024;
42
43 public static boolean isOdd(int n) {
44 return (n & 1) == 1;
45 }
46
47 public static boolean isEven(int n) {
48 return (n & 1) == 0;
49 }
50
51 /**
52 * Checks whether the specified integer is a power of two.
53 *
54 * @param val the value to check
55 * @return {@code true} if the value is a power of two; {@code false} otherwise
56 */
57 public static boolean isPowerOf2(int val) {
58 return val > 0 && (val & val - 1) == 0;
59 }
60
61 /**
62 * Checks whether the specified long is a power of two.
63 *
64 * @param val the value to check
65 * @return {@code true} if the value is a power of two; {@code false} otherwise
66 */
67 public static boolean isPowerOf2(long val) {
68 return val > 0 && (val & val - 1) == 0;
69 }
70
71 /**
72 * Computes the log (base 2) of the specified integer, rounding down. (E.g {@code log2(8) = 3},
73 * {@code log2(21) = 4} )
74 *
75 * @param val the value
76 * @return the log base 2 of the value
77 */
78 public static int log2(int val) {
79 assert val > 0;
80 return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val);
81 }
82
83 /**
84 * Computes the log (base 2) of the specified long, rounding down. (E.g {@code log2(8) = 3},
85 * {@code log2(21) = 4})
86 *
87 * @param val the value
88 * @return the log base 2 of the value
89 */
90 public static int log2(long val) {
91 assert val > 0;
92 return (Long.SIZE - 1) - Long.numberOfLeadingZeros(val);
93 }
94
95 /**
96 * Narrow an integer value to a given bit width, and return the result as a signed long.
97 *
98 * @param value the value
99 * @param resultBits the result bit width
100 * @return {@code value} interpreted as {@code resultBits} bit number, encoded as signed long
101 */
102 public static long narrow(long value, int resultBits) {
103 long ret = value & mask(resultBits);
104 return signExtend(ret, resultBits);
105 }
106
107 /**
108 * Sign extend an integer.
109 *
110 * @param value the input value
111 * @param inputBits the bit width of the input value
112 * @return a signed long with the same value as the signed {@code inputBits}-bit number
113 * {@code value}
114 */
115 public static long signExtend(long value, int inputBits) {
116 if (inputBits < 64) {
117 if ((value >>> (inputBits - 1) & 1) == 1) {
118 return value | (-1L << inputBits);
119 } else {
120 return value & ~(-1L << inputBits);
121 }
122 } else {
123 return value;
124 }
125 }
126
127 /**
128 * Zero extend an integer.
129 *
130 * @param value the input value
131 * @param inputBits the bit width of the input value
132 * @return an unsigned long with the same value as the unsigned {@code inputBits}-bit number
133 * {@code value}
134 */
135 public static long zeroExtend(long value, int inputBits) {
136 if (inputBits < 64) {
137 return value & ~(-1L << inputBits);
138 } else {
139 return value;
140 }
141 }
142
143 /**
144 * Convert an integer to long.
145 *
146 * @param value the input value
147 * @param inputBits the bit width of the input value
148 * @param unsigned whether the values should be interpreted as signed or unsigned
149 * @return a long with the same value as the {@code inputBits}-bit number {@code value}
150 */
151 public static long convert(long value, int inputBits, boolean unsigned) {
152 if (unsigned) {
153 return zeroExtend(value, inputBits);
154 } else {
155 return signExtend(value, inputBits);
156 }
157 }
158
159 /**
160 * Get a bitmask with the low {@code bits} bit set and the high {@code 64 - bits} bit clear.
161 */
162 public static long mask(int bits) {
163 assert 0 <= bits && bits <= 64;
164 if (bits == 64) {
165 return 0xffffffffffffffffL;
166 } else {
167 return (1L << bits) - 1;
168 }
169 }
170
171 /**
172 * Get the minimum value representable in a {@code bits} bit signed integer.
173 */
174 public static long minValue(int bits) {
175 assert 0 < bits && bits <= 64;
176 return -1L << (bits - 1);
177 }
178
179 /**
180 * Get the maximum value representable in a {@code bits} bit signed integer.
181 */
182 public static long maxValue(int bits) {
183 assert 0 < bits && bits <= 64;
184 return mask(bits - 1);
185 }
186
187 /**
188 * Formats the values in a frame as a tabulated string.
189 *
190 * @param frame
191 * @return the values in {@code frame} as a tabulated string
192 */
193 public static String tabulateValues(BytecodeFrame frame) {
194 int cols = Math.max(frame.numLocals, Math.max(frame.numStack, frame.numLocks));
195 assert cols > 0;
196 ArrayList<Object> cells = new ArrayList<>();
197 cells.add("");
198 for (int i = 0; i < cols; i++) {
199 cells.add(i);
200 }
201 cols++;
202 if (frame.numLocals != 0) {
203 cells.add("locals:");
204 cells.addAll(Arrays.asList(frame.values).subList(0, frame.numLocals));
205 cells.addAll(Collections.nCopies(cols - frame.numLocals - 1, ""));
206 }
207 if (frame.numStack != 0) {
208 cells.add("stack:");
209 cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals, frame.numLocals + frame.numStack));
210 cells.addAll(Collections.nCopies(cols - frame.numStack - 1, ""));
211 }
212 if (frame.numLocks != 0) {
213 cells.add("locks:");
214 cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals + frame.numStack, frame.values.length));
215 cells.addAll(Collections.nCopies(cols - frame.numLocks - 1, ""));
216 }
217 Object[] cellArray = cells.toArray();
218 for (int i = 0; i < cellArray.length; i++) {
219 if ((i % cols) != 0) {
220 cellArray[i] = "|" + cellArray[i];
221 }
222 }
223 return CodeUtil.tabulate(cellArray, cols, 1, 1);
224 }
225
226 /**
227 * Formats a given table as a string. The value of each cell is produced by
228 * {@link String#valueOf(Object)}.
229 *
230 * @param cells the cells of the table in row-major order
231 * @param cols the number of columns per row
232 * @param lpad the number of space padding inserted before each formatted cell value
233 * @param rpad the number of space padding inserted after each formatted cell value
234 * @return a string with one line per row and each column left-aligned
235 */
236 public static String tabulate(Object[] cells, int cols, int lpad, int rpad) {
237 int rows = (cells.length + (cols - 1)) / cols;
238 int[] colWidths = new int[cols];
239 for (int col = 0; col < cols; col++) {
240 for (int row = 0; row < rows; row++) {
241 int index = col + (row * cols);
242 if (index < cells.length) {
243 Object cell = cells[index];
244 colWidths[col] = Math.max(colWidths[col], String.valueOf(cell).length());
245 }
246 }
247 }
248 StringBuilder sb = new StringBuilder();
249 String nl = NEW_LINE;
250 for (int row = 0; row < rows; row++) {
251 for (int col = 0; col < cols; col++) {
252 int index = col + (row * cols);
253 if (index < cells.length) {
254 for (int i = 0; i < lpad; i++) {
255 sb.append(' ');
256 }
257 Object cell = cells[index];
258 String s = String.valueOf(cell);
259 int w = s.length();
260 sb.append(s);
261 while (w < colWidths[col]) {
262 sb.append(' ');
263 w++;
264 }
265 for (int i = 0; i < rpad; i++) {
266 sb.append(' ');
267 }
268 }
269 }
270 sb.append(nl);
271 }
272 return sb.toString();
273 }
274
275 /**
276 * Appends a formatted code position to a {@link StringBuilder}.
277 *
278 * @param sb the {@link StringBuilder} to append to
279 * @param pos the code position to format and append to {@code sb}
280 * @return the value of {@code sb}
281 */
282 public static StringBuilder append(StringBuilder sb, BytecodePosition pos) {
283 MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
284 if (pos.getCaller() != null) {
285 sb.append(NEW_LINE);
286 append(sb, pos.getCaller());
287 }
288 return sb;
289 }
290
291 /**
292 * Appends a formatted frame to a {@link StringBuilder}.
293 *
294 * @param sb the {@link StringBuilder} to append to
295 * @param frame the frame to format and append to {@code sb}
296 * @return the value of {@code sb}
297 */
298 public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) {
299 MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI());
300 assert sb.charAt(sb.length() - 1) == ']';
301 sb.deleteCharAt(sb.length() - 1);
302 sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']');
303 if (frame.values != null && frame.values.length > 0) {
304 sb.append(NEW_LINE);
305 String table = tabulateValues(frame);
306 String[] rows = table.split(NEW_LINE);
307 for (int i = 0; i < rows.length; i++) {
308 String row = rows[i];
309 if (!row.trim().isEmpty()) {
310 sb.append(" ").append(row);
311 if (i != rows.length - 1) {
312 sb.append(NEW_LINE);
313 }
314 }
315 }
316 }
317 if (frame.caller() != null) {
318 sb.append(NEW_LINE);
319 append(sb, frame.caller());
320 } else if (frame.getCaller() != null) {
321 sb.append(NEW_LINE);
322 append(sb, frame.getCaller());
323 }
324 return sb;
325 }
326
327 public interface RefMapFormatter {
328
329 String formatStackSlot(int frameRefMapIndex);
330
331 String formatRegister(int regRefMapIndex);
332 }
333
334 /**
335 * Formats a location in a register reference map.
336 */
337 public static class DefaultRegFormatter implements RefMapFormatter {
338
339 private final Register[] registers;
340
341 public DefaultRegFormatter(Architecture arch) {
342 registers = new Register[arch.getRegisterReferenceMapSize()];
343 for (Register r : arch.getRegisters()) {
344 if (r.getReferenceMapIndex() >= 0) {
345 registers[r.getReferenceMapIndex()] = r;
346 }
347 }
348 }
349
350 public String formatStackSlot(int frameRefMapIndex) {
351 return null;
352 }
353
354 public String formatRegister(int regRefMapIndex) {
355 int i = regRefMapIndex;
356 int idx = 0;
357 while (registers[i] == null) {
358 i--;
359 idx++;
360 }
361 if (idx == 0) {
362 return registers[i].toString();
363 } else {
364 return String.format("%s+%d", registers[i].toString(), idx);
365 }
366 }
367 }
368
369 /**
370 * Formats a location present in a register or frame reference map.
371 */
372 public static class DefaultRefMapFormatter extends DefaultRegFormatter {
373
374 /**
375 * The size of a stack slot.
376 */
377 public final int slotSize;
378
379 /**
380 * The register used as the frame pointer.
381 */
382 public final Register fp;
383
384 /**
385 * The offset (in bytes) from the slot pointed to by {@link #fp} to the slot corresponding
386 * to bit 0 in the frame reference map.
387 */
388 public final int refMapToFPOffset;
389
390 public DefaultRefMapFormatter(Architecture arch, int slotSize, Register fp, int refMapToFPOffset) {
391 super(arch);
392 this.slotSize = slotSize;
393 this.fp = fp;
394 this.refMapToFPOffset = refMapToFPOffset;
395 }
396
397 @Override
398 public String formatStackSlot(int frameRefMapIndex) {
399 int refMapOffset = frameRefMapIndex * slotSize;
400 int fpOffset = refMapOffset + refMapToFPOffset;
401 if (fpOffset >= 0) {
402 return fp + "+" + fpOffset;
403 }
404 return fp.name + fpOffset;
405 }
406 }
407
408 public static class NumberedRefMapFormatter implements RefMapFormatter {
409
410 public String formatStackSlot(int frameRefMapIndex) {
411 return "s" + frameRefMapIndex;
412 }
413
414 public String formatRegister(int regRefMapIndex) {
415 return "r" + regRefMapIndex;
416 }
417 }
418
419 /**
420 * Appends a formatted debug info to a {@link StringBuilder}.
421 *
422 * @param sb the {@link StringBuilder} to append to
423 * @param info the debug info to format and append to {@code sb}
424 * @return the value of {@code sb}
425 */
426 public static StringBuilder append(StringBuilder sb, DebugInfo info, RefMapFormatter formatterArg) {
427 RefMapFormatter formatter = formatterArg;
428 if (formatter == null) {
429 formatter = new NumberedRefMapFormatter();
430 }
431 String nl = NEW_LINE;
432 ReferenceMap refMap = info.getReferenceMap();
433 if (refMap != null && refMap.hasRegisterRefMap()) {
434 sb.append(" reg-ref-map:");
435 refMap.appendRegisterMap(sb, formatter);
436 sb.append(nl);
437 }
438 if (refMap != null && refMap.hasFrameRefMap()) {
439 sb.append("frame-ref-map:");
440 refMap.appendFrameMap(sb, formatter);
441 sb.append(nl);
442 }
443 RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
444 if (calleeSaveInfo != null) {
445 sb.append("callee-save-info:").append(nl);
446 Map<Integer, Register> map = calleeSaveInfo.slotsToRegisters(true);
447 for (Map.Entry<Integer, Register> e : map.entrySet()) {
448 sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl);
449 }
450 }
451 BytecodeFrame frame = info.frame();
452 if (frame != null) {
453 append(sb, frame);
454 } else if (info.getBytecodePosition() != null) {
455 append(sb, info.getBytecodePosition());
456 }
457 return sb;
458 }
459
460 /**
461 * Create a calling convention from a {@link ResolvedJavaMethod}.
462 */
463 public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) {
464 Signature sig = method.getSignature();
465 JavaType retType = sig.getReturnType(null);
466 int sigCount = sig.getParameterCount(false);
467 JavaType[] argTypes;
468 int argIndex = 0;
469 if (!method.isStatic()) {
470 argTypes = new JavaType[sigCount + 1];
471 argTypes[argIndex++] = method.getDeclaringClass();
472 } else {
473 argTypes = new JavaType[sigCount];
474 }
475 for (int i = 0; i < sigCount; i++) {
476 argTypes[argIndex++] = sig.getParameterType(i, null);
477 }
478
479 RegisterConfig registerConfig = codeCache.getRegisterConfig();
480 return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly);
481 }
482 }