# HG changeset patch # User Stefan Anzinger # Date 1431683752 -7200 # Node ID 307a1ee8f714ec63bc2973a48579632237df3802 # Parent 427f3b505656a71fde8a03d676b5b471905017ec# Parent f27373c035fb82a8af2d91bc46802390274e86fb Merge diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Fri May 15 11:55:52 2015 +0200 @@ -64,6 +64,13 @@ } /** + * Returns the name of this code blob. + */ + public String getName() { + return name; + } + + /** * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 * otherwise. */ diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Assumptions.java Fri May 15 11:55:52 2015 +0200 @@ -68,6 +68,10 @@ return result; } + public boolean isAssumptionFree() { + return assumptions.length == 0; + } + public void add(AssumptionResult other) { Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaConstant.java Fri May 15 11:55:52 2015 +0200 @@ -256,16 +256,18 @@ */ static PrimitiveConstant forIntegerKind(Kind kind, long i) { switch (kind) { + case Boolean: + return forBoolean(i != 0); case Byte: - return new PrimitiveConstant(kind, (byte) i); + return forByte((byte) i); case Short: - return new PrimitiveConstant(kind, (short) i); + return forShort((short) i); case Char: - return new PrimitiveConstant(kind, (char) i); + return forChar((char) i); case Int: - return new PrimitiveConstant(kind, (int) i); + return forInt((int) i); case Long: - return new PrimitiveConstant(kind, i); + return forLong(i); default: throw new IllegalArgumentException("not an integer kind: " + kind); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTableImpl.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,54 @@ +/* + * 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.api.meta; + +public class LineNumberTableImpl implements LineNumberTable { + + private final int[] lineNumbers; + private final int[] bci; + + public LineNumberTableImpl(int[] lineNumbers, int[] bci) { + this.lineNumbers = lineNumbers; + this.bci = bci; + } + + @Override + public int[] getLineNumberEntries() { + return lineNumbers; + } + + @Override + public int[] getBciEntries() { + return bci; + } + + @Override + public int getLineNumber(@SuppressWarnings("hiding") int bci) { + for (int i = 0; i < this.bci.length - 1; i++) { + if (this.bci[i] <= bci && bci < this.bci[i + 1]) { + return lineNumbers[i]; + } + } + return lineNumbers[lineNumbers.length - 1]; + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalImpl.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,84 @@ +/* + * 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.api.meta; + +public class LocalImpl implements Local { + + private final String name; + private final int startBci; + private final int endBci; + private final int slot; + private final JavaType type; + + public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { + this.name = name; + this.startBci = startBci; + this.endBci = endBci; + this.slot = slot; + this.type = type; + } + + @Override + public int getStartBCI() { + return startBci; + } + + @Override + public int getEndBCI() { + return endBci; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + return type; + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LocalImpl)) { + return false; + } + LocalImpl that = (LocalImpl) obj; + return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "LocalImpl"; + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocalVariableTableImpl.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,66 @@ +/* + * 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.api.meta; + +import java.util.*; + +public class LocalVariableTableImpl implements LocalVariableTable { + + private final Local[] locals; + + public LocalVariableTableImpl(Local[] locals) { + this.locals = locals; + } + + @Override + public Local getLocal(int slot, int bci) { + Local result = null; + for (Local local : locals) { + if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { + if (result == null) { + result = local; + } else { + throw new IllegalStateException("Locals overlap!"); + } + } + } + return result; + } + + @Override + public Local[] getLocals() { + return locals; + } + + @Override + public Local[] getLocalsAt(int bci) { + List result = new ArrayList<>(); + for (Local l : locals) { + if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { + result.add(l); + } + } + return result.toArray(new Local[result.size()]); + } + +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LocationIdentity.java Fri May 15 11:55:52 2015 +0200 @@ -54,26 +54,18 @@ */ public static final LocationIdentity ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("[].length"); - protected final boolean immutable; - public static LocationIdentity any() { return ANY_LOCATION; } - protected LocationIdentity(boolean immutable) { - this.immutable = immutable; - } - /** * Denotes a location is unchanging in all cases. Not that this is different than the Java * notion of final which only requires definite assignment. */ - public final boolean isImmutable() { - return immutable; - } + public abstract boolean isImmutable(); public final boolean isMutable() { - return !immutable; + return !isImmutable(); } public final boolean isAny() { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java Fri May 15 11:55:52 2015 +0200 @@ -46,11 +46,12 @@ } } - protected final String name; + private final String name; + private final boolean immutable; private NamedLocationIdentity(String name, boolean immutable) { - super(immutable); this.name = name; + this.immutable = immutable; } /** @@ -87,6 +88,11 @@ } @Override + public boolean isImmutable() { + return immutable; + } + + @Override public String toString() { return name + (isImmutable() ? ":final" : ""); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Fri May 15 11:55:52 2015 +0200 @@ -52,6 +52,7 @@ import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; +import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.amd64.*; @@ -64,6 +65,7 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove; +import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; @@ -130,6 +132,28 @@ } } + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + protected final boolean canStoreConstant(JavaConstant c) { + // there is no immediate move of 64-bit constants on Intel + switch (c.getKind()) { + case Long: + return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); + case Double: + return false; + case Object: + return c.isNull(); + default: + return true; + } + } + protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { if (src instanceof AMD64AddressValue) { return new LeaOp(dst, (AMD64AddressValue) src); @@ -263,6 +287,183 @@ return result; } + private static LIRKind toStackKind(LIRKind kind) { + if (kind.getPlatformKind() instanceof Kind) { + Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind(); + return kind.changeType(stackKind); + } else { + return kind; + } + } + + @Override + public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { + AMD64AddressValue loadAddress = asAddressValue(address); + Variable result = newVariable(toStackKind(kind)); + switch ((Kind) kind.getPlatformKind()) { + case Boolean: + append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); + break; + case Byte: + append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); + break; + case Char: + append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); + break; + case Short: + append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); + break; + case Int: + append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); + break; + case Long: + case Object: + append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); + break; + case Float: + append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); + break; + case Double: + append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { + if (value.isNull()) { + assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; + OperandSize size = kind == Kind.Int ? DWORD : QWORD; + append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); + } else { + AMD64MIOp op = AMD64MIOp.MOV; + OperandSize size; + long imm; + + switch (kind) { + case Boolean: + case Byte: + op = AMD64MIOp.MOVB; + size = BYTE; + imm = value.asInt(); + break; + case Char: + case Short: + size = WORD; + imm = value.asInt(); + break; + case Int: + size = DWORD; + imm = value.asInt(); + break; + case Long: + size = QWORD; + imm = value.asLong(); + break; + case Float: + size = DWORD; + imm = Float.floatToRawIntBits(value.asFloat()); + break; + case Double: + size = QWORD; + imm = Double.doubleToRawLongBits(value.asDouble()); + break; + default: + throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind); + } + + if (NumUtil.isInt(imm)) { + append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); + } else { + emitStore(kind, address, asAllocatable(value), state); + } + } + } + + protected void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { + switch (kind) { + case Boolean: + case Byte: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); + break; + case Char: + case Short: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); + break; + case Int: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); + break; + case Long: + case Object: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); + break; + case Float: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); + break; + case Double: + append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { + AMD64AddressValue storeAddress = asAddressValue(address); + Kind kind = (Kind) lirKind.getPlatformKind(); + if (isConstant(input)) { + emitStoreConst(kind, storeAddress, asConstant(input), state); + } else { + emitStore(kind, storeAddress, asAllocatable(input), state); + } + } + + @Override + public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { + LIRKind kind = newValue.getLIRKind(); + assert kind.equals(expectedValue.getLIRKind()); + Kind memKind = (Kind) kind.getPlatformKind(); + + AMD64AddressValue addressValue = asAddressValue(address); + RegisterValue raxRes = AMD64.rax.asValue(kind); + emitMove(raxRes, expectedValue); + append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); + + assert trueValue.getLIRKind().equals(falseValue.getLIRKind()); + Variable result = newVariable(trueValue.getLIRKind()); + append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); + return result; + } + + @Override + public Value emitAtomicReadAndAdd(Value address, Value delta) { + LIRKind kind = delta.getLIRKind(); + Kind memKind = (Kind) kind.getPlatformKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta))); + return result; + } + + @Override + public Value emitAtomicReadAndWrite(Value address, Value newValue) { + LIRKind kind = newValue.getLIRKind(); + Kind memKind = (Kind) kind.getPlatformKind(); + Variable result = newVariable(kind); + AMD64AddressValue addressValue = asAddressValue(address); + append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); + return result; + } + + @Override + public void emitNullCheck(Value address, LIRFrameState state) { + assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!"; + append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); + } + @Override public void emitJump(LabelRef label) { assert label != null; @@ -1066,16 +1267,36 @@ return result; } else { assert inputVal.getKind().getStackKind() == Kind.Int; - Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); - int mask = (int) CodeUtil.mask(fromBits); - append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); + + LIRKind resultKind = LIRKind.derive(inputVal); + OperandSize resultSize; if (toBits > 32) { - Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); - emitMove(longResult, result); - return longResult; + resultKind = resultKind.changeType(Kind.Long); + resultSize = QWORD; } else { - return result; + resultKind = resultKind.changeType(Kind.Int); + resultSize = DWORD; + } + + switch (fromBits) { + case 8: + return emitConvertOp(resultKind, MOVZXB, resultSize, inputVal); + case 16: + return emitConvertOp(resultKind, MOVZX, resultSize, inputVal); + case 32: + return emitConvertOp(resultKind, MOV, DWORD, inputVal); } + + // odd bit count, fall back on manual masking + Variable result = newVariable(resultKind); + JavaConstant mask; + if (toBits > 32) { + mask = JavaConstant.forLong(CodeUtil.mask(fromBits)); + } else { + mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits)); + } + append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask)); + return result; } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java Fri May 15 11:55:52 2015 +0200 @@ -45,4 +45,6 @@ public Fields getData() { return data; } + + public abstract Fields[] getAllFields(); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java Fri May 15 11:55:52 2015 +0200 @@ -48,6 +48,8 @@ */ private final Class[] types; + private final Class[] declaringClasses; + public static Fields forClass(Class clazz, Class endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) { FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset); scanner.scan(clazz, endClazz, includeTransient); @@ -59,11 +61,13 @@ this.offsets = new long[fields.size()]; this.names = new String[offsets.length]; this.types = new Class[offsets.length]; + this.declaringClasses = new Class[offsets.length]; int index = 0; for (FieldsScanner.FieldInfo f : fields) { offsets[index] = f.offset; names[index] = f.name; types[index] = f.type; + declaringClasses[index] = f.declaringClass; index++; } } @@ -77,7 +81,7 @@ public static void translateInto(Fields fields, ArrayList infos) { for (int index = 0; index < fields.getCount(); index++) { - infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index])); + infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index], fields.declaringClasses[index])); } } @@ -217,6 +221,10 @@ return other.offsets[index] == offsets[index]; } + public long[] getOffsets() { + return offsets; + } + /** * Gets the name of a field. * @@ -235,6 +243,10 @@ return types[index]; } + public Class getDeclaringClass(int index) { + return declaringClasses[index]; + } + /** * Checks that a given field is assignable from a given value. * diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java Fri May 15 11:55:52 2015 +0200 @@ -60,11 +60,13 @@ public final long offset; public final String name; public final Class type; + public final Class declaringClass; - public FieldInfo(long offset, String name, Class type) { + public FieldInfo(long offset, String name, Class type, Class declaringClass) { this.offset = offset; this.name = name; this.type = type; + this.declaringClass = declaringClass; } /** @@ -117,6 +119,6 @@ } protected void scanField(Field field, long offset) { - data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType())); + data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType(), field.getDeclaringClass())); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Fri May 15 11:55:52 2015 +0200 @@ -286,7 +286,7 @@ public static final OptionValue OptImplicitNullChecks = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) - public static final OptionValue OptLivenessAnalysis = new OptionValue<>(true); + public static final OptionValue OptClearNonLiveLocals = new OptionValue<>(true); @Option(help = "", type = OptionType.Debug) public static final OptionValue OptLoopTransform = new OptionValue<>(true); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Fri May 15 11:55:52 2015 +0200 @@ -113,7 +113,6 @@ } objectStates.clear(); - assert frame.validateFormat(false); return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java Fri May 15 11:55:52 2015 +0200 @@ -57,7 +57,7 @@ public static void translateInto(Edges edges, ArrayList infos) { for (int index = 0; index < edges.getCount(); index++) { - infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index))); + infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index))); } } @@ -547,10 +547,6 @@ } } - public long[] getOffsets() { - return this.offsets; - } - public void pushAll(Node node, NodeStack stack) { int index = 0; int curDirectCount = this.directCount; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java Fri May 15 11:55:52 2015 +0200 @@ -47,7 +47,7 @@ public static void translateInto(InputEdges inputs, ArrayList infos) { for (int index = 0; index < inputs.getCount(); index++) { - infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.inputTypes[index], inputs.isOptional(index))); + infos.add(new InputInfo(inputs.offsets[index], inputs.getName(index), inputs.getType(index), inputs.getDeclaringClass(index), inputs.inputTypes[index], inputs.isOptional(index))); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Fri May 15 11:55:52 2015 +0200 @@ -241,6 +241,11 @@ return shortName; } + @Override + public Fields[] getAllFields() { + return new Fields[]{data, inputs, successors}; + } + public int[] iterableIds() { nodeIterableCount.increment(); return iterableIds; @@ -288,8 +293,8 @@ */ protected static class EdgeInfo extends FieldsScanner.FieldInfo { - public EdgeInfo(long offset, String name, Class type) { - super(offset, name, type); + public EdgeInfo(long offset, String name, Class type, Class declaringClass) { + super(offset, name, type, declaringClass); } /** @@ -317,8 +322,8 @@ final InputType inputType; final boolean optional; - public InputInfo(long offset, String name, Class type, InputType inputType, boolean optional) { - super(offset, name, type); + public InputInfo(long offset, String name, Class type, Class declaringClass, InputType inputType, boolean optional) { + super(offset, name, type, declaringClass); this.inputType = inputType; this.optional = optional; } @@ -375,7 +380,7 @@ } else { inputType = optionalInputAnnotation.value(); } - inputs.add(new InputInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class))); + inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class))); } else if (successorAnnotation != null) { if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { // NodeSuccessorList fields should not be final since they are @@ -387,7 +392,7 @@ GraalInternalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field); directSuccessors++; } - successors.add(new EdgeInfo(offset, field.getName(), type)); + successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass())); } else { GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field); GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/ForeignCallPlugin.java Fri May 15 11:55:52 2015 +0200 @@ -41,7 +41,9 @@ } public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode[] args) { - b.addPush(new ForeignCallNode(foreignCalls, descriptor, args)); + ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, descriptor, args); + foreignCall.setBci(b.bci()); + b.addPush(foreignCall); return true; } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java Fri May 15 11:55:52 2015 +0200 @@ -131,9 +131,10 @@ private final boolean eagerResolving; private final boolean omitAllExceptionEdges; + private final boolean omitAssertions; private final ResolvedJavaType[] skippedExceptionTypes; private final DebugInfoMode debugInfoMode; - private final boolean doLivenessAnalysis; + private final boolean clearNonLiveLocals; private boolean useProfiling; private final Plugins plugins; @@ -161,13 +162,14 @@ Full, } - protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, boolean doLivenessAnalysis, - Plugins plugins) { + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges, boolean omitAssertions, DebugInfoMode debugInfoMode, ResolvedJavaType[] skippedExceptionTypes, + boolean clearNonLiveLocals, Plugins plugins) { this.eagerResolving = eagerResolving; this.omitAllExceptionEdges = omitAllExceptionEdges; + this.omitAssertions = omitAssertions; this.debugInfoMode = debugInfoMode; this.skippedExceptionTypes = skippedExceptionTypes; - this.doLivenessAnalysis = doLivenessAnalysis; + this.clearNonLiveLocals = clearNonLiveLocals; this.useProfiling = true; this.plugins = plugins; } @@ -179,7 +181,7 @@ */ public GraphBuilderConfiguration copy() { Plugins newPlugins = new Plugins(plugins); - GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins); + GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, newPlugins); result.useProfiling = useProfiling; return result; } @@ -193,20 +195,24 @@ } public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins); } public GraphBuilderConfiguration withOmitAllExceptionEdges(boolean newOmitAllExceptionEdges) { - return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, newOmitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins); + } + + public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) { + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newOmitAssertions, debugInfoMode, skippedExceptionTypes, clearNonLiveLocals, plugins); } public GraphBuilderConfiguration withDebugInfoMode(DebugInfoMode newDebugInfoMode) { ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length); - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, newDebugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis, plugins); + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, newDebugInfoMode, newSkippedExceptionTypes, clearNonLiveLocals, plugins); } - public GraphBuilderConfiguration withDoLivenessAnalysis(boolean newLivenessAnalysis) { - return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis, plugins); + public GraphBuilderConfiguration withClearNonLiveLocals(boolean newClearNonLiveLocals) { + return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, omitAssertions, debugInfoMode, skippedExceptionTypes, newClearNonLiveLocals, plugins); } public ResolvedJavaType[] getSkippedExceptionTypes() { @@ -221,6 +227,10 @@ return omitAllExceptionEdges; } + public boolean omitAssertions() { + return omitAssertions; + } + public boolean insertNonSafepointDebugInfo() { return debugInfoMode.ordinal() >= DebugInfoMode.Simple.ordinal(); } @@ -233,32 +243,32 @@ return debugInfoMode == DebugInfoMode.Simple; } - public boolean doLivenessAnalysis() { - return doLivenessAnalysis; + public boolean clearNonLiveLocals() { + return clearNonLiveLocals; } public static GraphBuilderConfiguration getDefault(Plugins plugins) { - return new GraphBuilderConfiguration(false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(false, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getInfopointDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getEagerDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getInfopointEagerDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Simple, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, true, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, true, false, DebugInfoMode.SafePointsOnly, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } public static GraphBuilderConfiguration getFullDebugDefault(Plugins plugins) { - return new GraphBuilderConfiguration(true, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptLivenessAnalysis.getValue(), plugins); + return new GraphBuilderConfiguration(true, false, false, DebugInfoMode.Full, EMPTY, GraalOptions.OptClearNonLiveLocals.getValue(), plugins); } /** diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java Fri May 15 11:55:52 2015 +0200 @@ -36,7 +36,8 @@ import com.oracle.graal.nodes.type.*; /** - * Used by a {@link GraphBuilderPlugin} to interface with a graph builder object. + * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a + * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} . */ public interface GraphBuilderContext { @@ -178,7 +179,7 @@ * Gets the first ancestor parsing context that is not parsing a * {@linkplain #parsingIntrinsic() intrinsic}. */ - default GraphBuilderContext getNonReplacementAncestor() { + default GraphBuilderContext getNonIntrinsicAncestor() { GraphBuilderContext ancestor = getParent(); while (ancestor != null && ancestor.parsingIntrinsic()) { ancestor = ancestor.getParent(); @@ -187,7 +188,7 @@ } /** - * Gets the method currently being parsed. + * Gets the method being parsed by this context. */ ResolvedJavaMethod getMethod(); @@ -206,9 +207,18 @@ */ JavaType getInvokeReturnType(); + default Stamp getInvokeReturnStamp() { + JavaType returnType = getInvokeReturnType(); + if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) { + return StampFactory.declared((ResolvedJavaType) returnType); + } else { + return StampFactory.forKind(returnType.getKind()); + } + } + /** - * Gets the inline depth of this context. 0 implies this is the context for the compilation root - * method. + * Gets the inline depth of this context. A return value of 0 implies that this is the context + * for the parse root. */ default int getDepth() { GraphBuilderContext parent = getParent(); @@ -216,7 +226,8 @@ } /** - * Determines if the current parsing context is a snippet or method substitution. + * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined + * by an intrinsic. */ default boolean parsingIntrinsic() { return getIntrinsic() != null; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Fri May 15 11:55:52 2015 +0200 @@ -227,6 +227,14 @@ } /** + * Disallows new registrations of new plugins, and creates the internal tables for method + * lookup. + */ + public void closeRegistration() { + plugins.createEntries(); + } + + /** * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} * before searching in this object. */ diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/LoadFieldPlugin.java Fri May 15 11:55:52 2015 +0200 @@ -40,7 +40,7 @@ JavaConstant result = constantReflection.readConstantFieldValue(field, receiver); if (result != null) { ConstantNode constantNode = ConstantNode.forConstant(result, metaAccess); - b.addPush(constantNode.getKind().getStackKind(), constantNode); + b.addPush(field.getKind(), constantNode); return true; } return false; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdHolder.java Fri May 15 11:55:52 2015 +0200 @@ -62,7 +62,7 @@ idVerifierMap.put(holder, id); } } else { - assert idVerifierMap.get(holder) == id; + assert !idVerifierMap.containsKey(holder) || idVerifierMap.get(holder) == id; } return id; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodIdMap.java Fri May 15 11:55:52 2015 +0200 @@ -199,38 +199,7 @@ public V get(MethodIdHolder method) { if (entries == null) { - // 'assignIds' synchronizes on a global lock which ensures thread safe - // allocation of identifiers across all MethodIdHolder objects - MethodIdHolder.assignIds(new Consumer() { - - public void accept(MethodIdAllocator idAllocator) { - if (entries == null) { - if (registrations.isEmpty()) { - entries = allocateEntries(0); - } else { - int max = Integer.MIN_VALUE; - for (MethodKey methodKey : registrations) { - MethodIdHolder m = methodKey.resolve(metaAccess); - int id = idAllocator.assignId(m); - if (id < minId) { - minId = id; - } - if (id > max) { - max = id; - } - methodKey.id = id; - } - - int length = (max - minId) + 1; - entries = allocateEntries(length); - for (MethodKey m : registrations) { - int index = m.id - minId; - entries[index] = m.value; - } - } - } - } - }); + createEntries(); } int id = method.getMethodId(); @@ -238,6 +207,41 @@ return index >= 0 && index < entries.length ? entries[index] : null; } + public void createEntries() { + // 'assignIds' synchronizes on a global lock which ensures thread safe + // allocation of identifiers across all MethodIdHolder objects + MethodIdHolder.assignIds(new Consumer() { + + public void accept(MethodIdAllocator idAllocator) { + if (entries == null) { + if (registrations.isEmpty()) { + entries = allocateEntries(0); + } else { + int max = Integer.MIN_VALUE; + for (MethodKey methodKey : registrations) { + MethodIdHolder m = methodKey.resolve(metaAccess); + int id = idAllocator.assignId(m); + if (id < minId) { + minId = id; + } + if (id > max) { + max = id; + } + methodKey.id = id; + } + + int length = (max - minId) + 1; + entries = allocateEntries(length); + for (MethodKey m : registrations) { + int index = m.id - minId; + entries[index] = m.value; + } + } + } + } + }); + } + @Override public String toString() { return registrations.stream().map(MethodKey::toString).collect(Collectors.joining(", ")); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Fri May 15 11:55:52 2015 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.amd64; import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; @@ -34,13 +33,10 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; -import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.spi.*; import com.oracle.graal.debug.*; import com.oracle.graal.hotspot.*; @@ -52,8 +48,6 @@ import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; -import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.asm.*; @@ -494,15 +488,6 @@ } } - private static LIRKind toStackKind(LIRKind kind) { - if (kind.getPlatformKind() instanceof Kind) { - Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind(); - return kind.changeType(stackKind); - } else { - return kind; - } - } - public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { Variable frameSizeVariable = load(frameSize); Variable framePcVariable = load(framePc); @@ -512,47 +497,8 @@ } @Override - public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { - AMD64AddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(toStackKind(kind)); - switch ((Kind) kind.getPlatformKind()) { - case Boolean: - append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); - break; - case Byte: - append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); - break; - case Char: - append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); - break; - case Short: - append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); - break; - case Int: - append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); - break; - case Long: - case Object: - append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); - break; - case Float: - append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); - break; - case Double: - append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - return result; - } - - private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { - if (value.isNull()) { - assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; - OperandSize size = kind == Kind.Int ? DWORD : QWORD; - append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); - } else if (value instanceof HotSpotConstant) { + protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { + if (value instanceof HotSpotConstant && value.isNonNull()) { HotSpotConstant c = (HotSpotConstant) value; if (c.isCompressed()) { assert kind == Kind.Int; @@ -565,86 +511,7 @@ emitStore(kind, address, asAllocatable(value), state); } } else { - AMD64MIOp op = AMD64MIOp.MOV; - OperandSize size; - long imm; - - switch (kind) { - case Boolean: - case Byte: - op = AMD64MIOp.MOVB; - size = BYTE; - imm = value.asInt(); - break; - case Char: - case Short: - size = WORD; - imm = value.asInt(); - break; - case Int: - size = DWORD; - imm = value.asInt(); - break; - case Long: - size = QWORD; - imm = value.asLong(); - break; - case Float: - size = DWORD; - imm = Float.floatToRawIntBits(value.asFloat()); - break; - case Double: - size = QWORD; - imm = Double.doubleToRawLongBits(value.asDouble()); - break; - default: - throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind); - } - - if (NumUtil.isInt(imm)) { - append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); - } else { - emitStore(kind, address, asAllocatable(value), state); - } - } - } - - private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { - switch (kind) { - case Boolean: - case Byte: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); - break; - case Char: - case Short: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); - break; - case Int: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); - break; - case Long: - case Object: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); - break; - case Float: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); - break; - case Double: - append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { - AMD64AddressValue storeAddress = asAddressValue(address); - Kind kind = (Kind) lirKind.getPlatformKind(); - if (isConstant(input)) { - emitStoreConst(kind, storeAddress, asConstant(input), state); - } else { - emitStore(kind, storeAddress, asAllocatable(input), state); + super.emitStoreConst(kind, address, value, state); } } @@ -699,40 +566,7 @@ } } - public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { - LIRKind kind = newValue.getLIRKind(); - assert kind.equals(expectedValue.getLIRKind()); - Kind memKind = (Kind) kind.getPlatformKind(); - - AMD64AddressValue addressValue = asAddressValue(address); - RegisterValue raxRes = AMD64.rax.asValue(kind); - emitMove(raxRes, expectedValue); - append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); - - assert trueValue.getLIRKind().equals(falseValue.getLIRKind()); - Variable result = newVariable(trueValue.getLIRKind()); - append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); - return result; - } - - public Value emitAtomicReadAndAdd(Value address, Value delta) { - LIRKind kind = delta.getLIRKind(); - Kind memKind = (Kind) kind.getPlatformKind(); - Variable result = newVariable(kind); - AMD64AddressValue addressValue = asAddressValue(address); - append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta))); - return result; - } - - public Value emitAtomicReadAndWrite(Value address, Value newValue) { - LIRKind kind = newValue.getLIRKind(); - Kind memKind = (Kind) kind.getPlatformKind(); - Variable result = newVariable(kind); - AMD64AddressValue addressValue = asAddressValue(address); - append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); - return result; - } - + @Override public void emitNullCheck(Value address, LIRFrameState state) { if (address.getLIRKind().getPlatformKind() == Kind.Int) { CompressEncoding encoding = config.getOopEncoding(); @@ -744,8 +578,7 @@ } append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state)); } else { - assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!"; - append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); + super.emitNullCheck(address, state); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Fri May 15 11:55:52 2015 +0200 @@ -27,7 +27,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.hotspot.word.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.replacements.*; @@ -63,10 +62,6 @@ return null; } } - } else if (substituteClass == CRC32Substitutions.class) { - if (!config.useCRC32Intrinsics) { - return null; - } } return super.registerMethodSubstitution(cr, originalMethod, substituteMethod); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +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.hotspot.debug; - -import com.oracle.graal.api.meta.*; - -public class LineNumberTableImpl implements LineNumberTable { - - private final int[] lineNumbers; - private final int[] bci; - - public LineNumberTableImpl(int[] lineNumbers, int[] bci) { - this.lineNumbers = lineNumbers; - this.bci = bci; - } - - @Override - public int[] getLineNumberEntries() { - return lineNumbers; - } - - @Override - public int[] getBciEntries() { - return bci; - } - - @Override - public int getLineNumber(@SuppressWarnings("hiding") int bci) { - for (int i = 0; i < this.bci.length - 1; i++) { - if (this.bci[i] <= bci && bci < this.bci[i + 1]) { - return lineNumbers[i]; - } - } - return lineNumbers[lineNumbers.length - 1]; - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalImpl.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +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.hotspot.debug; - -import com.oracle.graal.api.meta.*; - -public class LocalImpl implements Local { - - private final String name; - private final int startBci; - private final int endBci; - private final int slot; - private final JavaType type; - - public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { - this.name = name; - this.startBci = startBci; - this.endBci = endBci; - this.slot = slot; - this.type = type; - } - - @Override - public int getStartBCI() { - return startBci; - } - - @Override - public int getEndBCI() { - return endBci; - } - - @Override - public String getName() { - return name; - } - - @Override - public JavaType getType() { - return type; - } - - @Override - public int getSlot() { - return slot; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof LocalImpl)) { - return false; - } - LocalImpl that = (LocalImpl) obj; - return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public String toString() { - return "LocalImpl"; - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LocalVariableTableImpl.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +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.hotspot.debug; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -public class LocalVariableTableImpl implements LocalVariableTable { - - private final Local[] locals; - - public LocalVariableTableImpl(Local[] locals) { - this.locals = locals; - } - - @Override - public Local getLocal(int slot, int bci) { - Local result = null; - for (Local local : locals) { - if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { - if (result == null) { - result = local; - } else { - throw new IllegalStateException("Locals overlap!"); - } - } - } - return result; - } - - @Override - public Local[] getLocals() { - return locals; - } - - @Override - public Local[] getLocalsAt(int bci) { - List result = new ArrayList<>(); - for (Local l : locals) { - if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { - result.add(l); - } - } - return result.toArray(new Local[result.size()]); - } - -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java Fri May 15 11:55:52 2015 +0200 @@ -197,8 +197,7 @@ assert !ImmutableCode.getValue() || isCalledForSnippets() || SnippetGraphUnderConstruction.get() != null || HotSpotLoadFieldPlugin.FieldReadEnabledInImmutableCode.get() == Boolean.TRUE : receiver; HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; - if (receiver == null) { - assert hotspotField.isStatic(); + if (hotspotField.isStatic()) { if (hotspotField.isFinal() || hotspotField.isStable()) { ResolvedJavaType holder = hotspotField.getDeclaringClass(); if (holder.isInitialized() && !holder.getName().equals(SystemClassName) && isEmbeddable(hotspotField)) { @@ -213,7 +212,6 @@ * for non-static final fields, we must assume that they are only initialized if they * have a non-default value. */ - assert !hotspotField.isStatic(); Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); // Canonicalization may attempt to process an unsafe read before @@ -259,18 +257,17 @@ private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; - if (receiver == null) { - assert hotspotField.isStatic(); + if (hotspotField.isStatic()) { HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); if (holder.isInitialized()) { return memoryAccess.readUnsafeConstant(hotspotField.getKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); } - return null; } else { - assert !hotspotField.isStatic(); - assert receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object()); - return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset()); + if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) { + return memoryAccess.readUnsafeConstant(hotspotField.getKind(), receiver, hotspotField.offset()); + } } + return null; } public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri May 15 11:55:52 2015 +0200 @@ -26,6 +26,7 @@ import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; import java.lang.invoke.*; +import java.util.zip.*; import sun.reflect.*; @@ -65,7 +66,7 @@ */ public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) { - InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, constantReflection.getMethodHandleAccess()); + InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess); Plugins plugins = new Plugins(invocationPlugins); NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider); @@ -76,7 +77,8 @@ plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes)); plugins.setTypeCheckPlugin(wordOperationPlugin); plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements)); - plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, wordOperationPlugin)); + plugins.setGenericInvocationPlugin(new MethodHandleInvocationPlugin(constantReflection.getMethodHandleAccess(), new DefaultGenericInvocationPlugin(metaAccess, nodeIntrinsification, + wordOperationPlugin))); registerObjectPlugins(invocationPlugins); registerClassPlugins(plugins); @@ -86,6 +88,7 @@ registerReflectionPlugins(invocationPlugins); registerStableOptionPlugins(invocationPlugins); registerAESPlugins(invocationPlugins, config); + registerCRC32Plugins(invocationPlugins, config); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, invocationPlugins, !config.useHeapProfiler); return plugins; @@ -248,4 +251,17 @@ } } } + + private static void registerCRC32Plugins(InvocationPlugins plugins, HotSpotVMConfig config) { + if (config.useCRC32Intrinsics) { + assert config.aescryptEncryptBlockStub != 0L; + assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; + Registration r = new Registration(plugins, CRC32.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class); + r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class); + } + } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java Fri May 15 11:55:52 2015 +0200 @@ -22,23 +22,14 @@ */ package com.oracle.graal.hotspot.meta; -import static com.oracle.graal.hotspot.meta.HotSpotMethodHandleAccessProvider.*; - -import java.lang.invoke.*; -import java.util.*; - import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; import com.oracle.graal.compiler.common.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.MethodIdMap.Receiver; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.phases.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin; import com.oracle.graal.replacements.nodes.*; @@ -48,12 +39,10 @@ */ final class HotSpotInvocationPlugins extends InvocationPlugins { final HotSpotVMConfig config; - final MethodHandleAccessProvider methodHandleAccess; - public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, MethodHandleAccessProvider methodHandleAccess) { + public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) { super(metaAccess); this.config = config; - this.methodHandleAccess = methodHandleAccess; } @Override @@ -74,68 +63,6 @@ super.register(plugin, declaringClass, name, argumentTypes); } - private ResolvedJavaType methodHandleClass; - private final Map methodHandlePlugins = new EnumMap<>(IntrinsicMethod.class); - - @Override - public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) { - if (methodHandleClass == null) { - methodHandleClass = plugins.getMetaAccess().lookupJavaType(MethodHandle.class); - } - if (method.getDeclaringClass().equals(methodHandleClass)) { - HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; - int intrinsicId = hsMethod.intrinsicId(); - if (intrinsicId != 0) { - /* - * The methods of MethodHandle that need substitution are signature-polymorphic, - * i.e., the VM replicates them for every signature that they are actually used for. - */ - IntrinsicMethod intrinsicMethod = getMethodHandleIntrinsic(intrinsicId); - if (intrinsicMethod != null) { - InvocationPlugin plugin = methodHandlePlugins.get(intrinsicMethod); - if (plugin == null) { - plugin = new InvocationPlugin() { - public boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode... argsIncludingReceiver) { - InvokeKind invokeKind = b.getInvokeKind(); - if (invokeKind != InvokeKind.Static) { - receiver.get(); - } - JavaType invokeReturnType = b.getInvokeReturnType(); - InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, targetMethod, - b.bci(), invokeReturnType, argsIncludingReceiver); - if (invoke == null) { - MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, targetMethod, b.bci(), invokeReturnType, argsIncludingReceiver); - if (invokeReturnType.getKind() == Kind.Void) { - b.add(methodHandleNode); - } else { - b.addPush(methodHandleNode); - } - } else { - CallTargetNode callTarget = invoke.callTarget(); - NodeInputList argumentsList = callTarget.arguments(); - ValueNode[] args = argumentsList.toArray(new ValueNode[argumentsList.size()]); - for (ValueNode arg : args) { - b.recursiveAppend(arg); - } - b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), args); - } - return true; - } - - public boolean isSignaturePolymorphic() { - return true; - } - }; - methodHandlePlugins.put(intrinsicMethod, plugin); - } - return plugin; - } - } - - } - return super.lookupInvocation(method); - } - @Override public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable newNodes) { for (Node node : newNodes) { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Fri May 15 11:55:52 2015 +0200 @@ -25,7 +25,6 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.nodes.*; @@ -65,18 +64,6 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) { if (!ImmutableCode.getValue() || b.parsingIntrinsic()) { - // Javac does not allow use of "$assertionsDisabled" for a field name but - // Eclipse does in which case a suffix is added to the generated field. - if (b.parsingIntrinsic() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) { - // For methods called indirectly from intrinsics, we (silently) disable - // assertions so that the parser won't see calls to the AssertionError - // constructor (all Invokes must be removed from intrinsics - see - // HotSpotInlineInvokePlugin.notifyOfNoninlinedInvoke). Direct use of - // assertions in intrinsics is forbidden. - assert b.getMethod().getAnnotation(MethodSubstitution.class) == null : "cannot use assertions in " + b.getMethod().format("%H.%n(%p)"); - b.addPush(ConstantNode.forBoolean(true)); - return true; - } return tryReadField(b, staticField, null); } return false; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaFieldImpl.java Fri May 15 11:55:52 2015 +0200 @@ -54,11 +54,15 @@ HotSpotResolvedJavaField inner; public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { - super(false); this.inner = inner; } @Override + public boolean isImmutable() { + return false; + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java Fri May 15 11:55:52 2015 +0200 @@ -36,7 +36,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graphbuilderconf.*; import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.nodes.*; /** diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ResolvedMethodHandleCallTargetNode.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2013, 2015, 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.hotspot.nodes; - -import static sun.misc.Version.*; - -import java.lang.invoke.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.spi.*; - -/** - * A call target that replaces itself in the graph when being lowered by restoring the original - * {@link MethodHandle} invocation target. Prior to - * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a - * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In - * that case, the original invocation must be restored with all of its original arguments. Why? - * HotSpot linkage for {@link MethodHandle} intrinsics (see - * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be - * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo* - * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} - * invocation drops these arguments which means the interpreter won't find them. - */ -@NodeInfo -public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable { - - public static final NodeClass TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class); - - /** - * Creates a call target for an invocation on a direct target derived by resolving a constant - * {@link MethodHandle}. - */ - public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, JavaType originalReturnType) { - if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) { - // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60 - return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType); - } - return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType); - } - - protected final ResolvedJavaMethod originalTargetMethod; - protected final JavaType originalReturnType; - @Input NodeInputList originalArguments; - - protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, - ValueNode[] originalArguments, JavaType originalReturnType) { - super(TYPE, invokeKind, targetMethod, arguments, returnType); - this.originalTargetMethod = originalTargetMethod; - this.originalReturnType = originalReturnType; - this.originalArguments = new NodeInputList<>(this, originalArguments); - } - - @Override - public void lower(LoweringTool tool) { - InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special; - MethodCallTargetNode replacement = graph().add( - new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType)); - - // Replace myself... - this.replaceAndDelete(replacement); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - throw GraalInternalError.shouldNotReachHere("should have replaced itself"); - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CRC32Substitutions.java Fri May 15 11:55:52 2015 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; @@ -39,25 +38,8 @@ /** * Substitutions for {@link CRC32}. */ -@ClassSubstitution(value = CRC32.class, defaultGuard = CRC32Substitutions.Guard.class) public class CRC32Substitutions { - public static class Guard implements SubstitutionGuard { - - @SuppressWarnings("unused") private HotSpotVMConfig config; - - public Guard(HotSpotVMConfig config) { - this.config = config; - } - - public boolean execute() { - /* - * Disabled until MethodSubstitutions are compiled like snipppets. - */ - return false; // return config.useCRC32Intrinsics; - } - } - /** * Gets the address of {@code StubRoutines::x86::_crc_table} in {@code stubRoutines_x86.hpp}. */ @@ -66,7 +48,6 @@ return runtime().getConfig().crcTableAddress; } - @MethodSubstitution(isStatic = true) static int update(int crc, int b) { int c = ~crc; int index = (b ^ c) & 0xFF; @@ -76,13 +57,11 @@ return ~result; } - @MethodSubstitution(isStatic = true) static int updateBytes(int crc, byte[] buf, int off, int len) { Word bufAddr = Word.unsigned(GetObjectAddressNode.get(buf) + arrayBaseOffset(Kind.Byte) + off); return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len); } - @MethodSubstitution(isStatic = true, optional = true) static int updateByteBuffer(int crc, long addr, int off, int len) { Word bufAddr = Word.unsigned(addr).add(off); return updateBytes(UPDATE_BYTES_CRC32, crc, bufAddr, len); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java Fri May 15 11:55:52 2015 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.replacements; -import java.util.zip.*; - import sun.misc.*; import sun.reflect.*; @@ -43,7 +41,6 @@ replacements.registerSubstitutions(System.class, SystemSubstitutions.class); replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class); replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class); - replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class); replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class); replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2013, 2015, 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.hotspot.replacements; - -import java.lang.invoke.*; -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.Assumptions.AssumptionResult; -import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.spi.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Node for invocation methods defined on the class {@link MethodHandle}. - */ -@NodeInfo -public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable { - public static final NodeClass TYPE = NodeClass.create(MethodHandleNode.class); - - protected final IntrinsicMethod intrinsicMethod; - - public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { - super(TYPE, invokeKind, targetMethod, bci, returnType, arguments); - this.intrinsicMethod = intrinsicMethod; - } - - /** - * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an - * invocation on another method with possibly transformed arguments. - * - * @param assumptions object for recording any speculations made during the transformation - * @param methodHandleAccess objects for accessing the implementation internals of a - * {@link MethodHandle} - * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed - * @param bci the BCI of the original {@link MethodHandle} call - * @param returnType return type of the original {@link MethodHandle} call - * @param arguments arguments to the original {@link MethodHandle} call - * @return a more direct invocation derived from the {@link MethodHandle} call or null - */ - public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode... arguments) { - switch (intrinsicMethod) { - case INVOKE_BASIC: - return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); - case LINK_TO_STATIC: - case LINK_TO_SPECIAL: - case LINK_TO_VIRTUAL: - case LINK_TO_INTERFACE: - return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - @Override - public void simplify(SimplifierTool tool) { - MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess(); - ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]); - InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray); - if (invoke != null) { - assert invoke.graph() == null; - invoke = graph().addOrUniqueWithInputs(invoke); - invoke.setStateAfter(stateAfter()); - FixedNode currentNext = next(); - replaceAtUsages(invoke); - GraphUtil.removeFixedWithUnusedInputs(this); - graph().addBeforeFixed(currentNext, invoke); - } - } - - /** - * Get the receiver of a MethodHandle.invokeBasic call. - * - * @return the receiver argument node - */ - private static ValueNode getReceiver(ValueNode[] arguments) { - return arguments[0]; - } - - /** - * Get the MemberName argument of a MethodHandle.linkTo* call. - * - * @return the MemberName argument node (which is the last argument) - */ - private static ValueNode getMemberName(ValueNode[] arguments) { - return arguments[arguments.length - 1]; - } - - /** - * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC } - * method) to get the target {@link InvokeNode} if the method handle receiver is constant. - * - * @return invoke node for the {@link java.lang.invoke.MethodHandle} target - */ - private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode[] arguments) { - ValueNode methodHandleNode = getReceiver(arguments); - if (methodHandleNode.isConstant()) { - return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original); - } - return null; - } - - /** - * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC}, - * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and - * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if - * the member name argument is constant. - * - * @return invoke node for the member name target - */ - private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, - JavaType returnType, ValueNode[] arguments) { - ValueNode memberNameNode = getMemberName(arguments); - if (memberNameNode.isConstant()) { - return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original); - } - return null; - } - - /** - * Helper function to get the {@link InvokeNode} for the targetMethod of a - * java.lang.invoke.MemberName. - * - * @param target the target, already loaded from the member name node - * @return invoke node for the member name target - */ - private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target, - ResolvedJavaMethod original) { - if (target == null) { - return null; - } - - // In lambda forms we erase signature types to avoid resolving issues - // involving class loaders. When we optimize a method handle invoke - // to a direct call we must cast the receiver and arguments to its - // actual types. - Signature signature = target.getSignature(); - final boolean isStatic = target.isStatic(); - final int receiverSkip = isStatic ? 0 : 1; - - // Cast receiver to its type. - if (!isStatic) { - JavaType receiverType = target.getDeclaringClass(); - maybeCastArgument(arguments, 0, receiverType); - } - - // Cast reference arguments to its type. - for (int index = 0; index < signature.getParameterCount(false); index++) { - JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass()); - maybeCastArgument(arguments, receiverSkip + index, parameterType); - } - - if (target.canBeStaticallyBound()) { - return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments); - } - - // Try to get the most accurate receiver type - if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) { - ValueNode receiver = getReceiver(arguments); - ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp()); - if (receiverType != null) { - AssumptionResult concreteMethod = receiverType.findUniqueConcreteMethod(target); - if (concreteMethod != null) { - assumptions.record(concreteMethod); - return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); - } - } - } else { - AssumptionResult concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target); - if (concreteMethod != null) { - assumptions.record(concreteMethod); - return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); - } - } - - return null; - } - - /** - * Inserts a node to cast the argument at index to the given type if the given type is more - * concrete than the argument type. - * - * @param index of the argument to be cast - * @param type the type the argument should be cast to - */ - private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) { - if (type instanceof ResolvedJavaType) { - ResolvedJavaType targetType = (ResolvedJavaType) type; - if (!targetType.isPrimitive()) { - ValueNode argument = arguments[index]; - ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp()); - if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) { - PiNode piNode = new PiNode(argument, StampFactory.declared(targetType)); - arguments[index] = piNode; - } - } - } - } - - /** - * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed - * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}. - * - * @return invoke node for the member name target - */ - private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) { - InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special; - JavaType targetReturnType = target.getSignature().getReturnType(null); - - // MethodHandleLinkTo* nodes have a trailing MemberName argument which - // needs to be popped. - ValueNode[] targetArguments; - switch (intrinsicMethod) { - case INVOKE_BASIC: - targetArguments = arguments; - break; - case LINK_TO_STATIC: - case LINK_TO_SPECIAL: - case LINK_TO_VIRTUAL: - case LINK_TO_INTERFACE: - targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - - MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType); - - // The call target can have a different return type than the invoker, - // e.g. the target returns an Object but the invoker void. In this case - // we need to use the stamp of the invoker. Note: always using the - // invoker's stamp would be wrong because it's a less concrete type - // (usually java.lang.Object). - if (returnType.getKind() == Kind.Void) { - return new InvokeNode(callTarget, bci, StampFactory.forVoid()); - } else { - return new InvokeNode(callTarget, bci); - } - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1260 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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; - -import static com.oracle.graal.api.code.TypeCheckHints.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; -import static com.oracle.graal.bytecode.Bytecodes.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; - -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.common.*; -import com.oracle.graal.compiler.common.calc.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.options.*; -import com.oracle.graal.phases.*; - -public abstract class AbstractBytecodeParser { - - public static class Options { - // @formatter:off - @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) - public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); - - @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) - public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(false); - - @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert) - public static final StableOptionValue InlineIntrinsicsDuringParsing = new StableOptionValue<>(true); - - @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); - - @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); - - @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); - - @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) - public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); - - @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) - public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); - - @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) - public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); - - @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) - public static final OptionValue HideSubstitutionStates = new OptionValue<>(false); - - // @formatter:on - } - - /** - * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the - * bytecode instructions as they are parsed. - */ - public static final int TRACELEVEL_INSTRUCTIONS = 1; - - /** - * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the - * frame state before each bytecode instruction as it is parsed. - */ - public static final int TRACELEVEL_STATE = 2; - - protected HIRFrameStateBuilder frameState; - protected BciBlock currentBlock; - - protected final BytecodeStream stream; - protected final GraphBuilderConfiguration graphBuilderConfig; - protected final ResolvedJavaMethod method; - protected final ProfilingInfo profilingInfo; - protected final OptimisticOptimizations optimisticOpts; - protected final ConstantPool constantPool; - protected final MetaAccessProvider metaAccess; - - protected final IntrinsicContext intrinsicContext; - - /** - * Meters the number of actual bytecodes parsed. - */ - public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed"); - - public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, - IntrinsicContext intrinsicContext) { - this.graphBuilderConfig = graphBuilderConfig; - this.optimisticOpts = optimisticOpts; - this.metaAccess = metaAccess; - this.stream = new BytecodeStream(method.getCode()); - this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null); - this.constantPool = method.getConstantPool(); - this.method = method; - this.intrinsicContext = intrinsicContext; - assert metaAccess != null; - } - - public void setCurrentFrameState(HIRFrameStateBuilder frameState) { - this.frameState = frameState; - } - - protected final BytecodeStream getStream() { - return stream; - } - - public int bci() { - return stream.currentBCI(); - } - - public void loadLocal(int index, Kind kind) { - frameState.push(kind, frameState.loadLocal(index)); - } - - public void storeLocal(Kind kind, int index) { - ValueNode value; - if (kind == Kind.Object) { - value = frameState.xpop(); - // astore and astore_ may be used to store a returnAddress (jsr) - assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind(); - } else { - value = frameState.pop(kind); - } - frameState.storeLocal(index, value, kind); - } - - /** - * @param type the unresolved type of the constant - */ - protected abstract void handleUnresolvedLoadConstant(JavaType type); - - /** - * @param type the unresolved type of the type check - * @param object the object value whose type is being checked against {@code type} - */ - protected abstract void handleUnresolvedCheckCast(JavaType type, ValueNode object); - - /** - * @param type the unresolved type of the type check - * @param object the object value whose type is being checked against {@code type} - */ - protected abstract void handleUnresolvedInstanceOf(JavaType type, ValueNode object); - - /** - * @param type the type being instantiated - */ - protected abstract void handleUnresolvedNewInstance(JavaType type); - - /** - * @param type the type of the array being instantiated - * @param length the length of the array - */ - protected abstract void handleUnresolvedNewObjectArray(JavaType type, ValueNode length); - - /** - * @param type the type being instantiated - * @param dims the dimensions for the multi-array - */ - protected abstract void handleUnresolvedNewMultiArray(JavaType type, List dims); - - /** - * @param field the unresolved field - * @param receiver the object containing the field or {@code null} if {@code field} is static - */ - protected abstract void handleUnresolvedLoadField(JavaField field, ValueNode receiver); - - /** - * @param field the unresolved field - * @param value the value being stored to the field - * @param receiver the object containing the field or {@code null} if {@code field} is static - */ - protected abstract void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver); - - /** - * @param type - */ - protected abstract void handleUnresolvedExceptionType(JavaType type); - - // protected abstract void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind); - - // protected abstract DispatchBeginNode handleException(ValueNode exceptionObject, int bci); - - private void genLoadConstant(int cpi, int opcode) { - Object con = lookupConstant(cpi, opcode); - - if (con instanceof JavaType) { - // this is a load of class constant which might be unresolved - JavaType type = (JavaType) con; - if (type instanceof ResolvedJavaType) { - frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass())); - } else { - handleUnresolvedLoadConstant(type); - } - } else if (con instanceof JavaConstant) { - JavaConstant constant = (JavaConstant) con; - frameState.push(constant.getKind().getStackKind(), appendConstant(constant)); - } else { - throw new Error("lookupConstant returned an object of incorrect type"); - } - } - - protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind); - - private void genLoadIndexed(Kind kind) { - ValueNode index = frameState.ipop(); - ValueNode array = emitExplicitExceptions(frameState.apop(), index); - if (!tryLoadIndexedPlugin(kind, index, array)) { - frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); - } - } - - protected abstract void traceWithContext(String format, Object... args); - - protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) { - LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin(); - if (loadIndexedPlugin != null && loadIndexedPlugin.apply((GraphBuilderContext) this, array, index, kind)) { - if (TraceParserPlugins.getValue()) { - traceWithContext("used load indexed plugin"); - } - return true; - } else { - return false; - } - } - - protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value); - - private void genStoreIndexed(Kind kind) { - ValueNode value = frameState.pop(kind.getStackKind()); - ValueNode index = frameState.ipop(); - ValueNode array = emitExplicitExceptions(frameState.apop(), index); - genStoreIndexed(array, index, kind, value); - } - - private void stackOp(int opcode) { - switch (opcode) { - case DUP_X1: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP_X2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X1: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case DUP2_X2: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - ValueNode w3 = frameState.xpop(); - ValueNode w4 = frameState.xpop(); - frameState.xpush(w2); - frameState.xpush(w1); - frameState.xpush(w4); - frameState.xpush(w3); - frameState.xpush(w2); - frameState.xpush(w1); - break; - } - case SWAP: { - ValueNode w1 = frameState.xpop(); - ValueNode w2 = frameState.xpop(); - frameState.xpush(w1); - frameState.xpush(w2); - break; - } - default: - throw GraalInternalError.shouldNotReachHere(); - } - } - - protected abstract ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - protected abstract ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP); - - private void genArithmeticOp(Kind result, int opcode) { - ValueNode y = frameState.pop(result); - ValueNode x = frameState.pop(result); - boolean isStrictFP = method.isStrict(); - ValueNode v; - switch (opcode) { - case IADD: - case LADD: - v = genIntegerAdd(result, x, y); - break; - case FADD: - case DADD: - v = genFloatAdd(result, x, y, isStrictFP); - break; - case ISUB: - case LSUB: - v = genIntegerSub(result, x, y); - break; - case FSUB: - case DSUB: - v = genFloatSub(result, x, y, isStrictFP); - break; - case IMUL: - case LMUL: - v = genIntegerMul(result, x, y); - break; - case FMUL: - case DMUL: - v = genFloatMul(result, x, y, isStrictFP); - break; - case FDIV: - case DDIV: - v = genFloatDiv(result, x, y, isStrictFP); - break; - case FREM: - case DREM: - v = genFloatRem(result, x, y, isStrictFP); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(result, append(v)); - } - - protected abstract ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y); - - private void genIntegerDivOp(Kind result, int opcode) { - ValueNode y = frameState.pop(result); - ValueNode x = frameState.pop(result); - ValueNode v; - switch (opcode) { - case IDIV: - case LDIV: - v = genIntegerDiv(result, x, y); - break; - case IREM: - case LREM: - v = genIntegerRem(result, x, y); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(result, append(v)); - } - - protected abstract ValueNode genNegateOp(ValueNode x); - - private void genNegateOp(Kind kind) { - frameState.push(kind, append(genNegateOp(frameState.pop(kind)))); - } - - protected abstract ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y); - - private void genShiftOp(Kind kind, int opcode) { - ValueNode s = frameState.ipop(); - ValueNode x = frameState.pop(kind); - ValueNode v; - switch (opcode) { - case ISHL: - case LSHL: - v = genLeftShift(kind, x, s); - break; - case ISHR: - case LSHR: - v = genRightShift(kind, x, s); - break; - case IUSHR: - case LUSHR: - v = genUnsignedRightShift(kind, x, s); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(kind, append(v)); - } - - protected abstract ValueNode genAnd(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genOr(Kind kind, ValueNode x, ValueNode y); - - protected abstract ValueNode genXor(Kind kind, ValueNode x, ValueNode y); - - private void genLogicOp(Kind kind, int opcode) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - ValueNode v; - switch (opcode) { - case IAND: - case LAND: - v = genAnd(kind, x, y); - break; - case IOR: - case LOR: - v = genOr(kind, x, y); - break; - case IXOR: - case LXOR: - v = genXor(kind, x, y); - break; - default: - throw new GraalInternalError("should not reach"); - } - frameState.push(kind, append(v)); - } - - protected abstract ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess); - - private void genCompareOp(Kind kind, boolean isUnorderedLess) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess))); - } - - protected abstract ValueNode genFloatConvert(FloatConvert op, ValueNode input); - - private void genFloatConvert(FloatConvert op, Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - frameState.push(to.getStackKind(), append(genFloatConvert(op, input))); - } - - protected abstract ValueNode genNarrow(ValueNode input, int bitCount); - - protected abstract ValueNode genSignExtend(ValueNode input, int bitCount); - - protected abstract ValueNode genZeroExtend(ValueNode input, int bitCount); - - private void genSignExtend(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - if (from != from.getStackKind()) { - input = append(genNarrow(input, from.getBitCount())); - } - frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount()))); - } - - private void genZeroExtend(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - if (from != from.getStackKind()) { - input = append(genNarrow(input, from.getBitCount())); - } - frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount()))); - } - - private void genNarrow(Kind from, Kind to) { - ValueNode input = frameState.pop(from.getStackKind()); - frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount()))); - } - - private void genIncrement() { - int index = getStream().readLocalIndex(); - int delta = getStream().readIncrement(); - ValueNode x = frameState.loadLocal(index); - ValueNode y = appendConstant(JavaConstant.forInt(delta)); - frameState.storeLocal(index, append(genIntegerAdd(Kind.Int, x, y))); - } - - protected abstract void genGoto(); - - protected abstract ValueNode genObjectEquals(ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerEquals(ValueNode x, ValueNode y); - - protected abstract ValueNode genIntegerLessThan(ValueNode x, ValueNode y); - - protected abstract ValueNode genUnique(ValueNode x); - - protected abstract void genIf(ValueNode x, Condition cond, ValueNode y); - - private void genIfZero(Condition cond) { - ValueNode y = appendConstant(JavaConstant.INT_0); - ValueNode x = frameState.ipop(); - genIf(x, cond, y); - } - - private void genIfNull(Condition cond) { - ValueNode y = appendConstant(JavaConstant.NULL_POINTER); - ValueNode x = frameState.apop(); - genIf(x, cond, y); - } - - private void genIfSame(Kind kind, Condition cond) { - ValueNode y = frameState.pop(kind); - ValueNode x = frameState.pop(kind); - genIf(x, cond, y); - } - - protected abstract void genThrow(); - - protected JavaType lookupType(int cpi, int bytecode) { - maybeEagerlyResolve(cpi, bytecode); - JavaType result = constantPool.lookupType(cpi, bytecode); - assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; - return result; - } - - private JavaMethod lookupMethod(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - JavaMethod result = constantPool.lookupMethod(cpi, opcode); - /* - * In general, one cannot assume that the declaring class being initialized is useful, since - * the actual concrete receiver may be a different class (except for static calls). Also, - * interfaces are initialized only under special circumstances, so that this assertion would - * often fail for interface calls. - */ - assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; - return result; - } - - private JavaField lookupField(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - JavaField result = constantPool.lookupField(cpi, opcode); - assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; - return result; - } - - private Object lookupConstant(int cpi, int opcode) { - maybeEagerlyResolve(cpi, opcode); - Object result = constantPool.lookupConstant(cpi); - assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; - return result; - } - - private void maybeEagerlyResolve(int cpi, int bytecode) { - if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) { - constantPool.loadReferencedType(cpi, bytecode); - } - } - - private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { - if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { - return null; - } else { - return profilingInfo.getTypeProfile(bci()); - } - } - - protected abstract ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck); - - private void genCheckCast() { - int cpi = getStream().readCPI(); - JavaType type = lookupType(cpi, CHECKCAST); - ValueNode object = frameState.apop(); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !typeCheckPlugin.checkCast((GraphBuilderContext) this, object, resolvedType, profile)) { - ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); - frameState.apush(checkCastNode); - } - } else { - handleUnresolvedCheckCast(type, object); - } - } - - protected abstract ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck); - - protected abstract ValueNode genConditional(ValueNode x); - - private void genInstanceOf() { - int cpi = getStream().readCPI(); - JavaType type = lookupType(cpi, INSTANCEOF); - ValueNode object = frameState.apop(); - if (type instanceof ResolvedJavaType) { - ResolvedJavaType resolvedType = (ResolvedJavaType) type; - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); - TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); - if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf((GraphBuilderContext) this, object, resolvedType, profile)) { - ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile); - frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); - } - } else { - handleUnresolvedInstanceOf(type, object); - } - } - - protected abstract ValueNode createNewInstance(ResolvedJavaType type, boolean fillContents); - - void genNewInstance(int cpi) { - JavaType type = lookupType(cpi, NEW); - if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { - ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); - if (skippedExceptionTypes != null) { - for (ResolvedJavaType exceptionType : skippedExceptionTypes) { - if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) { - append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); - return; - } - } - } - frameState.apush(append(createNewInstance((ResolvedJavaType) type, true))); - } else { - handleUnresolvedNewInstance(type); - } - } - - /** - * Gets the kind of array elements for the array type code that appears in a - * {@link Bytecodes#NEWARRAY} bytecode. - * - * @param code the array type code - * @return the kind from the array type code - */ - public static Class arrayTypeCodeToClass(int code) { - // Checkstyle: stop - switch (code) { - case 4: - return boolean.class; - case 5: - return char.class; - case 6: - return float.class; - case 7: - return double.class; - case 8: - return byte.class; - case 9: - return short.class; - case 10: - return int.class; - case 11: - return long.class; - default: - throw new IllegalArgumentException("unknown array type code: " + code); - } - // Checkstyle: resume - } - - private void genNewPrimitiveArray(int typeCode) { - Class clazz = arrayTypeCodeToClass(typeCode); - ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz); - frameState.apush(append(createNewArray(elementType, frameState.ipop(), true))); - } - - private void genNewObjectArray(int cpi) { - JavaType type = lookupType(cpi, ANEWARRAY); - ValueNode length = frameState.ipop(); - if (type instanceof ResolvedJavaType) { - frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true))); - } else { - handleUnresolvedNewObjectArray(type, length); - } - - } - - protected abstract ValueNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents); - - private void genNewMultiArray(int cpi) { - JavaType type = lookupType(cpi, MULTIANEWARRAY); - int rank = getStream().readUByte(bci() + 3); - List dims = new ArrayList<>(Collections.nCopies(rank, null)); - for (int i = rank - 1; i >= 0; i--) { - dims.set(i, frameState.ipop()); - } - if (type instanceof ResolvedJavaType) { - frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims))); - } else { - handleUnresolvedNewMultiArray(type, dims); - } - } - - protected abstract ValueNode createNewMultiArray(ResolvedJavaType type, List dims); - - protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field); - - private void genGetField(JavaField field) { - Kind kind = field.getKind(); - ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); - if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { - appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); - } - } else { - handleUnresolvedLoadField(field, receiver); - } - } - - /** - * Emits control flow to null check a receiver if it's stamp does not indicate it is - * {@linkplain StampTool#isPointerNonNull always non-null}. - * - * @return the receiver with a stamp indicating non-nullness - */ - protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver); - - /** - * Emits control flow to check an array index is within bounds of an array's length. - * - * @param index the index to check - * @param length the length of the array being indexed - */ - protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length); - - private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); - - protected abstract ValueNode genArrayLength(ValueNode x); - - /** - * @param receiver the receiver of an object based operation - * @param index the index of an array based operation that is to be tested for out of bounds. - * This is null for a non-array operation. - * @return the receiver value possibly modified to have a tighter stamp - */ - protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { - assert receiver != null; - if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null || - (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { - return receiver; - } - - ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); - if (index != null) { - ValueNode length = append(genArrayLength(nonNullReceiver)); - emitExplicitBoundsCheck(index, length); - } - EXPLICIT_EXCEPTIONS.increment(); - return nonNullReceiver; - } - - protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value); - - private void genPutField(JavaField field) { - ValueNode value = frameState.pop(field.getKind().getStackKind()); - ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); - if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { - genStoreField(receiver, (ResolvedJavaField) field, value); - } else { - handleUnresolvedStoreField(field, value, receiver); - } - } - - private void genGetStatic(JavaField field) { - Kind kind = field.getKind(); - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); - if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) { - appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field)); - } - } else { - handleUnresolvedLoadField(field, null); - } - } - - public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) { - return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field); - } - - private void genPutStatic(JavaField field) { - ValueNode value = frameState.pop(field.getKind().getStackKind()); - if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - genStoreField(null, (ResolvedJavaField) field, value); - } else { - handleUnresolvedStoreField(field, value, null); - } - } - - protected void appendOptimizedLoadField(Kind kind, ValueNode load) { - // append the load to the instruction - ValueNode optimized = append(load); - frameState.push(kind.getStackKind(), optimized); - } - - protected abstract void genInvokeStatic(JavaMethod target); - - protected abstract void genInvokeInterface(JavaMethod target); - - protected abstract void genInvokeDynamic(JavaMethod target); - - protected abstract void genInvokeVirtual(JavaMethod target); - - protected abstract void genInvokeSpecial(JavaMethod target); - - protected abstract void genReturn(ValueNode x, Kind kind); - - protected abstract void genMonitorEnter(ValueNode x, int bci); - - protected abstract void genMonitorExit(ValueNode x, ValueNode returnValue, int bci); - - protected abstract void genJsr(int dest); - - protected abstract void genRet(int localIndex); - - private double[] switchProbability(int numberOfCases, int bci) { - double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); - if (prob != null) { - assert prob.length == numberOfCases; - } else { - Debug.log("Missing probability (switch) in %s at bci %d", method, bci); - prob = new double[numberOfCases]; - for (int i = 0; i < numberOfCases; i++) { - prob[i] = 1.0d / numberOfCases; - } - } - assert allPositive(prob); - return prob; - } - - private static boolean allPositive(double[] a) { - for (double d : a) { - if (d < 0) { - return false; - } - } - return true; - } - - /** - * Helper function that sums up the probabilities of all keys that lead to a specific successor. - * - * @return an array of size successorCount with the accumulated probability for each successor. - */ - public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { - double[] probability = new double[successorCount]; - for (int i = 0; i < keySuccessors.length; i++) { - probability[keySuccessors[i]] += keyProbabilities[i]; - } - return probability; - } - - private void genSwitch(BytecodeSwitch bs) { - int bci = bci(); - ValueNode value = frameState.ipop(); - - int nofCases = bs.numberOfCases(); - double[] keyProbabilities = switchProbability(nofCases + 1, bci); - - Map bciToBlockSuccessorIndex = new HashMap<>(); - for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { - assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); - if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { - bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); - } - } - - ArrayList actualSuccessors = new ArrayList<>(); - int[] keys = new int[nofCases]; - int[] keySuccessors = new int[nofCases + 1]; - int deoptSuccessorIndex = -1; - int nextSuccessorIndex = 0; - boolean constantValue = value.isConstant(); - for (int i = 0; i < nofCases + 1; i++) { - if (i < nofCases) { - keys[i] = bs.keyAt(i); - } - - if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { - if (deoptSuccessorIndex < 0) { - deoptSuccessorIndex = nextSuccessorIndex++; - actualSuccessors.add(null); - } - keySuccessors[i] = deoptSuccessorIndex; - } else { - int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); - SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); - if (info.actualIndex < 0) { - info.actualIndex = nextSuccessorIndex++; - actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); - } - keySuccessors[i] = info.actualIndex; - } - } - - genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); - - } - - protected abstract void genIntegerSwitch(ValueNode value, ArrayList actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors); - - private static class SuccessorInfo { - - int blockIndex; - int actualIndex; - - public SuccessorInfo(int blockSuccessorIndex) { - this.blockIndex = blockSuccessorIndex; - actualIndex = -1; - } - } - - protected abstract ValueNode appendConstant(JavaConstant constant); - - protected abstract T append(T v); - - protected boolean isNeverExecutedCode(double probability) { - return probability == 0 && optimisticOpts.removeNeverExecutedCode(); - } - - protected double branchProbability() { - if (profilingInfo == null) { - return 0.5; - } - assert assertAtIfBytecode(); - double probability = profilingInfo.getBranchTakenProbability(bci()); - if (probability < 0) { - assert probability == -1 : "invalid probability"; - Debug.log("missing probability in %s at bci %d", method, bci()); - probability = 0.5; - } - - if (!optimisticOpts.removeNeverExecutedCode()) { - if (probability == 0) { - probability = 0.0000001; - } else if (probability == 1) { - probability = 0.999999; - } - } - return probability; - } - - private boolean assertAtIfBytecode() { - int bytecode = stream.currentBC(); - switch (bytecode) { - case IFEQ: - case IFNE: - case IFLT: - case IFGE: - case IFGT: - case IFLE: - case IF_ICMPEQ: - case IF_ICMPNE: - case IF_ICMPLT: - case IF_ICMPGE: - case IF_ICMPGT: - case IF_ICMPLE: - case IF_ACMPEQ: - case IF_ACMPNE: - case IFNULL: - case IFNONNULL: - return true; - } - assert false : String.format("%x is not an if bytecode", bytecode); - return true; - } - - protected abstract void iterateBytecodesForBlock(BciBlock block); - - public final void processBytecode(int bci, int opcode) { - int cpi; - - // Checkstyle: stop - // @formatter:off - switch (opcode) { - case NOP : /* nothing to do */ break; - case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; - case ICONST_M1 : // fall through - case ICONST_0 : // fall through - case ICONST_1 : // fall through - case ICONST_2 : // fall through - case ICONST_3 : // fall through - case ICONST_4 : // fall through - case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; - case LCONST_0 : // fall through - case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; - case FCONST_0 : // fall through - case FCONST_1 : // fall through - case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; - case DCONST_0 : // fall through - case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; - case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; - case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; - case LDC : // fall through - case LDC_W : // fall through - case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; - case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; - case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; - case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; - case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; - case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; - case ILOAD_0 : // fall through - case ILOAD_1 : // fall through - case ILOAD_2 : // fall through - case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; - case LLOAD_0 : // fall through - case LLOAD_1 : // fall through - case LLOAD_2 : // fall through - case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; - case FLOAD_0 : // fall through - case FLOAD_1 : // fall through - case FLOAD_2 : // fall through - case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; - case DLOAD_0 : // fall through - case DLOAD_1 : // fall through - case DLOAD_2 : // fall through - case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; - case ALOAD_0 : // fall through - case ALOAD_1 : // fall through - case ALOAD_2 : // fall through - case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; - case IALOAD : genLoadIndexed(Kind.Int ); break; - case LALOAD : genLoadIndexed(Kind.Long ); break; - case FALOAD : genLoadIndexed(Kind.Float ); break; - case DALOAD : genLoadIndexed(Kind.Double); break; - case AALOAD : genLoadIndexed(Kind.Object); break; - case BALOAD : genLoadIndexed(Kind.Byte ); break; - case CALOAD : genLoadIndexed(Kind.Char ); break; - case SALOAD : genLoadIndexed(Kind.Short ); break; - case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; - case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; - case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; - case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; - case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; - case ISTORE_0 : // fall through - case ISTORE_1 : // fall through - case ISTORE_2 : // fall through - case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; - case LSTORE_0 : // fall through - case LSTORE_1 : // fall through - case LSTORE_2 : // fall through - case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; - case FSTORE_0 : // fall through - case FSTORE_1 : // fall through - case FSTORE_2 : // fall through - case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; - case DSTORE_0 : // fall through - case DSTORE_1 : // fall through - case DSTORE_2 : // fall through - case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; - case ASTORE_0 : // fall through - case ASTORE_1 : // fall through - case ASTORE_2 : // fall through - case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; - case IASTORE : genStoreIndexed(Kind.Int ); break; - case LASTORE : genStoreIndexed(Kind.Long ); break; - case FASTORE : genStoreIndexed(Kind.Float ); break; - case DASTORE : genStoreIndexed(Kind.Double); break; - case AASTORE : genStoreIndexed(Kind.Object); break; - case BASTORE : genStoreIndexed(Kind.Byte ); break; - case CASTORE : genStoreIndexed(Kind.Char ); break; - case SASTORE : genStoreIndexed(Kind.Short ); break; - case POP : frameState.xpop(); break; - case POP2 : frameState.xpop(); frameState.xpop(); break; - case DUP : frameState.xpush(frameState.xpeek()); break; - case DUP_X1 : // fall through - case DUP_X2 : // fall through - case DUP2 : // fall through - case DUP2_X1 : // fall through - case DUP2_X2 : // fall through - case SWAP : stackOp(opcode); break; - case IADD : // fall through - case ISUB : // fall through - case IMUL : genArithmeticOp(Kind.Int, opcode); break; - case IDIV : // fall through - case IREM : genIntegerDivOp(Kind.Int, opcode); break; - case LADD : // fall through - case LSUB : // fall through - case LMUL : genArithmeticOp(Kind.Long, opcode); break; - case LDIV : // fall through - case LREM : genIntegerDivOp(Kind.Long, opcode); break; - case FADD : // fall through - case FSUB : // fall through - case FMUL : // fall through - case FDIV : // fall through - case FREM : genArithmeticOp(Kind.Float, opcode); break; - case DADD : // fall through - case DSUB : // fall through - case DMUL : // fall through - case DDIV : // fall through - case DREM : genArithmeticOp(Kind.Double, opcode); break; - case INEG : genNegateOp(Kind.Int); break; - case LNEG : genNegateOp(Kind.Long); break; - case FNEG : genNegateOp(Kind.Float); break; - case DNEG : genNegateOp(Kind.Double); break; - case ISHL : // fall through - case ISHR : // fall through - case IUSHR : genShiftOp(Kind.Int, opcode); break; - case IAND : // fall through - case IOR : // fall through - case IXOR : genLogicOp(Kind.Int, opcode); break; - case LSHL : // fall through - case LSHR : // fall through - case LUSHR : genShiftOp(Kind.Long, opcode); break; - case LAND : // fall through - case LOR : // fall through - case LXOR : genLogicOp(Kind.Long, opcode); break; - case IINC : genIncrement(); break; - case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; - case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; - case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; - case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; - case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; - case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; - case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; - case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; - case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; - case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; - case L2I : genNarrow(Kind.Long, Kind.Int); break; - case I2L : genSignExtend(Kind.Int, Kind.Long); break; - case I2B : genSignExtend(Kind.Byte, Kind.Int); break; - case I2S : genSignExtend(Kind.Short, Kind.Int); break; - case I2C : genZeroExtend(Kind.Char, Kind.Int); break; - case LCMP : genCompareOp(Kind.Long, false); break; - case FCMPL : genCompareOp(Kind.Float, true); break; - case FCMPG : genCompareOp(Kind.Float, false); break; - case DCMPL : genCompareOp(Kind.Double, true); break; - case DCMPG : genCompareOp(Kind.Double, false); break; - case IFEQ : genIfZero(Condition.EQ); break; - case IFNE : genIfZero(Condition.NE); break; - case IFLT : genIfZero(Condition.LT); break; - case IFGE : genIfZero(Condition.GE); break; - case IFGT : genIfZero(Condition.GT); break; - case IFLE : genIfZero(Condition.LE); break; - case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; - case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; - case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; - case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; - case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; - case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; - case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; - case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; - case GOTO : genGoto(); break; - case JSR : genJsr(stream.readBranchDest()); break; - case RET : genRet(stream.readLocalIndex()); break; - case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; - case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; - case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; - case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; - case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; - case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; - case ARETURN : genReturn(frameState.apop(), Kind.Object); break; - case RETURN : genReturn(null, Kind.Void); break; - case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; - case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; - case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; - case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; - case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; - case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; - case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; - case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; - case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; - case NEW : genNewInstance(stream.readCPI()); break; - case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; - case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; - case ARRAYLENGTH : genArrayLength(); break; - case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; - case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; - case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; - case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; - case IFNULL : genIfNull(Condition.EQ); break; - case IFNONNULL : genIfNull(Condition.NE); break; - case GOTO_W : genGoto(); break; - case JSR_W : genJsr(stream.readBranchDest()); break; - case BREAKPOINT: - throw new BailoutException("concurrent setting of breakpoint"); - default: - throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); - } - // @formatter:on - // Checkstyle: resume - } - - private void genArrayLength() { - frameState.ipush(append(genArrayLength(frameState.apop()))); - } - - public ResolvedJavaMethod getMethod() { - return method; - } - - public HIRFrameStateBuilder getFrameState() { - return frameState; - } - - protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { - if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { - traceInstructionHelper(bci, opcode, blockStart); - } - return true; - } - - private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { - StringBuilder sb = new StringBuilder(40); - sb.append(blockStart ? '+' : '|'); - if (bci < 10) { - sb.append(" "); - } else if (bci < 100) { - sb.append(' '); - } - sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); - for (int i = bci + 1; i < stream.nextBCI(); ++i) { - sb.append(' ').append(stream.readUByte(i)); - } - if (!currentBlock.getJsrScope().isEmpty()) { - sb.append(' ').append(currentBlock.getJsrScope()); - } - Debug.log("%s", sb); - } - - public boolean parsingIntrinsic() { - return intrinsicContext != null; - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,451 +0,0 @@ -/* - * Copyright (c) 2014, 2014, 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; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; - -public abstract class AbstractFrameStateBuilder> { - - protected final ResolvedJavaMethod method; - protected int stackSize; - protected final T[] locals; - protected final T[] stack; - protected T[] lockedObjects; - - protected final BytecodeParser parser; - - /** - * @see BytecodeFrame#rethrowException - */ - protected boolean rethrowException; - - public AbstractFrameStateBuilder(ResolvedJavaMethod method, BytecodeParser parser) { - this.method = method; - this.parser = parser; - this.locals = allocateArray(method.getMaxLocals()); - this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); - this.lockedObjects = allocateArray(0); - } - - protected AbstractFrameStateBuilder(S other) { - this.method = other.method; - this.parser = other.parser; - this.stackSize = other.stackSize; - this.locals = other.locals.clone(); - this.stack = other.stack.clone(); - this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); - this.rethrowException = other.rethrowException; - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - } - - public abstract S copy(); - - protected abstract T[] allocateArray(int length); - - public abstract boolean isCompatibleWith(S other); - - public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { - /* - * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to - * remove it for normal compilations, but not for OSR compilations - otherwise dead object - * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with - * Kind.Illegal, because the conflicting branch might not have been parsed. - */ - if (liveness == null) { - return; - } - if (liveIn) { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveIn(block, i)) { - locals[i] = null; - } - } - } else { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveOut(block, i)) { - locals[i] = null; - } - } - } - } - - /** - * @see BytecodeFrame#rethrowException - */ - public boolean rethrowException() { - return rethrowException; - } - - /** - * @see BytecodeFrame#rethrowException - */ - public void setRethrowException(boolean b) { - rethrowException = b; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * @return the current lock depth - */ - public int lockDepth() { - return lockedObjects.length; - } - - /** - * Gets the value in the local variables at the specified index, without any sanity checking. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public T localAt(int i) { - return locals[i]; - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public T stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the lock at the specified index, without any sanity checking. - * - * @param i the index into the lock - * @return the instruction that produced the value for the specified lock - */ - public T lockAt(int i) { - return lockedObjects[i]; - } - - public void storeLock(int i, T lock) { - lockedObjects[i] = lock; - } - - /** - * Loads the local variable at the specified index, checking that the returned value is non-null - * and that two-stack values are properly handled. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public T loadLocal(int i) { - T x = locals[i]; - assert x != null : i; - assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); - assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); - return x; - } - - public void storeLocal(int i, T x) { - storeLocal(i, x, x == null ? null : x.getKind()); - } - - /** - * Stores a given local variable at the specified index. If the value occupies two slots, then - * the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, T x, Kind kind) { - assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; - locals[i] = x; - if (x != null) { - if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) { - // if this is a double word, then kill i+1 - locals[i + 1] = null; - } - if (i > 0 && !parser.parsingIntrinsic()) { - T p = locals[i - 1]; - if (p != null && p.getKind().needsTwoSlots()) { - // if there was a double word at i - 1, then kill it - locals[i - 1] = null; - } - } - } - } - - public void storeStack(int i, T x) { - assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; - stack[i] = x; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(Kind kind, T x) { - assert kind != Kind.Void && kind != Kind.Illegal : kind + ":" + x; - xpush(assertKind(kind, x)); - if (kind.needsTwoSlots()) { - xpush(null); - } - } - - /** - * Pushes a value onto the stack without checking the type. - * - * @param x the instruction to push onto the stack - */ - public void xpush(T x) { - assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); - stack[stackSize++] = x; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * - * @param x the instruction to push onto the stack - */ - public void ipush(T x) { - xpush(assertInt(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * - * @param x the instruction to push onto the stack - */ - public void fpush(T x) { - xpush(assertFloat(x)); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * - * @param x the instruction to push onto the stack - */ - public void apush(T x) { - xpush(assertObject(x)); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(T x) { - xpush(assertLong(x)); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * - * @param x the instruction to push onto the stack - */ - public void dpush(T x) { - xpush(assertDouble(x)); - xpush(null); - } - - public void pushReturn(Kind kind, T x) { - if (kind != Kind.Void) { - push(kind.getStackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public T pop(Kind kind) { - assert kind != Kind.Void; - if (kind.needsTwoSlots()) { - xpop(); - } - return assertKind(kind, xpop()); - } - - /** - * Pops a value off of the stack without checking the type. - * - * @return x the instruction popped off the stack - */ - public T xpop() { - T result = stack[--stackSize]; - return result; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * - * @return x the instruction popped off the stack - */ - public T ipop() { - return assertInt(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * - * @return x the instruction popped off the stack - */ - public T fpop() { - return assertFloat(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * - * @return x the instruction popped off the stack - */ - public T apop() { - return assertObject(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * - * @return x the instruction popped off the stack - */ - public T lpop() { - assertHigh(xpop()); - return assertLong(xpop()); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * - * @return x the instruction popped off the stack - */ - public T dpop() { - assertHigh(xpop()); - return assertDouble(xpop()); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of - * instructions. - * - * @return an array containing the arguments off of the stack - */ - public T[] popArguments(int argSize) { - T[] result = allocateArray(argSize); - int newStackSize = stackSize; - for (int i = argSize - 1; i >= 0; i--) { - newStackSize--; - if (stack[newStackSize] == null) { - /* Two-slot value. */ - newStackSize--; - assert stack[newStackSize].getKind().needsTwoSlots(); - } else { - assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1); - } - result[i] = stack[newStackSize]; - } - stackSize = newStackSize; - return result; - } - - /** - * Peeks an element from the operand stack. - * - * @param argumentNumber The number of the argument, relative from the top of the stack (0 = - * top). Long and double arguments only count as one argument, i.e., null-slots are - * ignored. - * @return The peeked argument. - */ - public T peek(int argumentNumber) { - int idx = stackSize() - 1; - for (int i = 0; i < argumentNumber; i++) { - if (stackAt(idx) == null) { - idx--; - assert stackAt(idx).getKind().needsTwoSlots(); - } - idx--; - } - return stackAt(idx); - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackSize = 0; - } - - private T assertKind(Kind kind, T x) { - assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind()); - return x; - } - - private T assertLong(T x) { - assert x != null && (x.getKind() == Kind.Long); - return x; - } - - private T assertInt(T x) { - assert x != null && (x.getKind() == Kind.Int); - return x; - } - - private T assertFloat(T x) { - assert x != null && (x.getKind() == Kind.Float); - return x; - } - - private T assertObject(T x) { - assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object)); - return x; - } - - private T assertDouble(T x) { - assert x != null && (x.getKind() == Kind.Double); - return x; - } - - private void assertHigh(T x) { - assert x == null; - } - -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,1036 @@ +/* + * Copyright (c) 2012, 2015, 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; + +import static com.oracle.graal.graph.iterators.NodePredicates.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graphbuilderconf.IntrinsicContext.SideEffectsState; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.util.*; + +public final class FrameStateBuilder implements SideEffectsState { + + static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; + static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; + + protected final BytecodeParser parser; + protected final ResolvedJavaMethod method; + protected int stackSize; + protected final ValueNode[] locals; + protected final ValueNode[] stack; + protected ValueNode[] lockedObjects; + + /** + * @see BytecodeFrame#rethrowException + */ + protected boolean rethrowException; + + private MonitorIdNode[] monitorIds; + private final StructuredGraph graph; + private FrameState outerFrameState; + + /** + * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more + * than one when the current block contains no side-effects but merging predecessor blocks do. + */ + protected List sideEffects; + + /** + * Creates a new frame state builder for the given method and the given target graph. + * + * @param method the method whose frame is simulated + * @param graph the target graph of Graal nodes created by the builder + */ + public FrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) { + this.parser = parser; + this.method = method; + this.locals = allocateArray(method.getMaxLocals()); + this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); + this.lockedObjects = allocateArray(0); + + assert graph != null; + + this.monitorIds = EMPTY_MONITOR_ARRAY; + this.graph = graph; + } + + public void initializeFromArgumentsArray(ValueNode[] arguments) { + + int javaIndex = 0; + int index = 0; + if (!method.isStatic()) { + // set the receiver + locals[javaIndex] = arguments[index]; + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + for (int i = 0; i < max; i++) { + Kind kind = sig.getParameterKind(i); + locals[javaIndex] = arguments[index]; + javaIndex += kind.getSlotCount(); + index++; + } + } + + public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { + + int javaIndex = 0; + int index = 0; + if (!method.isStatic()) { + // add the receiver + FloatingNode receiver = null; + Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass()); + if (parameterPlugin != null) { + receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp); + } + if (receiver == null) { + receiver = new ParameterNode(javaIndex, receiverStamp); + } + locals[javaIndex] = graph.unique(receiver); + javaIndex = 1; + index = 1; + } + Signature sig = method.getSignature(); + int max = sig.getParameterCount(false); + ResolvedJavaType accessingClass = method.getDeclaringClass(); + for (int i = 0; i < max; i++) { + JavaType type = sig.getParameterType(i, accessingClass); + if (eagerResolve) { + type = type.resolve(accessingClass); + } + Kind kind = type.getKind(); + Stamp stamp; + if (kind == Kind.Object && type instanceof ResolvedJavaType) { + stamp = StampFactory.declared((ResolvedJavaType) type); + } else { + stamp = StampFactory.forKind(kind); + } + FloatingNode param = null; + if (parameterPlugin != null) { + param = parameterPlugin.interceptParameter(parser, index, stamp); + } + if (param == null) { + param = new ParameterNode(index, stamp); + } + locals[javaIndex] = graph.unique(param); + javaIndex += kind.getSlotCount(); + index++; + } + } + + private FrameStateBuilder(FrameStateBuilder other) { + this.parser = other.parser; + this.method = other.method; + this.stackSize = other.stackSize; + this.locals = other.locals.clone(); + this.stack = other.stack.clone(); + this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); + this.rethrowException = other.rethrowException; + + assert locals.length == method.getMaxLocals(); + assert stack.length == Math.max(1, method.getMaxStackSize()); + + assert other.graph != null; + graph = other.graph; + monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); + + assert locals.length == method.getMaxLocals(); + assert stack.length == Math.max(1, method.getMaxStackSize()); + assert lockedObjects.length == monitorIds.length; + } + + private static ValueNode[] allocateArray(int length) { + return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("[locals: ["); + for (int i = 0; i < locals.length; i++) { + sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); + } + sb.append("] stack: ["); + for (int i = 0; i < stackSize; i++) { + sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); + } + sb.append("] locks: ["); + for (int i = 0; i < lockedObjects.length; i++) { + sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); + } + sb.append("]"); + if (rethrowException) { + sb.append(" rethrowException"); + } + sb.append("]"); + return sb.toString(); + } + + public FrameState create(int bci, StateSplit forStateSplit) { + if (parser.parsingIntrinsic()) { + return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit); + } + + // Skip intrinsic frames + return create(bci, parser.getNonIntrinsicAncestor(), false, (ValueNode[]) null); + } + + /** + * @param pushedValues if non-null, values to {@link #push(Kind, ValueNode)} to the stack before + * creating the {@link FrameState} + */ + public FrameState create(int bci, BytecodeParser parent, boolean duringCall, ValueNode... pushedValues) { + if (outerFrameState == null && parent != null) { + outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), null); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); + return newFrameState; + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw GraalInternalError.shouldNotReachHere(); + } + + if (pushedValues != null) { + int stackSizeToRestore = stackSize; + for (ValueNode arg : pushedValues) { + push(arg.getKind(), arg); + } + FrameState res = graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + stackSize = stackSizeToRestore; + return res; + } else { + return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); + } + } + + public BytecodePosition createBytecodePosition(int bci) { + BytecodeParser parent = parser.getParent(); + if (HideSubstitutionStates.getValue()) { + if (parser.parsingIntrinsic()) { + // Attribute to the method being replaced + return new BytecodePosition(parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1); + } + // Skip intrinsic frames + parent = parser.getNonIntrinsicAncestor(); + } + return create(null, bci, parent); + } + + private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) { + BytecodePosition outer = o; + if (outer == null && parent != null) { + outer = parent.getFrameStateBuilder().createBytecodePosition(parent.bci()); + } + if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { + return FrameState.toBytecodePosition(outerFrameState); + } + if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + throw GraalInternalError.shouldNotReachHere(); + } + return new BytecodePosition(outer, method, bci); + } + + public FrameStateBuilder copy() { + return new FrameStateBuilder(this); + } + + public boolean isCompatibleWith(FrameStateBuilder other) { + assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; + assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; + + if (stackSize() != other.stackSize()) { + return false; + } + for (int i = 0; i < stackSize(); i++) { + ValueNode x = stackAt(i); + ValueNode y = other.stackAt(i); + if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) { + return false; + } + } + if (lockedObjects.length != other.lockedObjects.length) { + return false; + } + for (int i = 0; i < lockedObjects.length; i++) { + if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { + throw new BailoutException("unbalanced monitors"); + } + } + return true; + } + + public void merge(AbstractMergeNode block, FrameStateBuilder other) { + assert isCompatibleWith(other); + + for (int i = 0; i < localsSize(); i++) { + ValueNode curLocal = localAt(i); + ValueNode mergedLocal = merge(curLocal, other.localAt(i), block); + if (curLocal != mergedLocal) { + storeLocal(i, mergedLocal); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode curStack = stackAt(i); + ValueNode mergedStack = merge(curStack, other.stackAt(i), block); + if (curStack != mergedStack) { + storeStack(i, mergedStack); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); + assert monitorIds[i] == other.monitorIds[i]; + } + + if (sideEffects == null) { + sideEffects = other.sideEffects; + } else { + if (other.sideEffects != null) { + sideEffects.addAll(other.sideEffects); + } + } + } + + private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + if (currentValue == null || currentValue.isDeleted()) { + return null; + } else if (block.isPhiAtMerge(currentValue)) { + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + propagateDelete((ValuePhiNode) currentValue); + return null; + } + ((PhiNode) currentValue).addInput(otherValue); + return currentValue; + } else if (currentValue != otherValue) { + assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); + if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { + return null; + } + return createValuePhi(currentValue, otherValue, block); + } else { + return currentValue; + } + } + + private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block)); + for (int i = 0; i < block.phiPredecessorCount(); i++) { + phi.addInput(currentValue); + } + phi.addInput(otherValue); + assert phi.valueCount() == block.phiPredecessorCount() + 1; + return phi; + } + + private void propagateDelete(FloatingNode node) { + assert node instanceof ValuePhiNode || node instanceof ProxyNode; + if (node.isDeleted()) { + return; + } + // Collect all phi functions that use this phi so that we can delete them recursively (after + // we delete ourselves to avoid circles). + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot(); + + // Remove the phi function from all FrameStates where it is used and then delete it. + assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + node.replaceAtUsages(null); + node.safeDelete(); + + for (FloatingNode phiUsage : propagateUsages) { + propagateDelete(phiUsage); + } + } + + public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis) { + for (int i = 0; i < localsSize(); i++) { + boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i); + if (changedInLoop || forcePhis) { + storeLocal(i, createLoopPhi(loopBegin, localAt(i), !changedInLoop)); + } + } + for (int i = 0; i < stackSize(); i++) { + storeStack(i, createLoopPhi(loopBegin, stackAt(i), false)); + } + for (int i = 0; i < lockedObjects.length; i++) { + lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false); + } + } + + public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, loopExit, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); + } + } + } + + public void insertProxies(AbstractBeginNode begin) { + for (int i = 0; i < localsSize(); i++) { + ValueNode value = localAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeLocal(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < stackSize(); i++) { + ValueNode value = stackAt(i); + if (value != null) { + Debug.log(" inserting proxy for %s", value); + storeStack(i, ProxyNode.forValue(value, begin, graph)); + } + } + for (int i = 0; i < lockedObjects.length; i++) { + ValueNode value = lockedObjects[i]; + if (value != null) { + Debug.log(" inserting proxy for %s", value); + lockedObjects[i] = ProxyNode.forValue(value, begin, graph); + } + } + } + + private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) { + if (value == null) { + return null; + } + assert !block.isPhiAtMerge(value) : "phi function for this block already created"; + + ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp() : value.stamp().unrestricted(), block)); + phi.addInput(value); + return phi; + } + + /** + * Adds a locked monitor to this frame state. + * + * @param object the object whose monitor will be locked. + */ + public void pushLock(ValueNode object, MonitorIdNode monitorId) { + assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object; + lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); + monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); + lockedObjects[lockedObjects.length - 1] = object; + monitorIds[monitorIds.length - 1] = monitorId; + assert lockedObjects.length == monitorIds.length; + } + + /** + * Removes a locked monitor from this frame state. + * + * @return the object whose monitor was removed from the locks list. + */ + public ValueNode popLock() { + try { + return lockedObjects[lockedObjects.length - 1]; + } finally { + lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); + monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); + assert lockedObjects.length == monitorIds.length; + } + } + + public MonitorIdNode peekMonitorId() { + return monitorIds[monitorIds.length - 1]; + } + + /** + * @return the current lock depth + */ + public int lockDepth() { + assert lockedObjects.length == monitorIds.length; + return lockedObjects.length; + } + + public boolean contains(ValueNode value) { + for (int i = 0; i < localsSize(); i++) { + if (localAt(i) == value) { + return true; + } + } + for (int i = 0; i < stackSize(); i++) { + if (stackAt(i) == value) { + return true; + } + } + assert lockedObjects.length == monitorIds.length; + for (int i = 0; i < lockedObjects.length; i++) { + if (lockedObjects[i] == value || monitorIds[i] == value) { + return true; + } + } + return false; + } + + public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { + /* + * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to + * remove it for normal compilations, but not for OSR compilations - otherwise dead object + * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with + * Kind.Illegal, because the conflicting branch might not have been parsed. + */ + if (!parser.graphBuilderConfig.clearNonLiveLocals()) { + return; + } + if (liveIn) { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveIn(block, i)) { + locals[i] = null; + } + } + } else { + for (int i = 0; i < locals.length; i++) { + if (!liveness.localIsLiveOut(block, i)) { + locals[i] = null; + } + } + } + } + + /** + * @see BytecodeFrame#rethrowException + */ + public boolean rethrowException() { + return rethrowException; + } + + /** + * @see BytecodeFrame#rethrowException + */ + public void setRethrowException(boolean b) { + rethrowException = b; + } + + /** + * Returns the size of the local variables. + * + * @return the size of the local variables + */ + public int localsSize() { + return locals.length; + } + + /** + * Gets the current size (height) of the stack. + */ + public int stackSize() { + return stackSize; + } + + /** + * Gets the value in the local variables at the specified index, without any sanity checking. + * + * @param i the index into the locals + * @return the instruction that produced the value for the specified local + */ + public ValueNode localAt(int i) { + return locals[i]; + } + + /** + * Get the value on the stack at the specified stack index. + * + * @param i the index into the stack, with {@code 0} being the bottom of the stack + * @return the instruction at the specified position in the stack + */ + public ValueNode stackAt(int i) { + return stack[i]; + } + + /** + * Gets the value in the lock at the specified index, without any sanity checking. + * + * @param i the index into the lock + * @return the instruction that produced the value for the specified lock + */ + public ValueNode lockAt(int i) { + return lockedObjects[i]; + } + + public void storeLock(int i, ValueNode lock) { + lockedObjects[i] = lock; + } + + /** + * Loads the local variable at the specified index, checking that the returned value is non-null + * and that two-stack values are properly handled. + * + * @param i the index of the local variable to load + * @return the instruction that produced the specified local + */ + public ValueNode loadLocal(int i) { + ValueNode x = locals[i]; + assert assertLoadLocal(i, x); + return x; + } + + private boolean assertLoadLocal(int i, ValueNode x) { + assert x != null : i; + assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); + assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); + return true; + } + + public void storeLocal(int i, ValueNode x) { + storeLocal(i, x, x == null ? null : x.getKind()); + } + + /** + * Stores a given local variable at the specified index. If the value occupies two slots, then + * the next local variable index is also overwritten. + * + * @param i the index at which to store + * @param x the instruction which produces the value for the local + */ + public void storeLocal(int i, ValueNode x, Kind kind) { + assert assertStoreLocal(x); + locals[i] = x; + if (x != null) { + if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) { + // if this is a double word, then kill i+1 + locals[i + 1] = null; + } + if (i > 0 && !parser.parsingIntrinsic()) { + ValueNode p = locals[i - 1]; + if (p != null && p.getKind().needsTwoSlots()) { + // if there was a double word at i - 1, then kill it + locals[i - 1] = null; + } + } + } + } + + private boolean assertStoreLocal(ValueNode x) { + assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; + return true; + } + + public void storeStack(int i, ValueNode x) { + assert assertStoreStack(i, x); + stack[i] = x; + } + + private boolean assertStoreStack(int i, ValueNode x) { + assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; + return true; + } + + /** + * Pushes an instruction onto the stack with the expected type. + * + * @param kind the type expected for this instruction + * @param x the instruction to push onto the stack + */ + public void push(Kind kind, ValueNode x) { + assert assertPush(kind, x); + xpush(x); + if (kind.needsTwoSlots()) { + xpush(null); + } + } + + private boolean assertPush(Kind kind, ValueNode x) { + assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); + assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); + return true; + } + + /** + * Pushes a value onto the stack without checking the type. + * + * @param x the instruction to push onto the stack + */ + public void xpush(ValueNode x) { + assert assertXpush(x); + stack[stackSize++] = x; + } + + private boolean assertXpush(ValueNode x) { + assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); + return true; + } + + /** + * Pushes a value onto the stack and checks that it is an int. + * + * @param x the instruction to push onto the stack + */ + public void ipush(ValueNode x) { + assert assertInt(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is a float. + * + * @param x the instruction to push onto the stack + */ + public void fpush(ValueNode x) { + assert assertFloat(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is an object. + * + * @param x the instruction to push onto the stack + */ + public void apush(ValueNode x) { + assert assertObject(x); + xpush(x); + } + + /** + * Pushes a value onto the stack and checks that it is a long. + * + * @param x the instruction to push onto the stack + */ + public void lpush(ValueNode x) { + assert assertLong(x); + xpush(x); + xpush(null); + } + + /** + * Pushes a value onto the stack and checks that it is a double. + * + * @param x the instruction to push onto the stack + */ + public void dpush(ValueNode x) { + assert assertDouble(x); + xpush(x); + xpush(null); + } + + public void pushReturn(Kind kind, ValueNode x) { + if (kind != Kind.Void) { + push(kind.getStackKind(), x); + } + } + + /** + * Pops an instruction off the stack with the expected type. + * + * @param kind the expected type + * @return the instruction on the top of the stack + */ + public ValueNode pop(Kind kind) { + if (kind.needsTwoSlots()) { + xpop(); + } + assert assertPop(kind); + return xpop(); + } + + private boolean assertPop(Kind kind) { + assert kind != Kind.Void; + ValueNode x = xpeek(); + assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); + return true; + } + + /** + * Pops a value off of the stack without checking the type. + * + * @return x the instruction popped off the stack + */ + public ValueNode xpop() { + return stack[--stackSize]; + } + + public ValueNode xpeek() { + return stack[stackSize - 1]; + } + + /** + * Pops a value off of the stack and checks that it is an int. + * + * @return x the instruction popped off the stack + */ + public ValueNode ipop() { + assert assertIntPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a float. + * + * @return x the instruction popped off the stack + */ + public ValueNode fpop() { + assert assertFloatPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is an object. + * + * @return x the instruction popped off the stack + */ + public ValueNode apop() { + assert assertObjectPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a long. + * + * @return x the instruction popped off the stack + */ + public ValueNode lpop() { + assert assertHighPeek(); + xpop(); + assert assertLongPeek(); + return xpop(); + } + + /** + * Pops a value off of the stack and checks that it is a double. + * + * @return x the instruction popped off the stack + */ + public ValueNode dpop() { + assert assertHighPeek(); + xpop(); + assert assertDoublePeek(); + return xpop(); + } + + /** + * Pop the specified number of slots off of this stack and return them as an array of + * instructions. + * + * @return an array containing the arguments off of the stack + */ + public ValueNode[] popArguments(int argSize) { + ValueNode[] result = allocateArray(argSize); + int newStackSize = stackSize; + for (int i = argSize - 1; i >= 0; i--) { + newStackSize--; + if (stack[newStackSize] == null) { + /* Two-slot value. */ + newStackSize--; + assert stack[newStackSize].getKind().needsTwoSlots(); + } else { + assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1); + } + result[i] = stack[newStackSize]; + } + stackSize = newStackSize; + return result; + } + + /** + * Peeks an element from the operand stack. + * + * @param argumentNumber The number of the argument, relative from the top of the stack (0 = + * top). Long and double arguments only count as one argument, i.e., null-slots are + * ignored. + * @return The peeked argument. + */ + public ValueNode peek(int argumentNumber) { + int idx = stackSize() - 1; + for (int i = 0; i < argumentNumber; i++) { + if (stackAt(idx) == null) { + idx--; + assert stackAt(idx).getKind().needsTwoSlots(); + } + idx--; + } + return stackAt(idx); + } + + /** + * Clears all values on this stack. + */ + public void clearStack() { + stackSize = 0; + } + + private boolean assertLongPeek() { + return assertLong(xpeek()); + } + + private static boolean assertLong(ValueNode x) { + assert x != null && (x.getKind() == Kind.Long); + return true; + } + + private boolean assertIntPeek() { + return assertInt(xpeek()); + } + + private static boolean assertInt(ValueNode x) { + assert x != null && (x.getKind() == Kind.Int); + return true; + } + + private boolean assertFloatPeek() { + return assertFloat(xpeek()); + } + + private static boolean assertFloat(ValueNode x) { + assert x != null && (x.getKind() == Kind.Float); + return true; + } + + private boolean assertObjectPeek() { + return assertObject(xpeek()); + } + + private boolean assertObject(ValueNode x) { + assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object)); + return true; + } + + private boolean assertDoublePeek() { + return assertDouble(xpeek()); + } + + private static boolean assertDouble(ValueNode x) { + assert x != null && (x.getKind() == Kind.Double); + return true; + } + + private boolean assertHighPeek() { + assert xpeek() == null; + return true; + } + + @Override + public int hashCode() { + int result = hashCode(locals, locals.length); + result *= 13; + result += hashCode(stack, this.stackSize); + return result; + } + + private static int hashCode(Object[] a, int length) { + int result = 1; + for (int i = 0; i < length; ++i) { + Object element = a[i]; + result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); + } + return result; + } + + private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { + for (int i = 0; i < length; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + @Override + public boolean equals(Object otherObject) { + if (otherObject instanceof FrameStateBuilder) { + FrameStateBuilder other = (FrameStateBuilder) otherObject; + if (!other.method.equals(method)) { + return false; + } + if (other.stackSize != stackSize) { + return false; + } + if (other.parser != parser) { + return false; + } + if (other.rethrowException != rethrowException) { + return false; + } + if (other.graph != graph) { + return false; + } + if (other.locals.length != locals.length) { + return false; + } + return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && + equals(other.monitorIds, monitorIds, monitorIds.length); + } + return false; + } + + public void replace(ValueNode oldValue, ValueNode newValue) { + for (int i = 0; i < locals.length; i++) { + if (locals[i] == oldValue) { + locals[i] = newValue; + } + } + for (int i = 0; i < stackSize; i++) { + if (stack[i] == oldValue) { + stack[i] = newValue; + } + } + } + + @Override + public boolean isAfterSideEffect() { + return sideEffects != null; + } + + @Override + public Iterable sideEffects() { + return sideEffects; + } + + @Override + public void addSideEffect(StateSplit sideEffect) { + assert sideEffect != null; + assert sideEffect.hasSideEffect(); + if (sideEffects == null) { + sideEffects = new ArrayList<>(4); + } + sideEffects.add(sideEffect); + } +} diff -r 427f3b505656 -r 307a1ee8f714 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 Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri May 15 11:55:52 2015 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.java; +import static com.oracle.graal.api.code.TypeCheckHints.*; import static com.oracle.graal.api.meta.DeoptimizationAction.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; @@ -29,7 +30,7 @@ import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.compiler.common.type.StampFactory.*; import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.nodes.StructuredGraph.*; import static com.oracle.graal.nodes.type.StampTool.*; import static java.lang.String.*; @@ -63,6 +64,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.tiers.*; @@ -71,6 +73,125 @@ */ public class GraphBuilderPhase extends BasePhase { + public static class Options { + // @formatter:off + @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) + public static final OptionValue TraceBytecodeParserLevel = new OptionValue<>(0); + + @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineDuringParsing = new StableOptionValue<>(false); + + @Option(help = "Inlines intrinsic methods during bytecode parsing.", type = OptionType.Expert) + public static final StableOptionValue InlineIntrinsicsDuringParsing = new StableOptionValue<>(true); + + @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceInlineDuringParsing = new StableOptionValue<>(false); + + @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue TraceParserPlugins = new StableOptionValue<>(false); + + @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue InlineDuringParsingMaxDepth = new StableOptionValue<>(10); + + @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) + public static final StableOptionValue DumpDuringGraphBuilding = new StableOptionValue<>(false); + + @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) + public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); + + @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) + public static final OptionValue FailedLoopExplosionIsFatal = new OptionValue<>(false); + + @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) + public static final OptionValue HideSubstitutionStates = new OptionValue<>(false); + + // @formatter:on + } + + /** + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * bytecode instructions as they are parsed. + */ + public static final int TRACELEVEL_INSTRUCTIONS = 1; + + /** + * The minimum value to which {@link Options#TraceBytecodeParserLevel} must be set to trace the + * frame state before each bytecode instruction as it is parsed. + */ + public static final int TRACELEVEL_STATE = 2; + + /** + * Meters the number of actual bytecodes parsed. + */ + public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed"); + + /** + * Gets the kind of array elements for the array type code that appears in a + * {@link Bytecodes#NEWARRAY} bytecode. + * + * @param code the array type code + * @return the kind from the array type code + */ + public static Class arrayTypeCodeToClass(int code) { + // Checkstyle: stop + switch (code) { + case 4: + return boolean.class; + case 5: + return char.class; + case 6: + return float.class; + case 7: + return double.class; + case 8: + return byte.class; + case 9: + return short.class; + case 10: + return int.class; + case 11: + return long.class; + default: + throw new IllegalArgumentException("unknown array type code: " + code); + } + // Checkstyle: resume + } + + protected static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions"); + + protected static boolean allPositive(double[] a) { + for (double d : a) { + if (d < 0) { + return false; + } + } + return true; + } + + /** + * Helper function that sums up the probabilities of all keys that lead to a specific successor. + * + * @return an array of size successorCount with the accumulated probability for each successor. + */ + public static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) { + double[] probability = new double[successorCount]; + for (int i = 0; i < keySuccessors.length; i++) { + probability[keySuccessors[i]] += keyProbabilities[i]; + } + return probability; + } + + static class SuccessorInfo { + + int blockIndex; + int actualIndex; + + public SuccessorInfo(int blockSuccessorIndex) { + this.blockIndex = blockSuccessorIndex; + actualIndex = -1; + } + } + private final GraphBuilderConfiguration graphBuilderConfig; public GraphBuilderPhase(GraphBuilderConfiguration config) { @@ -86,35 +207,38 @@ return graphBuilderConfig; } + /** + * A scoped object for tasks to be performed after parsing an intrinsic such as processing + * {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states. + */ static class IntrinsicScope implements AutoCloseable { FrameState stateBefore; final Mark mark; final BytecodeParser parser; - static IntrinsicScope create(boolean enteringIntrinsic, BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) { - if (enteringIntrinsic) { - return new IntrinsicScope(parser, currentFrameState, args); - } - return null; - } - - public IntrinsicScope(BytecodeParser parser, HIRFrameStateBuilder currentFrameState, ValueNode[] args) { + /** + * Creates a scope for root parsing an intrinsic. + * + * @param parser the parsing context of the intrinsic + */ + public IntrinsicScope(BytecodeParser parser) { this.parser = parser; - if (args == null) { - assert parser.parent == null; - assert parser.bci() == 0; - mark = null; - } else { - mark = parser.getGraph().getMark(); - for (ValueNode arg : args) { - currentFrameState.push(arg.getKind(), arg); - } - stateBefore = currentFrameState.create(parser.bci(), null); - for (int i = args.length - 1; i >= 0; i--) { - ValueNode arg = args[i]; - currentFrameState.pop(arg.getKind()); - } - } + assert parser.parent == null; + assert parser.bci() == 0; + mark = null; + } + + /** + * Creates a scope for parsing an intrinsic during graph builder inlining. + * + * @param parser the parsing context of the (non-intrinsic) method calling the intrinsic + * @param args the arguments to the call + */ + public IntrinsicScope(BytecodeParser parser, ValueNode[] args) { + assert !parser.parsingIntrinsic(); + this.parser = parser; + mark = parser.getGraph().getMark(); + stateBefore = parser.frameState.create(parser.bci(), parser.getNonIntrinsicAncestor(), false, args); } public void close() { @@ -123,43 +247,56 @@ return; } + processPlaceholderFrameStates(intrinsic); + } + + /** + * Fixes up the {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frame states + * added to the graph while parsing/inlining the intrinsic for which this object exists. + */ + private void processPlaceholderFrameStates(IntrinsicContext intrinsic) { FrameState stateAfterReturn = null; StructuredGraph graph = parser.getGraph(); for (Node node : graph.getNewNodes(mark)) { if (node instanceof FrameState) { - FrameState fs = (FrameState) node; - if (BytecodeFrame.isPlaceholderBci(fs.bci)) { - if (fs.bci == BytecodeFrame.AFTER_BCI) { - if (fs.stackSize() != 0) { - assert fs.usages().count() == 1; - ValueNode returnVal = fs.stackAt(0); - assert returnVal == fs.usages().first(); - - ValueNode tos = parser.frameState.pop(returnVal.getKind()); - parser.frameState.push(returnVal.getKind(), returnVal); - FrameState newFs = parser.frameState.create(parser.stream.nextBCI(), null); - fs.replaceAndDelete(newFs); - parser.frameState.pop(returnVal.getKind()); - parser.frameState.push(tos.getKind(), tos); + FrameState frameState = (FrameState) node; + if (BytecodeFrame.isPlaceholderBci(frameState.bci)) { + if (frameState.bci == BytecodeFrame.AFTER_BCI) { + FrameStateBuilder frameStateBuilder = parser.frameState; + if (frameState.stackSize() != 0) { + assert frameState.usages().count() == 1; + ValueNode returnVal = frameState.stackAt(0); + assert returnVal == frameState.usages().first(); + + /* + * Swap the top-of-stack value with the side-effect return value + * using the frame state. + */ + ValueNode tos = frameStateBuilder.pop(returnVal.getKind()); + assert tos.getKind() == returnVal.getKind(); + FrameState newFrameState = frameStateBuilder.create(parser.stream.nextBCI(), parser.getNonIntrinsicAncestor(), false, returnVal); + frameState.replaceAndDelete(newFrameState); + frameStateBuilder.push(tos.getKind(), tos); } else { if (stateAfterReturn == null) { - if (intrinsic != null && intrinsic.isCompilationRoot()) { + if (intrinsic != null) { + assert intrinsic.isCompilationRoot(); stateAfterReturn = graph.add(new FrameState(BytecodeFrame.INVALID_FRAMESTATE_BCI)); } else { - stateAfterReturn = parser.frameState.create(parser.stream.nextBCI(), null); + stateAfterReturn = frameStateBuilder.create(parser.stream.nextBCI(), null); } } - fs.replaceAndDelete(stateAfterReturn); + frameState.replaceAndDelete(stateAfterReturn); } - } else if (fs.bci == BytecodeFrame.BEFORE_BCI) { + } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) { if (stateBefore == null) { stateBefore = graph.start().stateAfter(); } - if (stateBefore != fs) { - fs.replaceAndDelete(stateBefore); + if (stateBefore != frameState) { + frameState.replaceAndDelete(stateBefore); } } else { - assert fs.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; + assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; } } } @@ -203,11 +340,11 @@ try { IntrinsicContext intrinsicContext = initialIntrinsicContext; BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, intrinsicContext); - HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph); + FrameStateBuilder frameState = new FrameStateBuilder(parser, method, graph); frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins().getParameterPlugin()); - try (IntrinsicScope s = IntrinsicScope.create(intrinsicContext != null, parser, frameState, null)) { + try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(parser) : null) { parser.build(graph.start(), frameState); } GraphUtil.normalizeLoops(graph); @@ -279,9 +416,9 @@ private static class Target { FixedNode fixed; - HIRFrameStateBuilder state; - - public Target(FixedNode fixed, HIRFrameStateBuilder state) { + FrameStateBuilder state; + + public Target(FixedNode fixed, FrameStateBuilder state) { this.fixed = fixed; this.state = state; } @@ -305,7 +442,7 @@ } } - public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { + public class BytecodeParser implements GraphBuilderContext { private BciBlockMapping blockMap; private LocalLiveness liveness; @@ -326,20 +463,28 @@ private FixedWithNextNode lastInstr; // the last instruction added private final boolean explodeLoops; private final boolean mergeExplosions; - private final Map mergeExplosionsMap; + private final Map mergeExplosionsMap; private Deque explodeLoopsContext; private int nextPeelIteration = 1; private boolean controlFlowSplit; private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this); private FixedWithNextNode[] firstInstructionArray; - private HIRFrameStateBuilder[] entryStateArray; + private FrameStateBuilder[] entryStateArray; private FixedWithNextNode[][] firstInstructionMatrix; - private HIRFrameStateBuilder[][] entryStateMatrix; + private FrameStateBuilder[][] entryStateMatrix; public BytecodeParser(BytecodeParser parent, MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI, IntrinsicContext intrinsicContext) { - super(metaAccess, method, graphBuilderConfig, optimisticOpts, intrinsicContext); + this.graphBuilderConfig = graphBuilderConfig; + this.optimisticOpts = optimisticOpts; + this.metaAccess = metaAccess; + this.stream = new BytecodeStream(method.getCode()); + this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null); + this.constantPool = method.getConstantPool(); + this.method = method; + this.intrinsicContext = intrinsicContext; + assert metaAccess != null; this.entryBCI = entryBCI; this.parent = parent; @@ -381,7 +526,7 @@ return this.beforeUnwindNode; } - protected void build(FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) { + protected void build(FixedWithNextNode startInstruction, FrameStateBuilder startFrameState) { if (PrintProfilingInformation.getValue() && profilingInfo != null) { TTY.println("Profiling info for " + method.format("%H.%n(%p)")); TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), " ")); @@ -393,15 +538,13 @@ BciBlockMapping newMapping = BciBlockMapping.create(stream, method); this.blockMap = newMapping; this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()]; - this.entryStateArray = new HIRFrameStateBuilder[blockMap.getBlockCount()]; - - if (graphBuilderConfig.doLivenessAnalysis()) { - try (Scope s = Debug.scope("LivenessAnalysis")) { - int maxLocals = method.getMaxLocals(); - liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); - } catch (Throwable e) { - throw Debug.handle(e); - } + this.entryStateArray = new FrameStateBuilder[blockMap.getBlockCount()]; + + try (Scope s = Debug.scope("LivenessAnalysis")) { + int maxLocals = method.getMaxLocals(); + liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount()); + } catch (Throwable e) { + throw Debug.handle(e); } lastInstr = startInstruction; @@ -704,7 +847,7 @@ return header.loopEnd + 1; } - private void addToMergeCache(HIRFrameStateBuilder key, int dimension) { + private void addToMergeCache(FrameStateBuilder key, int dimension) { mergeExplosionsMap.put(key, dimension); } @@ -743,7 +886,6 @@ /** * @param type the unresolved type of the constant */ - @Override protected void handleUnresolvedLoadConstant(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -753,7 +895,6 @@ * @param type the unresolved type of the type check * @param object the object value whose type is being checked against {@code type} */ - @Override protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { assert !graphBuilderConfig.eagerResolving(); append(new FixedGuardNode(graph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile)); @@ -764,7 +905,6 @@ * @param type the unresolved type of the type check * @param object the object value whose type is being checked against {@code type} */ - @Override protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { assert !graphBuilderConfig.eagerResolving(); AbstractBeginNode successor = graph.add(new BeginNode()); @@ -777,7 +917,6 @@ /** * @param type the type being instantiated */ - @Override protected void handleUnresolvedNewInstance(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -787,7 +926,6 @@ * @param type the type of the array being instantiated * @param length the length of the array */ - @Override protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -797,7 +935,6 @@ * @param type the type being instantiated * @param dims the dimensions for the multi-array */ - @Override protected void handleUnresolvedNewMultiArray(JavaType type, List dims) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -808,7 +945,6 @@ * @param receiver the object containing the field or {@code null} if {@code field} is * static */ - @Override protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -820,7 +956,6 @@ * @param receiver the object containing the field or {@code null} if {@code field} is * static */ - @Override protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -829,7 +964,6 @@ /** * @param type */ - @Override protected void handleUnresolvedExceptionType(JavaType type) { assert !graphBuilderConfig.eagerResolving(); append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); @@ -858,7 +992,7 @@ dispatchBlock = blockMap.getUnwindBlock(); } - HIRFrameStateBuilder dispatchState = frameState.copy(); + FrameStateBuilder dispatchState = frameState.copy(); dispatchState.clearStack(); DispatchBeginNode dispatchBegin; @@ -880,148 +1014,119 @@ return dispatchBegin; } - @Override protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, Kind kind) { return LoadIndexedNode.create(array, index, kind, metaAccess, constantReflection); } - @Override protected void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value) { add(new StoreIndexedNode(array, index, kind, value)); } - @Override - protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) { return AddNode.create(x, y); } - @Override - protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerSub(ValueNode x, ValueNode y) { return SubNode.create(x, y); } - @Override - protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerMul(ValueNode x, ValueNode y) { return MulNode.create(x, y); } - @Override - protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatAdd(ValueNode x, ValueNode y) { return AddNode.create(x, y); } - @Override - protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatSub(ValueNode x, ValueNode y) { return SubNode.create(x, y); } - @Override - protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatMul(ValueNode x, ValueNode y) { return MulNode.create(x, y); } - @Override - protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatDiv(ValueNode x, ValueNode y) { return DivNode.create(x, y); } - @Override - protected ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) { + protected ValueNode genFloatRem(ValueNode x, ValueNode y) { return new RemNode(x, y); } - @Override - protected ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) { return new IntegerDivNode(x, y); } - @Override - protected ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genIntegerRem(ValueNode x, ValueNode y) { return new IntegerRemNode(x, y); } - @Override protected ValueNode genNegateOp(ValueNode x) { return (new NegateNode(x)); } - @Override - protected ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genLeftShift(ValueNode x, ValueNode y) { return new LeftShiftNode(x, y); } - @Override - protected ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genRightShift(ValueNode x, ValueNode y) { return new RightShiftNode(x, y); } - @Override - protected ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) { return new UnsignedRightShiftNode(x, y); } - @Override - protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genAnd(ValueNode x, ValueNode y) { return AndNode.create(x, y); } - @Override - protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genOr(ValueNode x, ValueNode y) { return OrNode.create(x, y); } - @Override - protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) { + protected ValueNode genXor(ValueNode x, ValueNode y) { return XorNode.create(x, y); } - @Override protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) { return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection); } - @Override protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) { return FloatConvertNode.create(op, input); } - @Override protected ValueNode genNarrow(ValueNode input, int bitCount) { return NarrowNode.create(input, bitCount); } - @Override protected ValueNode genSignExtend(ValueNode input, int bitCount) { return SignExtendNode.create(input, bitCount); } - @Override protected ValueNode genZeroExtend(ValueNode input, int bitCount) { return ZeroExtendNode.create(input, bitCount); } - @Override protected void genGoto() { appendGoto(currentBlock.getSuccessor(0)); assert currentBlock.numNormalSuccessors() == 1; } - @Override protected LogicNode genObjectEquals(ValueNode x, ValueNode y) { return ObjectEqualsNode.create(x, y, constantReflection); } - @Override protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) { return IntegerEqualsNode.create(x, y, constantReflection); } - @Override protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) { return IntegerLessThanNode.create(x, y, constantReflection); } - @Override protected ValueNode genUnique(ValueNode x) { return (ValueNode) graph.unique((Node & ValueNumberable) x); } @@ -1030,49 +1135,40 @@ return new IfNode(condition, falseSuccessor, trueSuccessor, d); } - @Override protected void genThrow() { ValueNode exception = frameState.apop(); append(new FixedGuardNode(graph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); lastInstr.setNext(handleException(exception, bci())); } - @Override protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) { return CheckCastNode.create(type, object, profileForTypeCheck, forStoreCheck, graph.getAssumptions()); } - @Override protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) { return InstanceOfNode.create(type, object, profileForTypeCheck); } - @Override protected ValueNode genConditional(ValueNode x) { return new ConditionalNode((LogicNode) x); } - @Override protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { return new NewInstanceNode(type, fillContents); } - @Override protected NewArrayNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents) { return new NewArrayNode(elementType, length, fillContents); } - @Override protected NewMultiArrayNode createNewMultiArray(ResolvedJavaType type, List dimensions) { return new NewMultiArrayNode(type, dimensions.toArray(new ValueNode[0])); } - @Override protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { return new LoadFieldNode(receiver, field); } - @Override protected ValueNode emitExplicitNullCheck(ValueNode receiver) { if (StampTool.isPointerNonNull(receiver.stamp())) { return receiver; @@ -1089,7 +1185,6 @@ return nonNullReceiver; } - @Override protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = graph.add(new BeginNode()); BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); @@ -1100,12 +1195,10 @@ exception.setNext(handleException(exception, bci())); } - @Override protected ValueNode genArrayLength(ValueNode x) { return ArrayLengthNode.create(x, constantReflection); } - @Override protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) { StoreFieldNode storeFieldNode = new StoreFieldNode(receiver, field, value); append(storeFieldNode); @@ -1128,7 +1221,6 @@ return false; } - @Override protected void genInvokeStatic(JavaMethod target) { if (callTargetIsResolved(target)) { ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; @@ -1144,7 +1236,6 @@ } } - @Override protected void genInvokeInterface(JavaMethod target) { if (callTargetIsResolved(target)) { ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); @@ -1154,7 +1245,6 @@ } } - @Override protected void genInvokeDynamic(JavaMethod target) { if (target instanceof ResolvedJavaMethod) { JavaConstant appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); @@ -1168,7 +1258,6 @@ } } - @Override protected void genInvokeVirtual(JavaMethod target) { if (callTargetIsResolved(target)) { /* @@ -1195,7 +1284,6 @@ } - @Override protected void genInvokeSpecial(JavaMethod target) { if (callTargetIsResolved(target)) { assert target != null; @@ -1209,6 +1297,16 @@ private InvokeKind currentInvokeKind; private JavaType currentInvokeReturnType; + protected FrameStateBuilder frameState; + protected BciBlock currentBlock; + protected final BytecodeStream stream; + protected final GraphBuilderConfiguration graphBuilderConfig; + protected final ResolvedJavaMethod method; + protected final ProfilingInfo profilingInfo; + protected final OptimisticOptimizations optimisticOpts; + protected final ConstantPool constantPool; + protected final MetaAccessProvider metaAccess; + protected final IntrinsicContext intrinsicContext; public InvokeKind getInvokeKind() { return currentInvokeKind; @@ -1466,7 +1564,7 @@ * @param format a format string * @param args arguments to the format string */ - @Override + protected void traceWithContext(String format, Object... args) { StackTraceElement where = method.asStackTraceElement(bci()); TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(), @@ -1487,10 +1585,10 @@ } private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { - try (IntrinsicScope s = IntrinsicScope.create(calleeIntrinsicContext != null && !parsingIntrinsic(), this, frameState, args)) { + try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, args) : null) { BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); - HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, graph); + FrameStateBuilder startFrameState = new FrameStateBuilder(parser, targetMethod, graph); if (!targetMethod.isStatic()) { args[0] = nullCheckedValue(args[0]); } @@ -1533,6 +1631,14 @@ } protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, Kind resultType) { + if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) { + /* + * Clear non-live locals early so that the exception handler entry gets the + * cleared state. + */ + frameState.clearNonLiveLocals(currentBlock, liveness, false); + } + DispatchBeginNode exceptionEdge = handleException(null, bci()); InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci())); frameState.pushReturn(resultType, invoke); @@ -1540,7 +1646,6 @@ return invoke; } - @Override protected void genReturn(ValueNode returnVal, Kind returnKind) { if (parsingIntrinsic() && returnVal != null) { if (returnVal instanceof StateSplit) { @@ -1603,7 +1708,6 @@ } } - @Override protected void genMonitorEnter(ValueNode x, int bci) { MonitorIdNode monitorId = graph.add(new MonitorIdNode(frameState.lockDepth())); MonitorEnterNode monitorEnter = append(new MonitorEnterNode(x, monitorId)); @@ -1611,7 +1715,6 @@ monitorEnter.setStateAfter(createFrameState(bci, monitorEnter)); } - @Override protected void genMonitorExit(ValueNode x, ValueNode escapedReturnValue, int bci) { MonitorIdNode monitorId = frameState.peekMonitorId(); ValueNode lockedObject = frameState.popLock(); @@ -1622,7 +1725,6 @@ monitorExit.setStateAfter(createFrameState(bci, monitorExit)); } - @Override protected void genJsr(int dest) { BciBlock successor = currentBlock.getJsrSuccessor(); assert successor.startBci == dest : successor.startBci + " != " + dest + " @" + bci(); @@ -1639,7 +1741,6 @@ appendGoto(successor); } - @Override protected void genRet(int localIndex) { BciBlock successor = currentBlock.getRetSuccessor(); ValueNode local = frameState.loadLocal(localIndex); @@ -1662,7 +1763,6 @@ return graph.unique(nextBciNode); } - @Override protected void genIntegerSwitch(ValueNode value, ArrayList actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) { if (value.isConstant()) { JavaConstant constant = (JavaConstant) value.asConstant(); @@ -1684,7 +1784,6 @@ } } - @Override protected ConstantNode appendConstant(JavaConstant constant) { assert constant != null; return ConstantNode.forConstant(constant, metaAccess, graph); @@ -1727,7 +1826,7 @@ } } - private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { + private Target checkLoopExit(FixedNode target, BciBlock targetBlock, FrameStateBuilder state) { if (currentBlock != null && !explodeLoops) { long exits = currentBlock.loops & ~targetBlock.loops; if (exits != 0) { @@ -1757,7 +1856,7 @@ if (targetBlock instanceof ExceptionDispatchBlock) { bci = ((ExceptionDispatchBlock) targetBlock).deoptBci; } - HIRFrameStateBuilder newState = state.copy(); + FrameStateBuilder newState = state.copy(); for (BciBlock loop : exitLoops) { LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop, this.getCurrentDimension()); LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); @@ -1780,7 +1879,7 @@ return new Target(target, state); } - private HIRFrameStateBuilder getEntryState(BciBlock block, int dimension) { + private FrameStateBuilder getEntryState(BciBlock block, int dimension) { int id = block.id; if (dimension == 0) { return entryStateArray[id]; @@ -1789,9 +1888,9 @@ } } - private HIRFrameStateBuilder getEntryStateMultiDimension(int dimension, int id) { + private FrameStateBuilder getEntryStateMultiDimension(int dimension, int id) { if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) { - HIRFrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1]; + FrameStateBuilder[] entryStateArrayEntry = entryStateMatrix[dimension - 1]; if (entryStateArrayEntry == null) { return null; } @@ -1801,7 +1900,7 @@ } } - private void setEntryState(BciBlock block, int dimension, HIRFrameStateBuilder entryState) { + private void setEntryState(BciBlock block, int dimension, FrameStateBuilder entryState) { int id = block.id; if (dimension == 0) { this.entryStateArray[id] = entryState; @@ -1810,9 +1909,9 @@ } } - private void setEntryStateMultiDimension(int dimension, HIRFrameStateBuilder entryState, int id) { + private void setEntryStateMultiDimension(int dimension, FrameStateBuilder entryState, int id) { if (entryStateMatrix == null) { - entryStateMatrix = new HIRFrameStateBuilder[4][]; + entryStateMatrix = new FrameStateBuilder[4][]; } if (dimension - 1 < entryStateMatrix.length) { // We are within bounds. @@ -1821,7 +1920,7 @@ entryStateMatrix = Arrays.copyOf(entryStateMatrix, Math.max(entryStateMatrix.length * 2, dimension)); } if (entryStateMatrix[dimension - 1] == null) { - entryStateMatrix[dimension - 1] = new HIRFrameStateBuilder[blockMap.getBlockCount()]; + entryStateMatrix[dimension - 1] = new FrameStateBuilder[blockMap.getBlockCount()]; } entryStateMatrix[dimension - 1][id] = entryState; } @@ -1872,7 +1971,7 @@ } } - private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { + private FixedNode createTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1.01 : probability; if (isNeverExecutedCode(probability)) { return graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); @@ -1882,11 +1981,11 @@ } } - private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) { + private FixedNode createTarget(BciBlock block, FrameStateBuilder state) { return createTarget(block, state, false, false); } - private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { + private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { assert block != null && state != null; assert !block.isExceptionEntry || state.stackSize() == 1; @@ -1908,7 +2007,7 @@ targetNode = getFirstInstruction(block, operatingDimension); Target target = checkLoopExit(targetNode, block, state); FixedNode result = target.fixed; - HIRFrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; + FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; setEntryState(block, operatingDimension, currentEntryState); currentEntryState.clearNonLiveLocals(block, liveness, true); @@ -1981,14 +2080,14 @@ return result; } - private int findOperatingDimension(BciBlock block, HIRFrameStateBuilder state) { + private int findOperatingDimension(BciBlock block, FrameStateBuilder state) { if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) { return findOperatingDimensionWithLoopExplosion(block, state); } return this.getCurrentDimension(); } - private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) { + private int findOperatingDimensionWithLoopExplosion(BciBlock block, FrameStateBuilder state) { for (ExplodedLoopContext context : explodeLoopsContext) { if (context.header == block) { @@ -2039,7 +2138,7 @@ * Returns a block begin node with the specified state. If the specified probability is * 0, the block deoptimizes immediately. */ - private AbstractBeginNode createBlockTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) { + private AbstractBeginNode createBlockTarget(double probability, BciBlock block, FrameStateBuilder stateAfter) { FixedNode target = createTarget(probability, block, stateAfter); AbstractBeginNode begin = BeginNode.begin(target); @@ -2048,7 +2147,7 @@ return begin; } - private ValueNode synchronizedObject(HIRFrameStateBuilder state, ResolvedJavaMethod target) { + private ValueNode synchronizedObject(FrameStateBuilder state, ResolvedJavaMethod target) { if (target.isStatic()) { return appendConstant(target.getDeclaringClass().getJavaClass()); } else { @@ -2187,7 +2286,6 @@ } } - @Override protected void iterateBytecodesForBlock(BciBlock block) { if (block.isLoopHeader && !explodeLoops) { // Create the loop header block, which later will merge the backward branches of @@ -2197,7 +2295,7 @@ lastInstr = loopBegin; // Create phi functions for all local variables and operand stack slots. - frameState.insertLoopPhis(liveness, block.loopId, loopBegin); + frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis()); loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin)); /* @@ -2282,6 +2380,11 @@ } } + /* Also a hook for subclasses. */ + protected boolean forceLoopPhis() { + return graph.isOSR(); + } + protected boolean checkLastInstruction() { if (lastInstr instanceof BeginNode) { // ignore @@ -2310,7 +2413,7 @@ * @param state The current frame state. * @return Returns the (new) last instruction. */ - protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, HIRFrameStateBuilder state) { + protected FixedWithNextNode finishInstruction(FixedWithNextNode instr, FrameStateBuilder state) { return instr; } @@ -2350,7 +2453,6 @@ } } - @Override protected void genIf(ValueNode x, Condition cond, ValueNode y) { assert currentBlock.getSuccessorCount() == 2; BciBlock trueBlock = currentBlock.getSuccessor(0); @@ -2600,6 +2702,910 @@ private BytecodePosition createBytecodePosition() { return frameState.createBytecodePosition(bci()); } + + public void setCurrentFrameState(FrameStateBuilder frameState) { + this.frameState = frameState; + } + + protected final BytecodeStream getStream() { + return stream; + } + + public int bci() { + return stream.currentBCI(); + } + + public void loadLocal(int index, Kind kind) { + frameState.push(kind, frameState.loadLocal(index)); + } + + public void storeLocal(Kind kind, int index) { + ValueNode value; + if (kind == Kind.Object) { + value = frameState.xpop(); + // astore and astore_ may be used to store a returnAddress (jsr) + assert parsingIntrinsic() || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind(); + } else { + value = frameState.pop(kind); + } + frameState.storeLocal(index, value, kind); + } + + private void genLoadConstant(int cpi, int opcode) { + Object con = lookupConstant(cpi, opcode); + + if (con instanceof JavaType) { + // this is a load of class constant which might be unresolved + JavaType type = (JavaType) con; + if (type instanceof ResolvedJavaType) { + frameState.push(Kind.Object, appendConstant(((ResolvedJavaType) type).getJavaClass())); + } else { + handleUnresolvedLoadConstant(type); + } + } else if (con instanceof JavaConstant) { + JavaConstant constant = (JavaConstant) con; + frameState.push(constant.getKind().getStackKind(), appendConstant(constant)); + } else { + throw new Error("lookupConstant returned an object of incorrect type"); + } + } + + private void genLoadIndexed(Kind kind) { + ValueNode index = frameState.ipop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); + if (!tryLoadIndexedPlugin(kind, index, array)) { + frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind))); + } + } + + protected boolean tryLoadIndexedPlugin(Kind kind, ValueNode index, ValueNode array) { + LoadIndexedPlugin loadIndexedPlugin = graphBuilderConfig.getPlugins().getLoadIndexedPlugin(); + if (loadIndexedPlugin != null && loadIndexedPlugin.apply(this, array, index, kind)) { + if (TraceParserPlugins.getValue()) { + traceWithContext("used load indexed plugin"); + } + return true; + } else { + return false; + } + } + + private void genStoreIndexed(Kind kind) { + ValueNode value = frameState.pop(kind.getStackKind()); + ValueNode index = frameState.ipop(); + ValueNode array = emitExplicitExceptions(frameState.apop(), index); + genStoreIndexed(array, index, kind, value); + } + + private void stackOp(int opcode) { + switch (opcode) { + case DUP_X1: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP_X2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X1: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case DUP2_X2: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + ValueNode w3 = frameState.xpop(); + ValueNode w4 = frameState.xpop(); + frameState.xpush(w2); + frameState.xpush(w1); + frameState.xpush(w4); + frameState.xpush(w3); + frameState.xpush(w2); + frameState.xpush(w1); + break; + } + case SWAP: { + ValueNode w1 = frameState.xpop(); + ValueNode w2 = frameState.xpop(); + frameState.xpush(w1); + frameState.xpush(w2); + break; + } + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private void genArithmeticOp(Kind result, int opcode) { + ValueNode y = frameState.pop(result); + ValueNode x = frameState.pop(result); + ValueNode v; + switch (opcode) { + case IADD: + case LADD: + v = genIntegerAdd(x, y); + break; + case FADD: + case DADD: + v = genFloatAdd(x, y); + break; + case ISUB: + case LSUB: + v = genIntegerSub(x, y); + break; + case FSUB: + case DSUB: + v = genFloatSub(x, y); + break; + case IMUL: + case LMUL: + v = genIntegerMul(x, y); + break; + case FMUL: + case DMUL: + v = genFloatMul(x, y); + break; + case FDIV: + case DDIV: + v = genFloatDiv(x, y); + break; + case FREM: + case DREM: + v = genFloatRem(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(result, append(v)); + } + + private void genIntegerDivOp(Kind result, int opcode) { + ValueNode y = frameState.pop(result); + ValueNode x = frameState.pop(result); + ValueNode v; + switch (opcode) { + case IDIV: + case LDIV: + v = genIntegerDiv(x, y); + break; + case IREM: + case LREM: + v = genIntegerRem(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(result, append(v)); + } + + private void genNegateOp(Kind kind) { + frameState.push(kind, append(genNegateOp(frameState.pop(kind)))); + } + + private void genShiftOp(Kind kind, int opcode) { + ValueNode s = frameState.ipop(); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case ISHL: + case LSHL: + v = genLeftShift(x, s); + break; + case ISHR: + case LSHR: + v = genRightShift(x, s); + break; + case IUSHR: + case LUSHR: + v = genUnsignedRightShift(x, s); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genLogicOp(Kind kind, int opcode) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + ValueNode v; + switch (opcode) { + case IAND: + case LAND: + v = genAnd(x, y); + break; + case IOR: + case LOR: + v = genOr(x, y); + break; + case IXOR: + case LXOR: + v = genXor(x, y); + break; + default: + throw new GraalInternalError("should not reach"); + } + frameState.push(kind, append(v)); + } + + private void genCompareOp(Kind kind, boolean isUnorderedLess) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess))); + } + + private void genFloatConvert(FloatConvert op, Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(genFloatConvert(op, input))); + } + + private void genSignExtend(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(genSignExtend(input, to.getBitCount()))); + } + + private void genZeroExtend(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + if (from != from.getStackKind()) { + input = append(genNarrow(input, from.getBitCount())); + } + frameState.push(to.getStackKind(), append(genZeroExtend(input, to.getBitCount()))); + } + + private void genNarrow(Kind from, Kind to) { + ValueNode input = frameState.pop(from.getStackKind()); + frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount()))); + } + + private void genIncrement() { + int index = getStream().readLocalIndex(); + int delta = getStream().readIncrement(); + ValueNode x = frameState.loadLocal(index); + ValueNode y = appendConstant(JavaConstant.forInt(delta)); + frameState.storeLocal(index, append(genIntegerAdd(x, y))); + } + + private void genIfZero(Condition cond) { + ValueNode y = appendConstant(JavaConstant.INT_0); + ValueNode x = frameState.ipop(); + genIf(x, cond, y); + } + + private void genIfNull(Condition cond) { + ValueNode y = appendConstant(JavaConstant.NULL_POINTER); + ValueNode x = frameState.apop(); + genIf(x, cond, y); + } + + private void genIfSame(Kind kind, Condition cond) { + ValueNode y = frameState.pop(kind); + ValueNode x = frameState.pop(kind); + genIf(x, cond, y); + } + + protected JavaType lookupType(int cpi, int bytecode) { + maybeEagerlyResolve(cpi, bytecode); + JavaType result = constantPool.lookupType(cpi, bytecode); + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; + return result; + } + + private JavaMethod lookupMethod(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaMethod result = constantPool.lookupMethod(cpi, opcode); + /* + * In general, one cannot assume that the declaring class being initialized is + * useful, since the actual concrete receiver may be a different class (except for + * static calls). Also, interfaces are initialized only under special circumstances, + * so that this assertion would often fail for interface calls. + */ + assert !graphBuilderConfig.unresolvedIsError() || + (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result; + return result; + } + + private JavaField lookupField(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + JavaField result = constantPool.lookupField(cpi, opcode); + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + return result; + } + + private Object lookupConstant(int cpi, int opcode) { + maybeEagerlyResolve(cpi, opcode); + Object result = constantPool.lookupConstant(cpi); + assert !graphBuilderConfig.eagerResolving() || !(result instanceof JavaType) || (result instanceof ResolvedJavaType) : result; + return result; + } + + private void maybeEagerlyResolve(int cpi, int bytecode) { + if (graphBuilderConfig.eagerResolving() || intrinsicContext != null) { + constantPool.loadReferencedType(cpi, bytecode); + } + } + + private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { + if (parsingIntrinsic() || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { + return null; + } else { + return profilingInfo.getTypeProfile(bci()); + } + } + + private void genCheckCast() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, CHECKCAST); + ValueNode object = frameState.apop(); + if (type instanceof ResolvedJavaType) { + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) { + ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false)); + frameState.apush(checkCastNode); + } + } else { + handleUnresolvedCheckCast(type, object); + } + } + + private void genInstanceOf() { + int cpi = getStream().readCPI(); + JavaType type = lookupType(cpi, INSTANCEOF); + ValueNode object = frameState.apop(); + if (type instanceof ResolvedJavaType) { + ResolvedJavaType resolvedType = (ResolvedJavaType) type; + JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin(); + if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) { + ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile); + frameState.ipush(append(genConditional(genUnique(instanceOfNode)))); + } + } else { + handleUnresolvedInstanceOf(type, object); + } + } + + void genNewInstance(int cpi) { + JavaType type = lookupType(cpi, NEW); + if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) { + ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); + if (skippedExceptionTypes != null) { + for (ResolvedJavaType exceptionType : skippedExceptionTypes) { + if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) { + append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter)); + return; + } + } + } + frameState.apush(append(createNewInstance((ResolvedJavaType) type, true))); + } else { + handleUnresolvedNewInstance(type); + } + } + + private void genNewPrimitiveArray(int typeCode) { + Class clazz = arrayTypeCodeToClass(typeCode); + ResolvedJavaType elementType = metaAccess.lookupJavaType(clazz); + frameState.apush(append(createNewArray(elementType, frameState.ipop(), true))); + } + + private void genNewObjectArray(int cpi) { + JavaType type = lookupType(cpi, ANEWARRAY); + ValueNode length = frameState.ipop(); + if (type instanceof ResolvedJavaType) { + frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true))); + } else { + handleUnresolvedNewObjectArray(type, length); + } + + } + + private void genNewMultiArray(int cpi) { + JavaType type = lookupType(cpi, MULTIANEWARRAY); + int rank = getStream().readUByte(bci() + 3); + List dims = new ArrayList<>(Collections.nCopies(rank, null)); + for (int i = rank - 1; i >= 0; i--) { + dims.set(i, frameState.ipop()); + } + if (type instanceof ResolvedJavaType) { + frameState.apush(append(createNewMultiArray((ResolvedJavaType) type, dims))); + } else { + handleUnresolvedNewMultiArray(type, dims); + } + } + + private void genGetField(JavaField field) { + Kind kind = field.getKind(); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); + if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) { + appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field)); + } + } else { + handleUnresolvedLoadField(field, receiver); + } + } + + /** + * @param receiver the receiver of an object based operation + * @param index the index of an array based operation that is to be tested for out of + * bounds. This is null for a non-array operation. + * @return the receiver value possibly modified to have a tighter stamp + */ + protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) { + assert receiver != null; + if (graphBuilderConfig.omitAllExceptionEdges() || + profilingInfo == null || + (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) { + return receiver; + } + + ValueNode nonNullReceiver = emitExplicitNullCheck(receiver); + if (index != null) { + ValueNode length = append(genArrayLength(nonNullReceiver)); + emitExplicitBoundsCheck(index, length); + } + EXPLICIT_EXCEPTIONS.increment(); + return nonNullReceiver; + } + + private void genPutField(JavaField field) { + ValueNode value = frameState.pop(field.getKind().getStackKind()); + ValueNode receiver = emitExplicitExceptions(frameState.apop(), null); + if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) { + genStoreField(receiver, (ResolvedJavaField) field, value); + } else { + handleUnresolvedStoreField(field, value, receiver); + } + } + + private void genGetStatic(JavaField field) { + Kind kind = field.getKind(); + if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + // Javac does not allow use of "$assertionsDisabled" for a field name but + // Eclipse does in which case a suffix is added to the generated field. + if ((parsingIntrinsic() || graphBuilderConfig.omitAssertions()) && resolvedField.isSynthetic() && resolvedField.getName().startsWith("$assertionsDisabled")) { + appendOptimizedLoadField(kind, ConstantNode.forBoolean(true)); + return; + } + + LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin(); + if (loadFieldPlugin == null || !loadFieldPlugin.apply(this, resolvedField)) { + appendOptimizedLoadField(kind, genLoadField(null, resolvedField)); + } + } else { + handleUnresolvedLoadField(field, null); + } + } + + public boolean tryLoadFieldPlugin(JavaField field, LoadFieldPlugin loadFieldPlugin) { + return loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field); + } + + private void genPutStatic(JavaField field) { + ValueNode value = frameState.pop(field.getKind().getStackKind()); + if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { + genStoreField(null, (ResolvedJavaField) field, value); + } else { + handleUnresolvedStoreField(field, value, null); + } + } + + protected void appendOptimizedLoadField(Kind kind, ValueNode load) { + // append the load to the instruction + ValueNode optimized = append(load); + frameState.push(kind.getStackKind(), optimized); + } + + private double[] switchProbability(int numberOfCases, int bci) { + double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci)); + if (prob != null) { + assert prob.length == numberOfCases; + } else { + Debug.log("Missing probability (switch) in %s at bci %d", method, bci); + prob = new double[numberOfCases]; + for (int i = 0; i < numberOfCases; i++) { + prob[i] = 1.0d / numberOfCases; + } + } + assert allPositive(prob); + return prob; + } + + private void genSwitch(BytecodeSwitch bs) { + int bci = bci(); + ValueNode value = frameState.ipop(); + + int nofCases = bs.numberOfCases(); + double[] keyProbabilities = switchProbability(nofCases + 1, bci); + + Map bciToBlockSuccessorIndex = new HashMap<>(); + for (int i = 0; i < currentBlock.getSuccessorCount(); i++) { + assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci); + if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) { + bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i)); + } + } + + ArrayList actualSuccessors = new ArrayList<>(); + int[] keys = new int[nofCases]; + int[] keySuccessors = new int[nofCases + 1]; + int deoptSuccessorIndex = -1; + int nextSuccessorIndex = 0; + boolean constantValue = value.isConstant(); + for (int i = 0; i < nofCases + 1; i++) { + if (i < nofCases) { + keys[i] = bs.keyAt(i); + } + + if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) { + if (deoptSuccessorIndex < 0) { + deoptSuccessorIndex = nextSuccessorIndex++; + actualSuccessors.add(null); + } + keySuccessors[i] = deoptSuccessorIndex; + } else { + int targetBci = i >= nofCases ? bs.defaultTarget() : bs.targetAt(i); + SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci); + if (info.actualIndex < 0) { + info.actualIndex = nextSuccessorIndex++; + actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex)); + } + keySuccessors[i] = info.actualIndex; + } + } + + genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors); + + } + + protected boolean isNeverExecutedCode(double probability) { + return probability == 0 && optimisticOpts.removeNeverExecutedCode(); + } + + protected double branchProbability() { + if (profilingInfo == null) { + return 0.5; + } + assert assertAtIfBytecode(); + double probability = profilingInfo.getBranchTakenProbability(bci()); + if (probability < 0) { + assert probability == -1 : "invalid probability"; + Debug.log("missing probability in %s at bci %d", method, bci()); + probability = 0.5; + } + + if (!optimisticOpts.removeNeverExecutedCode()) { + if (probability == 0) { + probability = 0.0000001; + } else if (probability == 1) { + probability = 0.999999; + } + } + return probability; + } + + private boolean assertAtIfBytecode() { + int bytecode = stream.currentBC(); + switch (bytecode) { + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + case IFNULL: + case IFNONNULL: + return true; + } + assert false : String.format("%x is not an if bytecode", bytecode); + return true; + } + + public final void processBytecode(int bci, int opcode) { + int cpi; + + // Checkstyle: stop + // @formatter:off + switch (opcode) { + case NOP : /* nothing to do */ break; + case ACONST_NULL : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break; + case ICONST_M1 : // fall through + case ICONST_0 : // fall through + case ICONST_1 : // fall through + case ICONST_2 : // fall through + case ICONST_3 : // fall through + case ICONST_4 : // fall through + case ICONST_5 : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break; + case LCONST_0 : // fall through + case LCONST_1 : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break; + case FCONST_0 : // fall through + case FCONST_1 : // fall through + case FCONST_2 : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break; + case DCONST_0 : // fall through + case DCONST_1 : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break; + case BIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break; + case SIPUSH : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break; + case LDC : // fall through + case LDC_W : // fall through + case LDC2_W : genLoadConstant(stream.readCPI(), opcode); break; + case ILOAD : loadLocal(stream.readLocalIndex(), Kind.Int); break; + case LLOAD : loadLocal(stream.readLocalIndex(), Kind.Long); break; + case FLOAD : loadLocal(stream.readLocalIndex(), Kind.Float); break; + case DLOAD : loadLocal(stream.readLocalIndex(), Kind.Double); break; + case ALOAD : loadLocal(stream.readLocalIndex(), Kind.Object); break; + case ILOAD_0 : // fall through + case ILOAD_1 : // fall through + case ILOAD_2 : // fall through + case ILOAD_3 : loadLocal(opcode - ILOAD_0, Kind.Int); break; + case LLOAD_0 : // fall through + case LLOAD_1 : // fall through + case LLOAD_2 : // fall through + case LLOAD_3 : loadLocal(opcode - LLOAD_0, Kind.Long); break; + case FLOAD_0 : // fall through + case FLOAD_1 : // fall through + case FLOAD_2 : // fall through + case FLOAD_3 : loadLocal(opcode - FLOAD_0, Kind.Float); break; + case DLOAD_0 : // fall through + case DLOAD_1 : // fall through + case DLOAD_2 : // fall through + case DLOAD_3 : loadLocal(opcode - DLOAD_0, Kind.Double); break; + case ALOAD_0 : // fall through + case ALOAD_1 : // fall through + case ALOAD_2 : // fall through + case ALOAD_3 : loadLocal(opcode - ALOAD_0, Kind.Object); break; + case IALOAD : genLoadIndexed(Kind.Int ); break; + case LALOAD : genLoadIndexed(Kind.Long ); break; + case FALOAD : genLoadIndexed(Kind.Float ); break; + case DALOAD : genLoadIndexed(Kind.Double); break; + case AALOAD : genLoadIndexed(Kind.Object); break; + case BALOAD : genLoadIndexed(Kind.Byte ); break; + case CALOAD : genLoadIndexed(Kind.Char ); break; + case SALOAD : genLoadIndexed(Kind.Short ); break; + case ISTORE : storeLocal(Kind.Int, stream.readLocalIndex()); break; + case LSTORE : storeLocal(Kind.Long, stream.readLocalIndex()); break; + case FSTORE : storeLocal(Kind.Float, stream.readLocalIndex()); break; + case DSTORE : storeLocal(Kind.Double, stream.readLocalIndex()); break; + case ASTORE : storeLocal(Kind.Object, stream.readLocalIndex()); break; + case ISTORE_0 : // fall through + case ISTORE_1 : // fall through + case ISTORE_2 : // fall through + case ISTORE_3 : storeLocal(Kind.Int, opcode - ISTORE_0); break; + case LSTORE_0 : // fall through + case LSTORE_1 : // fall through + case LSTORE_2 : // fall through + case LSTORE_3 : storeLocal(Kind.Long, opcode - LSTORE_0); break; + case FSTORE_0 : // fall through + case FSTORE_1 : // fall through + case FSTORE_2 : // fall through + case FSTORE_3 : storeLocal(Kind.Float, opcode - FSTORE_0); break; + case DSTORE_0 : // fall through + case DSTORE_1 : // fall through + case DSTORE_2 : // fall through + case DSTORE_3 : storeLocal(Kind.Double, opcode - DSTORE_0); break; + case ASTORE_0 : // fall through + case ASTORE_1 : // fall through + case ASTORE_2 : // fall through + case ASTORE_3 : storeLocal(Kind.Object, opcode - ASTORE_0); break; + case IASTORE : genStoreIndexed(Kind.Int ); break; + case LASTORE : genStoreIndexed(Kind.Long ); break; + case FASTORE : genStoreIndexed(Kind.Float ); break; + case DASTORE : genStoreIndexed(Kind.Double); break; + case AASTORE : genStoreIndexed(Kind.Object); break; + case BASTORE : genStoreIndexed(Kind.Byte ); break; + case CASTORE : genStoreIndexed(Kind.Char ); break; + case SASTORE : genStoreIndexed(Kind.Short ); break; + case POP : frameState.xpop(); break; + case POP2 : frameState.xpop(); frameState.xpop(); break; + case DUP : frameState.xpush(frameState.xpeek()); break; + case DUP_X1 : // fall through + case DUP_X2 : // fall through + case DUP2 : // fall through + case DUP2_X1 : // fall through + case DUP2_X2 : // fall through + case SWAP : stackOp(opcode); break; + case IADD : // fall through + case ISUB : // fall through + case IMUL : genArithmeticOp(Kind.Int, opcode); break; + case IDIV : // fall through + case IREM : genIntegerDivOp(Kind.Int, opcode); break; + case LADD : // fall through + case LSUB : // fall through + case LMUL : genArithmeticOp(Kind.Long, opcode); break; + case LDIV : // fall through + case LREM : genIntegerDivOp(Kind.Long, opcode); break; + case FADD : // fall through + case FSUB : // fall through + case FMUL : // fall through + case FDIV : // fall through + case FREM : genArithmeticOp(Kind.Float, opcode); break; + case DADD : // fall through + case DSUB : // fall through + case DMUL : // fall through + case DDIV : // fall through + case DREM : genArithmeticOp(Kind.Double, opcode); break; + case INEG : genNegateOp(Kind.Int); break; + case LNEG : genNegateOp(Kind.Long); break; + case FNEG : genNegateOp(Kind.Float); break; + case DNEG : genNegateOp(Kind.Double); break; + case ISHL : // fall through + case ISHR : // fall through + case IUSHR : genShiftOp(Kind.Int, opcode); break; + case IAND : // fall through + case IOR : // fall through + case IXOR : genLogicOp(Kind.Int, opcode); break; + case LSHL : // fall through + case LSHR : // fall through + case LUSHR : genShiftOp(Kind.Long, opcode); break; + case LAND : // fall through + case LOR : // fall through + case LXOR : genLogicOp(Kind.Long, opcode); break; + case IINC : genIncrement(); break; + case I2F : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break; + case I2D : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break; + case L2F : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break; + case L2D : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break; + case F2I : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break; + case F2L : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break; + case F2D : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break; + case D2I : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break; + case D2L : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break; + case D2F : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break; + case L2I : genNarrow(Kind.Long, Kind.Int); break; + case I2L : genSignExtend(Kind.Int, Kind.Long); break; + case I2B : genSignExtend(Kind.Byte, Kind.Int); break; + case I2S : genSignExtend(Kind.Short, Kind.Int); break; + case I2C : genZeroExtend(Kind.Char, Kind.Int); break; + case LCMP : genCompareOp(Kind.Long, false); break; + case FCMPL : genCompareOp(Kind.Float, true); break; + case FCMPG : genCompareOp(Kind.Float, false); break; + case DCMPL : genCompareOp(Kind.Double, true); break; + case DCMPG : genCompareOp(Kind.Double, false); break; + case IFEQ : genIfZero(Condition.EQ); break; + case IFNE : genIfZero(Condition.NE); break; + case IFLT : genIfZero(Condition.LT); break; + case IFGE : genIfZero(Condition.GE); break; + case IFGT : genIfZero(Condition.GT); break; + case IFLE : genIfZero(Condition.LE); break; + case IF_ICMPEQ : genIfSame(Kind.Int, Condition.EQ); break; + case IF_ICMPNE : genIfSame(Kind.Int, Condition.NE); break; + case IF_ICMPLT : genIfSame(Kind.Int, Condition.LT); break; + case IF_ICMPGE : genIfSame(Kind.Int, Condition.GE); break; + case IF_ICMPGT : genIfSame(Kind.Int, Condition.GT); break; + case IF_ICMPLE : genIfSame(Kind.Int, Condition.LE); break; + case IF_ACMPEQ : genIfSame(Kind.Object, Condition.EQ); break; + case IF_ACMPNE : genIfSame(Kind.Object, Condition.NE); break; + case GOTO : genGoto(); break; + case JSR : genJsr(stream.readBranchDest()); break; + case RET : genRet(stream.readLocalIndex()); break; + case TABLESWITCH : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break; + case LOOKUPSWITCH : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break; + case IRETURN : genReturn(frameState.ipop(), Kind.Int); break; + case LRETURN : genReturn(frameState.lpop(), Kind.Long); break; + case FRETURN : genReturn(frameState.fpop(), Kind.Float); break; + case DRETURN : genReturn(frameState.dpop(), Kind.Double); break; + case ARETURN : genReturn(frameState.apop(), Kind.Object); break; + case RETURN : genReturn(null, Kind.Void); break; + case GETSTATIC : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break; + case PUTSTATIC : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break; + case GETFIELD : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break; + case PUTFIELD : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break; + case INVOKEVIRTUAL : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break; + case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; + case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; + case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; + case NEW : genNewInstance(stream.readCPI()); break; + case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; + case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; + case ARRAYLENGTH : genArrayLength(); break; + case ATHROW : genThrow(); break; + case CHECKCAST : genCheckCast(); break; + case INSTANCEOF : genInstanceOf(); break; + case MONITORENTER : genMonitorEnter(frameState.apop(), stream.nextBCI()); break; + case MONITOREXIT : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break; + case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; + case IFNULL : genIfNull(Condition.EQ); break; + case IFNONNULL : genIfNull(Condition.NE); break; + case GOTO_W : genGoto(); break; + case JSR_W : genJsr(stream.readBranchDest()); break; + case BREAKPOINT: + throw new BailoutException("concurrent setting of breakpoint"); + default: + throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci); + } + // @formatter:on + // Checkstyle: resume + } + + private void genArrayLength() { + frameState.ipush(append(genArrayLength(frameState.apop()))); + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + public FrameStateBuilder getFrameStateBuilder() { + return frameState; + } + + protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { + if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) { + traceInstructionHelper(bci, opcode, blockStart); + } + return true; + } + + private void traceInstructionHelper(int bci, int opcode, boolean blockStart) { + StringBuilder sb = new StringBuilder(40); + sb.append(blockStart ? '+' : '|'); + if (bci < 10) { + sb.append(" "); + } else if (bci < 100) { + sb.append(' '); + } + sb.append(bci).append(": ").append(Bytecodes.nameOf(opcode)); + for (int i = bci + 1; i < stream.nextBCI(); ++i) { + sb.append(' ').append(stream.readUByte(i)); + } + if (!currentBlock.getJsrScope().isEmpty()) { + sb.append(' ').append(currentBlock.getJsrScope()); + } + Debug.log("%s", sb); + } + + public boolean parsingIntrinsic() { + return intrinsicContext != null; + } + + public BytecodeParser getNonIntrinsicAncestor() { + BytecodeParser ancestor = parent; + while (ancestor != null && ancestor.parsingIntrinsic()) { + ancestor = ancestor.parent; + } + return ancestor; + } } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1020 +0,0 @@ -/* - * Copyright (c) 2012, 2015, 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; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.compiler.common.type.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.IntrinsicContext.*; -import com.oracle.graal.java.BciBlockMapping.BciBlock; -import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser; -import com.oracle.graal.nodeinfo.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.util.*; - -public final class HIRFrameStateBuilder implements SideEffectsState { - - static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; - static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; - - protected final BytecodeParser parser; - protected final ResolvedJavaMethod method; - protected int stackSize; - protected final ValueNode[] locals; - protected final ValueNode[] stack; - protected ValueNode[] lockedObjects; - - /** - * @see BytecodeFrame#rethrowException - */ - protected boolean rethrowException; - - private MonitorIdNode[] monitorIds; - private final StructuredGraph graph; - private FrameState outerFrameState; - - /** - * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more - * than one when the current block contains no side-effects but merging predecessor blocks do. - */ - protected List sideEffects; - - /** - * Creates a new frame state builder for the given method and the given target graph. - * - * @param method the method whose frame is simulated - * @param graph the target graph of Graal nodes created by the builder - */ - public HIRFrameStateBuilder(BytecodeParser parser, ResolvedJavaMethod method, StructuredGraph graph) { - this.parser = parser; - this.method = method; - this.locals = allocateArray(method.getMaxLocals()); - this.stack = allocateArray(Math.max(1, method.getMaxStackSize())); - this.lockedObjects = allocateArray(0); - - assert graph != null; - - this.monitorIds = EMPTY_MONITOR_ARRAY; - this.graph = graph; - } - - public void initializeFromArgumentsArray(ValueNode[] arguments) { - - int javaIndex = 0; - int index = 0; - if (!method.isStatic()) { - // set the receiver - locals[javaIndex] = arguments[index]; - javaIndex = 1; - index = 1; - } - Signature sig = method.getSignature(); - int max = sig.getParameterCount(false); - for (int i = 0; i < max; i++) { - Kind kind = sig.getParameterKind(i); - locals[javaIndex] = arguments[index]; - javaIndex += kind.getSlotCount(); - index++; - } - } - - public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { - - int javaIndex = 0; - int index = 0; - if (!method.isStatic()) { - // add the receiver - FloatingNode receiver = null; - Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass()); - if (parameterPlugin != null) { - receiver = parameterPlugin.interceptParameter(parser, index, receiverStamp); - } - if (receiver == null) { - receiver = new ParameterNode(javaIndex, receiverStamp); - } - locals[javaIndex] = graph.unique(receiver); - javaIndex = 1; - index = 1; - } - Signature sig = method.getSignature(); - int max = sig.getParameterCount(false); - ResolvedJavaType accessingClass = method.getDeclaringClass(); - for (int i = 0; i < max; i++) { - JavaType type = sig.getParameterType(i, accessingClass); - if (eagerResolve) { - type = type.resolve(accessingClass); - } - Kind kind = type.getKind(); - Stamp stamp; - if (kind == Kind.Object && type instanceof ResolvedJavaType) { - stamp = StampFactory.declared((ResolvedJavaType) type); - } else { - stamp = StampFactory.forKind(kind); - } - FloatingNode param = null; - if (parameterPlugin != null) { - param = parameterPlugin.interceptParameter(parser, index, stamp); - } - if (param == null) { - param = new ParameterNode(index, stamp); - } - locals[javaIndex] = graph.unique(param); - javaIndex += kind.getSlotCount(); - index++; - } - } - - private HIRFrameStateBuilder(HIRFrameStateBuilder other) { - this.parser = other.parser; - this.method = other.method; - this.stackSize = other.stackSize; - this.locals = other.locals.clone(); - this.stack = other.stack.clone(); - this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); - this.rethrowException = other.rethrowException; - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - - assert other.graph != null; - graph = other.graph; - monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); - - assert locals.length == method.getMaxLocals(); - assert stack.length == Math.max(1, method.getMaxStackSize()); - assert lockedObjects.length == monitorIds.length; - } - - private static ValueNode[] allocateArray(int length) { - return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[locals: ["); - for (int i = 0; i < locals.length; i++) { - sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString(Verbosity.Id)); - } - sb.append("] stack: ["); - for (int i = 0; i < stackSize; i++) { - sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString(Verbosity.Id)); - } - sb.append("] locks: ["); - for (int i = 0; i < lockedObjects.length; i++) { - sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); - } - sb.append("]"); - if (rethrowException) { - sb.append(" rethrowException"); - } - sb.append("]"); - return sb.toString(); - } - - public FrameState create(int bci, StateSplit forStateSplit) { - if (parser.parsingIntrinsic()) { - return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit); - } - - // Skip intrinsic frames - BytecodeParser parent = (BytecodeParser) parser.getNonReplacementAncestor(); - return create(bci, parent, false); - } - - public FrameState create(int bci, BytecodeParser parent, boolean duringCall) { - if (outerFrameState == null && parent != null) { - outerFrameState = parent.getFrameState().create(parent.bci(), null); - } - if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { - FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0)); - return newFrameState; - } - if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { - throw GraalInternalError.shouldNotReachHere(); - } - return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); - } - - public BytecodePosition createBytecodePosition(int bci) { - BytecodeParser parent = parser.getParent(); - if (AbstractBytecodeParser.Options.HideSubstitutionStates.getValue()) { - if (parser.parsingIntrinsic()) { - // Attribute to the method being replaced - return new BytecodePosition(parent.getFrameState().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1); - } - // Skip intrinsic frames - parent = (BytecodeParser) parser.getNonReplacementAncestor(); - } - return create(null, bci, parent); - } - - private BytecodePosition create(BytecodePosition o, int bci, BytecodeParser parent) { - BytecodePosition outer = o; - if (outer == null && parent != null) { - outer = parent.getFrameState().createBytecodePosition(parent.bci()); - } - if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { - return FrameState.toBytecodePosition(outerFrameState); - } - if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { - throw GraalInternalError.shouldNotReachHere(); - } - return new BytecodePosition(outer, method, bci); - } - - public HIRFrameStateBuilder copy() { - return new HIRFrameStateBuilder(this); - } - - public boolean isCompatibleWith(HIRFrameStateBuilder other) { - assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; - assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; - - if (stackSize() != other.stackSize()) { - return false; - } - for (int i = 0; i < stackSize(); i++) { - ValueNode x = stackAt(i); - ValueNode y = other.stackAt(i); - if (x != y && (x == null || x.isDeleted() || y == null || y.isDeleted() || x.getKind() != y.getKind())) { - return false; - } - } - if (lockedObjects.length != other.lockedObjects.length) { - return false; - } - for (int i = 0; i < lockedObjects.length; i++) { - if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { - throw new BailoutException("unbalanced monitors"); - } - } - return true; - } - - public void merge(AbstractMergeNode block, HIRFrameStateBuilder other) { - assert isCompatibleWith(other); - - for (int i = 0; i < localsSize(); i++) { - ValueNode curLocal = localAt(i); - ValueNode mergedLocal = merge(curLocal, other.localAt(i), block); - if (curLocal != mergedLocal) { - storeLocal(i, mergedLocal); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode curStack = stackAt(i); - ValueNode mergedStack = merge(curStack, other.stackAt(i), block); - if (curStack != mergedStack) { - storeStack(i, mergedStack); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); - assert monitorIds[i] == other.monitorIds[i]; - } - - if (sideEffects == null) { - sideEffects = other.sideEffects; - } else { - if (other.sideEffects != null) { - sideEffects.addAll(other.sideEffects); - } - } - } - - private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { - if (currentValue == null || currentValue.isDeleted()) { - return null; - } else if (block.isPhiAtMerge(currentValue)) { - if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { - propagateDelete((ValuePhiNode) currentValue); - return null; - } - ((PhiNode) currentValue).addInput(otherValue); - return currentValue; - } else if (currentValue != otherValue) { - assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); - if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) { - return null; - } - return createValuePhi(currentValue, otherValue, block); - } else { - return currentValue; - } - } - - private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { - ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block)); - for (int i = 0; i < block.phiPredecessorCount(); i++) { - phi.addInput(currentValue); - } - phi.addInput(otherValue); - assert phi.valueCount() == block.phiPredecessorCount() + 1; - return phi; - } - - private void propagateDelete(FloatingNode node) { - assert node instanceof ValuePhiNode || node instanceof ProxyNode; - if (node.isDeleted()) { - return; - } - // Collect all phi functions that use this phi so that we can delete them recursively (after - // we delete ourselves to avoid circles). - List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(ValuePhiNode.class).or(ProxyNode.class)).snapshot(); - - // Remove the phi function from all FrameStates where it is used and then delete it. - assert node.usages().filter(isNotA(FrameState.class).nor(ValuePhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; - node.replaceAtUsages(null); - node.safeDelete(); - - for (FloatingNode phiUsage : propagateUsages) { - propagateDelete(phiUsage); - } - } - - public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin) { - for (int i = 0; i < localsSize(); i++) { - if (loopBegin.graph().isOSR() || liveness.localIsChangedInLoop(loopId, i)) { - storeLocal(i, createLoopPhi(loopBegin, localAt(i))); - } - } - for (int i = 0; i < stackSize(); i++) { - storeStack(i, createLoopPhi(loopBegin, stackAt(i))); - } - for (int i = 0; i < lockedObjects.length; i++) { - lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i]); - } - } - - public void insertLoopProxies(LoopExitNode loopExit, HIRFrameStateBuilder loopEntryState) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, loopExit, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); - } - } - } - - public void insertProxies(AbstractBeginNode begin) { - for (int i = 0; i < localsSize(); i++) { - ValueNode value = localAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeLocal(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < stackSize(); i++) { - ValueNode value = stackAt(i); - if (value != null) { - Debug.log(" inserting proxy for %s", value); - storeStack(i, ProxyNode.forValue(value, begin, graph)); - } - } - for (int i = 0; i < lockedObjects.length; i++) { - ValueNode value = lockedObjects[i]; - if (value != null) { - Debug.log(" inserting proxy for %s", value); - lockedObjects[i] = ProxyNode.forValue(value, begin, graph); - } - } - } - - private ValuePhiNode createLoopPhi(AbstractMergeNode block, ValueNode value) { - if (value == null) { - return null; - } - assert !block.isPhiAtMerge(value) : "phi function for this block already created"; - - ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(value.stamp().unrestricted(), block)); - phi.addInput(value); - return phi; - } - - /** - * Adds a locked monitor to this frame state. - * - * @param object the object whose monitor will be locked. - */ - public void pushLock(ValueNode object, MonitorIdNode monitorId) { - assert object.isAlive() && object.getKind() == Kind.Object : "unexpected value: " + object; - lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); - monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); - lockedObjects[lockedObjects.length - 1] = object; - monitorIds[monitorIds.length - 1] = monitorId; - assert lockedObjects.length == monitorIds.length; - } - - /** - * Removes a locked monitor from this frame state. - * - * @return the object whose monitor was removed from the locks list. - */ - public ValueNode popLock() { - try { - return lockedObjects[lockedObjects.length - 1]; - } finally { - lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); - monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); - assert lockedObjects.length == monitorIds.length; - } - } - - public MonitorIdNode peekMonitorId() { - return monitorIds[monitorIds.length - 1]; - } - - /** - * @return the current lock depth - */ - public int lockDepth() { - assert lockedObjects.length == monitorIds.length; - return lockedObjects.length; - } - - public boolean contains(ValueNode value) { - for (int i = 0; i < localsSize(); i++) { - if (localAt(i) == value) { - return true; - } - } - for (int i = 0; i < stackSize(); i++) { - if (stackAt(i) == value) { - return true; - } - } - assert lockedObjects.length == monitorIds.length; - for (int i = 0; i < lockedObjects.length; i++) { - if (lockedObjects[i] == value || monitorIds[i] == value) { - return true; - } - } - return false; - } - - public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { - /* - * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to - * remove it for normal compilations, but not for OSR compilations - otherwise dead object - * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with - * Kind.Illegal, because the conflicting branch might not have been parsed. - */ - if (liveness == null) { - return; - } - if (liveIn) { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveIn(block, i)) { - locals[i] = null; - } - } - } else { - for (int i = 0; i < locals.length; i++) { - if (!liveness.localIsLiveOut(block, i)) { - locals[i] = null; - } - } - } - } - - /** - * @see BytecodeFrame#rethrowException - */ - public boolean rethrowException() { - return rethrowException; - } - - /** - * @see BytecodeFrame#rethrowException - */ - public void setRethrowException(boolean b) { - rethrowException = b; - } - - /** - * Returns the size of the local variables. - * - * @return the size of the local variables - */ - public int localsSize() { - return locals.length; - } - - /** - * Gets the current size (height) of the stack. - */ - public int stackSize() { - return stackSize; - } - - /** - * Gets the value in the local variables at the specified index, without any sanity checking. - * - * @param i the index into the locals - * @return the instruction that produced the value for the specified local - */ - public ValueNode localAt(int i) { - return locals[i]; - } - - /** - * Get the value on the stack at the specified stack index. - * - * @param i the index into the stack, with {@code 0} being the bottom of the stack - * @return the instruction at the specified position in the stack - */ - public ValueNode stackAt(int i) { - return stack[i]; - } - - /** - * Gets the value in the lock at the specified index, without any sanity checking. - * - * @param i the index into the lock - * @return the instruction that produced the value for the specified lock - */ - public ValueNode lockAt(int i) { - return lockedObjects[i]; - } - - public void storeLock(int i, ValueNode lock) { - lockedObjects[i] = lock; - } - - /** - * Loads the local variable at the specified index, checking that the returned value is non-null - * and that two-stack values are properly handled. - * - * @param i the index of the local variable to load - * @return the instruction that produced the specified local - */ - public ValueNode loadLocal(int i) { - ValueNode x = locals[i]; - assert assertLoadLocal(i, x); - return x; - } - - private boolean assertLoadLocal(int i, ValueNode x) { - assert x != null : i; - assert parser.parsingIntrinsic() || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null); - assert parser.parsingIntrinsic() || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1); - return true; - } - - public void storeLocal(int i, ValueNode x) { - storeLocal(i, x, x == null ? null : x.getKind()); - } - - /** - * Stores a given local variable at the specified index. If the value occupies two slots, then - * the next local variable index is also overwritten. - * - * @param i the index at which to store - * @param x the instruction which produces the value for the local - */ - public void storeLocal(int i, ValueNode x, Kind kind) { - assert assertStoreLocal(x); - locals[i] = x; - if (x != null) { - if (kind.needsTwoSlots() && !parser.parsingIntrinsic()) { - // if this is a double word, then kill i+1 - locals[i + 1] = null; - } - if (i > 0 && !parser.parsingIntrinsic()) { - ValueNode p = locals[i - 1]; - if (p != null && p.getKind().needsTwoSlots()) { - // if there was a double word at i - 1, then kill it - locals[i - 1] = null; - } - } - } - } - - private boolean assertStoreLocal(ValueNode x) { - assert x == null || parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x; - return true; - } - - public void storeStack(int i, ValueNode x) { - assert assertStoreStack(i, x); - stack[i] = x; - } - - private boolean assertStoreStack(int i, ValueNode x) { - assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values"; - return true; - } - - /** - * Pushes an instruction onto the stack with the expected type. - * - * @param kind the type expected for this instruction - * @param x the instruction to push onto the stack - */ - public void push(Kind kind, ValueNode x) { - assert assertPush(kind, x); - xpush(x); - if (kind.needsTwoSlots()) { - xpush(null); - } - } - - private boolean assertPush(Kind kind, ValueNode x) { - assert parser.parsingIntrinsic() || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal); - assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); - return true; - } - - /** - * Pushes a value onto the stack without checking the type. - * - * @param x the instruction to push onto the stack - */ - public void xpush(ValueNode x) { - assert assertXpush(x); - stack[stackSize++] = x; - } - - private boolean assertXpush(ValueNode x) { - assert parser.parsingIntrinsic() || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal)); - return true; - } - - /** - * Pushes a value onto the stack and checks that it is an int. - * - * @param x the instruction to push onto the stack - */ - public void ipush(ValueNode x) { - assert assertInt(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is a float. - * - * @param x the instruction to push onto the stack - */ - public void fpush(ValueNode x) { - assert assertFloat(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is an object. - * - * @param x the instruction to push onto the stack - */ - public void apush(ValueNode x) { - assert assertObject(x); - xpush(x); - } - - /** - * Pushes a value onto the stack and checks that it is a long. - * - * @param x the instruction to push onto the stack - */ - public void lpush(ValueNode x) { - assert assertLong(x); - xpush(x); - xpush(null); - } - - /** - * Pushes a value onto the stack and checks that it is a double. - * - * @param x the instruction to push onto the stack - */ - public void dpush(ValueNode x) { - assert assertDouble(x); - xpush(x); - xpush(null); - } - - public void pushReturn(Kind kind, ValueNode x) { - if (kind != Kind.Void) { - push(kind.getStackKind(), x); - } - } - - /** - * Pops an instruction off the stack with the expected type. - * - * @param kind the expected type - * @return the instruction on the top of the stack - */ - public ValueNode pop(Kind kind) { - if (kind.needsTwoSlots()) { - xpop(); - } - assert assertPop(kind); - return xpop(); - } - - private boolean assertPop(Kind kind) { - assert kind != Kind.Void; - ValueNode x = xpeek(); - assert x != null && (parser.parsingIntrinsic() || x.getKind() == kind); - return true; - } - - /** - * Pops a value off of the stack without checking the type. - * - * @return x the instruction popped off the stack - */ - public ValueNode xpop() { - return stack[--stackSize]; - } - - public ValueNode xpeek() { - return stack[stackSize - 1]; - } - - /** - * Pops a value off of the stack and checks that it is an int. - * - * @return x the instruction popped off the stack - */ - public ValueNode ipop() { - assert assertIntPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a float. - * - * @return x the instruction popped off the stack - */ - public ValueNode fpop() { - assert assertFloatPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is an object. - * - * @return x the instruction popped off the stack - */ - public ValueNode apop() { - assert assertObjectPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a long. - * - * @return x the instruction popped off the stack - */ - public ValueNode lpop() { - assert assertHighPeek(); - xpop(); - assert assertLongPeek(); - return xpop(); - } - - /** - * Pops a value off of the stack and checks that it is a double. - * - * @return x the instruction popped off the stack - */ - public ValueNode dpop() { - assert assertHighPeek(); - xpop(); - assert assertDoublePeek(); - return xpop(); - } - - /** - * Pop the specified number of slots off of this stack and return them as an array of - * instructions. - * - * @return an array containing the arguments off of the stack - */ - public ValueNode[] popArguments(int argSize) { - ValueNode[] result = allocateArray(argSize); - int newStackSize = stackSize; - for (int i = argSize - 1; i >= 0; i--) { - newStackSize--; - if (stack[newStackSize] == null) { - /* Two-slot value. */ - newStackSize--; - assert stack[newStackSize].getKind().needsTwoSlots(); - } else { - assert parser.parsingIntrinsic() || (stack[newStackSize].getKind().getSlotCount() == 1); - } - result[i] = stack[newStackSize]; - } - stackSize = newStackSize; - return result; - } - - /** - * Peeks an element from the operand stack. - * - * @param argumentNumber The number of the argument, relative from the top of the stack (0 = - * top). Long and double arguments only count as one argument, i.e., null-slots are - * ignored. - * @return The peeked argument. - */ - public ValueNode peek(int argumentNumber) { - int idx = stackSize() - 1; - for (int i = 0; i < argumentNumber; i++) { - if (stackAt(idx) == null) { - idx--; - assert stackAt(idx).getKind().needsTwoSlots(); - } - idx--; - } - return stackAt(idx); - } - - /** - * Clears all values on this stack. - */ - public void clearStack() { - stackSize = 0; - } - - private boolean assertLongPeek() { - return assertLong(xpeek()); - } - - private static boolean assertLong(ValueNode x) { - assert x != null && (x.getKind() == Kind.Long); - return true; - } - - private boolean assertIntPeek() { - return assertInt(xpeek()); - } - - private static boolean assertInt(ValueNode x) { - assert x != null && (x.getKind() == Kind.Int); - return true; - } - - private boolean assertFloatPeek() { - return assertFloat(xpeek()); - } - - private static boolean assertFloat(ValueNode x) { - assert x != null && (x.getKind() == Kind.Float); - return true; - } - - private boolean assertObjectPeek() { - return assertObject(xpeek()); - } - - private boolean assertObject(ValueNode x) { - assert x != null && (parser.parsingIntrinsic() || (x.getKind() == Kind.Object)); - return true; - } - - private boolean assertDoublePeek() { - return assertDouble(xpeek()); - } - - private static boolean assertDouble(ValueNode x) { - assert x != null && (x.getKind() == Kind.Double); - return true; - } - - private boolean assertHighPeek() { - assert xpeek() == null; - return true; - } - - @Override - public int hashCode() { - int result = hashCode(locals, locals.length); - result *= 13; - result += hashCode(stack, this.stackSize); - return result; - } - - private static int hashCode(Object[] a, int length) { - int result = 1; - for (int i = 0; i < length; ++i) { - Object element = a[i]; - result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); - } - return result; - } - - private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { - for (int i = 0; i < length; ++i) { - if (a[i] != b[i]) { - return false; - } - } - return true; - } - - @Override - public boolean equals(Object otherObject) { - if (otherObject instanceof HIRFrameStateBuilder) { - HIRFrameStateBuilder other = (HIRFrameStateBuilder) otherObject; - if (!other.method.equals(method)) { - return false; - } - if (other.stackSize != stackSize) { - return false; - } - if (other.parser != parser) { - return false; - } - if (other.rethrowException != rethrowException) { - return false; - } - if (other.graph != graph) { - return false; - } - if (other.locals.length != locals.length) { - return false; - } - return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && - equals(other.monitorIds, monitorIds, monitorIds.length); - } - return false; - } - - public void replace(ValueNode oldValue, ValueNode newValue) { - for (int i = 0; i < locals.length; i++) { - if (locals[i] == oldValue) { - locals[i] = newValue; - } - } - for (int i = 0; i < stackSize; i++) { - if (stack[i] == oldValue) { - stack[i] = newValue; - } - } - } - - @Override - public boolean isAfterSideEffect() { - return sideEffects != null; - } - - @Override - public Iterable sideEffects() { - return sideEffects; - } - - @Override - public void addSideEffect(StateSplit sideEffect) { - assert sideEffect != null; - assert sideEffect.hasSideEffect(); - if (sideEffects == null) { - sideEffects = new ArrayList<>(4); - } - sideEffects.add(sideEffect); - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Fri May 15 11:55:52 2015 +0200 @@ -71,9 +71,13 @@ } @Opcode("CALL_DIRECT") - public abstract static class DirectCallOp extends MethodCallOp { + public static class DirectCallOp extends MethodCallOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectCallOp.class); + public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + this(TYPE, callTarget, result, parameters, temps, state); + } + protected DirectCallOp(LIRInstructionClass c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { super(c, callTarget, result, parameters, temps, state); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri May 15 11:55:52 2015 +0200 @@ -38,13 +38,12 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; -import com.oracle.graal.lir.amd64.AMD64Call.CallOp; import com.oracle.graal.lir.asm.*; public class AMD64ControlFlow { public static final class ReturnOp extends AMD64LIRInstruction implements BlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CallOp.class); + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ReturnOp.class); @Use({REG, ILLEGAL}) protected Value x; public ReturnOp(Value x) { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java Fri May 15 11:55:52 2015 +0200 @@ -39,7 +39,7 @@ * such fields. * */ -public final class CompositeValueClass { +public final class CompositeValueClass extends FieldIntrospection { /** * The CompositeValueClass is only used for formatting for the most part so cache it as a @@ -56,16 +56,15 @@ }; - public static CompositeValueClass get(Class type) { - return compositeClass.get(type); + @SuppressWarnings("unchecked") + public static CompositeValueClass get(Class type) { + return (CompositeValueClass) compositeClass.get(type); } - private final Class clazz; private final Values values; - private final Fields data; private CompositeValueClass(Class clazz) { - this.clazz = clazz; + super(clazz); CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset()); vfs.scan(clazz, CompositeValue.class, false); @@ -94,9 +93,14 @@ } @Override + public Fields[] getAllFields() { + return new Fields[]{data, values}; + } + + @Override public String toString() { StringBuilder str = new StringBuilder(); - str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" components["); + str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components["); values.appendFields(str); str.append("] data["); data.appendFields(str); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Fri May 15 11:55:52 2015 +0200 @@ -76,6 +76,17 @@ } } + @SuppressWarnings("unchecked") + public static LIRInstructionClass get(Class clazz) { + try { + Field field = clazz.getDeclaredField("TYPE"); + field.setAccessible(true); + return (LIRInstructionClass) field.get(null); + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + throw new RuntimeException(e); + } + } + private static class LIRInstructionFieldsScanner extends LIRFieldsScanner { private String opcodeConstant; @@ -137,7 +148,7 @@ if (STATE_CLASS.isAssignableFrom(type)) { assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; - states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type)); + states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type, field.getDeclaringClass())); } else { super.scanField(field, offset); } @@ -151,6 +162,12 @@ } @Override + public Fields[] getAllFields() { + assert values == null; + return new Fields[]{data, uses, alives, temps, defs, states}; + } + + @Override public String toString() { StringBuilder str = new StringBuilder(); str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use["); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java Fri May 15 11:55:52 2015 +0200 @@ -100,8 +100,8 @@ final EnumSet flags; - public ValueFieldInfo(long offset, String name, Class type, EnumSet flags) { - super(offset, name, type); + public ValueFieldInfo(long offset, String name, Class type, Class declaringClass, EnumSet flags) { + super(offset, name, type, declaringClass); assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type); this.flags = flags; } @@ -171,14 +171,14 @@ assert annotation != null : "Field must have operand mode annotation: " + field; EnumSet flags = getFlags(field); assert verifyFlags(field, type, flags); - annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags)); + annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); annotation.directCount++; } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { OperandModeAnnotation annotation = getOperandModeAnnotation(field); assert annotation != null : "Field must have operand mode annotation: " + field; EnumSet flags = getFlags(field); assert verifyFlags(field, type.getComponentType(), flags); - annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags)); + annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, field.getDeclaringClass(), flags)); } else { assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java --- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java Fri May 15 11:55:52 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -123,8 +123,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Input list field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Input list field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Input list field must not be public"); } } else { if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) { @@ -133,8 +133,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Input field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Input field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Input field must not be public"); } } } else if (isSuccessor) { @@ -152,8 +152,8 @@ if (modifiers.contains(FINAL)) { throw new ElementException(field, "Successor field must not be final"); } - if (modifiers.contains(PUBLIC) || modifiers.contains(PRIVATE)) { - throw new ElementException(field, "Successor field must be protected or package-private"); + if (modifiers.contains(PUBLIC)) { + throw new ElementException(field, "Successor field must not be public"); } } @@ -167,12 +167,8 @@ if (isAssignableWithErasure(field, NodeSuccessorList)) { throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName()); } - if (modifiers.contains(PUBLIC)) { - if (!modifiers.contains(FINAL)) { - throw new ElementException(field, "Data field must be final if public otherwise it must be protected"); - } - } else if (!modifiers.contains(PROTECTED)) { - throw new ElementException(field, "Data field must be protected"); + if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) { + throw new ElementException(field, "Data field must be final if public"); } } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,10 +31,14 @@ import com.oracle.graal.nodeinfo.*; @NodeInfo -public abstract class DirectCallTargetNode extends LoweredCallTargetNode { +public class DirectCallTargetNode extends LoweredCallTargetNode { public static final NodeClass TYPE = NodeClass.create(DirectCallTargetNode.class); + public DirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { + this(TYPE, arguments, returnStamp, signature, target, callType, invokeKind); + } + protected DirectCallTargetNode(NodeClass c, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { super(c, arguments, returnStamp, signature, target, callType, invokeKind); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java Fri May 15 11:55:52 2015 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.compiler.common.util.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.util.*; /** * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for @@ -1154,32 +1153,14 @@ } } + /** + * Removes unnecessary nodes from the graph after decoding. + * + * @param methodScope The current method. + * @param start Marker for the begin of the current method in the graph. + */ protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { assert verifyEdges(methodScope); - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (node instanceof MergeNode) { - MergeNode mergeNode = (MergeNode) node; - if (mergeNode.forwardEndCount() == 1) { - methodScope.graph.reduceTrivialMerge(mergeNode); - } - } - } - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (node instanceof BeginNode || node instanceof KillingBeginNode) { - if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) { - GraphUtil.unlinkFixedNode((AbstractBeginNode) node); - node.safeDelete(); - } - } - } - - for (Node node : methodScope.graph.getNewNodes(start)) { - if (!(node instanceof FixedNode) && node.hasNoUsages()) { - GraphUtil.killCFG(node); - } - } } protected boolean verifyEdges(MethodScope methodScope) { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,11 +31,16 @@ import com.oracle.graal.nodeinfo.*; @NodeInfo -public abstract class IndirectCallTargetNode extends LoweredCallTargetNode { +public class IndirectCallTargetNode extends LoweredCallTargetNode { public static final NodeClass TYPE = NodeClass.create(IndirectCallTargetNode.class); @Input protected ValueNode computedAddress; + public IndirectCallTargetNode(ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, + InvokeKind invokeKind) { + this(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind); + } + protected IndirectCallTargetNode(NodeClass c, ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) { super(c, arguments, returnStamp, signature, target, callType, invokeKind); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimplifyingGraphDecoder.java Fri May 15 11:55:52 2015 +0200 @@ -79,6 +79,30 @@ protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) { GraphUtil.normalizeLoops(methodScope.graph); super.cleanupGraph(methodScope, start); + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (node instanceof MergeNode) { + MergeNode mergeNode = (MergeNode) node; + if (mergeNode.forwardEndCount() == 1) { + methodScope.graph.reduceTrivialMerge(mergeNode); + } + } + } + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (node instanceof BeginNode || node instanceof KillingBeginNode) { + if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) { + GraphUtil.unlinkFixedNode((AbstractBeginNode) node); + node.safeDelete(); + } + } + } + + for (Node node : methodScope.graph.getNewNodes(start)) { + if (!(node instanceof FixedNode) && node.hasNoUsages()) { + GraphUtil.killCFG(node); + } + } } @Override diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java Fri May 15 11:55:52 2015 +0200 @@ -59,6 +59,10 @@ @Override public boolean inferStamp() { - return updateStamp(StampTool.meet(values())); + Stamp valuesStamp = StampTool.meet(values()); + if (stamp.isCompatible(valuesStamp)) { + valuesStamp = stamp.join(valuesStamp); + } + return updateStamp(valuesStamp); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,11 +31,15 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "/") -public final class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(IntegerDivNode.class); public IntegerDivNode(ValueNode x, ValueNode y) { - super(TYPE, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y); + this(TYPE, x, y); + } + + protected IntegerDivNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y); } @Override diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,11 +31,15 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "%") -public final class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(IntegerRemNode.class); public IntegerRemNode(ValueNode x, ValueNode y) { - super(TYPE, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y); + this(TYPE, x, y); + } + + protected IntegerRemNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y); } @Override diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,12 +31,16 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "|/|") -public final class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(UnsignedDivNode.class); public UnsignedDivNode(ValueNode x, ValueNode y) { - super(TYPE, x.stamp().unrestricted(), x, y); + this(TYPE, x, y); + } + + protected UnsignedDivNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, x.stamp().unrestricted(), x, y); } @Override diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Fri May 15 11:55:52 2015 +0200 @@ -31,12 +31,16 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(shortName = "|%|") -public final class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { +public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable { public static final NodeClass TYPE = NodeClass.create(UnsignedRemNode.class); public UnsignedRemNode(ValueNode x, ValueNode y) { - super(TYPE, x.stamp().unrestricted(), x, y); + this(TYPE, x, y); + } + + protected UnsignedRemNode(NodeClass c, ValueNode x, ValueNode y) { + super(c, x.stamp().unrestricted(), x, y); } @Override diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java Fri May 15 11:55:52 2015 +0200 @@ -47,10 +47,7 @@ protected int bci = BytecodeFrame.UNKNOWN_BCI; public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { - super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); - this.arguments = new NodeInputList<>(this, arguments); - this.descriptor = descriptor; - this.foreignCalls = foreignCalls; + this(TYPE, foreignCalls, descriptor, arguments); } public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List arguments) { @@ -67,9 +64,9 @@ this.foreignCalls = foreignCalls; } - protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) { - super(c, stamp); - this.arguments = new NodeInputList<>(this); + protected ForeignCallNode(NodeClass c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(c, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType()))); + this.arguments = new NodeInputList<>(this, arguments); this.descriptor = descriptor; this.foreignCalls = foreignCalls; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Fri May 15 11:55:52 2015 +0200 @@ -41,7 +41,7 @@ * Implements a type check against a compile-time known type. */ @NodeInfo -public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy { +public class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy { public static final NodeClass TYPE = NodeClass.create(CheckCastNode.class); @Input protected ValueNode object; @@ -55,7 +55,11 @@ protected final boolean forStoreCheck; public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) { - super(TYPE, StampFactory.declaredTrusted(type)); + this(TYPE, type, object, profile, forStoreCheck); + } + + protected CheckCastNode(NodeClass c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) { + super(c, StampFactory.declaredTrusted(type)); assert object.stamp() instanceof ObjectStamp : object + ":" + object.stamp(); assert type != null; this.type = type; @@ -178,7 +182,7 @@ return this; } - private static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) { + protected static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) { ResolvedJavaType objectType = StampTool.typeOrNull(object); if (objectType != null && type.isAssignableFrom(objectType)) { // we don't have to check for null types here because they will also pass the diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Fri May 15 11:55:52 2015 +0200 @@ -36,14 +36,18 @@ * The {@code InstanceOfNode} represents an instanceof test. */ @NodeInfo -public final class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { +public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { public static final NodeClass TYPE = NodeClass.create(InstanceOfNode.class); protected final ResolvedJavaType type; protected JavaTypeProfile profile; public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { - super(TYPE, object); + this(TYPE, type, object, profile); + } + + protected InstanceOfNode(NodeClass c, ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) { + super(c, object); this.type = type; this.profile = profile; assert type != null; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java Fri May 15 11:55:52 2015 +0200 @@ -175,7 +175,7 @@ * interface methods calls. */ if (declaredReceiverType.isInterface()) { - tryCheckCastSingleImplementor(receiver, declaredReceiverType); + tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, declaredReceiverType); } if (receiver instanceof UncheckedInterfaceProvider) { @@ -184,14 +184,22 @@ if (uncheckedStamp != null) { ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp); if (uncheckedReceiverType.isInterface()) { - tryCheckCastSingleImplementor(receiver, uncheckedReceiverType); + tryCheckCastSingleImplementor(graph().getAssumptions(), receiver, uncheckedReceiverType); } } } } } - private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) { + private void tryCheckCastSingleImplementor(Assumptions assumptions, ValueNode receiver, ResolvedJavaType declaredReceiverType) { + if (assumptions == null) { + /* + * Even though we are not registering an assumption (see comment below), the + * optimization is only valid when speculative optimizations are enabled. + */ + return; + } + ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor(); if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) { ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Fri May 15 11:55:52 2015 +0200 @@ -37,13 +37,17 @@ * The {@code NewInstanceNode} represents the allocation of an instance class object. */ @NodeInfo(nameTemplate = "New {p#instanceClass/s}") -public final class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation { +public class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation { public static final NodeClass TYPE = NodeClass.create(NewInstanceNode.class); protected final ResolvedJavaType instanceClass; public NewInstanceNode(ResolvedJavaType type, boolean fillContents) { - super(TYPE, StampFactory.exactNonNull(type), fillContents); + this(TYPE, type, fillContents); + } + + protected NewInstanceNode(NodeClass c, ResolvedJavaType type, boolean fillContents) { + super(c, StampFactory.exactNonNull(type), fillContents); assert !type.isArray() && !type.isInterface() && !type.isPrimitive(); this.instanceClass = type; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Fri May 15 11:55:52 2015 +0200 @@ -33,7 +33,7 @@ * The {@code NewMultiArrayNode} represents an allocation of a multi-dimensional object array. */ @NodeInfo -public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider { +public class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider { public static final NodeClass TYPE = NodeClass.create(NewMultiArrayNode.class); @Input protected NodeInputList dimensions; @@ -52,7 +52,11 @@ } public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) { - super(TYPE, StampFactory.exactNonNull(type)); + this(TYPE, type, dimensions); + } + + protected NewMultiArrayNode(NodeClass c, ResolvedJavaType type, ValueNode[] dimensions) { + super(c, StampFactory.exactNonNull(type)); this.type = type; this.dimensions = new NodeInputList<>(this, dimensions); assert dimensions.length > 0 && type.isArray(); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Fri May 15 11:55:52 2015 +0200 @@ -68,10 +68,14 @@ ObjectStamp objectStamp = (ObjectStamp) object.stamp(); if (objectStamp.isExactType()) { return objectStamp.type().hasFinalizer(); - } else if (objectStamp.type() != null && assumptions != null) { + } else if (objectStamp.type() != null) { AssumptionResult result = objectStamp.type().hasFinalizableSubclass(); - assumptions.record(result); - return result.getResult(); + if (result.isAssumptionFree()) { + return result.getResult(); + } else if (assumptions != null) { + assumptions.record(result); + return result.getResult(); + } } return true; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Fri May 15 11:55:52 2015 +0200 @@ -33,14 +33,18 @@ import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") -public final class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { +public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { public static final NodeClass TYPE = NodeClass.create(VirtualArrayNode.class); protected final ResolvedJavaType componentType; protected final int length; public VirtualArrayNode(ResolvedJavaType componentType, int length) { - super(TYPE, componentType.getArrayClass(), true); + this(TYPE, componentType, length); + } + + protected VirtualArrayNode(NodeClass c, ResolvedJavaType componentType, int length) { + super(c, componentType.getArrayClass(), true); this.componentType = componentType; this.length = length; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java Fri May 15 11:55:52 2015 +0200 @@ -70,6 +70,31 @@ return false; } + /** + * Removes the first instance of the given phase class, looking recursively into inner phase + * suites. + */ + public boolean removePhase(Class> phaseClass) { + ListIterator> it = phases.listIterator(); + while (it.hasNext()) { + BasePhase phase = it.next(); + if (phaseClass.isInstance(phase)) { + it.remove(); + return true; + } else if (phase instanceof PhaseSuite) { + @SuppressWarnings("unchecked") + PhaseSuite innerSuite = (PhaseSuite) phase; + if (innerSuite.removePhase(phaseClass)) { + if (innerSuite.phases.isEmpty()) { + it.remove(); + } + return true; + } + } + } + return false; + } + @Override protected void run(StructuredGraph graph, C context) { for (BasePhase phase : phases) { diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Fri May 15 11:55:52 2015 +0200 @@ -412,4 +412,23 @@ test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"}); test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"}); } + + public int conditionalInstantiation(Object o) { + int total = 0; + if (o instanceof CharSequence) { + if (o instanceof StringBuilder || o instanceof String) { + total = 9; + } + total += (o instanceof String ? 2 : 1); + } + + return total; + } + + @Test + public void testInstantiation() { + test("conditionalInstantiation", "foo"); + test("conditionalInstantiation", new StringBuilder()); + test("conditionalInstantiation", 1); + } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultGenericInvocationPlugin.java Fri May 15 11:55:52 2015 +0200 @@ -148,12 +148,12 @@ /* * Need to update the BCI of a ForeignCallNode so that it gets the stateDuring in the * case that the foreign call can deoptimize. As with all deoptimization, we need a - * state in a normal method as opposed to an intrinsic. + * state in a non-intrinsic method. */ - GraphBuilderContext ancestor = b.getNonReplacementAncestor(); - if (ancestor != null) { + GraphBuilderContext nonIntrinsicAncestor = b.getNonIntrinsicAncestor(); + if (nonIntrinsicAncestor != null) { ForeignCallNode foreign = (ForeignCallNode) res; - foreign.setBci(ancestor.bci()); + foreign.setBci(nonIntrinsicAncestor.bci()); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java Fri May 15 11:55:52 2015 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.replacements; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graphbuilderconf.*; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Fri May 15 11:55:52 2015 +0200 @@ -143,13 +143,8 @@ ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object(); ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value()); ConstantLocationNode location = createFieldLocation(graph, field, false); + assert location != null; - if (location == null) { - /* Field has been eliminated, so no write necessary. */ - assert !storeField.isVolatile() : "missing memory barriers"; - graph.removeFixed(storeField); - return; - } WriteNode memoryWrite = graph.add(new WriteNode(object, value, location, fieldStoreBarrierType(storeField.field()))); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Fri May 15 11:55:52 2015 +0200 @@ -91,7 +91,7 @@ } public T changeToWord(T node) { - if (wordTypes.isWord(node)) { + if (wordTypes != null && wordTypes.isWord(node)) { node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node))); } return node; @@ -125,8 +125,13 @@ * @param name the name of the invoked method * @param args the arguments to the invocation */ - public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(Class declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { boolean isStatic = invokeKind == InvokeKind.Static; + ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic); + return createInvoke(method, invokeKind, frameStateBuilder, bci, args); + } + + public ResolvedJavaMethod findMethod(Class declaringClass, String name, boolean isStatic) { ResolvedJavaMethod method = null; for (Method m : declaringClass.getDeclaredMethods()) { if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) { @@ -135,14 +140,14 @@ } } assert method != null : "did not find method in " + declaringClass + " named " + name; - return createInvoke(method, invokeKind, frameStateBuilder, bci, args); + return method; } /** * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of * arguments. */ - public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, HIRFrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { + public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { assert method.isStatic() == (invokeKind == InvokeKind.Static); Signature signature = method.getSignature(); JavaType returnType = signature.getReturnType(null); @@ -181,12 +186,14 @@ } int argIndex = 0; if (!isStatic) { - Kind expected = wordTypes.asKind(method.getDeclaringClass()); + ResolvedJavaType expectedType = method.getDeclaringClass(); + Kind expected = wordTypes == null ? expectedType.getKind() : wordTypes.asKind(expectedType); Kind actual = args[argIndex++].stamp().getStackKind(); assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]"; } for (int i = 0; i != signature.getParameterCount(false); i++) { - Kind expected = wordTypes.asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind(); + JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass()); + Kind expected = wordTypes == null ? expectedType.getKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind(); Kind actual = args[argIndex++].stamp().getStackKind(); if (expected != actual) { throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]"); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Fri May 15 11:55:52 2015 +0200 @@ -96,7 +96,17 @@ protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, Instantiation instantiation, Node usage, final StructuredGraph graph) { InstanceOfUsageReplacer replacer; if (usage instanceof IfNode || usage instanceof FixedGuardNode || usage instanceof ShortCircuitOrNode || usage instanceof GuardingPiNode || usage instanceof ConditionAnchorNode) { - replacer = new NonMaterializationUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, usage); + ValueNode trueValue = ConstantNode.forInt(1, graph); + ValueNode falseValue = ConstantNode.forInt(0, graph); + if (instantiation.isInitialized() && (trueValue != instantiation.trueValue || falseValue != instantiation.falseValue)) { + /* + * This code doesn't really care what values are used so adopt the values from the + * previous instantiation. + */ + trueValue = instantiation.trueValue; + falseValue = instantiation.falseValue; + } + replacer = new NonMaterializationUsageReplacer(instantiation, trueValue, falseValue, instanceOf, usage); } else { assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage; ConditionalNode c = (ConditionalNode) usage; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MethodHandleInvocationPlugin.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015, 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.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; +import com.oracle.graal.graph.*; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.replacements.nodes.*; + +public class MethodHandleInvocationPlugin implements GenericInvocationPlugin { + private final MethodHandleAccessProvider methodHandleAccess; + private final GenericInvocationPlugin delegate; + + public MethodHandleInvocationPlugin(MethodHandleAccessProvider methodHandleAccess, GenericInvocationPlugin delegate) { + this.methodHandleAccess = methodHandleAccess; + this.delegate = delegate; + } + + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method); + if (intrinsicMethod != null) { + InvokeKind invokeKind = b.getInvokeKind(); + if (invokeKind != InvokeKind.Static) { + args[0] = b.nullCheckedValue(args[0]); + } + JavaType invokeReturnType = b.getInvokeReturnType(); + InvokeNode invoke = MethodHandleNode.tryResolveTargetInvoke(b.getAssumptions(), b.getConstantReflection().getMethodHandleAccess(), intrinsicMethod, method, b.bci(), invokeReturnType, args); + if (invoke == null) { + MethodHandleNode methodHandleNode = new MethodHandleNode(intrinsicMethod, invokeKind, method, b.bci(), invokeReturnType, args); + if (invokeReturnType.getKind() == Kind.Void) { + b.add(methodHandleNode); + } else { + b.addPush(methodHandleNode); + } + } else { + CallTargetNode callTarget = invoke.callTarget(); + NodeInputList argumentsList = callTarget.arguments(); + ValueNode[] newArgs = argumentsList.toArray(new ValueNode[argumentsList.size()]); + for (ValueNode arg : newArgs) { + b.recursiveAppend(arg); + } + b.handleReplacedInvoke(invoke.getInvokeKind(), callTarget.targetMethod(), newArgs); + } + return true; + } + return delegate.apply(b, method, args); + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java Fri May 15 11:55:52 2015 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.replacements; import static com.oracle.graal.compiler.common.GraalInternalError.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import java.util.*; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri May 15 11:55:52 2015 +0200 @@ -25,7 +25,7 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.compiler.common.GraalOptions.*; import static com.oracle.graal.graphbuilderconf.IntrinsicContext.CompilationContext.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*; import static java.lang.String.*; @@ -77,6 +77,10 @@ this.graphBuilderPlugins = plugins; } + public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() { + return graphBuilderPlugins; + } + protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) { return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null || method.getAnnotation(Fold.class) != null; } @@ -581,7 +585,19 @@ if (args != null) { plugins.setParameterPlugin(new ConstantBindingParameterPlugin(args, plugins.getParameterPlugin(), metaAccess, replacements.snippetReflection)); } - createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE).apply(graph); + + IntrinsicContext initialIntrinsicContext = null; + if (method.getAnnotation(Snippet.class) == null) { + // Post-parse inlined intrinsic + initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING); + } else { + // Snippet + ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; + initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING); + } + + createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply( + graph); if (OptCanonicalizer.getValue()) { new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers)); @@ -593,16 +609,7 @@ } protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, - OptimisticOptimizations optimisticOpts) { - IntrinsicContext initialIntrinsicContext = null; - if (method.getAnnotation(Snippet.class) == null) { - // Post-parse inlined intrinsic - initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, INLINE_AFTER_PARSING); - } else { - // Snippet - ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method; - initialIntrinsicContext = new IntrinsicContext(original, method, INLINE_AFTER_PARSING); - } + OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Fri May 15 11:55:52 2015 +0200 @@ -1098,11 +1098,12 @@ // rewire outgoing memory edges replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates)); - ReturnNode ret = (ReturnNode) duplicates.get(returnNode); - MemoryMapNode memoryMap = ret.getMemoryMap(); - ret.setMemoryMap(null); - memoryMap.safeDelete(); - + if (returnNode != null) { + ReturnNode ret = (ReturnNode) duplicates.get(returnNode); + MemoryMapNode memoryMap = ret.getMemoryMap(); + ret.setMemoryMap(null); + memoryMap.safeDelete(); + } if (memoryAnchor != null) { // rewire incoming memory edges MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MethodHandleNode.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements.nodes; + +import java.lang.invoke.*; +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.Assumptions.AssumptionResult; +import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; + +/** + * Node for invocation methods defined on the class {@link MethodHandle}. + */ +@NodeInfo +public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable { + public static final NodeClass TYPE = NodeClass.create(MethodHandleNode.class); + + protected final IntrinsicMethod intrinsicMethod; + + public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, JavaType returnType, ValueNode... arguments) { + super(TYPE, invokeKind, targetMethod, bci, returnType, arguments); + this.intrinsicMethod = intrinsicMethod; + } + + /** + * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an + * invocation on another method with possibly transformed arguments. + * + * @param assumptions object for recording any speculations made during the transformation + * @param methodHandleAccess objects for accessing the implementation internals of a + * {@link MethodHandle} + * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed + * @param bci the BCI of the original {@link MethodHandle} call + * @param returnType return type of the original {@link MethodHandle} call + * @param arguments arguments to the original {@link MethodHandle} call + * @return a more direct invocation derived from the {@link MethodHandle} call or null + */ + public static InvokeNode tryResolveTargetInvoke(Assumptions assumptions, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode... arguments) { + switch (intrinsicMethod) { + case INVOKE_BASIC: + return getInvokeBasicTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); + case LINK_TO_STATIC: + case LINK_TO_SPECIAL: + case LINK_TO_VIRTUAL: + case LINK_TO_INTERFACE: + return getLinkToTarget(assumptions, intrinsicMethod, methodHandleAccess, original, bci, returnType, arguments); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public void simplify(SimplifierTool tool) { + MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess(); + ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]); + InvokeNode invoke = tryResolveTargetInvoke(graph().getAssumptions(), methodHandleAccess, intrinsicMethod, targetMethod, bci, returnType, argumentsArray); + if (invoke != null) { + assert invoke.graph() == null; + invoke = graph().addOrUniqueWithInputs(invoke); + invoke.setStateAfter(stateAfter()); + FixedNode currentNext = next(); + replaceAtUsages(invoke); + GraphUtil.removeFixedWithUnusedInputs(this); + graph().addBeforeFixed(currentNext, invoke); + } + } + + /** + * Get the receiver of a MethodHandle.invokeBasic call. + * + * @return the receiver argument node + */ + private static ValueNode getReceiver(ValueNode[] arguments) { + return arguments[0]; + } + + /** + * Get the MemberName argument of a MethodHandle.linkTo* call. + * + * @return the MemberName argument node (which is the last argument) + */ + private static ValueNode getMemberName(ValueNode[] arguments) { + return arguments[arguments.length - 1]; + } + + /** + * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC } + * method) to get the target {@link InvokeNode} if the method handle receiver is constant. + * + * @return invoke node for the {@link java.lang.invoke.MethodHandle} target + */ + private static InvokeNode getInvokeBasicTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode[] arguments) { + ValueNode methodHandleNode = getReceiver(arguments); + if (methodHandleNode.isConstant()) { + return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original); + } + return null; + } + + /** + * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC}, + * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and + * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if + * the member name argument is constant. + * + * @return invoke node for the member name target + */ + private static InvokeNode getLinkToTarget(Assumptions assumptions, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess, ResolvedJavaMethod original, int bci, + JavaType returnType, ValueNode[] arguments) { + ValueNode memberNameNode = getMemberName(arguments); + if (memberNameNode.isConstant()) { + return getTargetInvokeNode(assumptions, intrinsicMethod, bci, returnType, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original); + } + return null; + } + + /** + * Helper function to get the {@link InvokeNode} for the targetMethod of a + * java.lang.invoke.MemberName. + * + * @param target the target, already loaded from the member name node + * @return invoke node for the member name target + */ + private static InvokeNode getTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, int bci, JavaType returnType, ValueNode[] arguments, ResolvedJavaMethod target, + ResolvedJavaMethod original) { + if (target == null) { + return null; + } + + // In lambda forms we erase signature types to avoid resolving issues + // involving class loaders. When we optimize a method handle invoke + // to a direct call we must cast the receiver and arguments to its + // actual types. + Signature signature = target.getSignature(); + final boolean isStatic = target.isStatic(); + final int receiverSkip = isStatic ? 0 : 1; + + // Cast receiver to its type. + if (!isStatic) { + JavaType receiverType = target.getDeclaringClass(); + maybeCastArgument(arguments, 0, receiverType); + } + + // Cast reference arguments to its type. + for (int index = 0; index < signature.getParameterCount(false); index++) { + JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass()); + maybeCastArgument(arguments, receiverSkip + index, parameterType); + } + + if (target.canBeStaticallyBound()) { + return createTargetInvokeNode(intrinsicMethod, target, original, bci, returnType, arguments); + } + + // Try to get the most accurate receiver type + if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) { + ValueNode receiver = getReceiver(arguments); + ResolvedJavaType receiverType = StampTool.typeOrNull(receiver.stamp()); + if (receiverType != null) { + AssumptionResult concreteMethod = receiverType.findUniqueConcreteMethod(target); + if (concreteMethod != null) { + assumptions.record(concreteMethod); + return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); + } + } + } else { + AssumptionResult concreteMethod = target.getDeclaringClass().findUniqueConcreteMethod(target); + if (concreteMethod != null) { + assumptions.record(concreteMethod); + return createTargetInvokeNode(intrinsicMethod, concreteMethod.getResult(), original, bci, returnType, arguments); + } + } + + return null; + } + + /** + * Inserts a node to cast the argument at index to the given type if the given type is more + * concrete than the argument type. + * + * @param index of the argument to be cast + * @param type the type the argument should be cast to + */ + private static void maybeCastArgument(ValueNode[] arguments, int index, JavaType type) { + if (type instanceof ResolvedJavaType) { + ResolvedJavaType targetType = (ResolvedJavaType) type; + if (!targetType.isPrimitive()) { + ValueNode argument = arguments[index]; + ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp()); + if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) { + PiNode piNode = new PiNode(argument, StampFactory.declared(targetType)); + arguments[index] = piNode; + } + } + } + } + + /** + * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed + * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}. + * + * @return invoke node for the member name target + */ + private static InvokeNode createTargetInvokeNode(IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, JavaType returnType, ValueNode[] arguments) { + InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special; + JavaType targetReturnType = target.getSignature().getReturnType(null); + + // MethodHandleLinkTo* nodes have a trailing MemberName argument which + // needs to be popped. + ValueNode[] targetArguments; + switch (intrinsicMethod) { + case INVOKE_BASIC: + targetArguments = arguments; + break; + case LINK_TO_STATIC: + case LINK_TO_SPECIAL: + case LINK_TO_VIRTUAL: + case LINK_TO_INTERFACE: + targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnType, original, arguments, returnType); + + // The call target can have a different return type than the invoker, + // e.g. the target returns an Object but the invoker void. In this case + // we need to use the stamp of the invoker. Note: always using the + // invoker's stamp would be wrong because it's a less concrete type + // (usually java.lang.Object). + if (returnType.getKind() == Kind.Void) { + return new InvokeNode(callTarget, bci, StampFactory.forVoid()); + } else { + return new InvokeNode(callTarget, bci); + } + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ResolvedMethodHandleCallTargetNode.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013, 2015, 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.replacements.nodes; + +import static sun.misc.Version.*; + +import java.lang.invoke.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A call target that replaces itself in the graph when being lowered by restoring the original + * {@link MethodHandle} invocation target. Prior to + * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a + * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In + * that case, the original invocation must be restored with all of its original arguments. Why? + * HotSpot linkage for {@link MethodHandle} intrinsics (see + * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be + * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo* + * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle} + * invocation drops these arguments which means the interpreter won't find them. + */ +@NodeInfo +public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable { + + public static final NodeClass TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class); + + /** + * Creates a call target for an invocation on a direct target derived by resolving a constant + * {@link MethodHandle}. + */ + public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, + ValueNode[] originalArguments, JavaType originalReturnType) { + if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) { + // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60 + return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType); + } + return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType); + } + + protected final ResolvedJavaMethod originalTargetMethod; + protected final JavaType originalReturnType; + @Input NodeInputList originalArguments; + + protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod, + ValueNode[] originalArguments, JavaType originalReturnType) { + super(TYPE, invokeKind, targetMethod, arguments, returnType); + this.originalTargetMethod = originalTargetMethod; + this.originalReturnType = originalReturnType; + this.originalArguments = new NodeInputList<>(this, originalArguments); + } + + @Override + public void lower(LoweringTool tool) { + InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special; + MethodCallTargetNode replacement = graph().add( + new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType)); + + // Replace myself... + this.replaceAndDelete(replacement); + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + throw GraalInternalError.shouldNotReachHere("should have replaced itself"); + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri May 15 11:55:52 2015 +0200 @@ -74,7 +74,6 @@ return new HotSpotTruffleRuntime(); } - private TruffleCompilerImpl truffleCompiler; private Map> compilations = newIdentityMap(); private final ThreadPoolExecutor compileQueue; @@ -213,21 +212,12 @@ @Override public void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous) { if (truffleCompiler == null) { - truffleCompiler = new TruffleCompilerImpl(); + truffleCompiler = DefaultTruffleCompiler.create(); } Runnable r = new Runnable() { @Override public void run() { - boolean success = true; - try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) { - truffleCompiler.compileMethod(optimizedCallTarget); - } catch (Throwable e) { - optimizedCallTarget.notifyCompilationFailed(e); - success = false; - } finally { - optimizedCallTarget.notifyCompilationFinished(success); - - } + doCompile(optimizedCallTarget); } }; Future future = compileQueue.submit(r); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java Fri May 15 11:55:52 2015 +0200 @@ -205,19 +205,19 @@ } @Test - public void constantValueInertToolEvalNodeFactory() { + public void constantValueInertAdvancedInstrumentRootFactory() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode result = new ConstantTestNode(42); RootTestNode root = new RootTestNode(fd, "constantValue", result); root.adoptChildren(); Probe testProbe = result.probe(); - // A factory that could insert a ToolEvalNode into the AST, but which never does. - Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { + // A factory that could insert a AdvancedInstrumentRoot into the AST, but which never does. + Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { - public ToolEvalNode createToolEvalNode(Probe probe, Node node) { + public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) { return null; } - }, null); + }, null, "test AdvancedInstrument"); testProbe.attach(instrument); // It all gets compiled away @@ -225,29 +225,30 @@ } @Test - public void constantValueInertToolEvalNode() { + public void constantValueInertAdvancedInstrumentRoot() { FrameDescriptor fd = new FrameDescriptor(); AbstractTestNode resultTestNode = new ConstantTestNode(42); RootTestNode rootTestNode = new RootTestNode(fd, "constantValue", resultTestNode); rootTestNode.adoptChildren(); Probe testProbe = resultTestNode.probe(); - // A factory that inserts a ToolEvalNode with empty methods into the instrumentation chain. - Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { + // Factory inserts a AdvancedInstrumentRoot with empty methods into instrumentation . + Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { - public ToolEvalNode createToolEvalNode(Probe probe, Node node) { - return new ToolEvalNode() { + @Override + public AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node) { + return new AdvancedInstrumentRoot() { public String instrumentationInfo() { return null; } @Override - public Object executeToolEvalNode(Node n, VirtualFrame frame) { + public Object executeRoot(Node n, VirtualFrame frame) { return null; } }; } - }, null); + }, null, "test AdvancedInstrument"); testProbe.attach(instrument); // It all gets compiled away. @@ -351,6 +352,7 @@ final boolean[] isCurrentlyCompiled = {false}; final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() { + @Override public void notifyIsCompiled(boolean isCompiled) { isCurrentlyCompiled[0] = isCompiled; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java --- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Fri May 15 11:55:52 2015 +0200 @@ -38,12 +38,12 @@ import com.oracle.truffle.api.nodes.*; public class PartialEvaluationTest extends GraalCompilerTest { - private final TruffleCompilerImpl truffleCompiler; + private final TruffleCompiler truffleCompiler; public PartialEvaluationTest() { // Make sure Truffle runtime is initialized. Assert.assertTrue(Truffle.getRuntime() != null); - this.truffleCompiler = new TruffleCompilerImpl(); + this.truffleCompiler = DefaultTruffleCompiler.create(); DebugEnvironment.initialize(System.out); } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/CompilationProfile.java Fri May 15 11:55:52 2015 +0200 @@ -28,8 +28,6 @@ public class CompilationProfile { - private static final int TIMESTAMP_THRESHOLD = Math.max(TruffleCompilationThreshold.getValue() / 2, 1); - /** * Number of times an installed code for this tree was invalidated. */ @@ -112,7 +110,7 @@ interpreterCallAndLoopCount++; int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; - if (callsMissing == TIMESTAMP_THRESHOLD) { + if (callsMissing == getTimestampThreshold()) { timestamp = System.nanoTime(); } } @@ -130,7 +128,7 @@ } public void deferCompilation() { - ensureProfiling(0, TIMESTAMP_THRESHOLD + 1); + ensureProfiling(0, getTimestampThreshold() + 1); timestamp = 0; deferedCount++; } @@ -139,7 +137,7 @@ interpreterCallAndLoopCount += count; int callsMissing = compilationCallAndLoopThreshold - interpreterCallAndLoopCount; - if (callsMissing <= TIMESTAMP_THRESHOLD && callsMissing + count > TIMESTAMP_THRESHOLD) { + if (callsMissing <= getTimestampThreshold() && callsMissing + count > getTimestampThreshold()) { timestamp = System.nanoTime(); } } @@ -154,4 +152,7 @@ return timestamp; } + private static int getTimestampThreshold() { + return Math.max(TruffleCompilationThreshold.getValue() / 2, 1); + } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleCompiler.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013, 2014, 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.truffle; + +import java.util.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.java.*; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.runtime.*; + +public final class DefaultTruffleCompiler extends TruffleCompiler { + + public static TruffleCompiler create() { + Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); + Suites suites = backend.getSuites().getDefaultSuites(); + LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites(); + GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); + Plugins plugins = phase.getGraphBuilderConfig().getPlugins(); + return new DefaultTruffleCompiler(plugins, suites, lirSuites, backend); + } + + private DefaultTruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) { + super(plugins, suites, lirSuites, backend); + } + + @Override + protected PartialEvaluator createPartialEvaluator() { + return new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch); + } + + @Override + protected PhaseSuite createGraphBuilderSuite() { + PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); + ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); + iterator.remove(); + iterator.add(new GraphBuilderPhase(config)); + return suite; + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Fri May 15 11:55:52 2015 +0200 @@ -31,6 +31,8 @@ import com.oracle.graal.api.code.stack.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.truffle.debug.*; import com.oracle.graal.truffle.unsafe.*; @@ -55,7 +57,8 @@ private final List compilationListeners = new ArrayList<>(); private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener(); - private LoopNodeFactory loopNodeFactory; + protected TruffleCompiler truffleCompiler; + protected LoopNodeFactory loopNodeFactory; public GraalTruffleRuntime() { Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); @@ -101,11 +104,14 @@ if (!(repeatingNode instanceof Node)) { throw new IllegalArgumentException("Repeating node must be of type Node."); } + return getLoopNodeFactory().create(repeatingNode); + } + + protected LoopNodeFactory getLoopNodeFactory() { if (loopNodeFactory == null) { loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class); } - - return loopNodeFactory.create(repeatingNode); + return loopNodeFactory; } @Override @@ -271,6 +277,18 @@ public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous); + protected void doCompile(OptimizedCallTarget optimizedCallTarget) { + boolean success = true; + try (Scope s = Debug.scope("Truffle", new TruffleDebugJavaMethod(optimizedCallTarget))) { + truffleCompiler.compileMethod(optimizedCallTarget); + } catch (Throwable e) { + optimizedCallTarget.notifyCompilationFailed(e); + success = false; + } finally { + optimizedCallTarget.notifyCompilationFinished(success); + } + } + public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason); public abstract void waitForCompilation(OptimizedCallTarget optimizedCallTarget, long timeout) throws ExecutionException, TimeoutException; diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedOSRLoopNode.java Fri May 15 11:55:52 2015 +0200 @@ -28,8 +28,6 @@ public final class OptimizedOSRLoopNode extends LoopNode implements ReplaceObserver { - private static final int OSR_THRESHOLD = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue(); - private int interpreterLoopCount; private OptimizedCallTarget compiledTarget; @@ -75,7 +73,8 @@ } private boolean profilingLoop(VirtualFrame frame) { - int overflowLoopCount = Integer.MAX_VALUE - OSR_THRESHOLD + interpreterLoopCount; + int osrThreshold = TruffleCompilerOptions.TruffleOSRCompilationThreshold.getValue(); + int overflowLoopCount = Integer.MAX_VALUE - osrThreshold + interpreterLoopCount; try { while (repeatableNode.executeRepeating(frame)) { try { @@ -86,7 +85,7 @@ } } } finally { - reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + OSR_THRESHOLD - interpreterLoopCount); + reportLoopCount(overflowLoopCount - Integer.MAX_VALUE + osrThreshold - interpreterLoopCount); } return true; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri May 15 11:55:52 2015 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.truffle; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; +import static com.oracle.graal.java.GraphBuilderPhase.Options.*; import static com.oracle.graal.truffle.TruffleCompilerOptions.*; import java.lang.invoke.*; @@ -71,8 +71,8 @@ @Option(help = "New partial evaluation on Graal graphs", type = OptionType.Expert)// public static final StableOptionValue GraphPE = new StableOptionValue<>(true); - private final Providers providers; - private final Architecture architecture; + protected final Providers providers; + protected final Architecture architecture; private final CanonicalizerPhase canonicalizer; private final SnippetReflectionProvider snippetReflection; private final ResolvedJavaMethod callDirectMethod; @@ -140,11 +140,6 @@ } public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) { - if (TruffleCompilerOptions.TruffleExcludeAssertions.getValue() && staticField.getName().equals("$assertionsDisabled")) { - ConstantNode trueNode = builder.add(ConstantNode.forBoolean(true)); - builder.addPush(trueNode); - return true; - } return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null); } } @@ -319,19 +314,17 @@ } plugins.setInlineInvokePlugin(inlinePlugin); plugins.setLoopExplosionPlugin(new PELoopExplosionPlugin()); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), newConfig, TruffleCompiler.Optimizations, null).apply(graph); if (PrintTruffleExpansionHistogram.getValue()) { ((HistogramInlineInvokePlugin) inlinePlugin).print(callTarget, System.out); } } - protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) { + protected PEGraphDecoder createGraphDecoder(StructuredGraph graph) { GraphBuilderConfiguration newConfig = configForRoot.copy(); InvocationPlugins parsingInvocationPlugins = newConfig.getPlugins().getInvocationPlugins(); TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), parsingInvocationPlugins, true, snippetReflection); - callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); - LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin(); newConfig.setUseProfiling(false); @@ -340,12 +333,18 @@ plugins.setInlineInvokePlugin(new ParsingInlineInvokePlugin((ReplacementsImpl) providers.getReplacements(), parsingInvocationPlugins, loopExplosionPlugin, !PrintTruffleExpansionHistogram.getValue())); - CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(providers, newConfig, TruffleCompilerImpl.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + return new CachingPEGraphDecoder(providers, newConfig, TruffleCompiler.Optimizations, AllowAssumptions.from(graph.getAssumptions() != null), architecture); + } + protected void doGraphPE(OptimizedCallTarget callTarget, StructuredGraph graph) { + callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy())); + + PEGraphDecoder decoder = createGraphDecoder(graph); + + LoopExplosionPlugin loopExplosionPlugin = new PELoopExplosionPlugin(); ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget); - InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess()); - TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection); + InvocationPlugins decodingInvocationPlugins = createDecodingInvocationPlugins(); InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements()); if (PrintTruffleExpansionHistogram.getValue()) { decodingInlinePlugin = new HistogramInlineInvokePlugin(graph, decodingInlinePlugin); @@ -358,6 +357,12 @@ } } + protected InvocationPlugins createDecodingInvocationPlugins() { + InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess()); + TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection); + return decodingInvocationPlugins; + } + @SuppressWarnings("unused") private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) { if (GraphPE.getValue()) { @@ -434,13 +439,13 @@ } public StructuredGraph createRootGraph(StructuredGraph graph) { - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph); return graph; } public StructuredGraph createInlineGraph(String name, StructuredGraph caller) { StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null)); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations, null).apply(graph); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompiler.Optimizations, null).apply(graph); return graph; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompiler.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2013, 2014, 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.truffle; + +import static com.oracle.graal.api.code.CodeUtil.*; +import static com.oracle.graal.compiler.GraalCompiler.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CallingConvention.Type; +import com.oracle.graal.api.meta.Assumptions.Assumption; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.phases.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.printer.*; +import com.oracle.graal.truffle.nodes.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Implementation of the Truffle compiler using Graal. + */ +public abstract class TruffleCompiler { + + protected final Providers providers; + protected final Suites suites; + protected final GraphBuilderConfiguration config; + protected final LIRSuites lirSuites; + protected final PartialEvaluator partialEvaluator; + protected final Backend backend; + protected final GraalTruffleCompilationListener compilationNotify; + + // @formatter:off + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{ + UnexpectedResultException.class, + SlowPathException.class, + ArithmeticException.class, + IllegalArgumentException.class, + VirtualMachineError.class, + StringIndexOutOfBoundsException.class, + ClassCastException.class + }; + // @formatter:on + + public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, + OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); + + public TruffleCompiler(Plugins plugins, Suites suites, LIRSuites lirSuites, Backend backend) { + GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime()); + this.compilationNotify = graalTruffleRuntime.getCompilationNotify(); + this.backend = backend; + Providers backendProviders = backend.getProviders(); + ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess()); + this.providers = backendProviders.copyWith(constantReflection); + this.suites = suites; + this.lirSuites = lirSuites; + + ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); + + GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(new Plugins(plugins)) + : GraphBuilderConfiguration.getDefault(new Plugins(plugins)); + this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes).withOmitAssertions(TruffleCompilerOptions.TruffleExcludeAssertions.getValue()); + + this.partialEvaluator = createPartialEvaluator(); + + if (Debug.isEnabled()) { + DebugEnvironment.initialize(System.out); + } + } + + protected abstract PartialEvaluator createPartialEvaluator(); + + public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { + ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; + for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { + skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); + } + return skippedExceptionTypes; + } + + public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime"); + public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); + public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); + + public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse"); + public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse"); + public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse"); + + public void compileMethod(final OptimizedCallTarget compilable) { + StructuredGraph graph = null; + + compilationNotify.notifyCompilationStarted(compilable); + + try { + PhaseSuite graphBuilderSuite = createGraphBuilderSuite(); + + try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) { + graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES); + } + + if (Thread.currentThread().isInterrupted()) { + return; + } + + compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph); + CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable); + compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult); + } catch (Throwable t) { + System.out.println("compilation failed!?"); + compilationNotify.notifyCompilationFailed(compilable, graph, t); + throw t; + } + } + + public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) { + try (Scope s = Debug.scope("TruffleFinal")) { + Debug.dump(1, graph, "After TruffleTier"); + } catch (Throwable e) { + throw Debug.handle(e); + } + + CompilationResult result = null; + try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) { + CodeCacheProvider codeCache = providers.getCodeCache(); + CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); + CompilationResult compilationResult = new CompilationResult(name); + result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, + compilationResult, CompilationResultBuilderFactory.Default); + } catch (Throwable e) { + throw Debug.handle(e); + } + + compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph); + + if (graph.isInlinedMethodRecordingEnabled()) { + result.setMethods(graph.method(), graph.getInlinedMethods()); + } else { + assert result.getMethods() == null; + } + + List validAssumptions = new ArrayList<>(); + Set newAssumptions = new HashSet<>(); + for (Assumption assumption : graph.getAssumptions()) { + processAssumption(newAssumptions, assumption, validAssumptions); + } + + if (result.getAssumptions() != null) { + for (Assumption assumption : result.getAssumptions()) { + processAssumption(newAssumptions, assumption, validAssumptions); + } + } + + result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); + + InstalledCode installedCode; + try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) { + installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode); + } catch (Throwable e) { + throw Debug.handle(e); + } + + for (AssumptionValidAssumption a : validAssumptions) { + a.getAssumption().registerInstalledCode(installedCode); + } + + if (Debug.isLogEnabled()) { + Debug.log(providers.getCodeCache().disassemble(result, installedCode)); + } + return result; + } + + protected abstract PhaseSuite createGraphBuilderSuite(); + + public void processAssumption(Set newAssumptions, Assumption assumption, List manual) { + if (assumption != null) { + if (assumption instanceof AssumptionValidAssumption) { + AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption; + manual.add(assumptionValidAssumption); + } else { + newAssumptions.add(assumption); + } + } + } + + public PartialEvaluator getPartialEvaluator() { + return partialEvaluator; + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2013, 2014, 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.truffle; - -import static com.oracle.graal.api.code.CodeUtil.*; -import static com.oracle.graal.compiler.GraalCompiler.*; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.CallingConvention.Type; -import com.oracle.graal.api.meta.Assumptions.Assumption; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.graphbuilderconf.*; -import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import com.oracle.graal.java.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.lir.phases.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.printer.*; -import com.oracle.graal.runtime.*; -import com.oracle.graal.truffle.nodes.*; -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Implementation of the Truffle compiler using Graal. - */ -public class TruffleCompilerImpl { - - private final Providers providers; - private final Suites suites; - private final LIRSuites lirSuites; - private final PartialEvaluator partialEvaluator; - private final Backend backend; - private final GraphBuilderConfiguration config; - private final RuntimeProvider runtime; - private final GraalTruffleCompilationListener compilationNotify; - - // @formatter:off - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{ - UnexpectedResultException.class, - SlowPathException.class, - ArithmeticException.class, - IllegalArgumentException.class, - VirtualMachineError.class, - StringIndexOutOfBoundsException.class, - ClassCastException.class - }; - // @formatter:on - - public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, - OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); - - public TruffleCompilerImpl() { - GraalTruffleRuntime graalTruffleRuntime = ((GraalTruffleRuntime) Truffle.getRuntime()); - this.runtime = Graal.getRequiredCapability(RuntimeProvider.class); - this.compilationNotify = graalTruffleRuntime.getCompilationNotify(); - this.backend = runtime.getHostBackend(); - Providers backendProviders = backend.getProviders(); - ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess()); - this.providers = backendProviders.copyWith(constantReflection); - this.suites = backend.getSuites().getDefaultSuites(); - this.lirSuites = backend.getSuites().getDefaultLIRSuites(); - - ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); - - GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous(); - // copy all plugins from the host - Plugins plugins = new Plugins(phase.getGraphBuilderConfig().getPlugins()); - GraphBuilderConfiguration baseConfig = graalTruffleRuntime.enableInfopoints() ? GraphBuilderConfiguration.getInfopointDefault(plugins) : GraphBuilderConfiguration.getDefault(plugins); - this.config = baseConfig.withSkippedExceptionTypes(skippedExceptionTypes); - - this.partialEvaluator = new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class), backend.getTarget().arch); - - if (Debug.isEnabled()) { - DebugEnvironment.initialize(System.out); - } - } - - public static ResolvedJavaType[] getSkippedExceptionTypes(MetaAccessProvider metaAccess) { - ResolvedJavaType[] skippedExceptionTypes = new ResolvedJavaType[SKIPPED_EXCEPTION_CLASSES.length]; - for (int i = 0; i < SKIPPED_EXCEPTION_CLASSES.length; i++) { - skippedExceptionTypes[i] = metaAccess.lookupJavaType(SKIPPED_EXCEPTION_CLASSES[i]); - } - return skippedExceptionTypes; - } - - public static final DebugTimer PartialEvaluationTime = Debug.timer("PartialEvaluationTime"); - public static final DebugTimer CompilationTime = Debug.timer("CompilationTime"); - public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation"); - - public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse"); - public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse"); - public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse"); - - public void compileMethod(final OptimizedCallTarget compilable) { - StructuredGraph graph = null; - - compilationNotify.notifyCompilationStarted(compilable); - - try { - PhaseSuite graphBuilderSuite = createGraphBuilderSuite(); - - try (DebugCloseable a = PartialEvaluationTime.start(); DebugCloseable c = PartialEvaluationMemUse.start()) { - graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES); - } - - if (Thread.currentThread().isInterrupted()) { - return; - } - - compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph); - CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable); - compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult); - } catch (Throwable t) { - System.out.println("compilation failed!?"); - compilationNotify.notifyCompilationFailed(compilable, graph, t); - throw t; - } - } - - public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) { - try (Scope s = Debug.scope("TruffleFinal")) { - Debug.dump(1, graph, "After TruffleTier"); - } catch (Throwable e) { - throw Debug.handle(e); - } - - CompilationResult result = null; - try (DebugCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); DebugCloseable c = CompilationMemUse.start()) { - CodeCacheProvider codeCache = providers.getCodeCache(); - CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false); - CompilationResult compilationResult = new CompilationResult(name); - result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, - compilationResult, CompilationResultBuilderFactory.Default); - } catch (Throwable e) { - throw Debug.handle(e); - } - - compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph); - - if (graph.isInlinedMethodRecordingEnabled()) { - result.setMethods(graph.method(), graph.getInlinedMethods()); - } else { - assert result.getMethods() == null; - } - - List validAssumptions = new ArrayList<>(); - Set newAssumptions = new HashSet<>(); - for (Assumption assumption : graph.getAssumptions()) { - processAssumption(newAssumptions, assumption, validAssumptions); - } - - if (result.getAssumptions() != null) { - for (Assumption assumption : result.getAssumptions()) { - processAssumption(newAssumptions, assumption, validAssumptions); - } - } - - result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()])); - - InstalledCode installedCode; - try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); DebugCloseable a = CodeInstallationTime.start(); DebugCloseable c = CodeInstallationMemUse.start()) { - installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode); - } catch (Throwable e) { - throw Debug.handle(e); - } - - for (AssumptionValidAssumption a : validAssumptions) { - a.getAssumption().registerInstalledCode(installedCode); - } - - if (Debug.isLogEnabled()) { - Debug.log(providers.getCodeCache().disassemble(result, installedCode)); - } - return result; - } - - private PhaseSuite createGraphBuilderSuite() { - PhaseSuite suite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); - ListIterator> iterator = suite.findPhase(GraphBuilderPhase.class); - iterator.remove(); - iterator.add(new GraphBuilderPhase(config)); - return suite; - } - - public void processAssumption(Set newAssumptions, Assumption assumption, List manual) { - if (assumption != null) { - if (assumption instanceof AssumptionValidAssumption) { - AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption; - manual.add(assumptionValidAssumption); - } else { - newAssumptions.add(assumption); - } - } - } - - public PartialEvaluator getPartialEvaluator() { - return partialEvaluator; - } -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/ObjectLocationIdentity.java Fri May 15 11:55:52 2015 +0200 @@ -53,11 +53,15 @@ } private ObjectLocationIdentity(JavaConstant object) { - super(false); this.object = object; } @Override + public boolean isImmutable() { + return false; + } + + @Override public String toString() { return "Identity(" + object + ")"; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Fri May 15 11:55:52 2015 +0200 @@ -109,6 +109,12 @@ return success; } + public static void trace(String format) { + if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format); + } + } + public static void trace(String format, Object obj) { if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { Debug.logv(format, obj); @@ -127,6 +133,12 @@ } } + public static void trace(String format, Object obj, Object obj2, Object obj3, Object obj4) { + if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) { + Debug.logv(format, obj, obj2, obj3, obj4); + } + } + public static boolean matches(StructuredGraph graph, String filter) { if (filter != null) { return matchesHelper(graph, filter); diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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.truffle.api.test.instrument; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; +import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdvancedInstrumentCounterRoot; + +/** + * Tests the kind of instrumentation where a client can provide an AST fragment to be + * spliced directly into the AST. + */ +public class AdvancedInstrumentTest { + + @Test + public void testAdvancedInstrumentListener() { + // Create a simple addition AST + final TruffleRuntime runtime = Truffle.getRuntime(); + final TestValueNode leftValueNode = new TestValueNode(6); + final TestValueNode rightValueNode = new TestValueNode(7); + final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); + final TestRootNode rootNode = new TestRootNode(addNode); + final CallTarget callTarget1 = runtime.createCallTarget(rootNode); + + // Ensure it executes correctly + assertEquals(13, callTarget1.call()); + + // Probe the addition node + final Probe probe = addNode.probe(); + + assertEquals(13, callTarget1.call()); + + // Attach a null factory; it never actually attaches a node. + final Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() { + + public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) { + return null; + } + }, null, "test AdvancedInstrument"); + probe.attach(instrument); + + assertEquals(13, callTarget1.call()); + + final TestAdvancedInstrumentCounterRoot counter = new TestAdvancedInstrumentCounterRoot(); + + // Attach a factory that splices an execution counter into the AST. + probe.attach(Instrument.create(null, new AdvancedInstrumentRootFactory() { + + public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) { + return counter; + } + }, null, "test AdvancedInstrument")); + assertEquals(0, counter.getCount()); + + assertEquals(13, callTarget1.call()); + + assertEquals(1, counter.getCount()); + } +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java Fri May 15 11:55:52 2015 +0200 @@ -167,12 +167,12 @@ } } - static class TestToolEvalCounterNode extends ToolEvalNode { + static class TestAdvancedInstrumentCounterRoot extends AdvancedInstrumentRoot { private long count; @Override - public Object executeToolEvalNode(Node node, VirtualFrame vFrame) { + public Object executeRoot(Node node, VirtualFrame vFrame) { count++; return null; } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolEvalInstrumentTest.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2015, 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.truffle.api.test.instrument; - -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode; -import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestToolEvalCounterNode; - -/** - * Tests the kind of instrumentation where a client can provide an AST fragment to be - * spliced directly into the AST. - */ -public class ToolEvalInstrumentTest { - - @Test - public void testSpliceInstrumentListener() { - // Create a simple addition AST - final TruffleRuntime runtime = Truffle.getRuntime(); - final TestValueNode leftValueNode = new TestValueNode(6); - final TestValueNode rightValueNode = new TestValueNode(7); - final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode); - final TestRootNode rootNode = new TestRootNode(addNode); - final CallTarget callTarget1 = runtime.createCallTarget(rootNode); - - // Ensure it executes correctly - assertEquals(13, callTarget1.call()); - - // Probe the addition node - final Probe probe = addNode.probe(); - - assertEquals(13, callTarget1.call()); - - // Attach a null listener; it never actually attaches a node. - final Instrument instrument = Instrument.create(new ToolEvalNodeFactory() { - - public ToolEvalNode createToolEvalNode(Probe p, Node n) { - return null; - } - }, null); - probe.attach(instrument); - - assertEquals(13, callTarget1.call()); - - final TestToolEvalCounterNode counter = new TestToolEvalCounterNode(); - - // Attach a listener that splices an execution counter into the AST. - probe.attach(Instrument.create(new ToolEvalNodeFactory() { - - public ToolEvalNode createToolEvalNode(Probe p, Node n) { - return counter; - } - }, null)); - assertEquals(0, counter.getCount()); - - assertEquals(13, callTarget1.call()); - - assertEquals(1, counter.getCount()); - - } - -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Listener for receiving the result a client-provided {@linkplain AdvancedInstrumentRoot AST + * fragment}, when executed by a + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRoot + * @see AdvancedInstrumentRootFactory + */ +public interface AdvancedInstrumentResultListener { + + /** + * Notifies listener that a client-provided {@linkplain AdvancedInstrumentRoot AST fragment} has + * been executed by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument} with the specified result, possibly {@code null}. + *

+ * Note: Truffle will attempt to optimize implementations through partial + * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted. + * + * @param node the guest-language AST node to which the host Instrument's {@link Probe} is + * attached + * @param vFrame execution frame at the guest-language AST node + * @param result the result of this AST fragment's execution + */ + void notifyResult(Node node, VirtualFrame vFrame, Object result); + + /** + * Notifies listener that execution of client-provided {@linkplain AdvancedInstrumentRoot AST + * fragment} filed during execution by a @linkplain + * Instrument#create(AdvancedInstrumentRootFactory, String) Advanced Instrument}. + *

+ * Note: Truffle will attempt to optimize implementations through partial + * evaluation; annotate with {@link TruffleBoundary} if this should not be permitted. + * + * @param node the guest-language AST node to which the host Instrument's {@link Probe} is + * attached + * @param vFrame execution frame at the guest-language AST node + * @param ex the exception + */ + void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex); + +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle + * optimization, by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRootFactory + * @see AdvancedInstrumentResultListener + */ +public abstract class AdvancedInstrumentRoot extends Node implements InstrumentationNode { + + /** + * Executes this AST fragment on behalf of a client {@link Instrument}, just before the + * guest-language AST node to which the {@link Probe} holding the Instrument is executed. + * + * @param node the guest-language AST node to which the host Instrument's Probe is attached + * @param vFrame execution frame at the guest-language AST node + * @return the result of this AST fragment's execution + */ + public abstract Object executeRoot(Node node, VirtualFrame vFrame); + +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java Fri May 15 11:55:52 2015 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.instrument; + +import com.oracle.truffle.api.nodes.*; + +/** + * Creator of {@linkplain AdvancedInstrumentRoot AST fragments} suitable for efficient execution, + * subject to full Truffle optimization, by an + * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String) + * Advanced Instrument}. + * + * @see Instrument + * @see AdvancedInstrumentRoot + */ +public interface AdvancedInstrumentRootFactory { + + /** + * Provider of {@linkplain AdvancedInstrumentRoot AST fragment} instances for efficient + * execution via instrumentation, subject to full Truffle optimization, at a {@linkplain Probe + * Probed} site in a guest-language AST. + * + * @param probe the Probe to which the Instrument requesting the AST fragment is attached + * @param node the guest-language AST location that is the context in which the requesting + * Instrument must execute the AST fragment. + * @return a newly created AST fragment suitable for execution, via instrumentation, in the + * execution context of the specified guest-language AST site. + */ + AdvancedInstrumentRoot createInstrumentRoot(Probe probe, Node node); +} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Fri May 15 11:40:02 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Fri May 15 11:55:52 2015 +0200 @@ -127,16 +127,19 @@ } /** - * Creates a Tool Eval Instrument: this Instrument executes efficiently, subject to + * Creates an Advanced Instrument: this Instrument executes efficiently, subject to * full Truffle optimization, a client-provided AST fragment every time the Probed node is * entered. * - * @param toolEvalNodeFactory provider of AST fragments on behalf of the client + * @param resultListener optional client callback for results/failure notification + * @param rootFactory provider of AST fragments on behalf of the client + * @param requiredResultType optional requirement, any non-assignable result is reported to the + * the listener, if any, as a failure * @param instrumentInfo optional description of the instrument's role, intended for debugging. * @return a new instrument, ready for attachment at a probe */ - public static Instrument create(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) { - return new ToolEvalInstrument(toolEvalNodeFactory, instrumentInfo); + public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class requiredResultType, String instrumentInfo) { + return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo); } // TODO (mlvdv) experimental @@ -379,22 +382,22 @@ * within a Probe's instrumentation chain, and thus directly in the executing Truffle * AST with potential for full optimization. */ - private static final class ToolEvalInstrument extends Instrument { + private static final class AdvancedInstrument extends Instrument { + + private final AdvancedInstrumentResultListener resultListener; + private final AdvancedInstrumentRootFactory rootFactory; + private final Class requiredResultType; - /** - * Client-provided supplier of new node instances to attach. - */ - private final ToolEvalNodeFactory toolEvalNodeFactory; - - private ToolEvalInstrument(ToolEvalNodeFactory toolEvalNodeFactory, String instrumentInfo) { + private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class requiredResultType, String instrumentInfo) { super(instrumentInfo); - this.toolEvalNodeFactory = toolEvalNodeFactory; - + this.resultListener = resultListener; + this.rootFactory = rootFactory; + this.requiredResultType = requiredResultType; } @Override AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) { - return new ToolEvalNodeInstrumentNode(nextNode); + return new AdvancedInstrumentNode(nextNode); } @Override @@ -406,7 +409,7 @@ return instrumentNode.nextInstrumentNode; } // Match not at the head of the chain; remove it. - found = instrumentNode.removeFromChain(ToolEvalInstrument.this); + found = instrumentNode.removeFromChain(AdvancedInstrument.this); } if (!found) { throw new IllegalStateException("Couldn't find instrument node to remove: " + this); @@ -415,35 +418,62 @@ } /** - * Node that implements a {@link ToolEvalInstrument} in a particular AST. + * Node that implements a {@link AdvancedInstrument} in a particular AST. */ @NodeInfo(cost = NodeCost.NONE) - private final class ToolEvalNodeInstrumentNode extends AbstractInstrumentNode { + private final class AdvancedInstrumentNode extends AbstractInstrumentNode { - @Child private ToolEvalNode toolEvalNode; + @Child private AdvancedInstrumentRoot instrumentRoot; - private ToolEvalNodeInstrumentNode(AbstractInstrumentNode nextNode) { + private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) { super(nextNode); } public void enter(Node node, VirtualFrame vFrame) { - if (toolEvalNode == null) { - final ToolEvalNode newToolEvalNodeNode = ToolEvalInstrument.this.toolEvalNodeFactory.createToolEvalNode(ToolEvalInstrument.this.probe, node); - if (newToolEvalNodeNode != null) { - toolEvalNode = newToolEvalNodeNode; - adoptChildren(); - ToolEvalInstrument.this.probe.invalidateProbeUnchanged(); + if (instrumentRoot == null) { + try { + final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node); + if (newInstrumentRoot != null) { + instrumentRoot = newInstrumentRoot; + adoptChildren(); + AdvancedInstrument.this.probe.invalidateProbeUnchanged(); + } + } catch (RuntimeException ex) { + if (resultListener != null) { + resultListener.notifyFailure(node, vFrame, ex); + } } } - if (toolEvalNode != null) { - // TODO (mlvdv) should report exception ; non-trivial architectural change - toolEvalNode.executeToolEvalNode(node, vFrame); + if (instrumentRoot != null) { + try { + final Object result = instrumentRoot.executeRoot(node, vFrame); + if (resultListener != null) { + checkResultType(result); + resultListener.notifyResult(node, vFrame, result); + } + } catch (RuntimeException ex) { + if (resultListener != null) { + resultListener.notifyFailure(node, vFrame, ex); + } + } } if (nextInstrumentNode != null) { nextInstrumentNode.enter(node, vFrame); } } + private void checkResultType(Object result) { + if (requiredResultType == null) { + return; + } + if (result == null) { + throw new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required"); + } + if (!(requiredResultType.isAssignableFrom(result.getClass()))) { + throw new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName()); + } + } + public void returnVoid(Node node, VirtualFrame vFrame) { if (nextInstrumentNode != null) { nextInstrumentNode.returnVoid(node, vFrame); @@ -464,7 +494,7 @@ public String instrumentationInfo() { final String info = getInstrumentInfo(); - return info != null ? info : toolEvalNodeFactory.getClass().getSimpleName(); + return info != null ? info : rootFactory.getClass().getSimpleName(); } } } diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNode.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Root of a client-provided AST fragment that can be executed efficiently, subject to full Truffle - * optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval - * Instrument}. - * - * @see Instrument - * @see ToolEvalNodeFactory - * @see ToolEvalResultListener - */ -public abstract class ToolEvalNode extends Node implements InstrumentationNode { - - /** - * Executes this AST fragment on behalf of a client {@link Instrument}, just before the - * guest-language AST node to which the {@link Probe} holding the Instrument is executed. - * - * @param node the guest-language AST node to which the host Instrument's Probe is attached - * @param vFrame execution frame at the guest-language AST node - * @return the result of this AST fragment's execution - */ - public abstract Object executeToolEvalNode(Node node, VirtualFrame vFrame); - -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalNodeFactory.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument; - -import com.oracle.truffle.api.nodes.*; - -/** - * Creator of {@linkplain ToolEvalNode AST fragments} suitable for efficient execution, subject to - * full Truffle optimization, by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool - * Eval Instrument}. - * - * @see Instrument - * @see ToolEvalNode - */ -public interface ToolEvalNodeFactory { - - /** - * Provider of {@linkplain ToolEvalNode AST fragment} instances for efficient execution via - * instrumentation, subject to full Truffle optimization, at a {@linkplain Probe Probed} site in - * a guest-language AST. - * - * @param probe the Probe to which the Instrument requesting the AST fragment is attached - * @param node the guest-language AST location that is the context in which the requesting - * Instrument must execute the AST fragment. - * @return a newly created AST fragment suitable for execution, via instrumentation, in the - * execution context of the specified guest-language AST site. - */ - ToolEvalNode createToolEvalNode(Probe probe, Node node); -} diff -r 427f3b505656 -r 307a1ee8f714 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolEvalResultListener.java Fri May 15 11:40:02 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2015, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.instrument; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Listener for receiving the result a client-provided {@linkplain ToolEvalNode AST fragment}, when - * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval Instrument}. - * - * @see Instrument - * @see ToolEvalNode - * @see ToolEvalNodeFactory - */ -public interface ToolEvalResultListener { - - /** - * Notifies listener that a client-provided {@linkplain ToolEvalNode AST fragment} has been - * executed by a {@linkplain Instrument#create(ToolEvalNodeFactory, String) Tool Eval - * Instrument} with the specified result, possibly {@code null}. - * - * @param node the guest-language AST node to which the host Instrument's {@link Probe} is - * attached - * @param vFrame execution frame at the guest-language AST node - * @param result the result of this AST fragment's execution - */ - void notifyToolEvalResult(Node node, VirtualFrame vFrame, Object result); - - /** - * Notifies listener that execution of client-provided {@linkplain ToolEvalNode AST fragment} - * filed during execution by a @linkplain Instrument#create(ToolEvalNodeFactory, String) Tool - * Eval Instrument}. - * - * @param node the guest-language AST node to which the host Instrument's {@link Probe} is - * attached - * @param vFrame execution frame at the guest-language AST node - * @param ex the exception - */ - void notifyToolEvalFailure(Node node, VirtualFrame vFrame, RuntimeException ex); - -} diff -r 427f3b505656 -r 307a1ee8f714 mxtool/mx.py --- a/mxtool/mx.py Fri May 15 11:40:02 2015 +0200 +++ b/mxtool/mx.py Fri May 15 11:55:52 2015 +0200 @@ -622,7 +622,7 @@ if not exists(cachePath) or sha1OfFile(cachePath) != sha1: if exists(cachePath): - log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - re-downloading') + log('SHA1 of ' + cachePath + ' does not match expected value (' + sha1 + ') - found ' + sha1OfFile(cachePath) + ' - re-downloading') print 'Downloading ' + ("sources " if sources else "") + name + ' from ' + str(urls) download(cachePath, urls) @@ -1019,6 +1019,7 @@ p = Project(self, name, srcDirs, deps, javaCompliance, workingSets, d) p.checkstyleProj = attrs.pop('checkstyle', name) p.native = attrs.pop('native', '') == 'true' + p.checkPackagePrefix = attrs.pop('checkPackagePrefix', 'true') == 'true' if not p.native and p.javaCompliance is None: abort('javaCompliance property required for non-native project ' + name) if len(ap) > 0: @@ -3355,9 +3356,10 @@ nonCanonical = [] for s in suites(True): for p in s.projects: - for pkg in p.defined_java_packages(): - if not pkg.startswith(p.name): - abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg)) + if p.checkPackagePrefix: + for pkg in p.defined_java_packages(): + if not pkg.startswith(p.name): + abort('package in {0} does not have prefix matching project name: {1}'.format(p, pkg)) ignoredDeps = set([name for name in p.deps if project(name, False) is not None]) for pkg in p.imported_java_packages(): @@ -3451,7 +3453,7 @@ config = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml') if not exists(config): - logv('[No Checkstyle configuration foudn for {0} - skipping]'.format(p)) + logv('[No Checkstyle configuration found for {0} - skipping]'.format(p)) continue # skip checking this Java project if its Java compliance level is "higher" than the configured JDK