# HG changeset patch # User Thomas Wuerthinger # Date 1339427166 -7200 # Node ID 102f87543d5e2a3e8ec91fd720c08aa33e474227 # Parent 30162e74f11f7d9b5e06240d36656eb5d7c2a4da# Parent 6a26710662046d24172e2604fc6d1e922450ea62 Merge. diff -r 6a2671066204 -r 102f87543d5e GRAAL_AUTHORS --- a/GRAAL_AUTHORS Mon Jun 11 15:39:57 2012 +0200 +++ b/GRAAL_AUTHORS Mon Jun 11 17:06:06 2012 +0200 @@ -1,20 +1,7 @@ -Doug Simon (doug.simon@oracle.com) -* Since December 2011 - -Christian Wimmer (christian.wimmer@oracle.com) -* Since December 2011 - -Lukas Stadler (stadler@ssw.jku.at) -* July - September 2010: Initial feature-complete implementation, remote compilation -* Since April 2011: New IR design - -Gilles Duboscq (gilles.duboscq@oracle.com) -* Since April 2011: New IR design - -Peter Hofer (hofer@ssw.jku.at) -* Since May 2011: Graphviz visualization - -Thomas Wuerthinger (thomas.wuerthinger@oracle.com) -* June 2011: Initial prototype -* October 2010 - January 2011: Bug fixes (all DaCapo's pass), better performance on SciMark than C1 -* Since April 2011: New IR design +Gilles Duboscq (gdub) +Peter Hofer +Christian Humer (chumer) +Christian Wimmer (cwimmer) +Doug Simon (dnsimon) +Lukas Stadler (lstadler) +Thomas Wuerthinger (thomaswue) diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/HelloWorldTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/HelloWorldTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2012, 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.boot; + + +public class HelloWorldTest { + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/test/helloworld/HelloWorldTestProgram.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/test/helloworld/HelloWorldTestProgram.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, 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.boot.test.helloworld; + + +public class HelloWorldTestProgram { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageGenerator.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2012, 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.boot; + + +public class BootImageGenerator { + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,67 @@ +/* + * 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.bytecode; + +/** + * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes. + */ +public class BytecodeLookupSwitch extends BytecodeSwitch { + private static final int OFFSET_TO_NUMBER_PAIRS = 4; + private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8; + private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12; + private static final int PAIR_SIZE = 8; + + /** + * Constructor for a {@link BytecodeStream}. + * @param stream the {@code BytecodeStream} containing the switch instruction + * @param bci the index in the stream of the switch instruction + */ + public BytecodeLookupSwitch(BytecodeStream stream, int bci) { + super(stream, bci); + } + + @Override + public int defaultOffset() { + return stream.readInt(alignedBci); + } + + @Override + public int offsetAt(int i) { + return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_OFFSET + PAIR_SIZE * i); + } + + @Override + public int keyAt(int i) { + return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * i); + } + + @Override + public int numberOfCases() { + return stream.readInt(alignedBci + OFFSET_TO_NUMBER_PAIRS); + } + + @Override + public int size() { + return alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * numberOfCases() - bci; + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,224 @@ +/* + * 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.bytecode; + + +/** + * A utility class that makes iterating over bytecodes and reading operands + * simpler and less error prone. For example, it handles the {@link Bytecodes#WIDE} instruction + * and wide variants of instructions internally. + */ +public final class BytecodeStream { + + private final byte[] code; + private int opcode; + private int curBCI; + private int nextBCI; + + /** + * Creates a new {@code BytecodeStream} for the specified bytecode. + * @param code the array of bytes that contains the bytecode + */ + public BytecodeStream(byte[] code) { + assert code != null; + this.code = code; + setBCI(0); + } + + /** + * Advances to the next bytecode. + */ + public void next() { + setBCI(nextBCI); + } + + /** + * Gets the next bytecode index (no side-effects). + * @return the next bytecode index + */ + public int nextBCI() { + return nextBCI; + } + + /** + * Gets the current bytecode index. + * @return the current bytecode index + */ + public int currentBCI() { + return curBCI; + } + + /** + * Gets the bytecode index of the end of the code. + * @return the index of the end of the code + */ + public int endBCI() { + return code.length; + } + + /** + * Gets the current opcode. This method will never return the + * {@link Bytecodes#WIDE WIDE} opcode, but will instead + * return the opcode that is modified by the {@code WIDE} opcode. + * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code + */ + public int currentBC() { + if (opcode == Bytecodes.WIDE) { + return Bytes.beU1(code, curBCI + 1); + } else { + return opcode; + } + } + + /** + * Reads the index of a local variable for one of the load or store instructions. + * The WIDE modifier is handled internally. + * @return the index of the local variable + */ + public int readLocalIndex() { + // read local variable index for load/store + if (opcode == Bytecodes.WIDE) { + return Bytes.beU2(code, curBCI + 2); + } + return Bytes.beU1(code, curBCI + 1); + } + + /** + * Read the delta for an {@link Bytecodes#IINC} bytecode. + * @return the delta for the {@code IINC} + */ + public int readIncrement() { + // read the delta for the iinc bytecode + if (opcode == Bytecodes.WIDE) { + return Bytes.beS2(code, curBCI + 4); + } + return Bytes.beS1(code, curBCI + 2); + } + + /** + * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions. + * @return the destination bytecode index + */ + public int readBranchDest() { + // reads the destination for a branch bytecode + if (opcode == Bytecodes.GOTO_W || opcode == Bytecodes.JSR_W) { + return curBCI + Bytes.beS4(code, curBCI + 1); + } else { + return curBCI + Bytes.beS2(code, curBCI + 1); + } + } + + /** + * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index. + * @param bci the bytecode index + * @return the integer value + */ + public int readInt(int bci) { + // reads a 4-byte signed value + return Bytes.beS4(code, bci); + } + + /** + * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index. + * @param bci the bytecode index + * @return the byte + */ + public int readUByte(int bci) { + return Bytes.beU1(code, bci); + } + + /** + * Reads a constant pool index for the current instruction. + * @return the constant pool index + */ + public char readCPI() { + if (opcode == Bytecodes.LDC) { + return (char) Bytes.beU1(code, curBCI + 1); + } + return (char) Bytes.beU2(code, curBCI + 1); + } + + /** + * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH). + * @return the byte + */ + public byte readByte() { + return code[curBCI + 1]; + } + + /** + * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH). + * @return the short value + */ + public short readShort() { + return (short) Bytes.beS2(code, curBCI + 1); + } + + /** + * Sets the bytecode index to the specified value. + * If {@code bci} is beyond the end of the array, {@link #currentBC} will return + * {@link Bytecodes#END} and other methods may throw {@link ArrayIndexOutOfBoundsException}. + * @param bci the new bytecode index + */ + public void setBCI(int bci) { + curBCI = bci; + if (curBCI < code.length) { + opcode = Bytes.beU1(code, bci); + assert opcode < Bytecodes.BREAKPOINT : "illegal bytecode"; + nextBCI = bci + lengthOf(); + } else { + opcode = Bytecodes.END; + nextBCI = curBCI; + } + } + + /** + * Gets the length of the current bytecode. + */ + private int lengthOf() { + int length = Bytecodes.lengthOf(opcode); + if (length == 0) { + switch (opcode) { + case Bytecodes.TABLESWITCH: { + return new BytecodeTableSwitch(this, curBCI).size(); + } + case Bytecodes.LOOKUPSWITCH: { + return new BytecodeLookupSwitch(this, curBCI).size(); + } + case Bytecodes.WIDE: { + int opc = Bytes.beU1(code, curBCI + 1); + if (opc == Bytecodes.RET) { + return 4; + } else if (opc == Bytecodes.IINC) { + return 6; + } else { + return 4; // a load or store bytecode + } + } + default: + throw new Error("unknown variable-length bytecode: " + opcode); + } + } + return length; + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeSwitch.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,110 @@ +/* + * 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.bytecode; + +/** + * An abstract class that provides the state and methods common to {@link Bytecodes#LOOKUPSWITCH} + * and {@link Bytecodes#TABLESWITCH} instructions. + */ +public abstract class BytecodeSwitch { + /** + * The {@link BytecodeStream} containing the bytecode array. + */ + protected final BytecodeStream stream; + /** + * Index of start of switch instruction. + */ + protected final int bci; + /** + * Index of the start of the additional data for the switch instruction, aligned to a multiple of four from the method start. + */ + protected final int alignedBci; + + /** + * Constructor for a {@link BytecodeStream}. + * @param stream the {@code BytecodeStream} containing the switch instruction + * @param bci the index in the stream of the switch instruction + */ + public BytecodeSwitch(BytecodeStream stream, int bci) { + this.stream = stream; + this.bci = bci; + this.alignedBci = (bci + 4) & 0xfffffffc; + } + + /** + * Gets the current bytecode index. + * @return the current bytecode index + */ + public int bci() { + return bci; + } + + /** + * Gets the index of the instruction denoted by the {@code i}'th switch target. + * @param i index of the switch target + * @return the index of the instruction denoted by the {@code i}'th switch target + */ + public int targetAt(int i) { + return bci + offsetAt(i); + } + + /** + * Gets the index of the instruction for the default switch target. + * @return the index of the instruction for the default switch target + */ + public int defaultTarget() { + return bci + defaultOffset(); + } + + /** + * Gets the offset from the start of the switch instruction to the default switch target. + * @return the offset to the default switch target + */ + public abstract int defaultOffset(); + + /** + * Gets the key at {@code i}'th switch target index. + * @param i the switch target index + * @return the key at {@code i}'th switch target index + */ + public abstract int keyAt(int i); + + /** + * Gets the offset from the start of the switch instruction for the {@code i}'th switch target. + * @param i the switch target index + * @return the offset to the {@code i}'th switch target + */ + public abstract int offsetAt(int i); + + /** + * Gets the number of switch targets. + * @return the number of switch targets + */ + public abstract int numberOfCases(); + + /** + * Gets the total size in bytes of the switch instruction. + * @return the total size in bytes of the switch instruction + */ + public abstract int size(); +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeTableSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeTableSwitch.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,83 @@ +/* + * 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.bytecode; + +/** + * A utility for processing {@link Bytecodes#TABLESWITCH} bytecodes. + */ +public class BytecodeTableSwitch extends BytecodeSwitch { + private static final int OFFSET_TO_LOW_KEY = 4; + private static final int OFFSET_TO_HIGH_KEY = 8; + private static final int OFFSET_TO_FIRST_JUMP_OFFSET = 12; + private static final int JUMP_OFFSET_SIZE = 4; + + /** + * Constructor for a {@link BytecodeStream}. + * @param stream the {@code BytecodeStream} containing the switch instruction + * @param bci the index in the stream of the switch instruction + */ + public BytecodeTableSwitch(BytecodeStream stream, int bci) { + super(stream, bci); + } + + /** + * Gets the low key of the table switch. + * @return the low key + */ + public int lowKey() { + return stream.readInt(alignedBci + OFFSET_TO_LOW_KEY); + } + + /** + * Gets the high key of the table switch. + * @return the high key + */ + public int highKey() { + return stream.readInt(alignedBci + OFFSET_TO_HIGH_KEY); + } + + @Override + public int keyAt(int i) { + return lowKey() + i; + } + + @Override + public int defaultOffset() { + return stream.readInt(alignedBci); + } + + @Override + public int offsetAt(int i) { + return stream.readInt(alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * i); + } + + @Override + public int numberOfCases() { + return highKey() - lowKey() + 1; + } + + @Override + public int size() { + return alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * numberOfCases() - bci; + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytecodes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytecodes.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,940 @@ +/* + * 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.bytecode; + +import static com.oracle.graal.bytecode.Bytecodes.Flags.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.regex.*; + +/** + * The definitions of the bytecodes that are valid input to the compiler and + * related utility methods. This comprises two groups: the standard Java + * bytecodes defined by + * Java Virtual Machine Specification, and a set of extended + * bytecodes that support low-level programming, for example, memory barriers. + * + * The extended bytecodes are one or three bytes in size. The one-byte bytecodes + * follow the values in the standard set, with no gap. The three-byte extended + * bytecodes share a common first byte and carry additional instruction-specific + * information in the second and third bytes. + */ +public class Bytecodes { + public static final int NOP = 0; // 0x00 + public static final int ACONST_NULL = 1; // 0x01 + public static final int ICONST_M1 = 2; // 0x02 + public static final int ICONST_0 = 3; // 0x03 + public static final int ICONST_1 = 4; // 0x04 + public static final int ICONST_2 = 5; // 0x05 + public static final int ICONST_3 = 6; // 0x06 + public static final int ICONST_4 = 7; // 0x07 + public static final int ICONST_5 = 8; // 0x08 + public static final int LCONST_0 = 9; // 0x09 + public static final int LCONST_1 = 10; // 0x0A + public static final int FCONST_0 = 11; // 0x0B + public static final int FCONST_1 = 12; // 0x0C + public static final int FCONST_2 = 13; // 0x0D + public static final int DCONST_0 = 14; // 0x0E + public static final int DCONST_1 = 15; // 0x0F + public static final int BIPUSH = 16; // 0x10 + public static final int SIPUSH = 17; // 0x11 + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int ILOAD = 21; // 0x15 + public static final int LLOAD = 22; // 0x16 + public static final int FLOAD = 23; // 0x17 + public static final int DLOAD = 24; // 0x18 + public static final int ALOAD = 25; // 0x19 + public static final int ILOAD_0 = 26; // 0x1A + public static final int ILOAD_1 = 27; // 0x1B + public static final int ILOAD_2 = 28; // 0x1C + public static final int ILOAD_3 = 29; // 0x1D + public static final int LLOAD_0 = 30; // 0x1E + public static final int LLOAD_1 = 31; // 0x1F + public static final int LLOAD_2 = 32; // 0x20 + public static final int LLOAD_3 = 33; // 0x21 + public static final int FLOAD_0 = 34; // 0x22 + public static final int FLOAD_1 = 35; // 0x23 + public static final int FLOAD_2 = 36; // 0x24 + public static final int FLOAD_3 = 37; // 0x25 + public static final int DLOAD_0 = 38; // 0x26 + public static final int DLOAD_1 = 39; // 0x27 + public static final int DLOAD_2 = 40; // 0x28 + public static final int DLOAD_3 = 41; // 0x29 + public static final int ALOAD_0 = 42; // 0x2A + public static final int ALOAD_1 = 43; // 0x2B + public static final int ALOAD_2 = 44; // 0x2C + public static final int ALOAD_3 = 45; // 0x2D + public static final int IALOAD = 46; // 0x2E + public static final int LALOAD = 47; // 0x2F + public static final int FALOAD = 48; // 0x30 + public static final int DALOAD = 49; // 0x31 + public static final int AALOAD = 50; // 0x32 + public static final int BALOAD = 51; // 0x33 + public static final int CALOAD = 52; // 0x34 + public static final int SALOAD = 53; // 0x35 + public static final int ISTORE = 54; // 0x36 + public static final int LSTORE = 55; // 0x37 + public static final int FSTORE = 56; // 0x38 + public static final int DSTORE = 57; // 0x39 + public static final int ASTORE = 58; // 0x3A + public static final int ISTORE_0 = 59; // 0x3B + public static final int ISTORE_1 = 60; // 0x3C + public static final int ISTORE_2 = 61; // 0x3D + public static final int ISTORE_3 = 62; // 0x3E + public static final int LSTORE_0 = 63; // 0x3F + public static final int LSTORE_1 = 64; // 0x40 + public static final int LSTORE_2 = 65; // 0x41 + public static final int LSTORE_3 = 66; // 0x42 + public static final int FSTORE_0 = 67; // 0x43 + public static final int FSTORE_1 = 68; // 0x44 + public static final int FSTORE_2 = 69; // 0x45 + public static final int FSTORE_3 = 70; // 0x46 + public static final int DSTORE_0 = 71; // 0x47 + public static final int DSTORE_1 = 72; // 0x48 + public static final int DSTORE_2 = 73; // 0x49 + public static final int DSTORE_3 = 74; // 0x4A + public static final int ASTORE_0 = 75; // 0x4B + public static final int ASTORE_1 = 76; // 0x4C + public static final int ASTORE_2 = 77; // 0x4D + public static final int ASTORE_3 = 78; // 0x4E + public static final int IASTORE = 79; // 0x4F + public static final int LASTORE = 80; // 0x50 + public static final int FASTORE = 81; // 0x51 + public static final int DASTORE = 82; // 0x52 + public static final int AASTORE = 83; // 0x53 + public static final int BASTORE = 84; // 0x54 + public static final int CASTORE = 85; // 0x55 + public static final int SASTORE = 86; // 0x56 + public static final int POP = 87; // 0x57 + public static final int POP2 = 88; // 0x58 + public static final int DUP = 89; // 0x59 + public static final int DUP_X1 = 90; // 0x5A + public static final int DUP_X2 = 91; // 0x5B + public static final int DUP2 = 92; // 0x5C + public static final int DUP2_X1 = 93; // 0x5D + public static final int DUP2_X2 = 94; // 0x5E + public static final int SWAP = 95; // 0x5F + public static final int IADD = 96; // 0x60 + public static final int LADD = 97; // 0x61 + public static final int FADD = 98; // 0x62 + public static final int DADD = 99; // 0x63 + public static final int ISUB = 100; // 0x64 + public static final int LSUB = 101; // 0x65 + public static final int FSUB = 102; // 0x66 + public static final int DSUB = 103; // 0x67 + public static final int IMUL = 104; // 0x68 + public static final int LMUL = 105; // 0x69 + public static final int FMUL = 106; // 0x6A + public static final int DMUL = 107; // 0x6B + public static final int IDIV = 108; // 0x6C + public static final int LDIV = 109; // 0x6D + public static final int FDIV = 110; // 0x6E + public static final int DDIV = 111; // 0x6F + public static final int IREM = 112; // 0x70 + public static final int LREM = 113; // 0x71 + public static final int FREM = 114; // 0x72 + public static final int DREM = 115; // 0x73 + public static final int INEG = 116; // 0x74 + public static final int LNEG = 117; // 0x75 + public static final int FNEG = 118; // 0x76 + public static final int DNEG = 119; // 0x77 + public static final int ISHL = 120; // 0x78 + public static final int LSHL = 121; // 0x79 + public static final int ISHR = 122; // 0x7A + public static final int LSHR = 123; // 0x7B + public static final int IUSHR = 124; // 0x7C + public static final int LUSHR = 125; // 0x7D + public static final int IAND = 126; // 0x7E + public static final int LAND = 127; // 0x7F + public static final int IOR = 128; // 0x80 + public static final int LOR = 129; // 0x81 + public static final int IXOR = 130; // 0x82 + public static final int LXOR = 131; // 0x83 + public static final int IINC = 132; // 0x84 + public static final int I2L = 133; // 0x85 + public static final int I2F = 134; // 0x86 + public static final int I2D = 135; // 0x87 + public static final int L2I = 136; // 0x88 + public static final int L2F = 137; // 0x89 + public static final int L2D = 138; // 0x8A + public static final int F2I = 139; // 0x8B + public static final int F2L = 140; // 0x8C + public static final int F2D = 141; // 0x8D + public static final int D2I = 142; // 0x8E + public static final int D2L = 143; // 0x8F + public static final int D2F = 144; // 0x90 + public static final int I2B = 145; // 0x91 + public static final int I2C = 146; // 0x92 + public static final int I2S = 147; // 0x93 + public static final int LCMP = 148; // 0x94 + public static final int FCMPL = 149; // 0x95 + public static final int FCMPG = 150; // 0x96 + public static final int DCMPL = 151; // 0x97 + public static final int DCMPG = 152; // 0x98 + public static final int IFEQ = 153; // 0x99 + public static final int IFNE = 154; // 0x9A + public static final int IFLT = 155; // 0x9B + public static final int IFGE = 156; // 0x9C + public static final int IFGT = 157; // 0x9D + public static final int IFLE = 158; // 0x9E + public static final int IF_ICMPEQ = 159; // 0x9F + public static final int IF_ICMPNE = 160; // 0xA0 + public static final int IF_ICMPLT = 161; // 0xA1 + public static final int IF_ICMPGE = 162; // 0xA2 + public static final int IF_ICMPGT = 163; // 0xA3 + public static final int IF_ICMPLE = 164; // 0xA4 + public static final int IF_ACMPEQ = 165; // 0xA5 + public static final int IF_ACMPNE = 166; // 0xA6 + public static final int GOTO = 167; // 0xA7 + public static final int JSR = 168; // 0xA8 + public static final int RET = 169; // 0xA9 + public static final int TABLESWITCH = 170; // 0xAA + public static final int LOOKUPSWITCH = 171; // 0xAB + public static final int IRETURN = 172; // 0xAC + public static final int LRETURN = 173; // 0xAD + public static final int FRETURN = 174; // 0xAE + public static final int DRETURN = 175; // 0xAF + public static final int ARETURN = 176; // 0xB0 + public static final int RETURN = 177; // 0xB1 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int XXXUNUSEDXXX = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int ARRAYLENGTH = 190; // 0xBE + public static final int ATHROW = 191; // 0xBF + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MONITORENTER = 194; // 0xC2 + public static final int MONITOREXIT = 195; // 0xC3 + public static final int WIDE = 196; // 0xC4 + public static final int MULTIANEWARRAY = 197; // 0xC5 + public static final int IFNULL = 198; // 0xC6 + public static final int IFNONNULL = 199; // 0xC7 + public static final int GOTO_W = 200; // 0xC8 + public static final int JSR_W = 201; // 0xC9 + public static final int BREAKPOINT = 202; // 0xCA + + public static final int ILLEGAL = 255; + public static final int END = 256; + + /** + * The last opcode defined by the JVM specification. To iterate over all JVM bytecodes: + *
+     *     for (int opcode = 0; opcode <= Bytecodes.LAST_JVM_OPCODE; ++opcode) {
+     *         //
+     *     }
+     * 
+ */ + public static final int LAST_JVM_OPCODE = JSR_W; + + /** + * A collection of flags describing various bytecode attributes. + */ + static class Flags { + + /** + * Denotes an instruction that ends a basic block and does not let control flow fall through to its lexical successor. + */ + static final int STOP = 0x00000001; + + /** + * Denotes an instruction that ends a basic block and may let control flow fall through to its lexical successor. + * In practice this means it is a conditional branch. + */ + static final int FALL_THROUGH = 0x00000002; + + /** + * Denotes an instruction that has a 2 or 4 byte operand that is an offset to another instruction in the same method. + * This does not include the {@link Bytecodes#TABLESWITCH} or {@link Bytecodes#LOOKUPSWITCH} instructions. + */ + static final int BRANCH = 0x00000004; + + /** + * Denotes an instruction that reads the value of a static or instance field. + */ + static final int FIELD_READ = 0x00000008; + + /** + * Denotes an instruction that writes the value of a static or instance field. + */ + static final int FIELD_WRITE = 0x00000010; + + /** + * Denotes an instruction that is not defined in the JVM specification. + */ + static final int EXTENSION = 0x00000020; + + /** + * Denotes an instruction that can cause a trap. + */ + static final int TRAP = 0x00000080; + /** + * Denotes an instruction that is commutative. + */ + static final int COMMUTATIVE = 0x00000100; + /** + * Denotes an instruction that is associative. + */ + static final int ASSOCIATIVE = 0x00000200; + /** + * Denotes an instruction that loads an operand. + */ + static final int LOAD = 0x00000400; + /** + * Denotes an instruction that stores an operand. + */ + static final int STORE = 0x00000800; + /** + * Denotes the 4 INVOKE* instructions. + */ + static final int INVOKE = 0x00001000; + } + + // Performs a sanity check that none of the flags overlap. + static { + int allFlags = 0; + try { + for (Field field : Flags.class.getDeclaredFields()) { + int flagsFilter = Modifier.FINAL | Modifier.STATIC; + if ((field.getModifiers() & flagsFilter) == flagsFilter && !field.isSynthetic()) { + assert field.getType() == int.class : "Field is not int : " + field; + final int flag = field.getInt(null); + assert flag != 0; + assert (flag & allFlags) == 0 : field.getName() + " has a value conflicting with another flag"; + allFlags |= flag; + } + } + } catch (Exception e) { + throw new InternalError(e.toString()); + } + } + + /** + * An array that maps from a bytecode value to a {@link String} for the corresponding instruction mnemonic. + * This will include the root instruction for the three-byte extended instructions. + */ + private static final String[] nameArray = new String[256]; + + /** + * An array that maps from a bytecode value to the set of {@link Flags} for the corresponding instruction. + */ + private static final int[] flagsArray = new int[256]; + + /** + * An array that maps from a bytecode value to the length in bytes for the corresponding instruction. + */ + private static final int[] lengthArray = new int[256]; + + /** + * An array that maps from a bytecode value to the estimated complexity of the bytecode in terms of generated machine code. + */ + private static final int[] compilationComplexityArray = new int[256]; + + // Checkstyle: stop + static { + def(NOP , "nop" , "b" , 0); + def(ACONST_NULL , "aconst_null" , "b" , 0); + def(ICONST_M1 , "iconst_m1" , "b" , 0); + def(ICONST_0 , "iconst_0" , "b" , 0); + def(ICONST_1 , "iconst_1" , "b" , 0); + def(ICONST_2 , "iconst_2" , "b" , 0); + def(ICONST_3 , "iconst_3" , "b" , 0); + def(ICONST_4 , "iconst_4" , "b" , 0); + def(ICONST_5 , "iconst_5" , "b" , 0); + def(LCONST_0 , "lconst_0" , "b" , 0); + def(LCONST_1 , "lconst_1" , "b" , 0); + def(FCONST_0 , "fconst_0" , "b" , 0); + def(FCONST_1 , "fconst_1" , "b" , 0); + def(FCONST_2 , "fconst_2" , "b" , 0); + def(DCONST_0 , "dconst_0" , "b" , 0); + def(DCONST_1 , "dconst_1" , "b" , 0); + def(BIPUSH , "bipush" , "bc" , 0); + def(SIPUSH , "sipush" , "bcc" , 0); + def(LDC , "ldc" , "bi" , 0, TRAP); + def(LDC_W , "ldc_w" , "bii" , 0, TRAP); + def(LDC2_W , "ldc2_w" , "bii" , 0, TRAP); + def(ILOAD , "iload" , "bi" , 0, LOAD); + def(LLOAD , "lload" , "bi" , 0, LOAD); + def(FLOAD , "fload" , "bi" , 0, LOAD); + def(DLOAD , "dload" , "bi" , 0, LOAD); + def(ALOAD , "aload" , "bi" , 0, LOAD); + def(ILOAD_0 , "iload_0" , "b" , 0, LOAD); + def(ILOAD_1 , "iload_1" , "b" , 0, LOAD); + def(ILOAD_2 , "iload_2" , "b" , 0, LOAD); + def(ILOAD_3 , "iload_3" , "b" , 0, LOAD); + def(LLOAD_0 , "lload_0" , "b" , 0, LOAD); + def(LLOAD_1 , "lload_1" , "b" , 0, LOAD); + def(LLOAD_2 , "lload_2" , "b" , 0, LOAD); + def(LLOAD_3 , "lload_3" , "b" , 0, LOAD); + def(FLOAD_0 , "fload_0" , "b" , 0, LOAD); + def(FLOAD_1 , "fload_1" , "b" , 0, LOAD); + def(FLOAD_2 , "fload_2" , "b" , 0, LOAD); + def(FLOAD_3 , "fload_3" , "b" , 0, LOAD); + def(DLOAD_0 , "dload_0" , "b" , 0, LOAD); + def(DLOAD_1 , "dload_1" , "b" , 0, LOAD); + def(DLOAD_2 , "dload_2" , "b" , 0, LOAD); + def(DLOAD_3 , "dload_3" , "b" , 0, LOAD); + def(ALOAD_0 , "aload_0" , "b" , 0, LOAD); + def(ALOAD_1 , "aload_1" , "b" , 0, LOAD); + def(ALOAD_2 , "aload_2" , "b" , 0, LOAD); + def(ALOAD_3 , "aload_3" , "b" , 0, LOAD); + def(IALOAD , "iaload" , "b" , 0, TRAP); + def(LALOAD , "laload" , "b" , 0, TRAP); + def(FALOAD , "faload" , "b" , 0, TRAP); + def(DALOAD , "daload" , "b" , 0, TRAP); + def(AALOAD , "aaload" , "b" , 0, TRAP); + def(BALOAD , "baload" , "b" , 0, TRAP); + def(CALOAD , "caload" , "b" , 0, TRAP); + def(SALOAD , "saload" , "b" , 0, TRAP); + def(ISTORE , "istore" , "bi" , 0, STORE); + def(LSTORE , "lstore" , "bi" , 0, STORE); + def(FSTORE , "fstore" , "bi" , 0, STORE); + def(DSTORE , "dstore" , "bi" , 0, STORE); + def(ASTORE , "astore" , "bi" , 0, STORE); + def(ISTORE_0 , "istore_0" , "b" , 0, STORE); + def(ISTORE_1 , "istore_1" , "b" , 0, STORE); + def(ISTORE_2 , "istore_2" , "b" , 0, STORE); + def(ISTORE_3 , "istore_3" , "b" , 0, STORE); + def(LSTORE_0 , "lstore_0" , "b" , 0, STORE); + def(LSTORE_1 , "lstore_1" , "b" , 0, STORE); + def(LSTORE_2 , "lstore_2" , "b" , 0, STORE); + def(LSTORE_3 , "lstore_3" , "b" , 0, STORE); + def(FSTORE_0 , "fstore_0" , "b" , 0, STORE); + def(FSTORE_1 , "fstore_1" , "b" , 0, STORE); + def(FSTORE_2 , "fstore_2" , "b" , 0, STORE); + def(FSTORE_3 , "fstore_3" , "b" , 0, STORE); + def(DSTORE_0 , "dstore_0" , "b" , 0, STORE); + def(DSTORE_1 , "dstore_1" , "b" , 0, STORE); + def(DSTORE_2 , "dstore_2" , "b" , 0, STORE); + def(DSTORE_3 , "dstore_3" , "b" , 0, STORE); + def(ASTORE_0 , "astore_0" , "b" , 0, STORE); + def(ASTORE_1 , "astore_1" , "b" , 0, STORE); + def(ASTORE_2 , "astore_2" , "b" , 0, STORE); + def(ASTORE_3 , "astore_3" , "b" , 0, STORE); + def(IASTORE , "iastore" , "b" , 3, TRAP); + def(LASTORE , "lastore" , "b" , 3, TRAP); + def(FASTORE , "fastore" , "b" , 3, TRAP); + def(DASTORE , "dastore" , "b" , 3, TRAP); + def(AASTORE , "aastore" , "b" , 4, TRAP); + def(BASTORE , "bastore" , "b" , 3, TRAP); + def(CASTORE , "castore" , "b" , 3, TRAP); + def(SASTORE , "sastore" , "b" , 3, TRAP); + def(POP , "pop" , "b" , 0); + def(POP2 , "pop2" , "b" , 0); + def(DUP , "dup" , "b" , 0); + def(DUP_X1 , "dup_x1" , "b" , 0); + def(DUP_X2 , "dup_x2" , "b" , 0); + def(DUP2 , "dup2" , "b" , 0); + def(DUP2_X1 , "dup2_x1" , "b" , 0); + def(DUP2_X2 , "dup2_x2" , "b" , 0); + def(SWAP , "swap" , "b" , 0); + def(IADD , "iadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(LADD , "ladd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(FADD , "fadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(DADD , "dadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(ISUB , "isub" , "b" , 1); + def(LSUB , "lsub" , "b" , 1); + def(FSUB , "fsub" , "b" , 1); + def(DSUB , "dsub" , "b" , 1); + def(IMUL , "imul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(LMUL , "lmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(FMUL , "fmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(DMUL , "dmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(IDIV , "idiv" , "b" , 1, TRAP); + def(LDIV , "ldiv" , "b" , 1, TRAP); + def(FDIV , "fdiv" , "b" , 1); + def(DDIV , "ddiv" , "b" , 1); + def(IREM , "irem" , "b" , 1, TRAP); + def(LREM , "lrem" , "b" , 1, TRAP); + def(FREM , "frem" , "b" , 1); + def(DREM , "drem" , "b" , 1); + def(INEG , "ineg" , "b" , 1); + def(LNEG , "lneg" , "b" , 1); + def(FNEG , "fneg" , "b" , 1); + def(DNEG , "dneg" , "b" , 1); + def(ISHL , "ishl" , "b" , 1); + def(LSHL , "lshl" , "b" , 1); + def(ISHR , "ishr" , "b" , 1); + def(LSHR , "lshr" , "b" , 1); + def(IUSHR , "iushr" , "b" , 1); + def(LUSHR , "lushr" , "b" , 1); + def(IAND , "iand" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(LAND , "land" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(IOR , "ior" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(LOR , "lor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(IXOR , "ixor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(LXOR , "lxor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); + def(IINC , "iinc" , "bic" , 1, LOAD | STORE); + def(I2L , "i2l" , "b" , 1); + def(I2F , "i2f" , "b" , 1); + def(I2D , "i2d" , "b" , 1); + def(L2I , "l2i" , "b" , 1); + def(L2F , "l2f" , "b" , 1); + def(L2D , "l2d" , "b" , 1); + def(F2I , "f2i" , "b" , 1); + def(F2L , "f2l" , "b" , 1); + def(F2D , "f2d" , "b" , 1); + def(D2I , "d2i" , "b" , 1); + def(D2L , "d2l" , "b" , 1); + def(D2F , "d2f" , "b" , 1); + def(I2B , "i2b" , "b" , 1); + def(I2C , "i2c" , "b" , 1); + def(I2S , "i2s" , "b" , 1); + def(LCMP , "lcmp" , "b" , 1); + def(FCMPL , "fcmpl" , "b" , 1); + def(FCMPG , "fcmpg" , "b" , 1); + def(DCMPL , "dcmpl" , "b" , 1); + def(DCMPG , "dcmpg" , "b" , 1); + def(IFEQ , "ifeq" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFNE , "ifne" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFLT , "iflt" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFGE , "ifge" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFGT , "ifgt" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFLE , "ifle" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IF_ICMPEQ , "if_icmpeq" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ICMPNE , "if_icmpne" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ICMPLT , "if_icmplt" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IF_ICMPGE , "if_icmpge" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IF_ICMPGT , "if_icmpgt" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IF_ICMPLE , "if_icmple" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IF_ACMPEQ , "if_acmpeq" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(IF_ACMPNE , "if_acmpne" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); + def(GOTO , "goto" , "boo" , 1, STOP | BRANCH); + def(JSR , "jsr" , "boo" , 0, STOP | BRANCH); + def(RET , "ret" , "bi" , 0, STOP); + def(TABLESWITCH , "tableswitch" , "" , 4, STOP); + def(LOOKUPSWITCH , "lookupswitch" , "" , 4, STOP); + def(IRETURN , "ireturn" , "b" , 1, TRAP | STOP); + def(LRETURN , "lreturn" , "b" , 1, TRAP | STOP); + def(FRETURN , "freturn" , "b" , 1, TRAP | STOP); + def(DRETURN , "dreturn" , "b" , 1, TRAP | STOP); + def(ARETURN , "areturn" , "b" , 1, TRAP | STOP); + def(RETURN , "return" , "b" , 1, TRAP | STOP); + def(GETSTATIC , "getstatic" , "bjj" , 2, TRAP | FIELD_READ); + def(PUTSTATIC , "putstatic" , "bjj" , 2, TRAP | FIELD_WRITE); + def(GETFIELD , "getfield" , "bjj" , 2, TRAP | FIELD_READ); + def(PUTFIELD , "putfield" , "bjj" , 2, TRAP | FIELD_WRITE); + def(INVOKEVIRTUAL , "invokevirtual" , "bjj" , 7, TRAP | INVOKE); + def(INVOKESPECIAL , "invokespecial" , "bjj" , 5, TRAP | INVOKE); + def(INVOKESTATIC , "invokestatic" , "bjj" , 5, TRAP | INVOKE); + def(INVOKEINTERFACE , "invokeinterface" , "bjja_", 7, TRAP | INVOKE); + def(XXXUNUSEDXXX , "xxxunusedxxx" , "" , 0); + def(NEW , "new" , "bii" , 6, TRAP); + def(NEWARRAY , "newarray" , "bc" , 6, TRAP); + def(ANEWARRAY , "anewarray" , "bii" , 6, TRAP); + def(ARRAYLENGTH , "arraylength" , "b" , 2, TRAP); + def(ATHROW , "athrow" , "b" , 5, TRAP | STOP); + def(CHECKCAST , "checkcast" , "bii" , 3, TRAP); + def(INSTANCEOF , "instanceof" , "bii" , 4, TRAP); + def(MONITORENTER , "monitorenter" , "b" , 5, TRAP); + def(MONITOREXIT , "monitorexit" , "b" , 5, TRAP); + def(WIDE , "wide" , "" , 0); + def(MULTIANEWARRAY , "multianewarray" , "biic" , 6, TRAP); + def(IFNULL , "ifnull" , "boo" , 2, FALL_THROUGH | BRANCH); + def(IFNONNULL , "ifnonnull" , "boo" , 2, FALL_THROUGH | BRANCH); + def(GOTO_W , "goto_w" , "boooo", 1, STOP | BRANCH); + def(JSR_W , "jsr_w" , "boooo", 0, STOP | BRANCH); + def(BREAKPOINT , "breakpoint" , "b" , 0, TRAP); + } + // Checkstyle: resume + + /** + * Determines if an opcode is commutative. + * @param opcode the opcode to check + * @return {@code true} iff commutative + */ + public static boolean isCommutative(int opcode) { + return (flagsArray[opcode & 0xff] & COMMUTATIVE) != 0; + } + + /** + * Gets the length of an instruction denoted by a given opcode. + * + * @param opcode an instruction opcode + * @return the length of the instruction denoted by {@code opcode}. If {@code opcode} is an illegal instruction or denotes a + * variable length instruction (e.g. {@link #TABLESWITCH}), then 0 is returned. + */ + public static int lengthOf(int opcode) { + return lengthArray[opcode & 0xff]; + } + + /** + * Gets the compilation complexity for a given opcode. + * @param opcode an opcode + * @return a value >= 0 + */ + public static int compilationComplexity(int opcode) { + return compilationComplexityArray[opcode & 0xff]; + } + + /** + * Gets the lower-case mnemonic for a given opcode. + * + * @param opcode an opcode + * @return the mnemonic for {@code opcode} or {@code ""} if {@code opcode} is not a legal opcode + */ + public static String nameOf(int opcode) throws IllegalArgumentException { + String name = nameArray[opcode & 0xff]; + if (name == null) { + return ""; + } + return name; + } + + /** + * Allocation-free version of {@linkplain #nameOf(int)}. + * @param opcode an opcode. + * @return the mnemonic for {@code opcode} or {@code ""} if {@code opcode} is not a legal opcode. + */ + public static String baseNameOf(int opcode) { + String name = nameArray[opcode & 0xff]; + if (name == null) { + return ""; + } + return name; + } + + /** + * Gets the opcode corresponding to a given mnemonic. + * + * @param name an opcode mnemonic + * @return the opcode corresponding to {@code mnemonic} + * @throws IllegalArgumentException if {@code name} does not denote a valid opcode + */ + public static int valueOf(String name) { + for (int opcode = 0; opcode < nameArray.length; ++opcode) { + if (name.equalsIgnoreCase(nameArray[opcode])) { + return opcode; + } + } + throw new IllegalArgumentException("No opcode for " + name); + } + + /** + * Determines if a given opcode denotes an instruction that can cause an implicit exception. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} can cause an implicit exception, {@code false} otherwise + */ + public static boolean canTrap(int opcode) { + return (flagsArray[opcode & 0xff] & TRAP) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that loads a local variable to the operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} loads a local variable to the operand stack, {@code false} otherwise + */ + public static boolean isLoad(int opcode) { + return (flagsArray[opcode & 0xff] & LOAD) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that ends a basic block and does not let control flow fall + * through to its lexical successor. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} properly ends a basic block + */ + public static boolean isStop(int opcode) { + return (flagsArray[opcode & 0xff] & STOP) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that stores a value to a local variable + * after popping it from the operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} otherwise + */ + public static boolean isInvoke(int opcode) { + return (flagsArray[opcode & 0xff] & INVOKE) != 0; + } + + /** + * Determines if a given opcode denotes an instruction that stores a value to a local variable + * after popping it from the operand stack. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} otherwise + */ + public static boolean isStore(int opcode) { + return (flagsArray[opcode & 0xff] & STORE) != 0; + } + + /** + * Determines if a given opcode is an instruction that delimits a basic block. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} delimits a basic block + */ + public static boolean isBlockEnd(int opcode) { + return (flagsArray[opcode & 0xff] & (STOP | FALL_THROUGH)) != 0; + } + + /** + * Determines if a given opcode is an instruction that has a 2 or 4 byte operand that is an offset to another + * instruction in the same method. This does not include the {@linkplain #TABLESWITCH switch} instructions. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} is a branch instruction with a single operand + */ + public static boolean isBranch(int opcode) { + return (flagsArray[opcode & 0xff] & BRANCH) != 0; + } + + /** + * Determines if a given opcode denotes a conditional branch. + * @param opcode + * @return {@code true} iff {@code opcode} is a conditional branch + */ + public static boolean isConditionalBranch(int opcode) { + return (flagsArray[opcode & 0xff] & FALL_THROUGH) != 0; + } + + /** + * Determines if a given opcode denotes a standard bytecode. A standard bytecode is + * defined in the JVM specification. + * + * @param opcode an opcode to test + * @return {@code true} iff {@code opcode} is a standard bytecode + */ + public static boolean isStandard(int opcode) { + return (flagsArray[opcode & 0xff] & EXTENSION) == 0; + } + + /** + * Determines if a given opcode denotes an extended bytecode. + * + * @param opcode an opcode to test + * @return {@code true} if {@code opcode} is an extended bytecode + */ + public static boolean isExtended(int opcode) { + return (flagsArray[opcode & 0xff] & EXTENSION) != 0; + } + + /** + * Determines if a given opcode is a three-byte extended bytecode. + * + * @param opcode an opcode to test + * @return {@code true} if {@code (opcode & ~0xff) != 0} + */ + public static boolean isThreeByteExtended(int opcode) { + return (opcode & ~0xff) != 0; + } + + /** + * Gets the arithmetic operator name for a given opcode. If {@code opcode} does not denote an + * arithmetic instruction, then the {@linkplain #nameOf(int) name} of the opcode is returned + * instead. + * + * @param op an opcode + * @return the arithmetic operator name + */ + public static String operator(int op) { + // Checkstyle: stop + switch (op) { + // arithmetic ops + case IADD : // fall through + case LADD : // fall through + case FADD : // fall through + case DADD : return "+"; + case ISUB : // fall through + case LSUB : // fall through + case FSUB : // fall through + case DSUB : return "-"; + case IMUL : // fall through + case LMUL : // fall through + case FMUL : // fall through + case DMUL : return "*"; + case IDIV : // fall through + case LDIV : // fall through + case FDIV : // fall through + case DDIV : return "/"; + case IREM : // fall through + case LREM : // fall through + case FREM : // fall through + case DREM : return "%"; + // shift ops + case ISHL : // fall through + case LSHL : return "<<"; + case ISHR : // fall through + case LSHR : return ">>"; + case IUSHR: // fall through + case LUSHR: return ">>>"; + // logic ops + case IAND : // fall through + case LAND : return "&"; + case IOR : // fall through + case LOR : return "|"; + case IXOR : // fall through + case LXOR : return "^"; + } + // Checkstyle: resume + return nameOf(op); + } + + /** + * Defines a bytecode by entering it into the arrays that record its name, length and flags. + * + * @param name instruction name (should be lower case) + * @param format encodes the length of the instruction + * @param flagsArray the set of {@link Flags} associated with the instruction + */ + private static void def(int opcode, String name, String format, int compilationComplexity) { + def(opcode, name, format, compilationComplexity, 0); + } + + /** + * Defines a bytecode by entering it into the arrays that record its name, length and flags. + * + * @param name instruction name (lower case) + * @param format encodes the length of the instruction + * @param flags the set of {@link Flags} associated with the instruction + */ + private static void def(int opcode, String name, String format, int compilationComplexity, int flags) { + assert nameArray[opcode] == null : "opcode " + opcode + " is already bound to name " + nameArray[opcode]; + nameArray[opcode] = name; + int instructionLength = format.length(); + lengthArray[opcode] = instructionLength; + compilationComplexityArray[opcode] = compilationComplexity; + Bytecodes.flagsArray[opcode] = flags; + + assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch"; + } + + /** + * Utility for ensuring that the extended opcodes are contiguous and follow on directly + * from the standard JVM opcodes. If these conditions do not hold for the input source + * file, then it is modified 'in situ' to fix the problem. + * + * @param args {@code args[0]} is the path to this source file + */ + public static void main(String[] args) throws Exception { + Method findWorkspaceDirectory = Class.forName("com.sun.max.ide.JavaProject").getDeclaredMethod("findWorkspaceDirectory"); + File base = new File((File) findWorkspaceDirectory.invoke(null), "com.oracle.max.cri/src"); + File file = new File(base, Bytecodes.class.getName().replace('.', File.separatorChar) + ".java").getAbsoluteFile(); + + Pattern opcodeDecl = Pattern.compile("(\\s*public static final int )(\\w+)(\\s*=\\s*)(\\d+)(;.*)"); + + BufferedReader br = new BufferedReader(new FileReader(file)); + CharArrayWriter buffer = new CharArrayWriter((int) file.length()); + PrintWriter out = new PrintWriter(buffer); + String line; + int lastExtendedOpcode = BREAKPOINT; + boolean modified = false; + int section = 0; + while ((line = br.readLine()) != null) { + if (section == 0) { + if (line.equals(" // Start extended bytecodes")) { + section = 1; + } + } else if (section == 1) { + if (line.equals(" // End extended bytecodes")) { + section = 2; + } else { + Matcher matcher = opcodeDecl.matcher(line); + if (matcher.matches()) { + String name = matcher.group(2); + String value = matcher.group(4); + int opcode = Integer.parseInt(value); + if (nameArray[opcode] == null || !nameArray[opcode].equalsIgnoreCase(name)) { + throw new RuntimeException("Missing definition of name and flags for " + opcode + ":" + name + " -- " + nameArray[opcode]); + } + if (opcode != lastExtendedOpcode + 1) { + System.err.println("Fixed declaration of opcode " + name + " to be " + (lastExtendedOpcode + 1) + " (was " + value + ")"); + opcode = lastExtendedOpcode + 1; + line = line.substring(0, matcher.start(4)) + opcode + line.substring(matcher.end(4)); + modified = true; + } + + if (opcode >= 256) { + throw new RuntimeException("Exceeded maximum opcode value with " + name); + } + + lastExtendedOpcode = opcode; + } + } + } + + out.println(line); + } + if (section == 0) { + throw new RuntimeException("Did not find line starting extended bytecode declarations:\n\n // Start extended bytecodes"); + } else if (section == 1) { + throw new RuntimeException("Did not find line ending extended bytecode declarations:\n\n // End extended bytecodes"); + } + + if (modified) { + out.flush(); + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(buffer.toCharArray()); + fileWriter.close(); + + System.out.println("Modified: " + file); + } + + + // Uncomment to print out visitor method declarations: +// for (int opcode = 0; opcode < flags.length; ++opcode) { +// if (isExtension(opcode)) { +// String visitorParams = length(opcode) == 1 ? "" : "int index"; +// System.out.println("@Override"); +// System.out.println("protected void " + name(opcode) + "(" + visitorParams + ") {"); +// System.out.println("}"); +// System.out.println(); +// } +// } + + // Uncomment to print out visitor method declarations: +// for (int opcode = 0; opcode < flags.length; ++opcode) { +// if (isExtension(opcode)) { +// System.out.println("case " + name(opcode).toUpperCase() + ": {"); +// String arg = ""; +// int length = length(opcode); +// if (length == 2) { +// arg = "readUnsigned1()"; +// } else if (length == 3) { +// arg = "readUnsigned2()"; +// } +// System.out.println(" bytecodeVisitor." + name(opcode) + "(" + arg + ");"); +// System.out.println(" break;"); +// System.out.println("}"); +// } +// } + + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytes.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,93 @@ +/* + * 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.bytecode; + +/** + * A collection of utility methods for dealing with bytes, particularly in byte arrays. + */ +public class Bytes { + /** + * Gets a signed 1-byte value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 1-byte value at index {@code bci} in array {@code data} + */ + public static int beS1(byte[] data, int bci) { + return data[bci]; + } + + /** + * Gets a signed 2-byte big-endian value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 2-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beS2(byte[] data, int bci) { + return (data[bci] << 8) | (data[bci + 1] & 0xff); + } + + /** + * Gets an unsigned 1-byte value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the unsigned 1-byte value at index {@code bci} in array {@code data} + */ + public static int beU1(byte[] data, int bci) { + return data[bci] & 0xff; + } + + /** + * Gets an unsigned 2-byte big-endian value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the unsigned 2-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beU2(byte[] data, int bci) { + return ((data[bci] & 0xff) << 8) | (data[bci + 1] & 0xff); + } + + /** + * Gets a signed 4-byte big-endian value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @return the signed 4-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beS4(byte[] data, int bci) { + return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff); + } + + /** + * Gets either a signed 2-byte or a signed 4-byte big-endian value. + * @param data the array containing the data + * @param bci the start index of the value to retrieve + * @param fourByte if true, this method will return a 4-byte value + * @return the signed 2 or 4-byte, big-endian, value at index {@code bci} in array {@code data} + */ + public static int beSVar(byte[] data, int bci, boolean fourByte) { + if (fourByte) { + return beS4(data, bci); + } else { + return beS2(data, bci); + } + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon Jun 11 17:06:06 2012 +0200 @@ -30,10 +30,10 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.*; import com.oracle.graal.compiler.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.counters.*; -import com.oracle.graal.java.bytecode.*; import com.oracle.max.criutils.*; /** diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,1658 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.interpreter.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.*; + +/** + * + *

Implementation notes

+ *
  • Native methods are invoked using standard java reflection.
  • + * + *

    Features:

    + * + * + *

    Limitations:

    + * + *
  • The interpreter is not able to recognize a native method that calls a java method. + * In that case the java method will be interpreted directly on the vm interpreter.
  • + */ +@SuppressWarnings("static-method") +public final class BytecodeInterpreter implements Interpreter { + + private static final String OPTION_MAX_STACK_SIZE = "maxStackSize"; + private static final boolean TRACE = false; + private static final boolean TRACE_BYTE_CODE = false; + + private static final int DEFAULT_MAX_STACK_SIZE = 200; + + private static final int NEXT = -1; + private static final int BRANCH = -2; + private static final int RETURN = -3; + private static final int CALL = -4; + + private InterpreterFrame callFrame; + + //TODO try to remove this reference + private ExceptionHandler catchAllExceptionHandler; + + private final Map methodDelegates = new HashMap<>(); + + private int maxStackFrames = DEFAULT_MAX_STACK_SIZE; + private int stackFrameDepth; + + private final ResolvedJavaMethod rootMethod; + private final VMAdapter vm; + + public BytecodeInterpreter() { + this(VMAdapter.getInstance()); + } + + public BytecodeInterpreter(VMAdapter accessor) { + if (accessor == null) { + throw new NullPointerException(); + } + this.vm = accessor; + this.rootMethod = resolveRootMethod(); + registerDelegates(); + } + + @Override + public void setOption(String name, String value) { + if (name != null && name.equals(OPTION_MAX_STACK_SIZE)) { + this.maxStackFrames = Integer.parseInt(value); + } + } + + + private void registerDelegates() { + addDelegate(findMethod(Throwable.class, "fillInStackTrace"), new InterpreterCallable() { + @Override + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { + setBackTrace(caller, (Throwable) base, createStackTraceElements(caller)); + return null; + } + }); + addDelegate(findMethod(Throwable.class, "getStackTraceDepth"), new InterpreterCallable() { + @Override + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { + StackTraceElement[] elements = getBackTrace(caller, (Throwable) base); + if (elements != null) { + return elements.length; + } + return 0; + } + }); + addDelegate(findMethod(Throwable.class, "getStackTraceElement", int.class), new InterpreterCallable() { + @Override + public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable { + StackTraceElement[] elements = getBackTrace(caller, (Throwable) base); + if (elements != null) { + Integer index = (Integer) arguments[0]; + if (index != null) { + return elements[index]; + } + } + return null; + } + }); + } + + public void setMaxStackFrames(int maxStackSize) { + this.maxStackFrames = maxStackSize; + } + + public int getMaxStackFrames() { + return maxStackFrames; + } + + public void addDelegate(Method method, InterpreterCallable callable) { + ResolvedJavaMethod resolvedMethod = vm.getRuntime().getResolvedJavaMethod(method); + if (methodDelegates.containsKey(resolvedMethod)) { + throw new IllegalArgumentException("Delegate for method " + method + " already added."); + } + methodDelegates.put(resolvedMethod, callable); + } + + public void removeDelegate(Method method) { + methodDelegates.remove(vm.getRuntime().getResolvedJavaMethod(method)); + } + + @Override + public Object execute(ResolvedJavaMethod method, Object... boxedArguments) { + Signature signature = method.signature(); + assert boxedArguments != null; + assert signature.argumentCount(false) == boxedArguments.length; + + if (!Modifier.isStatic(method.accessFlags())) { + throw new UnsupportedOperationException("The interpreter can currently only be started with static methods."); + } + + InterpreterFrame rootFrame = new InterpreterFrame(rootMethod, signature.argumentSlots(true)); + rootFrame.pushObject(this); + rootFrame.pushObject(method); + rootFrame.pushObject(boxedArguments); + + for (int i = 0; i < boxedArguments.length; i++) { + pushAsObject(rootFrame, signature.argumentKindAt(i), boxedArguments[i]); + } + + InterpreterFrame frame = rootFrame.create(method, false); + + try { + executeRoot(rootFrame, frame); + } catch (Throwable e) { + // clear backtrace for compatibilty and store it in stacktrace + StackTraceElement[] backtrace = getBackTrace(rootFrame, e); + setBackTrace(rootFrame, e, null); + setStackTrace(rootFrame, e, backtrace); + throw new InterpreterException(e); + } + + return popAsObject(rootFrame, signature.returnKind()); + } + + public Object execute(Method javaMethod, Object... boxedArguments) throws InterpreterException { + return execute(vm.getRuntime().getResolvedJavaMethod(javaMethod), boxedArguments); + } + + private void executeRoot(InterpreterFrame root, InterpreterFrame frame) throws Throwable { + //TODO reflection redirection + stackFrameDepth = 0; + + InterpreterFrame prevFrame = frame; + InterpreterFrame currentFrame = frame; + BytecodeStream bs = new BytecodeStream(currentFrame.getMethod().code()); + if (TRACE) { + traceCall(frame, "Call"); + } + while (currentFrame != root) { + if (prevFrame != currentFrame) { + bs = new BytecodeStream(currentFrame.getMethod().code()); + } + bs.setBCI(currentFrame.getBCI()); + + prevFrame = currentFrame; + currentFrame = loop(root, prevFrame, bs); + } + assert callFrame == null; + } + + private InterpreterFrame loop(InterpreterFrame root, final InterpreterFrame frame, final BytecodeStream bs) throws Throwable { + try { + while (true) { + int result = executeInstruction(frame, bs); + switch (result) { + case NEXT : + bs.next(); + break; + case RETURN : + return popFrame(frame); + case CALL: + return allocateFrame(frame, bs); + case BRANCH : + bs.setBCI(bs.readBranchDest()); + break; + default : + // the outcome depends on stack values + assert result >= 0 : "negative branch target"; + bs.setBCI(result); + break; + } + } + } catch (Throwable t) { + if (TRACE) { + traceOp("Exception " + t.toString()); + } + updateStackTrace(frame, t); + + // frame bci needs to be in sync when handling exceptions + frame.setBCI(bs.currentBCI()); + + InterpreterFrame handlerFrame = handleThrowable(root, frame, t); + if (handlerFrame == null) { + // matched root we just throw it again. + throw t; + } else { + if (TRACE) { + traceOp("Handler found " + handlerFrame.getMethod() + ":" + handlerFrame.getBCI()); + } + // update bci from frame + bs.setBCI(handlerFrame.getBCI()); + + // continue execution on the found frame + return handlerFrame; + } + } finally { + // TODO may be not necessary. + frame.setBCI(bs.currentBCI()); + } + } + + private int executeInstruction(InterpreterFrame frame, BytecodeStream bs) throws Throwable { + if (TRACE_BYTE_CODE) { + traceOp(bs.currentBCI() + ": " + Bytecodes.baseNameOf(bs.currentBC())); + } + switch(bs.currentBC()) { + case Bytecodes.NOP : break; + case Bytecodes.ACONST_NULL : + frame.pushObject(null); + break; + case Bytecodes.ICONST_M1 : + frame.pushInt(-1); + break; + case Bytecodes.ICONST_0 : + frame.pushInt(0); + break; + case Bytecodes.ICONST_1 : + frame.pushInt(1); + break; + case Bytecodes.ICONST_2 : + frame.pushInt(2); + break; + case Bytecodes.ICONST_3 : + frame.pushInt(3); + break; + case Bytecodes.ICONST_4 : + frame.pushInt(4); + break; + case Bytecodes.ICONST_5 : + frame.pushInt(5); + break; + case Bytecodes.LCONST_0 : + frame.pushLong(0L); + break; + case Bytecodes.LCONST_1 : + frame.pushLong(1L); + break; + case Bytecodes.FCONST_0 : + frame.pushFloat(0.0F); + break; + case Bytecodes.FCONST_1 : + frame.pushFloat(1.0F); + break; + case Bytecodes.FCONST_2 : + frame.pushFloat(2.0F); + break; + case Bytecodes.DCONST_0 : + frame.pushDouble(0.0D); + break; + case Bytecodes.DCONST_1 : + frame.pushDouble(1.0D); + break; + case Bytecodes.BIPUSH : + frame.pushInt(bs.readByte()); + break; + case Bytecodes.SIPUSH : + frame.pushInt(bs.readShort()); + break; + case Bytecodes.LDC : + case Bytecodes.LDC_W : + case Bytecodes.LDC2_W : + pushCPConstant(frame, bs.readCPI()); + break; + case Bytecodes.ILOAD : + frame.pushInt(frame.getInt(frame.resolveLocalIndex(bs.readLocalIndex()))); + break; + case Bytecodes.LLOAD : + frame.pushLong(frame.getLong(frame.resolveLocalIndex(bs.readLocalIndex()))); + break; + case Bytecodes.FLOAD : + frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(bs.readLocalIndex()))); + break; + case Bytecodes.DLOAD : + frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(bs.readLocalIndex()))); + break; + case Bytecodes.ALOAD : + frame.pushObject(frame.getObject(frame.resolveLocalIndex(bs.readLocalIndex()))); + break; + case Bytecodes.ILOAD_0: + frame.pushInt(frame.getInt(frame.resolveLocalIndex(0))); + break; + case Bytecodes.ILOAD_1: + frame.pushInt(frame.getInt(frame.resolveLocalIndex(1))); + break; + case Bytecodes.ILOAD_2: + frame.pushInt(frame.getInt(frame.resolveLocalIndex(2))); + break; + case Bytecodes.ILOAD_3: + frame.pushInt(frame.getInt(frame.resolveLocalIndex(3))); + break; + case Bytecodes.LLOAD_0 : + frame.pushLong(frame.getLong(frame.resolveLocalIndex(0))); + break; + case Bytecodes.LLOAD_1 : + frame.pushLong(frame.getLong(frame.resolveLocalIndex(1))); + break; + case Bytecodes.LLOAD_2 : + frame.pushLong(frame.getLong(frame.resolveLocalIndex(2))); + break; + case Bytecodes.LLOAD_3 : + frame.pushLong(frame.getLong(frame.resolveLocalIndex(3))); + break; + case Bytecodes.FLOAD_0 : + frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(0))); + break; + case Bytecodes.FLOAD_1 : + frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(1))); + break; + case Bytecodes.FLOAD_2 : + frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(2))); + break; + case Bytecodes.FLOAD_3 : + frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(3))); + break; + case Bytecodes.DLOAD_0 : + frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(0))); + break; + case Bytecodes.DLOAD_1 : + frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(1))); + break; + case Bytecodes.DLOAD_2 : + frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(2))); + break; + case Bytecodes.DLOAD_3 : + frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(3))); + break; + case Bytecodes.ALOAD_0 : + frame.pushObject(frame.getObject(frame.resolveLocalIndex(0))); + break; + case Bytecodes.ALOAD_1 : + frame.pushObject(frame.getObject(frame.resolveLocalIndex(1))); + break; + case Bytecodes.ALOAD_2 : + frame.pushObject(frame.getObject(frame.resolveLocalIndex(2))); + break; + case Bytecodes.ALOAD_3 : + frame.pushObject(frame.getObject(frame.resolveLocalIndex(3))); + break; + case Bytecodes.IALOAD : + frame.pushInt(vm.getArrayInt(frame.popInt(), frame.popObject())); + break; + case Bytecodes.LALOAD : + frame.pushLong(vm.getArrayLong(frame.popInt(), frame.popObject())); + break; + case Bytecodes.FALOAD : + frame.pushFloat(vm.getArrayFloat(frame.popInt(), frame.popObject())); + break; + case Bytecodes.DALOAD : + frame.pushDouble(vm.getArrayDouble(frame.popInt(), frame.popObject())); + break; + case Bytecodes.AALOAD : + frame.pushObject(vm.getArrayObject(frame.popInt(), frame.popObject())); + break; + case Bytecodes.BALOAD : + frame.pushInt(vm.getArrayByte(frame.popInt(), frame.popObject())); + break; + case Bytecodes.CALOAD : + frame.pushInt(vm.getArrayChar(frame.popInt(), frame.popObject())); + break; + case Bytecodes.SALOAD: + frame.pushInt(vm.getArrayShort(frame.popInt(), frame.popObject())); + break; + case Bytecodes.ISTORE: + frame.setInt(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popInt()); + break; + case Bytecodes.LSTORE : + frame.setLong(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popLong()); + break; + case Bytecodes.FSTORE : + frame.setFloat(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popFloat()); + break; + case Bytecodes.DSTORE : + frame.setDouble(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popDouble()); + break; + case Bytecodes.ASTORE : + frame.setObject(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popObject()); + break; + case Bytecodes.ISTORE_0 : + frame.setInt(frame.resolveLocalIndex(0), frame.popInt()); + break; + case Bytecodes.ISTORE_1 : + frame.setInt(frame.resolveLocalIndex(1), frame.popInt()); + break; + case Bytecodes.ISTORE_2 : + frame.setInt(frame.resolveLocalIndex(2), frame.popInt()); + break; + case Bytecodes.ISTORE_3 : + frame.setInt(frame.resolveLocalIndex(3), frame.popInt()); + break; + case Bytecodes.LSTORE_0 : + frame.setLong(frame.resolveLocalIndex(0), frame.popLong()); + break; + case Bytecodes.LSTORE_1 : + frame.setLong(frame.resolveLocalIndex(1), frame.popLong()); + break; + case Bytecodes.LSTORE_2 : + frame.setLong(frame.resolveLocalIndex(2), frame.popLong()); + break; + case Bytecodes.LSTORE_3 : + frame.setLong(frame.resolveLocalIndex(3), frame.popLong()); + break; + case Bytecodes.FSTORE_0 : + frame.setFloat(frame.resolveLocalIndex(0), frame.popFloat()); + break; + case Bytecodes.FSTORE_1 : + frame.setFloat(frame.resolveLocalIndex(1), frame.popFloat()); + break; + case Bytecodes.FSTORE_2 : + frame.setFloat(frame.resolveLocalIndex(2), frame.popFloat()); + break; + case Bytecodes.FSTORE_3 : + frame.setFloat(frame.resolveLocalIndex(3), frame.popFloat()); + break; + case Bytecodes.DSTORE_0 : + frame.setDouble(frame.resolveLocalIndex(0), frame.popDouble()); + break; + case Bytecodes.DSTORE_1 : + frame.setDouble(frame.resolveLocalIndex(1), frame.popDouble()); + break; + case Bytecodes.DSTORE_2 : + frame.setDouble(frame.resolveLocalIndex(2), frame.popDouble()); + break; + case Bytecodes.DSTORE_3 : + frame.setDouble(frame.resolveLocalIndex(3), frame.popDouble()); + break; + case Bytecodes.ASTORE_0 : + frame.setObject(frame.resolveLocalIndex(0), frame.popObject()); + break; + case Bytecodes.ASTORE_1 : + frame.setObject(frame.resolveLocalIndex(1), frame.popObject()); + break; + case Bytecodes.ASTORE_2 : + frame.setObject(frame.resolveLocalIndex(2), frame.popObject()); + break; + case Bytecodes.ASTORE_3 : + frame.setObject(frame.resolveLocalIndex(3), frame.popObject()); + break; + case Bytecodes.IASTORE : + vm.setArrayInt(frame.popInt(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.LASTORE : + vm.setArrayLong(frame.popLong(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.FASTORE : + vm.setArrayFloat(frame.popFloat(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.DASTORE : + vm.setArrayDouble(frame.popDouble(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.AASTORE : + vm.setArrayObject(frame.popObject(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.BASTORE : + vm.setArrayByte((byte) frame.popInt(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.CASTORE : + vm.setArrayChar((char) frame.popInt(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.SASTORE : + vm.setArrayShort((short) frame.popInt(), frame.popInt(), frame.popObject()); + break; + case Bytecodes.POP : + frame.popVoid(1); + break; + case Bytecodes.POP2 : + frame.popVoid(2); + break; + case Bytecodes.DUP : + frame.dup(1); + break; + case Bytecodes.DUP_X1 : + frame.dupx1(); + break; + case Bytecodes.DUP_X2 : + frame.dupx2(); + break; + case Bytecodes.DUP2 : + frame.dup(2); + break; + case Bytecodes.DUP2_X1 : + frame.dup2x1(); + break; + case Bytecodes.DUP2_X2 : + frame.dup2x2(); + break; + case Bytecodes.SWAP : + frame.swapSingle(); + break; + case Bytecodes.IADD : + frame.pushInt(frame.popInt() + frame.popInt()); + break; + case Bytecodes.LADD : + frame.pushLong(frame.popLong() + frame.popLong()); + break; + case Bytecodes.FADD : + frame.pushFloat(frame.popFloat() + frame.popFloat()); + break; + case Bytecodes.DADD : + frame.pushDouble(frame.popDouble() + frame.popDouble()); + break; + case Bytecodes.ISUB : + frame.pushInt(-frame.popInt() + frame.popInt()); + break; + case Bytecodes.LSUB : + frame.pushLong(-frame.popLong() + frame.popLong()); + break; + case Bytecodes.FSUB : + frame.pushFloat(-frame.popFloat() + frame.popFloat()); + break; + case Bytecodes.DSUB : + frame.pushDouble(-frame.popDouble() + frame.popDouble()); + break; + case Bytecodes.IMUL : + frame.pushInt(frame.popInt() * frame.popInt()); + break; + case Bytecodes.LMUL : + frame.pushLong(frame.popLong() * frame.popLong()); + break; + case Bytecodes.FMUL : + frame.pushFloat(frame.popFloat() * frame.popFloat()); + break; + case Bytecodes.DMUL : + frame.pushDouble(frame.popDouble() * frame.popDouble()); + break; + case Bytecodes.IDIV : + divInt(frame); + break; + case Bytecodes.LDIV : + divLong(frame); + break; + case Bytecodes.FDIV : + divFloat(frame); + break; + case Bytecodes.DDIV : + divDouble(frame); + break; + case Bytecodes.IREM : + remInt(frame); + break; + case Bytecodes.LREM : + remLong(frame); + break; + case Bytecodes.FREM : + remFloat(frame); + break; + case Bytecodes.DREM : + remDouble(frame); + break; + case Bytecodes.INEG : + frame.pushInt(-frame.popInt()); + break; + case Bytecodes.LNEG : + frame.pushLong(-frame.popLong()); + break; + case Bytecodes.FNEG : + frame.pushFloat(-frame.popFloat()); + break; + case Bytecodes.DNEG : + frame.pushDouble(-frame.popDouble()); + break; + case Bytecodes.ISHL : + shiftLeftInt(frame); + break; + case Bytecodes.LSHL : + shiftLeftLong(frame); + break; + case Bytecodes.ISHR : + shiftRightSignedInt(frame); + break; + case Bytecodes.LSHR : + shiftRightSignedLong(frame); + break; + case Bytecodes.IUSHR : + shiftRightUnsignedInt(frame); + break; + case Bytecodes.LUSHR : + shiftRightUnsignedLong(frame); + break; + case Bytecodes.IAND : + frame.pushInt(frame.popInt() & frame.popInt()); + break; + case Bytecodes.LAND : + frame.pushLong(frame.popLong() & frame.popLong()); + break; + case Bytecodes.IOR : + frame.pushInt(frame.popInt() | frame.popInt()); + break; + case Bytecodes.LOR : + frame.pushLong(frame.popLong() | frame.popLong()); + break; + case Bytecodes.IXOR : + frame.pushInt(frame.popInt() ^ frame.popInt()); + break; + case Bytecodes.LXOR : + frame.pushLong(frame.popLong() ^ frame.popLong()); + break; + case Bytecodes.IINC : + iinc(frame, bs); + break; + case Bytecodes.I2L : + frame.pushLong(frame.popInt()); + break; + case Bytecodes.I2F : + frame.pushFloat(frame.popInt()); + break; + case Bytecodes.I2D : + frame.pushDouble(frame.popInt()); + break; + case Bytecodes.L2I : + frame.pushInt((int) frame.popLong()); + break; + case Bytecodes.L2F : + frame.pushFloat(frame.popLong()); + break; + case Bytecodes.L2D : + frame.pushDouble(frame.popLong()); + break; + case Bytecodes.F2I : + frame.pushInt((int) frame.popFloat()); + break; + case Bytecodes.F2L : + frame.pushLong((long) frame.popFloat()); + break; + case Bytecodes.F2D : + frame.pushDouble(frame.popFloat()); + break; + case Bytecodes.D2I : + frame.pushInt((int) frame.popDouble()); + break; + case Bytecodes.D2L : + frame.pushLong((long) frame.popDouble()); + break; + case Bytecodes.D2F : + frame.pushFloat((float) frame.popDouble()); + break; + case Bytecodes.I2B : + frame.pushInt((byte) frame.popInt()); + break; + case Bytecodes.I2C : + frame.pushInt((char) frame.popInt()); + break; + case Bytecodes.I2S : + frame.pushInt((short) frame.popInt()); + break; + case Bytecodes.LCMP : + compareLong(frame); + break; + case Bytecodes.FCMPL : + compareFloatLess(frame); + break; + case Bytecodes.FCMPG : + compareFloatGreater(frame); + break; + case Bytecodes.DCMPL : + compareDoubleLess(frame); + break; + case Bytecodes.DCMPG : + compareDoubleGreater(frame); + break; + case Bytecodes.IFEQ : + if (frame.popInt() == 0) { + return BRANCH; + } + break; + case Bytecodes.IFNE : + if (frame.popInt() != 0) { + return BRANCH; + } + break; + case Bytecodes.IFLT : + if (frame.popInt() < 0) { + return BRANCH; + } + break; + case Bytecodes.IFGE : + if (frame.popInt() >= 0) { + return BRANCH; + } + break; + case Bytecodes.IFGT : + if (frame.popInt() > 0) { + return BRANCH; + } + break; + case Bytecodes.IFLE : + if (frame.popInt() <= 0) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPEQ : + if (frame.popInt() == frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPNE : + if (frame.popInt() != frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPLT : + if (frame.popInt() > frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPGE : + if (frame.popInt() <= frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPGT : + if (frame.popInt() < frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ICMPLE : + if (frame.popInt() >= frame.popInt()) { + return BRANCH; + } + break; + case Bytecodes.IF_ACMPEQ : + if (frame.popObject() == frame.popObject()) { + return BRANCH; + } + break; + case Bytecodes.IF_ACMPNE : + if (frame.popObject() != frame.popObject()) { + return BRANCH; + } + break; + case Bytecodes.GOTO: + case Bytecodes.GOTO_W: + return BRANCH; + case Bytecodes.JSR : + case Bytecodes.JSR_W : + frame.pushInt(bs.currentBCI()); + return BRANCH; + case Bytecodes.RET : + return frame.getInt(frame.resolveLocalIndex(bs.readLocalIndex())); + case Bytecodes.TABLESWITCH : + return tableSwitch(frame, bs); + case Bytecodes.LOOKUPSWITCH : + return lookupSwitch(frame, bs); + case Bytecodes.IRETURN : + frame.getParentFrame().pushInt(frame.popInt()); + return RETURN; + case Bytecodes.LRETURN : + frame.getParentFrame().pushLong(frame.popLong()); + return RETURN; + case Bytecodes.FRETURN : + frame.getParentFrame().pushFloat(frame.popFloat()); + return RETURN; + case Bytecodes.DRETURN : + frame.getParentFrame().pushDouble(frame.popDouble()); + return RETURN; + case Bytecodes.ARETURN : + frame.getParentFrame().pushObject(frame.popObject()); + return RETURN; + case Bytecodes.RETURN : + return RETURN; + case Bytecodes.GETSTATIC : + getField(frame, null, bs.currentBC(), bs.readCPI()); + break; + case Bytecodes.PUTSTATIC : + putStatic(frame, bs.readCPI()); + break; + case Bytecodes.GETFIELD: + getField(frame, nullCheck(frame.popObject()), bs.currentBC(), bs.readCPI()); + break; + case Bytecodes.PUTFIELD : + putField(frame, bs.readCPI()); + break; + case Bytecodes.INVOKEVIRTUAL : + callFrame = invokeVirtual(frame, bs.readCPI()); + if (callFrame == null) { + break; + } + return CALL; + case Bytecodes.INVOKESPECIAL : + callFrame = invokeSpecial(frame, bs.readCPI()); + if (callFrame == null) { + break; + } + return CALL; + case Bytecodes.INVOKESTATIC : + callFrame = invokeStatic(frame, bs.readCPI()); + if (callFrame == null) { + break; + } + return CALL; + case Bytecodes.INVOKEINTERFACE: + callFrame = invokeInterface(frame, bs.readCPI()); + if (callFrame == null) { + break; + } + return CALL; + case Bytecodes.XXXUNUSEDXXX : + assert false : "unused bytecode used. behaviour unspecfied."; + // nop + break; + case Bytecodes.NEW : + frame.pushObject(allocateInstance(frame, bs.readCPI())); + break; + case Bytecodes.NEWARRAY : + frame.pushObject(allocateNativeArray(frame, bs.readByte())); + break; + case Bytecodes.ANEWARRAY : + frame.pushObject(allocateArray(frame, bs.readCPI())); + break; + case Bytecodes.ARRAYLENGTH : + frame.pushInt(Array.getLength(nullCheck(frame.popObject()))); + break; + case Bytecodes.ATHROW : + throw (Throwable) frame.popObject(); + case Bytecodes.CHECKCAST : + checkCast(frame, bs.readCPI()); + break; + case Bytecodes.INSTANCEOF : + instanceOf(frame, bs.readCPI()); + break; + case Bytecodes.MONITORENTER : + vm.monitorEnter(frame.popObject()); + break; + case Bytecodes.MONITOREXIT : + vm.monitorExit(frame.popObject()); + break; + case Bytecodes.WIDE : + assert false; + break; + case Bytecodes.MULTIANEWARRAY : + frame.pushObject(allocateMultiArray(frame, bs.readCPI(), bs.readUByte(bs.currentBCI() + 3))); + break; + case Bytecodes.IFNULL : + if (frame.popObject() == null) { + return BRANCH; + } + break; + case Bytecodes.IFNONNULL : + if (frame.popObject() != null) { + return BRANCH; + } + break; + case Bytecodes.BREAKPOINT : + assert false : "no breakpoints supported at this time."; + break; // nop + } + return NEXT; + } + + private InterpreterFrame handleThrowable(InterpreterFrame root, InterpreterFrame frame, Throwable t) { + ExceptionHandler handler; + InterpreterFrame currentFrame = frame; + do { + handler = resolveExceptionHandlers(currentFrame, currentFrame.getBCI(), t); + if (handler == null) { + // no handler found pop frame + // and continue searching + currentFrame = popFrame(currentFrame); + } else { + // found a handler -> execute it + if (handler.isCatchAll()) { + catchAllExceptionHandler = handler; + } else { + catchAllExceptionHandler = null; + } + currentFrame.setBCI(handler.handlerBCI()); + currentFrame.popStack(); + currentFrame.pushObject(t); + return currentFrame; + } + } while (handler == null && currentFrame != root); + + // will throw exception up the interpreter + return null; + } + + private void updateStackTrace(InterpreterFrame frame, Throwable t) { + StackTraceElement[] elements = getBackTrace(frame, t); + if (elements != null) { + setStackTrace(frame, t, elements); + setBackTrace(frame, t, null); + } else { + setBackTrace(frame, t, createStackTraceElements(frame)); + } + } + + + private void setStackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] stackTrace) { + vm.setField(stackTrace, t, findThrowableField(frame, "stackTrace")); + } + + private StackTraceElement[] getBackTrace(InterpreterFrame frame, Throwable t) { + Object value = vm.getField(t, findThrowableField(frame, "backtrace")); + if (value instanceof StackTraceElement[]) { + return (StackTraceElement[]) value; + } + return null; + } + + private void setBackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] backtrace) { + vm.setField(backtrace, t, findThrowableField(frame, "backtrace")); + } + + private ExceptionHandler resolveExceptionHandlers(InterpreterFrame frame, int bci, Throwable t) { + ExceptionHandler[] handlers = frame.getMethod().exceptionHandlers(); + for (int i = 0; i < handlers.length; i++) { + ExceptionHandler handler = handlers[i]; + if (bci >= handler.startBCI() + && bci <= handler.endBCI() + && (catchAllExceptionHandler == null || !handler.isCatchAll())) { + ResolvedJavaType catchType = null; + if (!handler.isCatchAll()) { + catchType = resolveType(frame, bci, (char) handler.catchTypeCPI()); + } + + if (catchType == null + || catchType.toJava().isInstance(t)) { + // the first found exception handler is our exception handler + return handler; + } + } + } + return null; + } + + private InterpreterFrame allocateFrame(InterpreterFrame frame, BytecodeStream bs) { + try { + stackFrameDepth++; + + InterpreterFrame nextFrame = this.callFrame; + + assert nextFrame != null; + assert nextFrame.getParentFrame() == frame; + + // store bci when leaving method + frame.setBCI(bs.currentBCI()); + + if (TRACE) { + traceCall(nextFrame, "Call"); + } + if (Modifier.isSynchronized(nextFrame.getMethod().accessFlags())) { + if (TRACE) { + traceOp("Method monitor enter"); + } + if (Modifier.isStatic(nextFrame.getMethod().accessFlags())) { + vm.monitorEnter(nextFrame.getMethod().holder().toJava()); + } else { + Object enterObject = nextFrame.getObject(frame.resolveLocalIndex(0)); + assert enterObject != null; + vm.monitorEnter(enterObject); + } + } + + return nextFrame; + } finally { + // catch all exception handlers are not allowed to call any method anyway. + catchAllExceptionHandler = null; + callFrame = null; + bs.next(); + } + } + + private InterpreterFrame popFrame(InterpreterFrame frame) { + catchAllExceptionHandler = null; + InterpreterFrame parent = frame.getParentFrame(); + if (Modifier.isSynchronized(frame.getMethod().accessFlags())) { + if (TRACE) { + traceOp("Method monitor exit"); + } + if (Modifier.isStatic(frame.getMethod().accessFlags())) { + vm.monitorExit(frame.getMethod().holder().toJava()); + } else { + Object exitObject = frame.getObject(frame.resolveLocalIndex(0)); + if (exitObject != null) { + vm.monitorExit(exitObject); + } + } + } + if (TRACE) { + traceCall(frame, "Ret"); + } + stackFrameDepth--; + + frame.dispose(); + return parent; + } + + private void traceOp(String opName) { + trace(stackFrameDepth + 1, opName); + } + + private void traceCall(InterpreterFrame frame, String type) { + trace(stackFrameDepth, type + " " + + frame.getMethod() + " - " + frame.getMethod().signature().asString()); + } + + private void trace(int level, String message) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < level; i++) { + builder.append(" "); + } + builder.append(message); + System.out.println(builder); + } + + + private void divInt(InterpreterFrame frame) { + int dividend = frame.popInt(); + int divisor = frame.popInt(); + frame.pushInt(divisor / dividend); + } + + private void divLong(InterpreterFrame frame) { + long dividend = frame.popLong(); + long divisor = frame.popLong(); + frame.pushLong(divisor / dividend); + } + + private void divFloat(InterpreterFrame frame) { + float dividend = frame.popFloat(); + float divisor = frame.popFloat(); + frame.pushFloat(divisor / dividend); + } + + private void divDouble(InterpreterFrame frame) { + double dividend = frame.popDouble(); + double divisor = frame.popDouble(); + frame.pushDouble(divisor / dividend); + } + + + private void remInt(InterpreterFrame frame) { + int dividend = frame.popInt(); + int divisor = frame.popInt(); + frame.pushInt(divisor % dividend); + } + + private void remLong(InterpreterFrame frame) { + long dividend = frame.popLong(); + long divisor = frame.popLong(); + frame.pushLong(divisor % dividend); + } + + private void remFloat(InterpreterFrame frame) { + float dividend = frame.popFloat(); + float divisor = frame.popFloat(); + frame.pushFloat(divisor % dividend); + } + + private void remDouble(InterpreterFrame frame) { + double dividend = frame.popDouble(); + double divisor = frame.popDouble(); + frame.pushDouble(divisor % dividend); + } + + private void shiftLeftInt(InterpreterFrame frame) { + int bits = frame.popInt(); + int value = frame.popInt(); + frame.pushInt(value << bits); + } + + private void shiftLeftLong(InterpreterFrame frame) { + int bits = frame.popInt(); + long value = frame.popLong(); + frame.pushLong(value << bits); + } + + private void shiftRightSignedInt(InterpreterFrame frame) { + int bits = frame.popInt(); + int value = frame.popInt(); + frame.pushInt(value >> bits); + } + + private void shiftRightSignedLong(InterpreterFrame frame) { + int bits = frame.popInt(); + long value = frame.popLong(); + frame.pushLong(value >> bits); + } + + private void shiftRightUnsignedInt(InterpreterFrame frame) { + int bits = frame.popInt(); + int value = frame.popInt(); + frame.pushInt(value >>> bits); + } + + private void shiftRightUnsignedLong(InterpreterFrame frame) { + int bits = frame.popInt(); + long value = frame.popLong(); + frame.pushLong(value >>> bits); + } + + private int lookupSwitch(InterpreterFrame frame, BytecodeStream bs) { + return lookupSearch( + new BytecodeLookupSwitch(bs, bs.currentBCI()), frame.popInt()); + } + + /** + * Binary search implementation for the lookup switch. + */ + private int lookupSearch(BytecodeLookupSwitch switchHelper, int key) { + int low = 0; + int high = switchHelper.numberOfCases() - 1; + while (low <= high) { + int mid = (low + high) >>> 1; + int midVal = switchHelper.keyAt(mid); + + if (midVal < key) { + low = mid + 1; + } else if (midVal > key) { + high = mid - 1; + } else { + return switchHelper.bci() + switchHelper.offsetAt(mid); // key found + } + } + return switchHelper.defaultTarget(); // key not found. + } + + private int tableSwitch(InterpreterFrame frame, BytecodeStream bs) { + BytecodeTableSwitch switchHelper = new BytecodeTableSwitch(bs, bs.currentBCI()); + + int low = switchHelper.lowKey(); + int high = switchHelper.highKey(); + + assert low <= high; + + int index = frame.popInt(); + if (index < low || index > high) { + return switchHelper.defaultTarget(); + } else { + return switchHelper.targetAt(index - low); + } + } + + private void checkCast(InterpreterFrame frame, char cpi) { + frame.pushObject(resolveType(frame, Bytecodes.CHECKCAST, cpi).toJava().cast(frame.popObject())); + } + + private ResolvedJavaType resolveType(InterpreterFrame frame, int opcode, char cpi) { + ConstantPool constantPool = frame.getConstantPool(); + constantPool.loadReferencedType(cpi, opcode); + return constantPool.lookupType(cpi, opcode).resolve(frame.getMethod().holder()); + } + + private ResolvedJavaType resolveType(InterpreterFrame frame, Class javaClass) { + return vm.getRuntime().getResolvedJavaType(javaClass).resolve(frame.getMethod().holder()); + } + + private ResolvedJavaMethod resolveMethod(InterpreterFrame frame, int opcode, char cpi) { + ConstantPool constantPool = frame.getConstantPool(); + constantPool.loadReferencedType(cpi, opcode); + return (ResolvedJavaMethod) constantPool.lookupMethod(cpi, opcode); + } + + private ResolvedJavaField resolveField(InterpreterFrame frame, int opcode, char cpi) { + ConstantPool constantPool = frame.getConstantPool(); + constantPool.loadReferencedType(cpi, opcode); + return (ResolvedJavaField) constantPool.lookupField(cpi, opcode); + } + + private void instanceOf(InterpreterFrame frame, char cpi) { + frame.pushInt(resolveType(frame, Bytecodes.INSTANCEOF, cpi). + toJava().isInstance(frame.popObject()) + ? 1 : 0); + } + + private void pushCPConstant(InterpreterFrame frame, char cpi) { + ResolvedJavaMethod method = frame.getMethod(); + Object constant = method.getConstantPool().lookupConstant(cpi); + + if (constant instanceof Constant) { + Constant c = ((Constant) constant); + switch (c.kind) { + case Int : + frame.pushInt(c.asInt()); + break; + case Float: + frame.pushFloat(c.asFloat()); + break; + case Object: + frame.pushObject(c.asObject()); + break; + case Double : + frame.pushDouble(c.asDouble()); + break; + case Long : + frame.pushLong(c.asLong()); + break; + default: + assert false : "unspecified case"; + } + } else if (constant instanceof JavaType) { + frame.pushObject(((JavaType) constant).resolve(method.holder()).toJava()); + } else { + assert false : "unexpected case"; + } + } + + private void compareLong(InterpreterFrame frame) { + long y = frame.popLong(); + long x = frame.popLong(); + frame.pushInt((x < y) ? -1 : ((x == y) ? 0 : 1)); + } + + private void compareDoubleGreater(InterpreterFrame frame) { + double y = frame.popDouble(); + double x = frame.popDouble(); + frame.pushInt(x < y ? -1 : ((x == y) ? 0 : 1)); + } + + private void compareDoubleLess(InterpreterFrame frame) { + double y = frame.popDouble(); + double x = frame.popDouble(); + frame.pushInt(x > y ? 1 : ((x == y) ? 0 : -1)); + } + + private void compareFloatGreater(InterpreterFrame frame) { + float y = frame.popFloat(); + float x = frame.popFloat(); + frame.pushInt(x < y ? -1 : ((x == y) ? 0 : 1)); + } + + private void compareFloatLess(InterpreterFrame frame) { + float y = frame.popFloat(); + float x = frame.popFloat(); + frame.pushInt(x > y ? 1 : ((x == y) ? 0 : -1)); + } + + private Object nullCheck(Object value) { + if (value == null) { + throw new NullPointerException(); + } + return value; + } + private InterpreterFrame invokeStatic(InterpreterFrame frame, char cpi) throws Throwable { + return invoke(frame, resolveMethod(frame, Bytecodes.INVOKESTATIC, cpi), null); + } + + private InterpreterFrame invokeInterface(InterpreterFrame frame, char cpi) throws Throwable { + return resolveAndInvoke(frame, resolveMethod(frame, Bytecodes.INVOKEINTERFACE, cpi)); + } + + private InterpreterFrame resolveAndInvoke(InterpreterFrame parent, ResolvedJavaMethod m) throws Throwable { + Object receiver = nullCheck(parent.peekReceiver(m)); + + ResolvedJavaMethod method = resolveType(parent, receiver.getClass()).resolveMethodImpl(m); + + if (method == null) { + throw new AbstractMethodError(); + } + + return invoke(parent, method, receiver); + } + + private InterpreterFrame invokeVirtual(InterpreterFrame frame, char cpi) throws Throwable { + ResolvedJavaMethod m = resolveMethod(frame, Bytecodes.INVOKEVIRTUAL, cpi); + if (Modifier.isFinal(m.accessFlags())) { + return invoke(frame, m, nullCheck(frame.peekReceiver(m))); + } else { + return resolveAndInvoke(frame, m); + } + } + + private InterpreterFrame invokeSpecial(InterpreterFrame frame, char cpi) throws Throwable { + ResolvedJavaMethod m = resolveMethod(frame, Bytecodes.INVOKESPECIAL, cpi); + return invoke(frame, m, nullCheck(frame.peekReceiver(m))); + } + + private void invokeReflective(InterpreterFrame frame, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { + Class[] parameterTypes = resolveMethodArguments(method); + Object[] parameters = popArgumentsAsObject(frame, method); + Class javaClass = method.holder().toJava(); + + Object parentObject = null; + if (hasReceiver) { + parentObject = frame.popObject(); + nullCheck(parentObject); + } + Object returnValue = null; + + if (redirect(method)) { + if (TRACE) { + traceCall(frame, "Delegate " + method); + } + try { + returnValue = methodDelegates.get(method).invoke(frame, method, parentObject, parameters); + } catch (Throwable e) { + throw e; + } + } else { + if (TRACE) { + traceCall(frame, "Reflective " + method); + } + try { + Method javaMethod = javaClass.getDeclaredMethod(method.name(), parameterTypes); + javaMethod.setAccessible(true); + returnValue = javaMethod.invoke(parentObject, parameters); + } catch (InvocationTargetException e) { + e.printStackTrace(System.out); + throw e.getTargetException(); + } catch (NoSuchMethodException | SecurityException e) { + throw new AbstractMethodError(); + } + } + + pushAsObject(frame, method.signature().returnKind(), returnValue); + } + + private Object[] popArgumentsAsObject(InterpreterFrame frame, ResolvedJavaMethod method) { + Signature signature = method.signature(); + int argumentCount = method.signature().argumentCount(false); + Object[] parameters = new Object[argumentCount]; + for (int i = argumentCount - 1; i >= 0; i--) { + ResolvedJavaType type = signature.argumentTypeAt(i, method.holder()).resolve(method.holder()); + parameters[i] = popAsObject(frame, type.kind()); + } + return parameters; + } + + private Class[] resolveMethodArguments(ResolvedJavaMethod method) { + Signature signature = method.signature(); + int argumentCount = signature.argumentCount(false); + Class[] parameterTypes = new Class[argumentCount]; + + for (int i = 0; i < argumentCount; i++) { + JavaType type = signature.argumentTypeAt(i, method.holder()); + ResolvedJavaType resolvedType = type.resolve(method.holder()); + parameterTypes[i] = resolvedType.toJava(); + } + return parameterTypes; + } + + private InterpreterFrame invoke(InterpreterFrame parent, ResolvedJavaMethod method, Object receiver) throws Throwable { + if (stackFrameDepth >= maxStackFrames) { + throw new StackOverflowError("Maximum callstack of " + maxStackFrames + " exceeded."); + } + if (redirect(method)) { + invokeReflective(parent, method, receiver != null); + + // returning null results in a jump to the next instruction + // since the method is already successfully invoked. + return null; + } else { + if (Modifier.isNative(method.accessFlags())) { + invokeReflective(parent, method, receiver != null); + return null; + } else { + return parent.create(method, receiver != null); + } + } + } + + private boolean redirect(ResolvedJavaMethod method) { + return methodDelegates.containsKey(method); + } + + + private Object allocateMultiArray(InterpreterFrame frame, char cpi, int dimension) { + ResolvedJavaType type = resolveType(frame, Bytecodes.MULTIANEWARRAY, cpi); + int[] dimensions = new int[dimension]; + for (int i = 0; i < dimension; i++) { + dimensions[i] = frame.popInt(); + } + return Array.newInstance(type.toJava(), dimensions); + } + + private Object allocateArray(InterpreterFrame frame, char cpi) { + ResolvedJavaType type = resolveType(frame, Bytecodes.ANEWARRAY, cpi); + return Array.newInstance(type.toJava(), frame.popInt()); + } + + private Object allocateNativeArray(InterpreterFrame frame, byte cpi) { + // the constants for the cpi are loosely defined and no real cpi indices. + switch (cpi) { + case 4 : + return new byte[frame.popInt()]; + case 8 : + return new byte[frame.popInt()]; + case 5 : + return new char[frame.popInt()]; + case 7 : + return new double[frame.popInt()]; + case 6 : + return new float[frame.popInt()]; + case 10 : + return new int[frame.popInt()]; + case 11 : + return new long[frame.popInt()]; + case 9 : + return new short[frame.popInt()]; + default: + assert false : "unexpected case"; + return null; + } + } + + private Object allocateInstance(InterpreterFrame frame, char cpi) throws InstantiationException { + return vm.newObject(resolveType(frame, Bytecodes.NEW, cpi)); + } + + private void iinc(InterpreterFrame frame, BytecodeStream bs) { + int index = frame.resolveLocalIndex(bs.readLocalIndex()); + frame.setInt(index, frame.getInt(index) + bs.readIncrement()); + } + + private void putStatic(InterpreterFrame frame, char cpi) { + putFieldStatic(frame, resolveField(frame, Bytecodes.PUTSTATIC, cpi)); + } + + private void putField(InterpreterFrame frame, char cpi) { + putFieldVirtual(frame, resolveField(frame, Bytecodes.PUTFIELD, cpi)); + } + + private void putFieldStatic(InterpreterFrame frame, ResolvedJavaField field) { + switch (field.kind()) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : + vm.setFieldInt(frame.popInt(), null, field); + break; + case Double : + vm.setFieldDouble(frame.popDouble(), null, field); + break; + case Float : + vm.setFieldFloat(frame.popFloat(), null, field); + break; + case Long : + vm.setFieldLong(frame.popLong(), null, field); + break; + case Object : + vm.setField(frame.popObject(), null, field); + break; + default : + assert false : "unexpected case"; + } + } + + private void putFieldVirtual(InterpreterFrame frame, ResolvedJavaField field) { + switch (field.kind()) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : + vm.setFieldInt(frame.popInt(), nullCheck(frame.popObject()), field); + break; + case Double : + vm.setFieldDouble(frame.popDouble(), nullCheck(frame.popObject()), field); + break; + case Float : + vm.setFieldFloat(frame.popFloat(), nullCheck(frame.popObject()), field); + break; + case Long : + vm.setFieldLong(frame.popLong(), nullCheck(frame.popObject()), field); + break; + case Object : + vm.setField(frame.popObject(), nullCheck(frame.popObject()), field); + break; + default : + assert false : "unexpected case"; + } + } + + private void getField(InterpreterFrame frame, Object base, int opcode, char cpi) { + ResolvedJavaField field = resolveField(frame, opcode, cpi); + switch (field.kind()) { + case Boolean : + case Byte : + case Char : + case Short : + case Int : + frame.pushInt(vm.getFieldInt(base, field)); + break; + case Double : + frame.pushDouble(vm.getFieldDouble(base, field)); + break; + case Float : + frame.pushFloat(vm.getFieldFloat(base, field)); + break; + case Long : + frame.pushLong(vm.getFieldLong(base, field)); + break; + case Object : + frame.pushObject(vm.getField(base, field)); + break; + default : + assert false : "unexpected case"; + } + } + + + private int pushAsObject(InterpreterFrame frame, Kind typeKind, Object value) { + switch(typeKind) { + case Int : + frame.pushInt((int) value); + break; + case Long : + frame.pushLong((long) value); + return 2; + case Boolean : + frame.pushInt(((boolean) value) ? 1 : 0); + break; + case Byte : + frame.pushInt((byte) value); + break; + case Char : + frame.pushInt((char) value); + break; + case Double : + frame.pushDouble((double) value); + return 2; + case Float : + frame.pushFloat((float) value); + break; + case Short : + frame.pushInt((short) value); + break; + case Object : + frame.pushObject(value); + break; + case Void : + return 0; + default : + assert false : "case not specified"; + } + return 1; + } + + private Object popAsObject(InterpreterFrame frame, Kind typeKind) { + switch (typeKind) { + case Boolean : + return frame.popInt() == 1 ? true : false; + case Byte : + return (byte) frame.popInt(); + case Char : + return (char) frame.popInt(); + case Double : + return frame.popDouble(); + case Int : + return frame.popInt(); + case Float : + return frame.popFloat(); + case Long : + return frame.popLong(); + case Short : + return (short) frame.popInt(); + case Object : + return frame.popObject(); + case Void : + return null; + default : + assert false : "unexpected case"; + } + return null; + } + + private ResolvedJavaMethod resolveRootMethod() { + try { + return vm.getRuntime().getResolvedJavaMethod(BytecodeInterpreter.class.getDeclaredMethod("execute", Method.class, Object[].class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static Method findMethod(Class clazz, String name, Class ... parameters) { + try { + return clazz.getDeclaredMethod(name, parameters); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static StackTraceElement[] createStackTraceElements(InterpreterFrame frame) { + InterpreterFrame tmp = frame; + List elements = new ArrayList<>(); + boolean first = false; // filter only first stack elements + while (tmp != null) { + if (first || !filterStackElement(tmp)) { + first = true; + elements.add(tmp.getMethod().toStackTraceElement(tmp.getBCI())); + } + tmp = tmp.getParentFrame(); + } + return elements.toArray(new StackTraceElement[elements.size()]); + } + + private static boolean filterStackElement(InterpreterFrame frame) { + return Throwable.class.isAssignableFrom(frame.getMethod().holder().toJava()); + } + + private ResolvedJavaField findThrowableField(InterpreterFrame frame, String name) { + ResolvedJavaType throwableType = resolveType(frame, Throwable.class); + ResolvedJavaField[] fields = throwableType.declaredFields(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].name().equals(name)) { + return fields[i]; + } + } + assert false; + return null; + } + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/Frame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/Frame.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +import java.lang.reflect.*; + +import sun.misc.*; + +public class Frame { + + public static final Object[] EMPTY_ARRAY = new Object[0]; + public static final int PARENT_FRAME_SLOT = 0; + public static final int MIN_FRAME_SIZE = 1; + private static final Unsafe unsafe = getUnsafe(); + + protected final Object[] locals; + protected final long[] primitiveLocals; + + public Frame(int numLocals, Frame parent) { + assert numLocals >= MIN_FRAME_SIZE; + this.locals = new Object[numLocals]; + this.locals[PARENT_FRAME_SLOT] = parent; + this.primitiveLocals = new long[numLocals]; + } + + public Frame(int numLocals) { + this(numLocals, null); + } + + public Object getObject(int index) { + return locals[index]; + } + + public void setObject(int index, Object value) { + locals[index] = value; + } + + public float getFloat(int index) { + return unsafe.getFloat(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET); + } + + public void setFloat(int index, float value) { + unsafe.putFloat(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value); + } + + public long getLong(int index) { + return unsafe.getLong(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET); + } + + public void setLong(int index, long value) { + unsafe.putLong(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value); + } + + public int getInt(int index) { + return unsafe.getInt(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET); + } + + public void setInt(int index, int value) { + unsafe.putInt(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value); + } + + public double getDouble(int index) { + return unsafe.getDouble(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET); + } + + public void setDouble(int index, double value) { + unsafe.putDouble(primitiveLocals, (long) index * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value); + } + + public static Frame getParentFrame(Frame frame, int level) { + assert level >= 0; + if (level == 0) { + return frame; + } else { + return getParentFrame((Frame) frame.getObject(PARENT_FRAME_SLOT), level - 1); + } + } + + public static Frame getTopFrame(Frame frame) { + Frame parentFrame = (Frame) frame.getObject(PARENT_FRAME_SLOT); + if (parentFrame == null) { + return frame; + } else { + return getTopFrame(parentFrame); + } + } + + public static Object[] getArguments(Frame frame, int argOffset) { + return (Object[]) frame.getObject(argOffset); + } + + public int size() { + return locals.length; + } + + @SuppressWarnings("unused") + private boolean indexExists(int index) { + return index >= 0 && index < locals.length; + } + + private static Unsafe getUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterCallable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterCallable.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +import com.oracle.graal.api.meta.*; + + +public interface InterpreterCallable { + + Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object base, Object[] arguments) throws Throwable; + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterException.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +/** + * Thrown if executed byte code caused an error in {@link BytecodeInterpreter}. The actual execution exception is + * accessible using {@link #getCause()} or {@link #getExecutionThrowable()}. + */ +public class InterpreterException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public InterpreterException(Throwable cause) { + super(cause); + } + + public Throwable getExecutionThrowable() { + return getCause(); + } + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/InterpreterFrame.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +import java.util.*; + +import com.oracle.graal.api.meta.*; + +public class InterpreterFrame extends Frame { + + public static final int BASE_LENGTH = 3; + + private static final int METHOD_FRAME_SLOT = 1; + private static final int BCI_FRAME_SLOT = 2; + + private static final int DOUBLE = 2; + private static final int SINGLE = 1; + + /** Pointer to the top-most stack frame element. */ + private int tos; + + public InterpreterFrame(ResolvedJavaMethod method, int additionalStackSpace) { + this(method, null, additionalStackSpace); + } + + private InterpreterFrame(ResolvedJavaMethod method, InterpreterFrame parent, int additionalStackSpace) { + super(method.maxLocals() + method.maxStackSize() + BASE_LENGTH + additionalStackSpace, parent); + setMethod(method); + setBCI(0); + this.tos = BASE_LENGTH; + } + + public InterpreterFrame create(ResolvedJavaMethod method, boolean hasReceiver) { + InterpreterFrame frame = new InterpreterFrame(method, this, 0); + int length = method.signature().argumentSlots(hasReceiver); + + frame.pushVoid(method.maxLocals()); + if (length > 0) { + copyArguments(frame, length); + popVoid(length); + } + + return frame; + } + + public int resolveLocalIndex(int index) { + return BASE_LENGTH + index; + } + + private int stackTos() { + return BASE_LENGTH + getMethod().maxLocals(); + } + + private void copyArguments(InterpreterFrame dest, int length) { + System.arraycopy(locals, tosSingle(length - 1), dest.locals, + BASE_LENGTH, length); + System.arraycopy(primitiveLocals, tosSingle(length - 1), dest.primitiveLocals, + BASE_LENGTH, length); + } + + + public Object peekReceiver(ResolvedJavaMethod method) { + return getObject(tosSingle(method.signature().argumentSlots(false))); + } + + public void pushBoth(Object oValue, int intValue) { + incrementTos(SINGLE); + setObject(tosSingle(0), oValue); + setInt(tosSingle(0), intValue); + } + + public void pushBoth(Object oValue, long longValue) { + incrementTos(SINGLE); + setObject(tosSingle(0), oValue); + setLong(tosSingle(0), longValue); + } + + public void pushObject(Object value) { + incrementTos(SINGLE); + setObject(tosSingle(0), value); + } + + public void pushInt(int value) { + incrementTos(SINGLE); + setInt(tosSingle(0), value); + } + + public void pushDouble(double value) { + incrementTos(DOUBLE); + setDouble(tosDouble(0), value); + } + + public void pushFloat(float value) { + incrementTos(SINGLE); + setFloat(tosSingle(0), value); + } + + public void pushLong(long value) { + incrementTos(DOUBLE); + setLong(tosDouble(0), value); + } + + public int popInt() { + int value = getInt(tosSingle(0)); + decrementTos(SINGLE); + return value; + } + + public double popDouble() { + double value = getDouble(tosDouble(0)); + decrementTos(DOUBLE); + return value; + } + + public float popFloat() { + float value = getFloat(tosSingle(0)); + decrementTos(SINGLE); + return value; + } + + public long popLong() { + long value = getLong(tosDouble(0)); + decrementTos(DOUBLE); + return value; + } + + public Object popObject() { + Object value = getObject(tosSingle(0)); + decrementTos(SINGLE); + return value; + } + + public void swapSingle() { + int tmpInt = getInt(tosSingle(1)); + Object tmpObject = getObject(tosSingle(1)); + + setInt(tosSingle(1), getInt(tosSingle(0))); + setObject(tosSingle(1), getObject(tosSingle(0))); + + setInt(tosSingle(0), tmpInt); + setObject(tosSingle(0), tmpObject); + } + + public void dupx1() { + long tosLong = getLong(tosSingle(0)); + Object tosObject = getObject(tosSingle(0)); + + swapSingle(); + + pushBoth(tosObject, tosLong); + } + + public void dup2x1() { + long tosLong2 = getLong(tosSingle(2)); + Object tosObject2 = getObject(tosSingle(2)); + long tosLong1 = getLong(tosSingle(1)); + Object tosObject1 = getObject(tosSingle(1)); + long tosLong0 = getLong(tosSingle(0)); + Object tosObject0 = getObject(tosSingle(0)); + + popVoid(3); + + pushBoth(tosObject1, tosLong1); + pushBoth(tosObject0, tosLong0); + + pushBoth(tosObject2, tosLong2); + + pushBoth(tosObject1, tosLong1); + pushBoth(tosObject0, tosLong0); + } + + public void dup2x2() { + long tosLong3 = getLong(tosSingle(3)); + Object tosObject3 = getObject(tosSingle(3)); + long tosLong2 = getLong(tosSingle(2)); + Object tosObject2 = getObject(tosSingle(2)); + long tosLong1 = getLong(tosSingle(1)); + Object tosObject1 = getObject(tosSingle(1)); + long tosLong0 = getLong(tosSingle(0)); + Object tosObject0 = getObject(tosSingle(0)); + + popVoid(4); + + pushBoth(tosObject1, tosLong1); + pushBoth(tosObject0, tosLong0); + + pushBoth(tosObject3, tosLong3); + pushBoth(tosObject2, tosLong2); + + pushBoth(tosObject1, tosLong1); + pushBoth(tosObject0, tosLong0); + } + + public void dupx2() { + long tosLong2 = getLong(tosSingle(2)); + Object tosObject2 = getObject(tosSingle(2)); + long tosLong1 = getLong(tosSingle(1)); + Object tosObject1 = getObject(tosSingle(1)); + long tosLong0 = getLong(tosSingle(0)); + Object tosObject0 = getObject(tosSingle(0)); + + popVoid(3); + + pushBoth(tosObject0, tosLong0); + pushBoth(tosObject2, tosLong2); + pushBoth(tosObject1, tosLong1); + pushBoth(tosObject0, tosLong0); + } + + public void dup(int length) { + assert length > 0; + for (int i = 0; i < length; i++) { + long valueN1 = getLong(tosSingle(length - i - 1)); + Object valueO1 = getObject(tosSingle(length - i - 1)); + + pushVoid(1); + + setLong(tosSingle(0), valueN1); + setObject(tosSingle(0), valueO1); + } + } + + private void incrementTos(int size) { + tos += size; + } + + private void decrementTos(int size) { + tos -= size; + } + + private int tosDouble(int offset) { + assert offset >= 0; + return tos - DOUBLE - (offset * DOUBLE); + } + + private int tosSingle(int offset) { + assert offset >= 0; + return tos - SINGLE - offset; + } + + public int getStackTop() { + return tos; + } + + public void pushVoid(int count) { + incrementTos(count * SINGLE); + } + + public void popVoid(int count) { + decrementTos(count * SINGLE); + } + + public ConstantPool getConstantPool() { + return getMethod().getConstantPool(); + } + + private void setMethod(ResolvedJavaMethod method) { + setObject(METHOD_FRAME_SLOT, method); + } + + public ResolvedJavaMethod getMethod() { + return (ResolvedJavaMethod) getObject(METHOD_FRAME_SLOT); + } + + public void setBCI(int bci) { + setInt(BCI_FRAME_SLOT, bci); + } + + public int getBCI() { + return getInt(BCI_FRAME_SLOT); + } + + public void pushTo(InterpreterFrame childFrame, int argumentSlots) { + System.arraycopy(locals, tos - argumentSlots, childFrame.locals, + InterpreterFrame.MIN_FRAME_SIZE, argumentSlots); + + System.arraycopy(primitiveLocals, tos - argumentSlots, childFrame.primitiveLocals, + InterpreterFrame.MIN_FRAME_SIZE, argumentSlots); + popVoid(argumentSlots); + } + + public InterpreterFrame getParentFrame() { + return (InterpreterFrame) getObject(PARENT_FRAME_SLOT); + } + + public void dispose() { + // Clear out references in locals array. + Arrays.fill(locals, null); + } + + @Override + public String toString() { + ResolvedJavaMethod method = getMethod(); + StringBuilder b = new StringBuilder(getMethod().toStackTraceElement(getBCI()).toString()); + for (int i = 0; i < tos; i++) { + Object object = getObject(tosSingle(i)); + long primitive = getLong(tosSingle(i)); + + String objectString = null; + if (object != null) { + objectString = object.getClass().getSimpleName() + "@" + Integer.toHexString(object.hashCode()); + } + String primitiveString = "0x" + Long.toHexString(primitive).toUpperCase(); + String typeString; + + int index = tosSingle(i); + if (index == METHOD_FRAME_SLOT) { + typeString = "method"; + } else if (index == BCI_FRAME_SLOT) { + typeString = "bci"; + } else if (index == PARENT_FRAME_SLOT) { + typeString = "parent"; + } else if (index < BASE_LENGTH + method.maxLocals()) { + typeString = "var " + (index - BASE_LENGTH); + } else { + typeString = "local"; + } + b.append(String.format("%n [%d] %7s Primitive: %10s Object: %s", index, typeString, primitiveString, objectString)); + } + if (getParentFrame() != null) { + b.append("\n").append(getParentFrame().toString()); + } + return b.toString(); + } + + public void popStack() { + // TODO(chumer): prevent popping local variables. + popVoid(tos - stackTos()); + } + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/VMAdapter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/VMAdapter.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2012, 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.interpreter; + +import java.lang.reflect.*; + +import sun.misc.*; + +import com.oracle.graal.api.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; + + +/** + * This class encapsulates all vm specific methods for the {@link BytecodeInterpreter}. + */ +public class VMAdapter { + + private static final Unsafe unsafe = loadUnsafe(); + + protected VMAdapter() { + } + + public MetaAccessProvider getRuntime() { + return Graal.getRuntime().getCapability(MetaAccessProvider.class); + } + + public void monitorEnter(Object value) { + nullCheck(value); + unsafe.monitorEnter(value); + } + + public void monitorExit(Object value) { + nullCheck(value); + unsafe.monitorExit(value); + } + + public Object newObject(ResolvedJavaType type) throws InstantiationException { + return unsafe.allocateInstance(type.toJava()); + } + + public Object getField(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getObjectVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getObject(resolveBase(base, field), offset); + } + } + + public int getFieldInt(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getIntVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getInt(resolveBase(base, field), offset); + } + } + + public long getFieldLong(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getLongVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getLong(resolveBase(base, field), offset); + } + } + + public double getFieldDouble(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getDoubleVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getDouble(resolveBase(base, field), offset); + } + } + + public float getFieldFloat(Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + return unsafe.getFloatVolatile(resolveBase(base, field), offset); + } else { + return unsafe.getFloat(resolveBase(base, field), offset); + } + } + + public void setField(Object value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putObjectVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putObject(resolveBase(base, field), offset, value); + } + } + + public void setFieldInt(int value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putIntVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putInt(resolveBase(base, field), offset, value); + } + } + + + public void setFieldFloat(float value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putFloatVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putFloat(resolveBase(base, field), offset, value); + } + } + + public void setFieldDouble(double value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putDouble(resolveBase(base, field), offset, value); + } + } + + public void setFieldLong(long value, Object base, ResolvedJavaField field) { + long offset = resolveOffset(field); + if (isVolatile(field)) { + unsafe.putDoubleVolatile(resolveBase(base, field), offset, value); + } else { + unsafe.putDouble(resolveBase(base, field), offset, value); + } + } + + public byte getArrayByte(long index, Object array) { + checkArray(array, index); + return unsafe.getByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index); + } + + public char getArrayChar(long index, Object array) { + checkArray(array, index); + return unsafe.getChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index); + } + + public short getArrayShort(long index, Object array) { + checkArray(array, index); + return unsafe.getShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index); + } + + public int getArrayInt(long index, Object array) { + checkArray(array, index); + return unsafe.getInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index); + } + + public long getArrayLong(long index, Object array) { + checkArray(array, index); + return unsafe.getLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index); + } + + public double getArrayDouble(long index, Object array) { + checkArray(array, index); + return unsafe.getDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index); + } + + public float getArrayFloat(long index, Object array) { + checkArray(array, index); + return unsafe.getFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index); + } + + public Object getArrayObject(long index, Object array) { + checkArray(array, index); + return unsafe.getObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index); + } + + public void setArrayByte(byte value, long index, Object array) { + checkArray(array, index); + if (array instanceof boolean[]) { + checkArrayType(array, boolean.class); + } else { + checkArrayType(array, byte.class); + } + unsafe.putByte(array, Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * index, value); + } + + public void setArrayChar(char value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, char.class); + unsafe.putChar(array, Unsafe.ARRAY_CHAR_BASE_OFFSET + Unsafe.ARRAY_CHAR_INDEX_SCALE * index, value); + } + + public void setArrayShort(short value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, short.class); + unsafe.putShort(array, Unsafe.ARRAY_SHORT_BASE_OFFSET + Unsafe.ARRAY_SHORT_INDEX_SCALE * index, value); + } + + public void setArrayInt(int value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, int.class); + unsafe.putInt(array, Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * index, value); + } + + public void setArrayLong(long value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, long.class); + unsafe.putLong(array, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * index, value); + } + + public void setArrayFloat(float value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, float.class); + unsafe.putFloat(array, Unsafe.ARRAY_FLOAT_BASE_OFFSET + Unsafe.ARRAY_FLOAT_INDEX_SCALE * index, value); + } + + public void setArrayDouble(double value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, double.class); + unsafe.putDouble(array, Unsafe.ARRAY_DOUBLE_BASE_OFFSET + Unsafe.ARRAY_DOUBLE_INDEX_SCALE * index, value); + } + + public void setArrayObject(Object value, long index, Object array) { + checkArray(array, index); + checkArrayType(array, value != null ? value.getClass() : null); + unsafe.putObject(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * index, value); + } + + private static void nullCheck(Object value) { + if (value == null) { + throw new NullPointerException(); + } + } + + private void checkArrayType(Object array, Class arrayType) { + if (arrayType == null) { + return; + } + ResolvedJavaType type = getRuntime().getResolvedJavaType(array.getClass()).componentType(); + if (!type.toJava().isAssignableFrom(arrayType)) { + throw new ArrayStoreException(arrayType.getName()); + } + } + + private void checkArray(Object array, long index) { + nullCheck(array); + ResolvedJavaType type = getRuntime().getResolvedJavaType(array.getClass()); + if (!type.isArrayClass()) { + throw new ArrayStoreException(array.getClass().getName()); + } + if (index < 0 || index >= arrayLength(array)) { + throw new ArrayIndexOutOfBoundsException((int) index); + } + } + + private static int arrayLength(Object array) { + assert array != null; + return Array.getLength(array); + } + + private static boolean isVolatile(ResolvedJavaField field) { + return Modifier.isVolatile(field.accessFlags()); + } + + private static long resolveOffset(ResolvedJavaField field) { + return ((HotSpotResolvedJavaField) field).offset(); + } + + private static Object resolveBase(Object base, ResolvedJavaField field) { + Object accessorBase = base; + if (accessorBase == null) { + accessorBase = field.holder().toJava(); + } + return accessorBase; + } + + private static Unsafe loadUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } + + private static final VMAdapter instance = new VMAdapter(); + public static VMAdapter getInstance() { + return instance; + } + + +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Mon Jun 11 17:06:06 2012 +0200 @@ -22,15 +22,15 @@ */ package com.oracle.graal.java; -import static com.oracle.graal.java.bytecode.Bytecodes.*; +import static com.oracle.graal.bytecode.Bytecodes.*; import java.util.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; -import com.oracle.graal.java.bytecode.*; import com.oracle.graal.nodes.*; /** diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Jun 11 17:06:06 2012 +0200 @@ -22,7 +22,7 @@ */ package com.oracle.graal.java; -import static com.oracle.graal.java.bytecode.Bytecodes.*; +import static com.oracle.graal.bytecode.Bytecodes.*; import static java.lang.reflect.Modifier.*; import java.lang.reflect.*; @@ -32,6 +32,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.JavaType.*; import com.oracle.graal.api.meta.JavaTypeProfile.*; +import com.oracle.graal.bytecode.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.util.*; @@ -39,7 +40,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.java.BciBlockMapping.Block; import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock; -import com.oracle.graal.java.bytecode.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeLookupSwitch.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeLookupSwitch.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +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.graal.java.bytecode; - -/** - * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes. - */ -public class BytecodeLookupSwitch extends BytecodeSwitch { - private static final int OFFSET_TO_NUMBER_PAIRS = 4; - private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8; - private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12; - private static final int PAIR_SIZE = 8; - - /** - * Constructor for a {@link BytecodeStream}. - * @param stream the {@code BytecodeStream} containing the switch instruction - * @param bci the index in the stream of the switch instruction - */ - public BytecodeLookupSwitch(BytecodeStream stream, int bci) { - super(stream, bci); - } - - @Override - public int defaultOffset() { - return stream.readInt(alignedBci); - } - - @Override - public int offsetAt(int i) { - return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_OFFSET + PAIR_SIZE * i); - } - - @Override - public int keyAt(int i) { - return stream.readInt(alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * i); - } - - @Override - public int numberOfCases() { - return stream.readInt(alignedBci + OFFSET_TO_NUMBER_PAIRS); - } - - @Override - public int size() { - return alignedBci + OFFSET_TO_FIRST_PAIR_MATCH + PAIR_SIZE * numberOfCases() - bci; - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeStream.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeStream.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +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.graal.java.bytecode; - - -/** - * A utility class that makes iterating over bytecodes and reading operands - * simpler and less error prone. For example, it handles the {@link Bytecodes#WIDE} instruction - * and wide variants of instructions internally. - */ -public final class BytecodeStream { - - private final byte[] code; - private int opcode; - private int curBCI; - private int nextBCI; - - /** - * Creates a new {@code BytecodeStream} for the specified bytecode. - * @param code the array of bytes that contains the bytecode - */ - public BytecodeStream(byte[] code) { - assert code != null; - this.code = code; - setBCI(0); - } - - /** - * Advances to the next bytecode. - */ - public void next() { - setBCI(nextBCI); - } - - /** - * Gets the next bytecode index (no side-effects). - * @return the next bytecode index - */ - public int nextBCI() { - return nextBCI; - } - - /** - * Gets the current bytecode index. - * @return the current bytecode index - */ - public int currentBCI() { - return curBCI; - } - - /** - * Gets the bytecode index of the end of the code. - * @return the index of the end of the code - */ - public int endBCI() { - return code.length; - } - - /** - * Gets the current opcode. This method will never return the - * {@link Bytecodes#WIDE WIDE} opcode, but will instead - * return the opcode that is modified by the {@code WIDE} opcode. - * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code - */ - public int currentBC() { - if (opcode == Bytecodes.WIDE) { - return Bytes.beU1(code, curBCI + 1); - } else { - return opcode; - } - } - - /** - * Reads the index of a local variable for one of the load or store instructions. - * The WIDE modifier is handled internally. - * @return the index of the local variable - */ - public int readLocalIndex() { - // read local variable index for load/store - if (opcode == Bytecodes.WIDE) { - return Bytes.beU2(code, curBCI + 2); - } - return Bytes.beU1(code, curBCI + 1); - } - - /** - * Read the delta for an {@link Bytecodes#IINC} bytecode. - * @return the delta for the {@code IINC} - */ - public int readIncrement() { - // read the delta for the iinc bytecode - if (opcode == Bytecodes.WIDE) { - return Bytes.beS2(code, curBCI + 4); - } - return Bytes.beS1(code, curBCI + 2); - } - - /** - * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions. - * @return the destination bytecode index - */ - public int readBranchDest() { - // reads the destination for a branch bytecode - if (opcode == Bytecodes.GOTO_W || opcode == Bytecodes.JSR_W) { - return curBCI + Bytes.beS4(code, curBCI + 1); - } else { - return curBCI + Bytes.beS2(code, curBCI + 1); - } - } - - /** - * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index. - * @param bci the bytecode index - * @return the integer value - */ - public int readInt(int bci) { - // reads a 4-byte signed value - return Bytes.beS4(code, bci); - } - - /** - * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index. - * @param bci the bytecode index - * @return the byte - */ - public int readUByte(int bci) { - return Bytes.beU1(code, bci); - } - - /** - * Reads a constant pool index for the current instruction. - * @return the constant pool index - */ - public char readCPI() { - if (opcode == Bytecodes.LDC) { - return (char) Bytes.beU1(code, curBCI + 1); - } - return (char) Bytes.beU2(code, curBCI + 1); - } - - /** - * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH). - * @return the byte - */ - public byte readByte() { - return code[curBCI + 1]; - } - - /** - * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH). - * @return the short value - */ - public short readShort() { - return (short) Bytes.beS2(code, curBCI + 1); - } - - /** - * Sets the bytecode index to the specified value. - * If {@code bci} is beyond the end of the array, {@link #currentBC} will return - * {@link Bytecodes#END} and other methods may throw {@link ArrayIndexOutOfBoundsException}. - * @param bci the new bytecode index - */ - public void setBCI(int bci) { - curBCI = bci; - if (curBCI < code.length) { - opcode = Bytes.beU1(code, bci); - assert opcode < Bytecodes.BREAKPOINT : "illegal bytecode"; - nextBCI = bci + lengthOf(); - } else { - opcode = Bytecodes.END; - nextBCI = curBCI; - } - } - - /** - * Gets the length of the current bytecode. - */ - private int lengthOf() { - int length = Bytecodes.lengthOf(opcode); - if (length == 0) { - switch (opcode) { - case Bytecodes.TABLESWITCH: { - return new BytecodeTableSwitch(this, curBCI).size(); - } - case Bytecodes.LOOKUPSWITCH: { - return new BytecodeLookupSwitch(this, curBCI).size(); - } - case Bytecodes.WIDE: { - int opc = Bytes.beU1(code, curBCI + 1); - if (opc == Bytecodes.RET) { - return 4; - } else if (opc == Bytecodes.IINC) { - return 6; - } else { - return 4; // a load or store bytecode - } - } - default: - throw new Error("unknown variable-length bytecode: " + opcode); - } - } - return length; - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeSwitch.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeSwitch.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +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.graal.java.bytecode; - -/** - * An abstract class that provides the state and methods common to {@link Bytecodes#LOOKUPSWITCH} - * and {@link Bytecodes#TABLESWITCH} instructions. - */ -public abstract class BytecodeSwitch { - /** - * The {@link BytecodeStream} containing the bytecode array. - */ - protected final BytecodeStream stream; - /** - * Index of start of switch instruction. - */ - protected final int bci; - /** - * Index of the start of the additional data for the switch instruction, aligned to a multiple of four from the method start. - */ - protected final int alignedBci; - - /** - * Constructor for a {@link BytecodeStream}. - * @param stream the {@code BytecodeStream} containing the switch instruction - * @param bci the index in the stream of the switch instruction - */ - public BytecodeSwitch(BytecodeStream stream, int bci) { - this.stream = stream; - this.bci = bci; - this.alignedBci = (bci + 4) & 0xfffffffc; - } - - /** - * Gets the current bytecode index. - * @return the current bytecode index - */ - public int bci() { - return bci; - } - - /** - * Gets the index of the instruction denoted by the {@code i}'th switch target. - * @param i index of the switch target - * @return the index of the instruction denoted by the {@code i}'th switch target - */ - public int targetAt(int i) { - return bci + offsetAt(i); - } - - /** - * Gets the index of the instruction for the default switch target. - * @return the index of the instruction for the default switch target - */ - public int defaultTarget() { - return bci + defaultOffset(); - } - - /** - * Gets the offset from the start of the switch instruction to the default switch target. - * @return the offset to the default switch target - */ - public abstract int defaultOffset(); - - /** - * Gets the key at {@code i}'th switch target index. - * @param i the switch target index - * @return the key at {@code i}'th switch target index - */ - public abstract int keyAt(int i); - - /** - * Gets the offset from the start of the switch instruction for the {@code i}'th switch target. - * @param i the switch target index - * @return the offset to the {@code i}'th switch target - */ - public abstract int offsetAt(int i); - - /** - * Gets the number of switch targets. - * @return the number of switch targets - */ - public abstract int numberOfCases(); - - /** - * Gets the total size in bytes of the switch instruction. - * @return the total size in bytes of the switch instruction - */ - public abstract int size(); -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeTableSwitch.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/BytecodeTableSwitch.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +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.graal.java.bytecode; - -/** - * A utility for processing {@link Bytecodes#TABLESWITCH} bytecodes. - */ -public class BytecodeTableSwitch extends BytecodeSwitch { - private static final int OFFSET_TO_LOW_KEY = 4; - private static final int OFFSET_TO_HIGH_KEY = 8; - private static final int OFFSET_TO_FIRST_JUMP_OFFSET = 12; - private static final int JUMP_OFFSET_SIZE = 4; - - /** - * Constructor for a {@link BytecodeStream}. - * @param stream the {@code BytecodeStream} containing the switch instruction - * @param bci the index in the stream of the switch instruction - */ - public BytecodeTableSwitch(BytecodeStream stream, int bci) { - super(stream, bci); - } - - /** - * Gets the low key of the table switch. - * @return the low key - */ - public int lowKey() { - return stream.readInt(alignedBci + OFFSET_TO_LOW_KEY); - } - - /** - * Gets the high key of the table switch. - * @return the high key - */ - public int highKey() { - return stream.readInt(alignedBci + OFFSET_TO_HIGH_KEY); - } - - @Override - public int keyAt(int i) { - return lowKey() + i; - } - - @Override - public int defaultOffset() { - return stream.readInt(alignedBci); - } - - @Override - public int offsetAt(int i) { - return stream.readInt(alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * i); - } - - @Override - public int numberOfCases() { - return highKey() - lowKey() + 1; - } - - @Override - public int size() { - return alignedBci + OFFSET_TO_FIRST_JUMP_OFFSET + JUMP_OFFSET_SIZE * numberOfCases() - bci; - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/Bytecodes.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/Bytecodes.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,940 +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.graal.java.bytecode; - -import static com.oracle.graal.java.bytecode.Bytecodes.Flags.*; - -import java.io.*; -import java.lang.reflect.*; -import java.util.regex.*; - -/** - * The definitions of the bytecodes that are valid input to the compiler and - * related utility methods. This comprises two groups: the standard Java - * bytecodes defined by - * Java Virtual Machine Specification, and a set of extended - * bytecodes that support low-level programming, for example, memory barriers. - * - * The extended bytecodes are one or three bytes in size. The one-byte bytecodes - * follow the values in the standard set, with no gap. The three-byte extended - * bytecodes share a common first byte and carry additional instruction-specific - * information in the second and third bytes. - */ -public class Bytecodes { - public static final int NOP = 0; // 0x00 - public static final int ACONST_NULL = 1; // 0x01 - public static final int ICONST_M1 = 2; // 0x02 - public static final int ICONST_0 = 3; // 0x03 - public static final int ICONST_1 = 4; // 0x04 - public static final int ICONST_2 = 5; // 0x05 - public static final int ICONST_3 = 6; // 0x06 - public static final int ICONST_4 = 7; // 0x07 - public static final int ICONST_5 = 8; // 0x08 - public static final int LCONST_0 = 9; // 0x09 - public static final int LCONST_1 = 10; // 0x0A - public static final int FCONST_0 = 11; // 0x0B - public static final int FCONST_1 = 12; // 0x0C - public static final int FCONST_2 = 13; // 0x0D - public static final int DCONST_0 = 14; // 0x0E - public static final int DCONST_1 = 15; // 0x0F - public static final int BIPUSH = 16; // 0x10 - public static final int SIPUSH = 17; // 0x11 - public static final int LDC = 18; // 0x12 - public static final int LDC_W = 19; // 0x13 - public static final int LDC2_W = 20; // 0x14 - public static final int ILOAD = 21; // 0x15 - public static final int LLOAD = 22; // 0x16 - public static final int FLOAD = 23; // 0x17 - public static final int DLOAD = 24; // 0x18 - public static final int ALOAD = 25; // 0x19 - public static final int ILOAD_0 = 26; // 0x1A - public static final int ILOAD_1 = 27; // 0x1B - public static final int ILOAD_2 = 28; // 0x1C - public static final int ILOAD_3 = 29; // 0x1D - public static final int LLOAD_0 = 30; // 0x1E - public static final int LLOAD_1 = 31; // 0x1F - public static final int LLOAD_2 = 32; // 0x20 - public static final int LLOAD_3 = 33; // 0x21 - public static final int FLOAD_0 = 34; // 0x22 - public static final int FLOAD_1 = 35; // 0x23 - public static final int FLOAD_2 = 36; // 0x24 - public static final int FLOAD_3 = 37; // 0x25 - public static final int DLOAD_0 = 38; // 0x26 - public static final int DLOAD_1 = 39; // 0x27 - public static final int DLOAD_2 = 40; // 0x28 - public static final int DLOAD_3 = 41; // 0x29 - public static final int ALOAD_0 = 42; // 0x2A - public static final int ALOAD_1 = 43; // 0x2B - public static final int ALOAD_2 = 44; // 0x2C - public static final int ALOAD_3 = 45; // 0x2D - public static final int IALOAD = 46; // 0x2E - public static final int LALOAD = 47; // 0x2F - public static final int FALOAD = 48; // 0x30 - public static final int DALOAD = 49; // 0x31 - public static final int AALOAD = 50; // 0x32 - public static final int BALOAD = 51; // 0x33 - public static final int CALOAD = 52; // 0x34 - public static final int SALOAD = 53; // 0x35 - public static final int ISTORE = 54; // 0x36 - public static final int LSTORE = 55; // 0x37 - public static final int FSTORE = 56; // 0x38 - public static final int DSTORE = 57; // 0x39 - public static final int ASTORE = 58; // 0x3A - public static final int ISTORE_0 = 59; // 0x3B - public static final int ISTORE_1 = 60; // 0x3C - public static final int ISTORE_2 = 61; // 0x3D - public static final int ISTORE_3 = 62; // 0x3E - public static final int LSTORE_0 = 63; // 0x3F - public static final int LSTORE_1 = 64; // 0x40 - public static final int LSTORE_2 = 65; // 0x41 - public static final int LSTORE_3 = 66; // 0x42 - public static final int FSTORE_0 = 67; // 0x43 - public static final int FSTORE_1 = 68; // 0x44 - public static final int FSTORE_2 = 69; // 0x45 - public static final int FSTORE_3 = 70; // 0x46 - public static final int DSTORE_0 = 71; // 0x47 - public static final int DSTORE_1 = 72; // 0x48 - public static final int DSTORE_2 = 73; // 0x49 - public static final int DSTORE_3 = 74; // 0x4A - public static final int ASTORE_0 = 75; // 0x4B - public static final int ASTORE_1 = 76; // 0x4C - public static final int ASTORE_2 = 77; // 0x4D - public static final int ASTORE_3 = 78; // 0x4E - public static final int IASTORE = 79; // 0x4F - public static final int LASTORE = 80; // 0x50 - public static final int FASTORE = 81; // 0x51 - public static final int DASTORE = 82; // 0x52 - public static final int AASTORE = 83; // 0x53 - public static final int BASTORE = 84; // 0x54 - public static final int CASTORE = 85; // 0x55 - public static final int SASTORE = 86; // 0x56 - public static final int POP = 87; // 0x57 - public static final int POP2 = 88; // 0x58 - public static final int DUP = 89; // 0x59 - public static final int DUP_X1 = 90; // 0x5A - public static final int DUP_X2 = 91; // 0x5B - public static final int DUP2 = 92; // 0x5C - public static final int DUP2_X1 = 93; // 0x5D - public static final int DUP2_X2 = 94; // 0x5E - public static final int SWAP = 95; // 0x5F - public static final int IADD = 96; // 0x60 - public static final int LADD = 97; // 0x61 - public static final int FADD = 98; // 0x62 - public static final int DADD = 99; // 0x63 - public static final int ISUB = 100; // 0x64 - public static final int LSUB = 101; // 0x65 - public static final int FSUB = 102; // 0x66 - public static final int DSUB = 103; // 0x67 - public static final int IMUL = 104; // 0x68 - public static final int LMUL = 105; // 0x69 - public static final int FMUL = 106; // 0x6A - public static final int DMUL = 107; // 0x6B - public static final int IDIV = 108; // 0x6C - public static final int LDIV = 109; // 0x6D - public static final int FDIV = 110; // 0x6E - public static final int DDIV = 111; // 0x6F - public static final int IREM = 112; // 0x70 - public static final int LREM = 113; // 0x71 - public static final int FREM = 114; // 0x72 - public static final int DREM = 115; // 0x73 - public static final int INEG = 116; // 0x74 - public static final int LNEG = 117; // 0x75 - public static final int FNEG = 118; // 0x76 - public static final int DNEG = 119; // 0x77 - public static final int ISHL = 120; // 0x78 - public static final int LSHL = 121; // 0x79 - public static final int ISHR = 122; // 0x7A - public static final int LSHR = 123; // 0x7B - public static final int IUSHR = 124; // 0x7C - public static final int LUSHR = 125; // 0x7D - public static final int IAND = 126; // 0x7E - public static final int LAND = 127; // 0x7F - public static final int IOR = 128; // 0x80 - public static final int LOR = 129; // 0x81 - public static final int IXOR = 130; // 0x82 - public static final int LXOR = 131; // 0x83 - public static final int IINC = 132; // 0x84 - public static final int I2L = 133; // 0x85 - public static final int I2F = 134; // 0x86 - public static final int I2D = 135; // 0x87 - public static final int L2I = 136; // 0x88 - public static final int L2F = 137; // 0x89 - public static final int L2D = 138; // 0x8A - public static final int F2I = 139; // 0x8B - public static final int F2L = 140; // 0x8C - public static final int F2D = 141; // 0x8D - public static final int D2I = 142; // 0x8E - public static final int D2L = 143; // 0x8F - public static final int D2F = 144; // 0x90 - public static final int I2B = 145; // 0x91 - public static final int I2C = 146; // 0x92 - public static final int I2S = 147; // 0x93 - public static final int LCMP = 148; // 0x94 - public static final int FCMPL = 149; // 0x95 - public static final int FCMPG = 150; // 0x96 - public static final int DCMPL = 151; // 0x97 - public static final int DCMPG = 152; // 0x98 - public static final int IFEQ = 153; // 0x99 - public static final int IFNE = 154; // 0x9A - public static final int IFLT = 155; // 0x9B - public static final int IFGE = 156; // 0x9C - public static final int IFGT = 157; // 0x9D - public static final int IFLE = 158; // 0x9E - public static final int IF_ICMPEQ = 159; // 0x9F - public static final int IF_ICMPNE = 160; // 0xA0 - public static final int IF_ICMPLT = 161; // 0xA1 - public static final int IF_ICMPGE = 162; // 0xA2 - public static final int IF_ICMPGT = 163; // 0xA3 - public static final int IF_ICMPLE = 164; // 0xA4 - public static final int IF_ACMPEQ = 165; // 0xA5 - public static final int IF_ACMPNE = 166; // 0xA6 - public static final int GOTO = 167; // 0xA7 - public static final int JSR = 168; // 0xA8 - public static final int RET = 169; // 0xA9 - public static final int TABLESWITCH = 170; // 0xAA - public static final int LOOKUPSWITCH = 171; // 0xAB - public static final int IRETURN = 172; // 0xAC - public static final int LRETURN = 173; // 0xAD - public static final int FRETURN = 174; // 0xAE - public static final int DRETURN = 175; // 0xAF - public static final int ARETURN = 176; // 0xB0 - public static final int RETURN = 177; // 0xB1 - public static final int GETSTATIC = 178; // 0xB2 - public static final int PUTSTATIC = 179; // 0xB3 - public static final int GETFIELD = 180; // 0xB4 - public static final int PUTFIELD = 181; // 0xB5 - public static final int INVOKEVIRTUAL = 182; // 0xB6 - public static final int INVOKESPECIAL = 183; // 0xB7 - public static final int INVOKESTATIC = 184; // 0xB8 - public static final int INVOKEINTERFACE = 185; // 0xB9 - public static final int XXXUNUSEDXXX = 186; // 0xBA - public static final int NEW = 187; // 0xBB - public static final int NEWARRAY = 188; // 0xBC - public static final int ANEWARRAY = 189; // 0xBD - public static final int ARRAYLENGTH = 190; // 0xBE - public static final int ATHROW = 191; // 0xBF - public static final int CHECKCAST = 192; // 0xC0 - public static final int INSTANCEOF = 193; // 0xC1 - public static final int MONITORENTER = 194; // 0xC2 - public static final int MONITOREXIT = 195; // 0xC3 - public static final int WIDE = 196; // 0xC4 - public static final int MULTIANEWARRAY = 197; // 0xC5 - public static final int IFNULL = 198; // 0xC6 - public static final int IFNONNULL = 199; // 0xC7 - public static final int GOTO_W = 200; // 0xC8 - public static final int JSR_W = 201; // 0xC9 - public static final int BREAKPOINT = 202; // 0xCA - - public static final int ILLEGAL = 255; - public static final int END = 256; - - /** - * The last opcode defined by the JVM specification. To iterate over all JVM bytecodes: - *
    -     *     for (int opcode = 0; opcode <= Bytecodes.LAST_JVM_OPCODE; ++opcode) {
    -     *         //
    -     *     }
    -     * 
    - */ - public static final int LAST_JVM_OPCODE = JSR_W; - - /** - * A collection of flags describing various bytecode attributes. - */ - static class Flags { - - /** - * Denotes an instruction that ends a basic block and does not let control flow fall through to its lexical successor. - */ - static final int STOP = 0x00000001; - - /** - * Denotes an instruction that ends a basic block and may let control flow fall through to its lexical successor. - * In practice this means it is a conditional branch. - */ - static final int FALL_THROUGH = 0x00000002; - - /** - * Denotes an instruction that has a 2 or 4 byte operand that is an offset to another instruction in the same method. - * This does not include the {@link Bytecodes#TABLESWITCH} or {@link Bytecodes#LOOKUPSWITCH} instructions. - */ - static final int BRANCH = 0x00000004; - - /** - * Denotes an instruction that reads the value of a static or instance field. - */ - static final int FIELD_READ = 0x00000008; - - /** - * Denotes an instruction that writes the value of a static or instance field. - */ - static final int FIELD_WRITE = 0x00000010; - - /** - * Denotes an instruction that is not defined in the JVM specification. - */ - static final int EXTENSION = 0x00000020; - - /** - * Denotes an instruction that can cause a trap. - */ - static final int TRAP = 0x00000080; - /** - * Denotes an instruction that is commutative. - */ - static final int COMMUTATIVE = 0x00000100; - /** - * Denotes an instruction that is associative. - */ - static final int ASSOCIATIVE = 0x00000200; - /** - * Denotes an instruction that loads an operand. - */ - static final int LOAD = 0x00000400; - /** - * Denotes an instruction that stores an operand. - */ - static final int STORE = 0x00000800; - /** - * Denotes the 4 INVOKE* instructions. - */ - static final int INVOKE = 0x00001000; - } - - // Performs a sanity check that none of the flags overlap. - static { - int allFlags = 0; - try { - for (Field field : Flags.class.getDeclaredFields()) { - int flagsFilter = Modifier.FINAL | Modifier.STATIC; - if ((field.getModifiers() & flagsFilter) == flagsFilter && !field.isSynthetic()) { - assert field.getType() == int.class : "Field is not int : " + field; - final int flag = field.getInt(null); - assert flag != 0; - assert (flag & allFlags) == 0 : field.getName() + " has a value conflicting with another flag"; - allFlags |= flag; - } - } - } catch (Exception e) { - throw new InternalError(e.toString()); - } - } - - /** - * An array that maps from a bytecode value to a {@link String} for the corresponding instruction mnemonic. - * This will include the root instruction for the three-byte extended instructions. - */ - private static final String[] nameArray = new String[256]; - - /** - * An array that maps from a bytecode value to the set of {@link Flags} for the corresponding instruction. - */ - private static final int[] flagsArray = new int[256]; - - /** - * An array that maps from a bytecode value to the length in bytes for the corresponding instruction. - */ - private static final int[] lengthArray = new int[256]; - - /** - * An array that maps from a bytecode value to the estimated complexity of the bytecode in terms of generated machine code. - */ - private static final int[] compilationComplexityArray = new int[256]; - - // Checkstyle: stop - static { - def(NOP , "nop" , "b" , 0); - def(ACONST_NULL , "aconst_null" , "b" , 0); - def(ICONST_M1 , "iconst_m1" , "b" , 0); - def(ICONST_0 , "iconst_0" , "b" , 0); - def(ICONST_1 , "iconst_1" , "b" , 0); - def(ICONST_2 , "iconst_2" , "b" , 0); - def(ICONST_3 , "iconst_3" , "b" , 0); - def(ICONST_4 , "iconst_4" , "b" , 0); - def(ICONST_5 , "iconst_5" , "b" , 0); - def(LCONST_0 , "lconst_0" , "b" , 0); - def(LCONST_1 , "lconst_1" , "b" , 0); - def(FCONST_0 , "fconst_0" , "b" , 0); - def(FCONST_1 , "fconst_1" , "b" , 0); - def(FCONST_2 , "fconst_2" , "b" , 0); - def(DCONST_0 , "dconst_0" , "b" , 0); - def(DCONST_1 , "dconst_1" , "b" , 0); - def(BIPUSH , "bipush" , "bc" , 0); - def(SIPUSH , "sipush" , "bcc" , 0); - def(LDC , "ldc" , "bi" , 0, TRAP); - def(LDC_W , "ldc_w" , "bii" , 0, TRAP); - def(LDC2_W , "ldc2_w" , "bii" , 0, TRAP); - def(ILOAD , "iload" , "bi" , 0, LOAD); - def(LLOAD , "lload" , "bi" , 0, LOAD); - def(FLOAD , "fload" , "bi" , 0, LOAD); - def(DLOAD , "dload" , "bi" , 0, LOAD); - def(ALOAD , "aload" , "bi" , 0, LOAD); - def(ILOAD_0 , "iload_0" , "b" , 0, LOAD); - def(ILOAD_1 , "iload_1" , "b" , 0, LOAD); - def(ILOAD_2 , "iload_2" , "b" , 0, LOAD); - def(ILOAD_3 , "iload_3" , "b" , 0, LOAD); - def(LLOAD_0 , "lload_0" , "b" , 0, LOAD); - def(LLOAD_1 , "lload_1" , "b" , 0, LOAD); - def(LLOAD_2 , "lload_2" , "b" , 0, LOAD); - def(LLOAD_3 , "lload_3" , "b" , 0, LOAD); - def(FLOAD_0 , "fload_0" , "b" , 0, LOAD); - def(FLOAD_1 , "fload_1" , "b" , 0, LOAD); - def(FLOAD_2 , "fload_2" , "b" , 0, LOAD); - def(FLOAD_3 , "fload_3" , "b" , 0, LOAD); - def(DLOAD_0 , "dload_0" , "b" , 0, LOAD); - def(DLOAD_1 , "dload_1" , "b" , 0, LOAD); - def(DLOAD_2 , "dload_2" , "b" , 0, LOAD); - def(DLOAD_3 , "dload_3" , "b" , 0, LOAD); - def(ALOAD_0 , "aload_0" , "b" , 0, LOAD); - def(ALOAD_1 , "aload_1" , "b" , 0, LOAD); - def(ALOAD_2 , "aload_2" , "b" , 0, LOAD); - def(ALOAD_3 , "aload_3" , "b" , 0, LOAD); - def(IALOAD , "iaload" , "b" , 0, TRAP); - def(LALOAD , "laload" , "b" , 0, TRAP); - def(FALOAD , "faload" , "b" , 0, TRAP); - def(DALOAD , "daload" , "b" , 0, TRAP); - def(AALOAD , "aaload" , "b" , 0, TRAP); - def(BALOAD , "baload" , "b" , 0, TRAP); - def(CALOAD , "caload" , "b" , 0, TRAP); - def(SALOAD , "saload" , "b" , 0, TRAP); - def(ISTORE , "istore" , "bi" , 0, STORE); - def(LSTORE , "lstore" , "bi" , 0, STORE); - def(FSTORE , "fstore" , "bi" , 0, STORE); - def(DSTORE , "dstore" , "bi" , 0, STORE); - def(ASTORE , "astore" , "bi" , 0, STORE); - def(ISTORE_0 , "istore_0" , "b" , 0, STORE); - def(ISTORE_1 , "istore_1" , "b" , 0, STORE); - def(ISTORE_2 , "istore_2" , "b" , 0, STORE); - def(ISTORE_3 , "istore_3" , "b" , 0, STORE); - def(LSTORE_0 , "lstore_0" , "b" , 0, STORE); - def(LSTORE_1 , "lstore_1" , "b" , 0, STORE); - def(LSTORE_2 , "lstore_2" , "b" , 0, STORE); - def(LSTORE_3 , "lstore_3" , "b" , 0, STORE); - def(FSTORE_0 , "fstore_0" , "b" , 0, STORE); - def(FSTORE_1 , "fstore_1" , "b" , 0, STORE); - def(FSTORE_2 , "fstore_2" , "b" , 0, STORE); - def(FSTORE_3 , "fstore_3" , "b" , 0, STORE); - def(DSTORE_0 , "dstore_0" , "b" , 0, STORE); - def(DSTORE_1 , "dstore_1" , "b" , 0, STORE); - def(DSTORE_2 , "dstore_2" , "b" , 0, STORE); - def(DSTORE_3 , "dstore_3" , "b" , 0, STORE); - def(ASTORE_0 , "astore_0" , "b" , 0, STORE); - def(ASTORE_1 , "astore_1" , "b" , 0, STORE); - def(ASTORE_2 , "astore_2" , "b" , 0, STORE); - def(ASTORE_3 , "astore_3" , "b" , 0, STORE); - def(IASTORE , "iastore" , "b" , 3, TRAP); - def(LASTORE , "lastore" , "b" , 3, TRAP); - def(FASTORE , "fastore" , "b" , 3, TRAP); - def(DASTORE , "dastore" , "b" , 3, TRAP); - def(AASTORE , "aastore" , "b" , 4, TRAP); - def(BASTORE , "bastore" , "b" , 3, TRAP); - def(CASTORE , "castore" , "b" , 3, TRAP); - def(SASTORE , "sastore" , "b" , 3, TRAP); - def(POP , "pop" , "b" , 0); - def(POP2 , "pop2" , "b" , 0); - def(DUP , "dup" , "b" , 0); - def(DUP_X1 , "dup_x1" , "b" , 0); - def(DUP_X2 , "dup_x2" , "b" , 0); - def(DUP2 , "dup2" , "b" , 0); - def(DUP2_X1 , "dup2_x1" , "b" , 0); - def(DUP2_X2 , "dup2_x2" , "b" , 0); - def(SWAP , "swap" , "b" , 0); - def(IADD , "iadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(LADD , "ladd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(FADD , "fadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(DADD , "dadd" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(ISUB , "isub" , "b" , 1); - def(LSUB , "lsub" , "b" , 1); - def(FSUB , "fsub" , "b" , 1); - def(DSUB , "dsub" , "b" , 1); - def(IMUL , "imul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(LMUL , "lmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(FMUL , "fmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(DMUL , "dmul" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(IDIV , "idiv" , "b" , 1, TRAP); - def(LDIV , "ldiv" , "b" , 1, TRAP); - def(FDIV , "fdiv" , "b" , 1); - def(DDIV , "ddiv" , "b" , 1); - def(IREM , "irem" , "b" , 1, TRAP); - def(LREM , "lrem" , "b" , 1, TRAP); - def(FREM , "frem" , "b" , 1); - def(DREM , "drem" , "b" , 1); - def(INEG , "ineg" , "b" , 1); - def(LNEG , "lneg" , "b" , 1); - def(FNEG , "fneg" , "b" , 1); - def(DNEG , "dneg" , "b" , 1); - def(ISHL , "ishl" , "b" , 1); - def(LSHL , "lshl" , "b" , 1); - def(ISHR , "ishr" , "b" , 1); - def(LSHR , "lshr" , "b" , 1); - def(IUSHR , "iushr" , "b" , 1); - def(LUSHR , "lushr" , "b" , 1); - def(IAND , "iand" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(LAND , "land" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(IOR , "ior" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(LOR , "lor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(IXOR , "ixor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(LXOR , "lxor" , "b" , 1, COMMUTATIVE | ASSOCIATIVE); - def(IINC , "iinc" , "bic" , 1, LOAD | STORE); - def(I2L , "i2l" , "b" , 1); - def(I2F , "i2f" , "b" , 1); - def(I2D , "i2d" , "b" , 1); - def(L2I , "l2i" , "b" , 1); - def(L2F , "l2f" , "b" , 1); - def(L2D , "l2d" , "b" , 1); - def(F2I , "f2i" , "b" , 1); - def(F2L , "f2l" , "b" , 1); - def(F2D , "f2d" , "b" , 1); - def(D2I , "d2i" , "b" , 1); - def(D2L , "d2l" , "b" , 1); - def(D2F , "d2f" , "b" , 1); - def(I2B , "i2b" , "b" , 1); - def(I2C , "i2c" , "b" , 1); - def(I2S , "i2s" , "b" , 1); - def(LCMP , "lcmp" , "b" , 1); - def(FCMPL , "fcmpl" , "b" , 1); - def(FCMPG , "fcmpg" , "b" , 1); - def(DCMPL , "dcmpl" , "b" , 1); - def(DCMPG , "dcmpg" , "b" , 1); - def(IFEQ , "ifeq" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFNE , "ifne" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFLT , "iflt" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFGE , "ifge" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFGT , "ifgt" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFLE , "ifle" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IF_ICMPEQ , "if_icmpeq" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); - def(IF_ICMPNE , "if_icmpne" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); - def(IF_ICMPLT , "if_icmplt" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IF_ICMPGE , "if_icmpge" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IF_ICMPGT , "if_icmpgt" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IF_ICMPLE , "if_icmple" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IF_ACMPEQ , "if_acmpeq" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); - def(IF_ACMPNE , "if_acmpne" , "boo" , 2, COMMUTATIVE | FALL_THROUGH | BRANCH); - def(GOTO , "goto" , "boo" , 1, STOP | BRANCH); - def(JSR , "jsr" , "boo" , 0, STOP | BRANCH); - def(RET , "ret" , "bi" , 0, STOP); - def(TABLESWITCH , "tableswitch" , "" , 4, STOP); - def(LOOKUPSWITCH , "lookupswitch" , "" , 4, STOP); - def(IRETURN , "ireturn" , "b" , 1, TRAP | STOP); - def(LRETURN , "lreturn" , "b" , 1, TRAP | STOP); - def(FRETURN , "freturn" , "b" , 1, TRAP | STOP); - def(DRETURN , "dreturn" , "b" , 1, TRAP | STOP); - def(ARETURN , "areturn" , "b" , 1, TRAP | STOP); - def(RETURN , "return" , "b" , 1, TRAP | STOP); - def(GETSTATIC , "getstatic" , "bjj" , 2, TRAP | FIELD_READ); - def(PUTSTATIC , "putstatic" , "bjj" , 2, TRAP | FIELD_WRITE); - def(GETFIELD , "getfield" , "bjj" , 2, TRAP | FIELD_READ); - def(PUTFIELD , "putfield" , "bjj" , 2, TRAP | FIELD_WRITE); - def(INVOKEVIRTUAL , "invokevirtual" , "bjj" , 7, TRAP | INVOKE); - def(INVOKESPECIAL , "invokespecial" , "bjj" , 5, TRAP | INVOKE); - def(INVOKESTATIC , "invokestatic" , "bjj" , 5, TRAP | INVOKE); - def(INVOKEINTERFACE , "invokeinterface" , "bjja_", 7, TRAP | INVOKE); - def(XXXUNUSEDXXX , "xxxunusedxxx" , "" , 0); - def(NEW , "new" , "bii" , 6, TRAP); - def(NEWARRAY , "newarray" , "bc" , 6, TRAP); - def(ANEWARRAY , "anewarray" , "bii" , 6, TRAP); - def(ARRAYLENGTH , "arraylength" , "b" , 2, TRAP); - def(ATHROW , "athrow" , "b" , 5, TRAP | STOP); - def(CHECKCAST , "checkcast" , "bii" , 3, TRAP); - def(INSTANCEOF , "instanceof" , "bii" , 4, TRAP); - def(MONITORENTER , "monitorenter" , "b" , 5, TRAP); - def(MONITOREXIT , "monitorexit" , "b" , 5, TRAP); - def(WIDE , "wide" , "" , 0); - def(MULTIANEWARRAY , "multianewarray" , "biic" , 6, TRAP); - def(IFNULL , "ifnull" , "boo" , 2, FALL_THROUGH | BRANCH); - def(IFNONNULL , "ifnonnull" , "boo" , 2, FALL_THROUGH | BRANCH); - def(GOTO_W , "goto_w" , "boooo", 1, STOP | BRANCH); - def(JSR_W , "jsr_w" , "boooo", 0, STOP | BRANCH); - def(BREAKPOINT , "breakpoint" , "b" , 0, TRAP); - } - // Checkstyle: resume - - /** - * Determines if an opcode is commutative. - * @param opcode the opcode to check - * @return {@code true} iff commutative - */ - public static boolean isCommutative(int opcode) { - return (flagsArray[opcode & 0xff] & COMMUTATIVE) != 0; - } - - /** - * Gets the length of an instruction denoted by a given opcode. - * - * @param opcode an instruction opcode - * @return the length of the instruction denoted by {@code opcode}. If {@code opcode} is an illegal instruction or denotes a - * variable length instruction (e.g. {@link #TABLESWITCH}), then 0 is returned. - */ - public static int lengthOf(int opcode) { - return lengthArray[opcode & 0xff]; - } - - /** - * Gets the compilation complexity for a given opcode. - * @param opcode an opcode - * @return a value >= 0 - */ - public static int compilationComplexity(int opcode) { - return compilationComplexityArray[opcode & 0xff]; - } - - /** - * Gets the lower-case mnemonic for a given opcode. - * - * @param opcode an opcode - * @return the mnemonic for {@code opcode} or {@code ""} if {@code opcode} is not a legal opcode - */ - public static String nameOf(int opcode) throws IllegalArgumentException { - String name = nameArray[opcode & 0xff]; - if (name == null) { - return ""; - } - return name; - } - - /** - * Allocation-free version of {@linkplain #nameOf(int)}. - * @param opcode an opcode. - * @return the mnemonic for {@code opcode} or {@code ""} if {@code opcode} is not a legal opcode. - */ - public static String baseNameOf(int opcode) { - String name = nameArray[opcode & 0xff]; - if (name == null) { - return ""; - } - return name; - } - - /** - * Gets the opcode corresponding to a given mnemonic. - * - * @param name an opcode mnemonic - * @return the opcode corresponding to {@code mnemonic} - * @throws IllegalArgumentException if {@code name} does not denote a valid opcode - */ - public static int valueOf(String name) { - for (int opcode = 0; opcode < nameArray.length; ++opcode) { - if (name.equalsIgnoreCase(nameArray[opcode])) { - return opcode; - } - } - throw new IllegalArgumentException("No opcode for " + name); - } - - /** - * Determines if a given opcode denotes an instruction that can cause an implicit exception. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} can cause an implicit exception, {@code false} otherwise - */ - public static boolean canTrap(int opcode) { - return (flagsArray[opcode & 0xff] & TRAP) != 0; - } - - /** - * Determines if a given opcode denotes an instruction that loads a local variable to the operand stack. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} loads a local variable to the operand stack, {@code false} otherwise - */ - public static boolean isLoad(int opcode) { - return (flagsArray[opcode & 0xff] & LOAD) != 0; - } - - /** - * Determines if a given opcode denotes an instruction that ends a basic block and does not let control flow fall - * through to its lexical successor. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} properly ends a basic block - */ - public static boolean isStop(int opcode) { - return (flagsArray[opcode & 0xff] & STOP) != 0; - } - - /** - * Determines if a given opcode denotes an instruction that stores a value to a local variable - * after popping it from the operand stack. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} otherwise - */ - public static boolean isInvoke(int opcode) { - return (flagsArray[opcode & 0xff] & INVOKE) != 0; - } - - /** - * Determines if a given opcode denotes an instruction that stores a value to a local variable - * after popping it from the operand stack. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} stores a value to a local variable, {@code false} otherwise - */ - public static boolean isStore(int opcode) { - return (flagsArray[opcode & 0xff] & STORE) != 0; - } - - /** - * Determines if a given opcode is an instruction that delimits a basic block. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} delimits a basic block - */ - public static boolean isBlockEnd(int opcode) { - return (flagsArray[opcode & 0xff] & (STOP | FALL_THROUGH)) != 0; - } - - /** - * Determines if a given opcode is an instruction that has a 2 or 4 byte operand that is an offset to another - * instruction in the same method. This does not include the {@linkplain #TABLESWITCH switch} instructions. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} is a branch instruction with a single operand - */ - public static boolean isBranch(int opcode) { - return (flagsArray[opcode & 0xff] & BRANCH) != 0; - } - - /** - * Determines if a given opcode denotes a conditional branch. - * @param opcode - * @return {@code true} iff {@code opcode} is a conditional branch - */ - public static boolean isConditionalBranch(int opcode) { - return (flagsArray[opcode & 0xff] & FALL_THROUGH) != 0; - } - - /** - * Determines if a given opcode denotes a standard bytecode. A standard bytecode is - * defined in the JVM specification. - * - * @param opcode an opcode to test - * @return {@code true} iff {@code opcode} is a standard bytecode - */ - public static boolean isStandard(int opcode) { - return (flagsArray[opcode & 0xff] & EXTENSION) == 0; - } - - /** - * Determines if a given opcode denotes an extended bytecode. - * - * @param opcode an opcode to test - * @return {@code true} if {@code opcode} is an extended bytecode - */ - public static boolean isExtended(int opcode) { - return (flagsArray[opcode & 0xff] & EXTENSION) != 0; - } - - /** - * Determines if a given opcode is a three-byte extended bytecode. - * - * @param opcode an opcode to test - * @return {@code true} if {@code (opcode & ~0xff) != 0} - */ - public static boolean isThreeByteExtended(int opcode) { - return (opcode & ~0xff) != 0; - } - - /** - * Gets the arithmetic operator name for a given opcode. If {@code opcode} does not denote an - * arithmetic instruction, then the {@linkplain #nameOf(int) name} of the opcode is returned - * instead. - * - * @param op an opcode - * @return the arithmetic operator name - */ - public static String operator(int op) { - // Checkstyle: stop - switch (op) { - // arithmetic ops - case IADD : // fall through - case LADD : // fall through - case FADD : // fall through - case DADD : return "+"; - case ISUB : // fall through - case LSUB : // fall through - case FSUB : // fall through - case DSUB : return "-"; - case IMUL : // fall through - case LMUL : // fall through - case FMUL : // fall through - case DMUL : return "*"; - case IDIV : // fall through - case LDIV : // fall through - case FDIV : // fall through - case DDIV : return "/"; - case IREM : // fall through - case LREM : // fall through - case FREM : // fall through - case DREM : return "%"; - // shift ops - case ISHL : // fall through - case LSHL : return "<<"; - case ISHR : // fall through - case LSHR : return ">>"; - case IUSHR: // fall through - case LUSHR: return ">>>"; - // logic ops - case IAND : // fall through - case LAND : return "&"; - case IOR : // fall through - case LOR : return "|"; - case IXOR : // fall through - case LXOR : return "^"; - } - // Checkstyle: resume - return nameOf(op); - } - - /** - * Defines a bytecode by entering it into the arrays that record its name, length and flags. - * - * @param name instruction name (should be lower case) - * @param format encodes the length of the instruction - * @param flagsArray the set of {@link Flags} associated with the instruction - */ - private static void def(int opcode, String name, String format, int compilationComplexity) { - def(opcode, name, format, compilationComplexity, 0); - } - - /** - * Defines a bytecode by entering it into the arrays that record its name, length and flags. - * - * @param name instruction name (lower case) - * @param format encodes the length of the instruction - * @param flags the set of {@link Flags} associated with the instruction - */ - private static void def(int opcode, String name, String format, int compilationComplexity, int flags) { - assert nameArray[opcode] == null : "opcode " + opcode + " is already bound to name " + nameArray[opcode]; - nameArray[opcode] = name; - int instructionLength = format.length(); - lengthArray[opcode] = instructionLength; - compilationComplexityArray[opcode] = compilationComplexity; - Bytecodes.flagsArray[opcode] = flags; - - assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch"; - } - - /** - * Utility for ensuring that the extended opcodes are contiguous and follow on directly - * from the standard JVM opcodes. If these conditions do not hold for the input source - * file, then it is modified 'in situ' to fix the problem. - * - * @param args {@code args[0]} is the path to this source file - */ - public static void main(String[] args) throws Exception { - Method findWorkspaceDirectory = Class.forName("com.sun.max.ide.JavaProject").getDeclaredMethod("findWorkspaceDirectory"); - File base = new File((File) findWorkspaceDirectory.invoke(null), "com.oracle.max.cri/src"); - File file = new File(base, Bytecodes.class.getName().replace('.', File.separatorChar) + ".java").getAbsoluteFile(); - - Pattern opcodeDecl = Pattern.compile("(\\s*public static final int )(\\w+)(\\s*=\\s*)(\\d+)(;.*)"); - - BufferedReader br = new BufferedReader(new FileReader(file)); - CharArrayWriter buffer = new CharArrayWriter((int) file.length()); - PrintWriter out = new PrintWriter(buffer); - String line; - int lastExtendedOpcode = BREAKPOINT; - boolean modified = false; - int section = 0; - while ((line = br.readLine()) != null) { - if (section == 0) { - if (line.equals(" // Start extended bytecodes")) { - section = 1; - } - } else if (section == 1) { - if (line.equals(" // End extended bytecodes")) { - section = 2; - } else { - Matcher matcher = opcodeDecl.matcher(line); - if (matcher.matches()) { - String name = matcher.group(2); - String value = matcher.group(4); - int opcode = Integer.parseInt(value); - if (nameArray[opcode] == null || !nameArray[opcode].equalsIgnoreCase(name)) { - throw new RuntimeException("Missing definition of name and flags for " + opcode + ":" + name + " -- " + nameArray[opcode]); - } - if (opcode != lastExtendedOpcode + 1) { - System.err.println("Fixed declaration of opcode " + name + " to be " + (lastExtendedOpcode + 1) + " (was " + value + ")"); - opcode = lastExtendedOpcode + 1; - line = line.substring(0, matcher.start(4)) + opcode + line.substring(matcher.end(4)); - modified = true; - } - - if (opcode >= 256) { - throw new RuntimeException("Exceeded maximum opcode value with " + name); - } - - lastExtendedOpcode = opcode; - } - } - } - - out.println(line); - } - if (section == 0) { - throw new RuntimeException("Did not find line starting extended bytecode declarations:\n\n // Start extended bytecodes"); - } else if (section == 1) { - throw new RuntimeException("Did not find line ending extended bytecode declarations:\n\n // End extended bytecodes"); - } - - if (modified) { - out.flush(); - FileWriter fileWriter = new FileWriter(file); - fileWriter.write(buffer.toCharArray()); - fileWriter.close(); - - System.out.println("Modified: " + file); - } - - - // Uncomment to print out visitor method declarations: -// for (int opcode = 0; opcode < flags.length; ++opcode) { -// if (isExtension(opcode)) { -// String visitorParams = length(opcode) == 1 ? "" : "int index"; -// System.out.println("@Override"); -// System.out.println("protected void " + name(opcode) + "(" + visitorParams + ") {"); -// System.out.println("}"); -// System.out.println(); -// } -// } - - // Uncomment to print out visitor method declarations: -// for (int opcode = 0; opcode < flags.length; ++opcode) { -// if (isExtension(opcode)) { -// System.out.println("case " + name(opcode).toUpperCase() + ": {"); -// String arg = ""; -// int length = length(opcode); -// if (length == 2) { -// arg = "readUnsigned1()"; -// } else if (length == 3) { -// arg = "readUnsigned2()"; -// } -// System.out.println(" bytecodeVisitor." + name(opcode) + "(" + arg + ");"); -// System.out.println(" break;"); -// System.out.println("}"); -// } -// } - - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/Bytes.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/bytecode/Bytes.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +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.graal.java.bytecode; - -/** - * A collection of utility methods for dealing with bytes, particularly in byte arrays. - */ -public class Bytes { - /** - * Gets a signed 1-byte value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @return the signed 1-byte value at index {@code bci} in array {@code data} - */ - public static int beS1(byte[] data, int bci) { - return data[bci]; - } - - /** - * Gets a signed 2-byte big-endian value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @return the signed 2-byte, big-endian, value at index {@code bci} in array {@code data} - */ - public static int beS2(byte[] data, int bci) { - return (data[bci] << 8) | (data[bci + 1] & 0xff); - } - - /** - * Gets an unsigned 1-byte value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @return the unsigned 1-byte value at index {@code bci} in array {@code data} - */ - public static int beU1(byte[] data, int bci) { - return data[bci] & 0xff; - } - - /** - * Gets an unsigned 2-byte big-endian value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @return the unsigned 2-byte, big-endian, value at index {@code bci} in array {@code data} - */ - public static int beU2(byte[] data, int bci) { - return ((data[bci] & 0xff) << 8) | (data[bci + 1] & 0xff); - } - - /** - * Gets a signed 4-byte big-endian value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @return the signed 4-byte, big-endian, value at index {@code bci} in array {@code data} - */ - public static int beS4(byte[] data, int bci) { - return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff); - } - - /** - * Gets either a signed 2-byte or a signed 4-byte big-endian value. - * @param data the array containing the data - * @param bci the start index of the value to retrieve - * @param fourByte if true, this method will return a 4-byte value - * @return the signed 2 or 4-byte, big-endian, value at index {@code bci} in array {@code data} - */ - public static int beSVar(byte[] data, int bci, boolean fourByte) { - if (fourByte) { - return beS4(data, bci); - } else { - return beS2(data, bci); - } - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Mon Jun 11 17:06:06 2012 +0200 @@ -27,12 +27,12 @@ import java.util.Map.Entry; import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.*; import com.oracle.graal.compiler.schedule.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.graph.NodeClass.NodeClassIterator; import com.oracle.graal.graph.NodeClass.Position; -import com.oracle.graal.java.bytecode.*; import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.snippets/test/test/com/oracle/graal/snippets/package-info.java --- a/graal/com.oracle.graal.snippets/test/test/com/oracle/graal/snippets/package-info.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/** - * Test cases for Graal snippets. - */ -package test.com.oracle.graal.snippets; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -38,7 +38,7 @@ * elimination is applied and it is verified that the resulting graph is equal to the graph of the method that just has * a "return 1" statement in it. */ -public class BoxingEliminationTest extends GraphTest { +public class BoxingEliminationTest extends GraalCompilerTest { private static final Short s = 2; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -27,7 +27,7 @@ import com.oracle.graal.compiler.phases.*; import com.oracle.graal.nodes.*; -public class CompareCanonicalizerTest extends GraphTest { +public class CompareCanonicalizerTest extends GraalCompilerTest { @Test public void testCanonicalComparison() { diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -39,7 +39,7 @@ * canonicalization is applied and it is verified that the resulting graph is equal to the graph of the method that just * has a "return 1" statement in it. */ -public class CompiledMethodTest extends GraphTest { +public class CompiledMethodTest extends GraalCompilerTest { public static Object testMethod(Object arg1, Object arg2, Object arg3) { return arg1 + " " + arg2 + " " + arg3; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -33,7 +33,7 @@ * Then canonicalization is applied and it is verified that the resulting graph is equal to the * graph of the method that just has a "return 1" statement in it. */ -public class DegeneratedLoopsTest extends GraphTest { +public class DegeneratedLoopsTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "referenceSnippet"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/EscapeAnalysisTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -37,7 +37,7 @@ * In these test cases the probability of all invokes is set to a high value, such that an InliningPhase should inline them all. * After that, the EscapeAnalysisPhase is expected to remove all allocations and return the correct values. */ -public class EscapeAnalysisTest extends GraphTest { +public class EscapeAnalysisTest extends GraalCompilerTest { @Test public void test1() { diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 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.compiler.tests; + +import java.lang.reflect.*; +import java.util.concurrent.*; + +import junit.framework.*; + +import com.oracle.graal.api.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.phases.*; +import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; +import com.oracle.graal.compiler.schedule.*; +import com.oracle.graal.cri.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.java.*; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +/** + * Base class for Graal compiler unit tests. These are white box tests + * for Graal compiler transformations. The general pattern for a test is: + *
      + *
    1. Create a graph by {@linkplain #parse(String) parsing} a method.
    2. + *
    3. Manually modify the graph (e.g. replace a parameter node with a constant).
    4. + *
    5. Apply a transformation to the graph.
    6. + *
    7. Assert that the transformed graph is equal to an expected graph.
    8. + *
    + *

    + * See {@link InvokeTest} as an example. + *

    + * The tests can be run in Eclipse with the "Compiler Unit Test" Eclipse + * launch configuration found in the top level of this project or by + * running {@code mx unittest} on the command line. + */ +public abstract class GraalCompilerTest { + + protected final ExtendedRiRuntime runtime; + + public GraalCompilerTest() { + Debug.enable(); + this.runtime = Graal.getRuntime().getCapability(ExtendedRiRuntime.class); + } + + protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { + String expectedString = getCanonicalGraphString(expected); + String actualString = getCanonicalGraphString(graph); + String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString; + + if (expected.getNodeCount() != graph.getNodeCount()) { + Debug.dump(expected, "Node count not matching - expected"); + Debug.dump(graph, "Node count not matching - actual"); + Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); + } + if (!expectedString.equals(actualString)) { + Debug.dump(expected, "mismatching graphs - expected"); + Debug.dump(graph, "mismatching graphs - actual"); + Assert.fail(mismatchString); + } + } + + private static String getCanonicalGraphString(StructuredGraph graph) { + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + + NodeMap canonicalId = graph.createNodeMap(); + int nextId = 0; + + StringBuilder result = new StringBuilder(); + for (Block block : schedule.getCFG().getBlocks()) { + result.append("Block " + block + " "); + if (block == schedule.getCFG().getStartBlock()) { + result.append("* "); + } + result.append("-> "); + for (Block succ : block.getSuccessors()) { + result.append(succ + " "); + } + result.append("\n"); + for (Node node : schedule.getBlockToNodesMap().get(block)) { + int id; + if (canonicalId.get(node) != null) { + id = canonicalId.get(node); + } else { + id = nextId++; + canonicalId.set(node, id); + } + String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); + result.append(" " + id + "|" + name + " (" + node.usages().size() + ")\n"); + } + } + return result.toString(); + } + + protected ExtendedRiRuntime runtime() { + return runtime; + } + + /** + * Parses a Java method to produce a graph. + * + * @param methodName the name of the method in {@code this.getClass()} to be parsed + */ + protected StructuredGraph parse(String methodName) { + return parse(getMethod(methodName)); + } + + protected Method getMethod(String methodName) { + Method found = null; + for (Method m : this.getClass().getMethods()) { + if (m.getName().equals(methodName)) { + Assert.assertNull(found); + found = m; + } + } + if (found != null) { + return found; + } else { + throw new RuntimeException("method not found: " + methodName); + } + } + + private static int compilationId = 0; + + protected void test(String name, Object... args) { + Method method = getMethod(name); + Object expect = null; + Throwable exception = null; + try { + // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved + expect = method.invoke(null, args); + } catch (InvocationTargetException e) { + exception = e.getTargetException(); + } catch (Exception e) { + throw new RuntimeException(e); + } + InstalledCode compiledMethod = compile(runtime.getResolvedJavaMethod(method), parse(method)); + compiledMethod.method(); + + if (exception != null) { + try { + compiledMethod.executeVarargs(args); + Assert.fail("expected " + exception); + } catch (Throwable e) { + Assert.assertEquals(exception.getClass(), e.getClass()); + } + } else { + Object actual = compiledMethod.executeVarargs(args); + Assert.assertEquals(expect, actual); + } + } + + protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) { + return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable() { + public InstalledCode call() throws Exception { + CompilationResult targetMethod = runtime.compile(method, graph); + return addMethod(method, targetMethod); + } + }); + } + + protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult tm) { + GraalCompiler graalCompiler = Graal.getRuntime().getCapability(GraalCompiler.class); + assert graalCompiler != null; + return Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { + @Override + public InstalledCode call() throws Exception { + final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null; + InstalledCode installedMethod = runtime.addMethod(method, tm, info); + if (info != null) { + Debug.dump(new Object[] {tm, info[0]}, "After code installation"); + } + return installedMethod; + } + }); + } + + /** + * Parses a Java method to produce a graph. + * + * @param methodName the name of the method in {@code this.getClass()} to be parsed + */ + protected StructuredGraph parseProfiled(String methodName) { + return parseProfiled(getMethod(methodName)); + } + + /** + * Parses a Java method to produce a graph. + */ + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(m); + StructuredGraph graph = new StructuredGraph(riMethod); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph); + return graph; + } + + /** + * Parses a Java method to produce a graph. + */ + protected StructuredGraph parseProfiled(Method m) { + ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(m); + StructuredGraph graph = new StructuredGraph(riMethod); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); + return graph; + } + + protected PhasePlan getDefaultPhasePlan() { + PhasePlan plan = new PhasePlan(); + plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL)); + return plan; + } +} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphScheduleTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -31,7 +31,7 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; -public class GraphScheduleTest extends GraphTest { +public class GraphScheduleTest extends GraalCompilerTest { protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) { SchedulePhase ibp = new SchedulePhase(); ibp.apply(graph); diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java Mon Jun 11 15:39:57 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * Copyright (c) 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.compiler.tests; - -import java.lang.reflect.*; -import java.util.concurrent.*; - -import junit.framework.*; - -import com.oracle.graal.api.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.phases.*; -import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition; -import com.oracle.graal.compiler.schedule.*; -import com.oracle.graal.cri.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.Verbosity; -import com.oracle.graal.java.*; -import com.oracle.graal.lir.cfg.*; -import com.oracle.graal.nodes.*; - -/** - * Base class for Graal compiler unit tests. These are white box tests - * for Graal compiler transformations. The general pattern for a test is: - *

      - *
    1. Create a graph by {@linkplain #parse(String) parsing} a method.
    2. - *
    3. Manually modify the graph (e.g. replace a parameter node with a constant).
    4. - *
    5. Apply a transformation to the graph.
    6. - *
    7. Assert that the transformed graph is equal to an expected graph.
    8. - *
    - *

    - * See {@link InvokeTest} as an example. - *

    - * The tests can be run in Eclipse with the "Compiler Unit Test" Eclipse - * launch configuration found in the top level of this project or by - * running {@code mx unittest} on the command line. - */ -public abstract class GraphTest { - - protected final ExtendedRiRuntime runtime; - - public GraphTest() { - Debug.enable(); - this.runtime = Graal.getRuntime().getCapability(ExtendedRiRuntime.class); - } - - protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { - String expectedString = getCanonicalGraphString(expected); - String actualString = getCanonicalGraphString(graph); - String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString; - - if (expected.getNodeCount() != graph.getNodeCount()) { - Debug.dump(expected, "Node count not matching - expected"); - Debug.dump(graph, "Node count not matching - actual"); - Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); - } - if (!expectedString.equals(actualString)) { - Debug.dump(expected, "mismatching graphs - expected"); - Debug.dump(graph, "mismatching graphs - actual"); - Assert.fail(mismatchString); - } - } - - private static String getCanonicalGraphString(StructuredGraph graph) { - SchedulePhase schedule = new SchedulePhase(); - schedule.apply(graph); - - NodeMap canonicalId = graph.createNodeMap(); - int nextId = 0; - - StringBuilder result = new StringBuilder(); - for (Block block : schedule.getCFG().getBlocks()) { - result.append("Block " + block + " "); - if (block == schedule.getCFG().getStartBlock()) { - result.append("* "); - } - result.append("-> "); - for (Block succ : block.getSuccessors()) { - result.append(succ + " "); - } - result.append("\n"); - for (Node node : schedule.getBlockToNodesMap().get(block)) { - int id; - if (canonicalId.get(node) != null) { - id = canonicalId.get(node); - } else { - id = nextId++; - canonicalId.set(node, id); - } - String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); - result.append(" " + id + "|" + name + " (" + node.usages().size() + ")\n"); - } - } - return result.toString(); - } - - protected ExtendedRiRuntime runtime() { - return runtime; - } - - /** - * Parses a Java method to produce a graph. - * - * @param methodName the name of the method in {@code this.getClass()} to be parsed - */ - protected StructuredGraph parse(String methodName) { - return parse(getMethod(methodName)); - } - - protected Method getMethod(String methodName) { - Method found = null; - for (Method m : this.getClass().getMethods()) { - if (m.getName().equals(methodName)) { - Assert.assertNull(found); - found = m; - } - } - if (found != null) { - return found; - } else { - throw new RuntimeException("method not found: " + methodName); - } - } - - private static int compilationId = 0; - - protected void test(String name, Object... args) { - Method method = getMethod(name); - Object expect = null; - Throwable exception = null; - try { - // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved - expect = method.invoke(null, args); - } catch (InvocationTargetException e) { - exception = e.getTargetException(); - } catch (Exception e) { - throw new RuntimeException(e); - } - InstalledCode compiledMethod = compile(runtime.getResolvedJavaMethod(method), parse(method)); - compiledMethod.method(); - - if (exception != null) { - try { - compiledMethod.executeVarargs(args); - Assert.fail("expected " + exception); - } catch (Throwable e) { - Assert.assertEquals(exception.getClass(), e.getClass()); - } - } else { - Object actual = compiledMethod.executeVarargs(args); - Assert.assertEquals(expect, actual); - } - } - - protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) { - return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable() { - public InstalledCode call() throws Exception { - CompilationResult targetMethod = runtime.compile(method, graph); - return addMethod(method, targetMethod); - } - }); - } - - protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult tm) { - GraalCompiler graalCompiler = Graal.getRuntime().getCapability(GraalCompiler.class); - assert graalCompiler != null; - return Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable() { - @Override - public InstalledCode call() throws Exception { - final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null; - InstalledCode installedMethod = runtime.addMethod(method, tm, info); - if (info != null) { - Debug.dump(new Object[] {tm, info[0]}, "After code installation"); - } - return installedMethod; - } - }); - } - - /** - * Parses a Java method to produce a graph. - * - * @param methodName the name of the method in {@code this.getClass()} to be parsed - */ - protected StructuredGraph parseProfiled(String methodName) { - return parseProfiled(getMethod(methodName)); - } - - /** - * Parses a Java method to produce a graph. - */ - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(m); - StructuredGraph graph = new StructuredGraph(riMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph); - return graph; - } - - /** - * Parses a Java method to produce a graph. - */ - protected StructuredGraph parseProfiled(Method m) { - ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(m); - StructuredGraph graph = new StructuredGraph(riMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); - return graph; - } - - protected PhasePlan getDefaultPhasePlan() { - PhasePlan plan = new PhasePlan(); - plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL)); - return plan; - } -} diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfBoxingEliminationTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -33,7 +33,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; -public class IfBoxingEliminationTest extends GraphTest { +public class IfBoxingEliminationTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "referenceSnippet"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfCanonicalizerTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfCanonicalizerTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/IfCanonicalizerTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -36,7 +36,7 @@ * Then canonicalization is applied and it is verified that the resulting graph is equal to the * graph of the method that just has a "return 1" statement in it. */ -public class IfCanonicalizerTest extends GraphTest { +public class IfCanonicalizerTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "referenceSnippet"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeExceptionTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -30,7 +30,7 @@ import com.oracle.graal.compiler.phases.*; import com.oracle.graal.nodes.*; -public class InvokeExceptionTest extends GraphTest { +public class InvokeExceptionTest extends GraalCompilerTest { public static synchronized void throwException(int i) { if (i == 1) { diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -35,7 +35,7 @@ * Then canonicalization is applied and it is verified that the resulting graph is equal to the * graph of the method that just has a "return 1" statement in it. */ -public class InvokeTest extends GraphTest { +public class InvokeTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "referenceSnippet"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/MonitorTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -40,7 +40,7 @@ * Then canonicalization is applied and it is verified that the resulting graph is equal to the * graph of the method that just has a "return 1" statement in it. */ -public class MonitorTest extends GraphTest { +public class MonitorTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "referenceSnippet"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NestedLoopTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NestedLoopTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/NestedLoopTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -29,7 +29,7 @@ import com.oracle.graal.lir.cfg.*; import com.oracle.graal.nodes.*; -public class NestedLoopTest extends GraphTest { +public class NestedLoopTest extends GraalCompilerTest { @Test public void test1() { diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/PhiCreationTests.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/PhiCreationTests.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/PhiCreationTests.java Mon Jun 11 17:06:06 2012 +0200 @@ -30,7 +30,7 @@ /** * In the following tests, the correct removal of redundant phis during graph building is tested. */ -public class PhiCreationTests extends GraphTest { +public class PhiCreationTests extends GraalCompilerTest { /** * Dummy method to avoid javac dead code elimination. diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -31,7 +31,7 @@ /** * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions. */ -public class ScalarTypeSystemTest extends GraphTest { +public class ScalarTypeSystemTest extends GraalCompilerTest { public static int referenceSnippet1(int a) { if (a > 0) { diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/StraighteningTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -28,7 +28,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; -public class StraighteningTest extends GraphTest { +public class StraighteningTest extends GraalCompilerTest { private static final String REFERENCE_SNIPPET = "ref"; diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -29,7 +29,7 @@ /** * Base class for checkcast and instanceof test classes. */ -public abstract class TypeCheckTest extends GraphTest { +public abstract class TypeCheckTest extends GraalCompilerTest { protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); diff -r 6a2671066204 -r 102f87543d5e graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java --- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Mon Jun 11 15:39:57 2012 +0200 +++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java Mon Jun 11 17:06:06 2012 +0200 @@ -40,7 +40,7 @@ /** * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions. */ -public class TypeSystemTest extends GraphTest { +public class TypeSystemTest extends GraalCompilerTest { @Test public void test1() { diff -r 6a2671066204 -r 102f87543d5e mx/projects --- a/mx/projects Mon Jun 11 15:39:57 2012 +0200 +++ b/mx/projects Mon Jun 11 17:06:06 2012 +0200 @@ -111,11 +111,18 @@ # graal.snippets project@com.oracle.graal.snippets@subDir=graal -project@com.oracle.graal.snippets@sourceDirs=src,test +project@com.oracle.graal.snippets@sourceDirs=src project@com.oracle.graal.snippets@dependencies=com.oracle.graal.printer project@com.oracle.graal.snippets@checkstyle=com.oracle.graal.graph project@com.oracle.graal.snippets@javaCompliance=1.7 +# graal.snippets.test +project@com.oracle.graal.snippets.test@subDir=graal +project@com.oracle.graal.snippets.test@sourceDirs=src +project@com.oracle.graal.snippets.test@dependencies=com.oracle.graal.snippets +project@com.oracle.graal.snippets.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.snippets.test@javaCompliance=1.7 + # graal.nodes project@com.oracle.graal.nodes@subDir=graal project@com.oracle.graal.nodes@sourceDirs=src,test @@ -123,6 +130,13 @@ project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph project@com.oracle.graal.nodes@javaCompliance=1.7 +# graal.interpreter +project@com.oracle.graal.interpreter@subDir=graal +project@com.oracle.graal.interpreter@sourceDirs=src +project@com.oracle.graal.interpreter@dependencies=com.oracle.graal.hotspot +project@com.oracle.graal.interpreter@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.interpreter@javaCompliance=1.7 + # graal.compiler project@com.oracle.graal.compiler@subDir=graal project@com.oracle.graal.compiler@sourceDirs=src @@ -130,10 +144,30 @@ project@com.oracle.graal.compiler@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler@javaCompliance=1.7 +# graal.boot +project@com.oracle.graal.boot@subDir=graal +project@com.oracle.graal.boot@sourceDirs=src +project@com.oracle.graal.boot@dependencies=com.oracle.graal.compiler +project@com.oracle.graal.boot@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.boot@javaCompliance=1.7 + +# graal.boot.test +project@com.oracle.graal.boot.test@subDir=graal +project@com.oracle.graal.boot.test@sourceDirs=src +project@com.oracle.graal.boot.test@dependencies=JUNIT,com.oracle.graal.boot +project@com.oracle.graal.boot.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.boot.test@javaCompliance=1.7 + +# graal.bytecode +project@com.oracle.graal.bytecode@subDir=graal +project@com.oracle.graal.bytecode@sourceDirs=src +project@com.oracle.graal.bytecode@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.bytecode@javaCompliance=1.7 + # graal.java project@com.oracle.graal.java@subDir=graal project@com.oracle.graal.java@sourceDirs=src -project@com.oracle.graal.java@dependencies=com.oracle.graal.compiler +project@com.oracle.graal.java@dependencies=com.oracle.graal.compiler,com.oracle.graal.bytecode project@com.oracle.graal.java@checkstyle=com.oracle.graal.graph project@com.oracle.graal.java@javaCompliance=1.7 diff -r 6a2671066204 -r 102f87543d5e src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Jun 11 15:39:57 2012 +0200 +++ b/src/share/vm/runtime/arguments.cpp Mon Jun 11 17:06:06 2012 +0200 @@ -2147,6 +2147,7 @@ "com.oracle.graal.graph", "com.oracle.graal.lir", "com.oracle.graal.lir.amd64", + "com.oracle.graal.bytecode", "com.oracle.graal.java" };