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