# HG changeset patch # User Christian Haeubl # Date 1355212092 -3600 # Node ID 2ae3e26b7e9aeddeb6a9ea196941156505529869 # Parent fcae6d960acd5c2360eac6d0c4eac6a94477f20e# Parent 6a8b22829e369f92f20837314d5fd83c53bb386d Merge. diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.api.code; import com.oracle.graal.api.code.CompilationResult.DataPatch; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; /** @@ -39,7 +39,7 @@ * @param compResult the compilation result to be added * @param info the object into which details of the installed code will be written. Ignored if null, otherwise the * info is written to index 0 of this array. - * @return a reference to the compiled and ready-to-run code + * @return a reference to the compiled and ready-to-run code or null if the code installation failed */ InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info); @@ -61,7 +61,7 @@ * * @param method the top level method of a compilation */ - RegisterConfig lookupRegisterConfig(JavaMethod method); + RegisterConfig lookupRegisterConfig(ResolvedJavaMethod method); /** * Custom area on the stack of each compiled method that the VM can use for its own purposes. @@ -81,12 +81,12 @@ /** * Performs any runtime-specific conversion on the object used to describe the target of a call. */ - Object lookupCallTarget(Object target); + Object lookupCallTarget(Object callTarget); /** * Gets the signature and linkage information for a runtime call. */ - RuntimeCall lookupRuntimeCall(Descriptor descriptor); + RuntimeCallTarget lookupRuntimeCall(Descriptor descriptor); /** * Encodes a deoptimization action and a deoptimization reason in an integer value. diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCall.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCall.java Tue Dec 11 08:28:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.api.code; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -/** - * The name, signature and calling convention of a call from compiled code to the runtime. - * The target of such a call may be a leaf stub or a call into the runtime code proper. - */ -public interface RuntimeCall { - - /** - * The name and signature of a runtime call. - */ - public static class Descriptor { - private final String name; - private final boolean hasSideEffect; - private final Kind resultKind; - private final Kind[] argumentKinds; - - public Descriptor(String name, boolean hasSideEffect, Kind resultKind, Kind... args) { - this.name = name; - this.hasSideEffect = hasSideEffect; - this.resultKind = resultKind; - this.argumentKinds = args; - } - - /** - * Gets the name of this runtime call. - */ - public String getName() { - return name; - } - - /** - * Determines if this call changes state visible to other threads. - * Such calls denote boundaries across which deoptimization - * points cannot be moved. - */ - public boolean hasSideEffect() { - return hasSideEffect; - } - - /** - * Gets the return kind of this runtime call. - */ - public Kind getResultKind() { - return resultKind; - } - - /** - * Gets the argument kinds of this runtime call. - */ - public Kind[] getArgumentKinds() { - return argumentKinds.clone(); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Descriptor) { - Descriptor nas = (Descriptor) obj; - return nas.name.equals(name) && nas.resultKind.equals(resultKind) && Arrays.equals(nas.argumentKinds, argumentKinds); - } - return false; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(name).append('('); - String sep = ""; - for (Kind arg : argumentKinds) { - sb.append(sep).append(arg); - sep = ","; - } - return sb.append(')').append(resultKind).toString(); - } - } - - CallingConvention getCallingConvention(); - - /** - * Returns the maximum absolute offset of PC relative call to this stub from any position in the code cache or -1 - * when not applicable. Intended for determining the required size of address/offset fields. - */ - long getMaxCallTargetOffset(); - - Descriptor getDescriptor(); -} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.api.code; + +import java.util.*; + +import com.oracle.graal.api.meta.*; + +/** + * The name, signature and calling convention of a call from compiled code to the runtime. + * The target of such a call may be a leaf stub or a call into the runtime code proper. + */ +public interface RuntimeCallTarget { + + /** + * The name and signature of a runtime call. + */ + public static class Descriptor { + private final String name; + private final boolean hasSideEffect; + private final Kind resultKind; + private final Kind[] argumentKinds; + + public Descriptor(String name, boolean hasSideEffect, Kind resultKind, Kind... args) { + this.name = name; + this.hasSideEffect = hasSideEffect; + this.resultKind = resultKind; + this.argumentKinds = args; + } + + /** + * Gets the name of this runtime call. + */ + public String getName() { + return name; + } + + /** + * Determines if this call changes state visible to other threads. + * Such calls denote boundaries across which deoptimization + * points cannot be moved. + */ + public boolean hasSideEffect() { + return hasSideEffect; + } + + /** + * Gets the return kind of this runtime call. + */ + public Kind getResultKind() { + return resultKind; + } + + /** + * Gets the argument kinds of this runtime call. + */ + public Kind[] getArgumentKinds() { + return argumentKinds.clone(); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Descriptor) { + Descriptor nas = (Descriptor) obj; + return nas.name.equals(name) && nas.resultKind.equals(resultKind) && Arrays.equals(nas.argumentKinds, argumentKinds); + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name).append('('); + String sep = ""; + for (Kind arg : argumentKinds) { + sb.append(sep).append(arg); + sep = ","; + } + return sb.append(')').append(resultKind).toString(); + } + } + + CallingConvention getCallingConvention(); + + /** + * Returns the maximum absolute offset of PC relative call to this stub from any position in the code cache or -1 + * when not applicable. Intended for determining the required size of address/offset fields. + */ + long getMaxCallTargetOffset(); + + Descriptor getDescriptor(); +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Tue Dec 11 08:48:12 2012 +0100 @@ -215,9 +215,12 @@ /** * Returns the instance fields of this class, including {@linkplain ResolvedJavaField#isInternal() internal} fields. * A zero-length array is returned for array and primitive types. The order of fields returned by this method is - * stable. That is, for a single JVM execution the same order is returned each time this method is called. + * stable. That is, for a single JVM execution the same order is returned each time this method is called. It is + * also the "natural" order, which means that the JVM would expect the fields in this order if no specific order is + * given. * - * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this type are included in the result + * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this type are included in + * the result * @return an array of instance fields */ ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64DeoptimizationStub.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64DeoptimizationStub.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,7 +25,7 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.*; +import com.oracle.graal.api.code.RuntimeCallTarget.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; diff -r fcae6d960acd -r 2ae3e26b7e9a 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 Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Tue Dec 11 08:48:12 2012 +0100 @@ -29,7 +29,7 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; @@ -382,11 +382,11 @@ append(new DivOp(LREM, RDX_L, RAX_L, load(b), state())); return emitMove(RDX_L); case Float: { - RuntimeCall stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM); + RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM); return emitCall(stub, stub.getCallingConvention(), false, a, b); } case Double: { - RuntimeCall stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM); + RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM); return emitCall(stub, stub.getCallingConvention(), false, a, b); } default: @@ -571,11 +571,11 @@ } @Override - protected void emitCall(Object targetMethod, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info) { + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info) { if (isConstant(targetAddress)) { - append(new DirectCallOp(targetMethod, result, arguments, temps, info)); + append(new DirectCallOp(callTarget, result, arguments, temps, info)); } else { - append(new IndirectCallOp(targetMethod, result, arguments, temps, targetAddress, info)); + append(new IndirectCallOp(callTarget, result, arguments, temps, targetAddress, info)); } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Tue Dec 11 08:48:12 2012 +0100 @@ -216,13 +216,20 @@ return LabelRef.forSuccessor(lir, currentBlock, suxIndex); } + /** + * Determines if only oop maps are required for the code generated from the LIR. + */ + protected boolean needOnlyOopMaps() { + return false; + } + public LIRFrameState state() { - assert lastState != null : "must have state before instruction"; + assert lastState != null || needOnlyOopMaps() : "must have state before instruction"; return stateFor(lastState, StructuredGraph.INVALID_GRAPH_ID); } public LIRFrameState state(long leafGraphId) { - assert lastState != null : "must have state before instruction"; + assert lastState != null || needOnlyOopMaps() : "must have state before instruction"; return stateFor(lastState, leafGraphId); } @@ -231,6 +238,9 @@ } public LIRFrameState stateFor(FrameState state, List pointerSlots, LabelRef exceptionEdge, long leafGraphId) { + if (needOnlyOopMaps()) { + return new LIRFrameState(null, null, null, null); + } return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), pointerSlots, exceptionEdge, leafGraphId); } @@ -731,7 +741,7 @@ protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); - protected abstract void emitCall(Object targetMethod, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info); + protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info); private static Value toStackKind(Value value) { if (value.getKind().getStackKind() != value.getKind()) { @@ -768,7 +778,7 @@ protected abstract LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo); @Override - public Variable emitCall(@SuppressWarnings("hiding") Object target, CallingConvention cc, boolean canTrap, Value... args) { + public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args) { LIRFrameState info = canTrap ? state() : null; // move the arguments into the correct location @@ -781,7 +791,7 @@ emitMove(arg, loc); argLocations[i] = loc; } - emitCall(target, cc.getReturn(), argLocations, cc.getTemporaries(), Constant.forLong(0), info); + emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), Constant.forLong(0), info); if (isLegal(cc.getReturn())) { return emitMove(cc.getReturn()); @@ -792,7 +802,7 @@ @Override public void visitRuntimeCall(RuntimeCallNode x) { - RuntimeCall call = runtime.lookupRuntimeCall(x.getDescriptor()); + RuntimeCallTarget call = runtime.lookupRuntimeCall(x.getDescriptor()); CallingConvention cc = call.getCallingConvention(); frameMap.callsMethod(cc); Value resultOperand = cc.getReturn(); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java Tue Dec 11 08:48:12 2012 +0100 @@ -74,8 +74,8 @@ private final InvokeKind invokeKind; - AMD64DirectCallOp(Object targetMethod, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, LIR lir) { - super(targetMethod, result, parameters, temps, state); + AMD64DirectCallOp(Object target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, LIR lir) { + super(target, result, parameters, temps, state); this.invokeKind = invokeKind; if (invokeKind == Static || invokeKind == Special) { @@ -116,6 +116,6 @@ callsiteMark = tasm.recordMark(null); } - AMD64Call.directCall(tasm, masm, targetMethod, state); + AMD64Call.directCall(tasm, masm, callTarget, state); } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Tue Dec 11 08:48:12 2012 +0100 @@ -40,6 +40,7 @@ import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; @@ -73,7 +74,18 @@ } @Override + protected boolean needOnlyOopMaps() { + // Stubs only need oop maps + return runtime().asStub(method) != null; + } + + @Override protected CallingConvention createCallingConvention() { + Stub stub = runtime().asStub(method); + if (stub != null) { + return stub.getLinkage().getCallingConvention(); + } + if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { return super.createCallingConvention(); } else { @@ -219,14 +231,14 @@ // - has no callee-saved registers // - has no incoming arguments passed on the stack // - has no instructions with debug info - boolean canOmitFrame = GraalOptions.CanOmitFrame && + boolean omitFrame = GraalOptions.CanOmitFrame && frameMap.frameSize() == frameMap.initialFrameSize && frameMap.registerConfig.getCalleeSaveLayout().registers.length == 0 && !lir.hasArgInCallerFrame() && !lir.hasDebugInfo(); AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig); - HotSpotFrameContext frameContext = canOmitFrame ? null : new HotSpotFrameContext(); + HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(); TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, lir.stubs); tasm.setFrameSize(frameMap.frameSize()); tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); @@ -239,11 +251,11 @@ FrameMap frameMap = tasm.frameMap; RegisterConfig regConfig = frameMap.registerConfig; HotSpotVMConfig config = runtime().config; - Label unverifiedStub = new Label(); + boolean isStatic = Modifier.isStatic(method.getModifiers()); + Label unverifiedStub = isStatic ? null : new Label(); // Emit the prefix - boolean isStatic = Modifier.isStatic(method.getModifiers()); if (!isStatic) { tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY); CallingConvention cc = regConfig.getCallingConvention(JavaCallee, Kind.Void, new Kind[] {Kind.Object}, target, false); @@ -277,7 +289,7 @@ assert !frameMap.accessesCallerFrame(); } - if (!isStatic) { + if (unverifiedStub != null) { asm.bind(unverifiedStub); AMD64Call.directJmp(tasm, asm, config.inlineCacheMissStub); } @@ -285,5 +297,6 @@ for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) { asm.int3(); } + } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Tue Dec 11 08:48:12 2012 +0100 @@ -27,7 +27,9 @@ import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*; import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; +import static com.oracle.graal.hotspot.nodes.NewArraySlowStubCall.*; import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; +import static com.oracle.graal.hotspot.nodes.NewInstanceSlowStubCall.*; import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; @@ -74,30 +76,35 @@ /* arg1: b */ arg(1, Kind.Double)); addRuntimeCall(MONITORENTER, config.monitorEnterStub, - /* temps */ new Register[] {rax, rbx}, + /* temps */ null, /* ret */ ret(Kind.Void), /* arg0: object */ arg(0, Kind.Object), /* arg1: lock */ arg(1, word)); addRuntimeCall(MONITOREXIT, config.monitorExitStub, - /* temps */ new Register[] {rax, rbx}, + /* temps */ null, /* ret */ ret(Kind.Void), /* arg0: object */ arg(0, Kind.Object), /* arg1: lock */ arg(1, word)); - addRuntimeCall(NEW_OBJECT_ARRAY, config.newObjectArrayStub, - /* temps */ new Register[] {rcx, rdi, rsi}, + addRuntimeCall(NEW_ARRAY, 0L, + /* temps */ null, /* ret */ rax.asValue(Kind.Object), /* arg0: hub */ rdx.asValue(word), /* arg1: length */ rbx.asValue(Kind.Int)); - addRuntimeCall(NEW_TYPE_ARRAY, config.newTypeArrayStub, - /* temps */ new Register[] {rcx, rdi, rsi}, + addRuntimeCall(NEW_ARRAY_SLOW, config.newArrayStub, + /* temps */ null, /* ret */ rax.asValue(Kind.Object), /* arg0: hub */ rdx.asValue(word), /* arg1: length */ rbx.asValue(Kind.Int)); - addRuntimeCall(NEW_INSTANCE, config.newInstanceStub, + addRuntimeCall(NEW_INSTANCE, 0L, + /* temps */ null, + /* ret */ rax.asValue(Kind.Object), + /* arg0: hub */ rdx.asValue(word)); + + addRuntimeCall(NEW_INSTANCE_SLOW, c.newInstanceStub, /* temps */ null, /* ret */ rax.asValue(Kind.Object), /* arg0: hub */ rdx.asValue(word)); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Tue Dec 11 08:48:12 2012 +0100 @@ -62,7 +62,7 @@ tasm.recordMark(Marks.MARK_INLINE_INVOKEVIRTUAL); Register callReg = asRegister(targetAddress); assert callReg != METHOD; - AMD64Call.indirectCall(tasm, masm, callReg, targetMethod, state); + AMD64Call.indirectCall(tasm, masm, callReg, callTarget, state); } @Override diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCall.java Tue Dec 11 08:28:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.hotspot.bridge.*; - -/** - * The details required to link a HotSpot runtime or stub call. - */ -public class HotSpotRuntimeCall implements RuntimeCall { - - /** - * The descriptor of the stub. This is for informational purposes only. - */ - public final Descriptor descriptor; - - /** - * The entry point address of the stub. - */ - public final long address; - - /** - * Where the stub gets its arguments and where it places its result. - */ - public final CallingConvention cc; - - private final CompilerToVM vm; - - public HotSpotRuntimeCall(Descriptor descriptor, long address, CallingConvention cc, CompilerToVM vm) { - this.address = address; - this.descriptor = descriptor; - this.cc = cc; - this.vm = vm; - } - - @Override - public String toString() { - return descriptor + "@0x" + Long.toHexString(address) + ":" + cc; - } - - public CallingConvention getCallingConvention() { - return cc; - } - - public long getMaxCallTargetOffset() { - return vm.getMaxCallTargetOffset(address); - } - - public Descriptor getDescriptor() { - return descriptor; - } -} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.stubs.*; + +/** + * The details required to link a HotSpot runtime or stub call. + */ +public class HotSpotRuntimeCallTarget implements RuntimeCallTarget { + + /** + * The descriptor of the stub. This is for informational purposes only. + */ + public final Descriptor descriptor; + + /** + * The entry point address of the stub. + */ + private long address; + + /** + * Non-null (eventually) iff this is a call to a snippet-based {@linkplain Stub stub}. + */ + private Stub stub; + + /** + * Where the stub gets its arguments and where it places its result. + */ + public final CallingConvention cc; + + private final CompilerToVM vm; + + public HotSpotRuntimeCallTarget(Descriptor descriptor, long address, CallingConvention cc, CompilerToVM vm) { + this.address = address; + this.descriptor = descriptor; + this.cc = cc; + this.vm = vm; + } + + @Override + public String toString() { + return (stub == null ? descriptor.toString() : MetaUtil.format("%h.%n", stub.getMethod())) + "@0x" + Long.toHexString(address) + ":" + cc; + } + + public CallingConvention getCallingConvention() { + return cc; + } + + public long getMaxCallTargetOffset() { + return vm.getMaxCallTargetOffset(address); + } + + public Descriptor getDescriptor() { + return descriptor; + } + + public void setStub(Stub stub) { + assert address == 0L : "cannot stub for linkage that already has an address: " + this; + this.stub = stub; + } + + public void setAddress(long address) { + assert this.address == 0L : "cannot re-initialize address of " + this; + this.address = address; + } + + public long getAddress() { + assert address != 0L : "address not yet initialized for " + this; + return address; + } +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Dec 11 08:48:12 2012 +0100 @@ -262,6 +262,29 @@ public int methodCompiledEntryOffset; public int basicLockSize; public int basicLockDisplacedHeaderOffset; + public long tlabIntArrayMarkWord; + public long heapEndAddress; + public long heapTopAddress; + public int threadTlabStartOffset; + public int threadTlabSizeOffset; + public int threadAllocatedBytesOffset; + public int tlabRefillWasteLimitOffset; + public int tlabRefillWasteIncrement; + public int tlabAlignmentReserve; + public int tlabSlowAllocationsOffset; + public int tlabFastRefillWasteOffset; + public int tlabNumberOfRefillsOffset; + public boolean tlabStats; + public int klassInstanceSizeOffset; + public boolean inlineContiguousAllocationSupported; + public long arrayPrototypeMarkWord; + public int layoutHelperLog2ElementSizeShift; + public int layoutHelperLog2ElementSizeMask; + public int layoutHelperElementTypeShift; + public int layoutHelperElementTypeMask; + public int layoutHelperHeaderSizeShift; + public int layoutHelperHeaderSizeMask; + public int layoutHelperOffset; // methodData information public int methodDataOopDataOffset; @@ -279,8 +302,7 @@ public long debugStub; public long instanceofStub; public long newInstanceStub; - public long newTypeArrayStub; - public long newObjectArrayStub; + public long newArrayStub; public long newMultiArrayStub; public long inlineCacheMissStub; public long handleExceptionStub; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Tue Dec 11 08:48:12 2012 +0100 @@ -192,6 +192,4 @@ long[] getDeoptedLeafGraphIds(); String decodePC(long pc); - - long getPrototypeMarkWord(HotSpotResolvedObjectType hotSpotResolvedJavaType); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Tue Dec 11 08:48:12 2012 +0100 @@ -139,7 +139,4 @@ @Override public native String decodePC(long pc); - - @Override - public native long getPrototypeMarkWord(HotSpotResolvedObjectType type); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue Dec 11 08:48:12 2012 +0100 @@ -136,7 +136,8 @@ @Override public void run() { - Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions); + // Snippets cannot have speculative optimizations since they have to be valid for the entire run of the VM. + Assumptions assumptions = new Assumptions(false); VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime, assumptions); SnippetInstaller installer = new SnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); GraalIntrinsics.installIntrinsics(installer); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Tue Dec 11 08:48:12 2012 +0100 @@ -57,7 +57,7 @@ @Override public String toString() { - return "compiled method " + method + " @" + nmethod; + return String.format("InstalledCode[method=%s, nmethod=0x%x]", method, nmethod); } @Override diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Tue Dec 11 08:48:12 2012 +0100 @@ -63,7 +63,7 @@ private final boolean hasFinalizableSubclass; /** - * The instance size for an instance type, {@link HotSpotResolvedObjectType#INTERFACE_SPECIES_VALUE} denoting + * The instance size (in bytes) for an instance type, {@link HotSpotResolvedObjectType#INTERFACE_SPECIES_VALUE} denoting * an interface type or {@link HotSpotResolvedObjectType#ARRAY_SPECIES_VALUE} denoting an array type. */ private final int sizeOrSpecies; @@ -106,6 +106,7 @@ * @return the {@link HotSpotResolvedObjectType} corresponding to {@code javaClass} */ public static ResolvedJavaType fromClass(Class javaClass) { + assert javaClass != null; ResolvedJavaType type = (ResolvedJavaType) unsafe.getObject(javaClass, (long) HotSpotGraalRuntime.getInstance().getConfig().graalMirrorInClassOffset); if (type == null) { type = HotSpotGraalRuntime.getInstance().getCompilerToVM().getResolvedType(javaClass); @@ -395,6 +396,13 @@ return ((HotSpotResolvedJavaMethod) method).uniqueConcreteMethod(); } + private static class OffsetComparator implements Comparator { + @Override + public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { + return o1.offset() - o2.offset(); + } + } + @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { if (instanceFields == null) { @@ -402,6 +410,7 @@ instanceFields = new HotSpotResolvedJavaField[0]; } else { HotSpotResolvedJavaField[] myFields = HotSpotGraalRuntime.getInstance().getCompilerToVM().getInstanceFields(this); + Arrays.sort(myFields, new OffsetComparator()); if (javaMirror != Object.class) { HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); @@ -461,7 +470,12 @@ } public long prototypeMarkWord() { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().getPrototypeMarkWord(this); + HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + if (isArray()) { + return config.arrayPrototypeMarkWord; + } else { + return unsafeReadWord(metaspaceKlass + config.prototypeMarkWordOffset); + } } @Override diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue Dec 11 08:48:12 2012 +0100 @@ -46,7 +46,7 @@ import com.oracle.graal.api.code.CompilationResult.Mark; import com.oracle.graal.api.code.CompilationResult.Safepoint; import com.oracle.graal.api.code.Register.RegisterFlag; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; @@ -55,6 +55,7 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.phases.*; import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; @@ -81,7 +82,19 @@ private NewObjectSnippets.Templates newObjectSnippets; private MonitorSnippets.Templates monitorSnippets; - private final Map runtimeCalls = new HashMap<>(); + private NewInstanceStub newInstanceStub; + private NewArrayStub newArrayStub; + + private final Map runtimeCalls = new HashMap<>(); + private final Map stubs = new HashMap<>(); + + /** + * Holds onto objects that will be embedded in compiled code. HotSpot treats oops + * embedded in code as weak references so without an external strong root, such + * an embedded oop will quickly die. This in turn will cause the nmethod to + * be unloaded. + */ + private final Map gcRoots = new HashMap<>(); /** * The offset from the origin of an array to the first element. @@ -259,10 +272,23 @@ for (int i = 0; i < argKinds.length; i++) { assert argKinds[i].equals(args[i].getKind()) : descriptor + " incompatible with argument location " + i + ": " + args[i]; } - HotSpotRuntimeCall runtimeCall = new HotSpotRuntimeCall(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); + HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); runtimeCalls.put(descriptor, runtimeCall); } + /** + * Binds a snippet-base {@link Stub} to a runtime call descriptor. + * + * @return the linkage information for a call to the stub + */ + public HotSpotRuntimeCallTarget registerStub(Descriptor descriptor, Stub stub) { + HotSpotRuntimeCallTarget linkage = runtimeCalls.get(descriptor); + assert linkage != null; + linkage.setStub(stub); + stubs.put(stub.getMethod(), stub); + return linkage; + } + protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); public void installSnippets(SnippetInstaller installer, Assumptions assumptions) { @@ -290,13 +316,20 @@ installer.install(NewObjectSnippets.class); installer.install(MonitorSnippets.class); + installer.install(NewInstanceStub.class); + installer.install(NewArrayStub.class); + checkcastSnippets = new CheckCastSnippets.Templates(this, assumptions, graalRuntime.getTarget()); instanceofSnippets = new InstanceOfSnippets.Templates(this, assumptions, graalRuntime.getTarget()); newObjectSnippets = new NewObjectSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useTLAB); monitorSnippets = new MonitorSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useFastLocking); + + newInstanceStub = new NewInstanceStub(this, assumptions, graalRuntime.getTarget()); + newArrayStub = new NewArrayStub(this, assumptions, graalRuntime.getTarget()); + newInstanceStub.install(graalRuntime.getCompiler()); + newArrayStub.install(graalRuntime.getCompiler()); } - public HotSpotGraalRuntime getGraalRuntime() { return graalRuntime; } @@ -425,7 +458,7 @@ } @Override - public RegisterConfig lookupRegisterConfig(JavaMethod method) { + public RegisterConfig lookupRegisterConfig(ResolvedJavaMethod method) { return regConfig; } @@ -631,6 +664,10 @@ ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()))); hub.dependencies().add(guard); graph.replaceFixed(loadHub, hub); + } else if (n instanceof FixedGuardNode) { + FixedGuardNode node = (FixedGuardNode) n; + ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated(), node.getLeafGraphId()))); + graph.replaceFixedWithFixed(node, newAnchor); } else if (n instanceof CheckCastNode) { checkcastSnippets.lower((CheckCastNode) n, tool); } else if (n instanceof CheckCastDynamicNode) { @@ -689,14 +726,24 @@ return HotSpotResolvedObjectType.fromClass(clazz); } - public Object lookupCallTarget(Object target) { - if (target instanceof HotSpotRuntimeCall) { - return ((HotSpotRuntimeCall) target).address; + public Object lookupCallTarget(Object callTarget) { + if (callTarget instanceof HotSpotRuntimeCallTarget) { + return ((HotSpotRuntimeCallTarget) callTarget).getAddress(); } - return target; + return callTarget; } - public RuntimeCall lookupRuntimeCall(Descriptor descriptor) { + /** + * Gets the stub corresponding to a given method. + * + * @return the stub {@linkplain Stub#getMethod() implemented} by {@code method} or null if {@code method} does not + * implement a stub + */ + public Stub asStub(ResolvedJavaMethod method) { + return stubs.get(method); + } + + public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) { assert runtimeCalls.containsKey(descriptor) : descriptor; return runtimeCalls.get(descriptor); } @@ -792,4 +839,18 @@ public boolean needsDataPatch(Constant constant) { return constant.getPrimitiveAnnotation() instanceof HotSpotResolvedObjectType; } + + /** + * Registers an object created by the compiler and referenced by some generated code. + * HotSpot treats oops embedded in code as weak references so without an external strong root, such + * an embedded oop will quickly die. This in turn will cause the nmethod to be unloaded. + */ + public synchronized Object registerGCRoot(Object object) { + Object existing = gcRoots.get(object); + if (existing != null) { + return existing; + } + gcRoots.put(object, object); + return object; + } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -37,17 +37,17 @@ @Input private final ValueNode memory; @Input private final ValueNode length; - @Input private final ValueNode size; + @Input private final ValueNode allocationSize; private final ResolvedJavaType type; private final boolean fillContents; private final boolean locked; - public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode size, ResolvedJavaType type, boolean fillContents, boolean locked) { + public InitializeArrayNode(ValueNode memory, ValueNode length, ValueNode allocationSize, ResolvedJavaType type, boolean fillContents, boolean locked) { super(StampFactory.exactNonNull(type)); this.memory = memory; this.type = type; this.length = length; - this.size = size; + this.allocationSize = allocationSize; this.fillContents = fillContents; this.locked = locked; } @@ -61,8 +61,11 @@ return length; } - public ValueNode size() { - return size; + /** + * Gets the size (in bytes) of the memory chunk allocated for the array. + */ + public ValueNode allocationSize() { + return allocationSize; } public ResolvedJavaType type() { @@ -83,5 +86,5 @@ } @NodeIntrinsic - public static native Object initialize(Object memory, int length, int size, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter boolean locked); + public static native Object initialize(Object memory, int length, int allocationSize, @ConstantNodeParameter ResolvedJavaType type, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter boolean locked); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,7 +25,7 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -50,7 +50,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(MonitorEnterStubCall.MONITORENTER); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorEnterStubCall.MONITORENTER); gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.operand(lock)); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,7 +25,7 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -47,7 +47,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT); gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(gen.peekLock())); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.snippets.*; + +/** + * Node implementing a call to the {@code new_array} stub. + */ +public class NewArraySlowStubCall extends FixedWithNextNode implements LIRGenLowerable { + + private static final Stamp defaultStamp = StampFactory.objectNonNull(); + + @Input private final ValueNode hub; + @Input private final ValueNode length; + + public static final Descriptor NEW_ARRAY_SLOW = new Descriptor("new_array_slow", false, Kind.Object, wordKind(), Kind.Int); + + public NewArraySlowStubCall(ValueNode hub, ValueNode length) { + super(defaultStamp); + this.hub = hub; + this.length = length; + } + + @Override + public boolean inferStamp() { + if (stamp() == defaultStamp && hub.isConstant()) { + updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); + return true; + } + return false; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), gen.operand(length)); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Object call(Word hub, int length); +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,18 +25,19 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.snippets.*; /** - * Node implementing a call to HotSpot's {@code new_[object|type]_array} stub. + * A call to the {@link NewArrayStub}. */ public class NewArrayStubCall extends FixedWithNextNode implements LIRGenLowerable { @@ -44,15 +45,11 @@ @Input private final ValueNode hub; @Input private final ValueNode length; - private final boolean isObjectArray; - public static final Descriptor NEW_OBJECT_ARRAY = new Descriptor("new_object_array", false, Kind.Object, wordKind(), Kind.Int); + public static final Descriptor NEW_ARRAY = new Descriptor("new_array", false, Kind.Object, wordKind(), Kind.Int); - public static final Descriptor NEW_TYPE_ARRAY = new Descriptor("new_type_array", false, Kind.Object, wordKind(), Kind.Int); - - public NewArrayStubCall(boolean isObjectArray, ValueNode hub, ValueNode length) { + public NewArrayStubCall(ValueNode hub, ValueNode length) { super(defaultStamp); - this.isObjectArray = isObjectArray; this.hub = hub; this.length = length; } @@ -68,11 +65,11 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(isObjectArray ? NewArrayStubCall.NEW_OBJECT_ARRAY : NewArrayStubCall.NEW_TYPE_ARRAY); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY); Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), gen.operand(length)); gen.setResult(this, result); } @NodeIntrinsic - public static native Object call(@ConstantNodeParameter boolean isObjectArray, Word hub, int length); + public static native Object call(Word hub, int length); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.nodes; + +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.snippets.*; + +/** + * Node implementing a call to HotSpot's {@code new_instance} stub. + */ +public class NewInstanceSlowStubCall extends FixedWithNextNode implements LIRGenLowerable { + + private static final Stamp defaultStamp = StampFactory.objectNonNull(); + + @Input private final ValueNode hub; + + public static final Descriptor NEW_INSTANCE_SLOW = new Descriptor("new_instance_slow", false, Kind.Object, wordKind()); + + public NewInstanceSlowStubCall(ValueNode hub) { + super(defaultStamp); + this.hub = hub; + } + + @Override + public boolean inferStamp() { + if (stamp() == defaultStamp && hub.isConstant()) { + updateStamp(StampFactory.exactNonNull(HotSpotResolvedObjectType.fromMetaspaceKlass(hub.asConstant()))); + return true; + } + return false; + } + + @Override + public void generate(LIRGenerator gen) { + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub)); + gen.setResult(this, result); + } + + @NodeIntrinsic + public static native Object call(Word hub); +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,18 +25,19 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.snippets.*; /** - * Node implementing a call to HotSpot's {@code new_instance} stub. + * A call to the {@link NewInstanceStub}. */ public class NewInstanceStubCall extends FixedWithNextNode implements LIRGenLowerable { @@ -62,7 +63,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(NewInstanceStubCall.NEW_INSTANCE); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE); Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub)); gen.setResult(this, result); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,7 +25,7 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -66,7 +66,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(NewMultiArrayStubCall.NEW_MULTI_ARRAY); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NewMultiArrayStubCall.NEW_MULTI_ARRAY); Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), Constant.forInt(rank), gen.operand(dims)); gen.setResult(this, result); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,10 +23,11 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -60,8 +61,17 @@ where = "in compiled code for " + MetaUtil.format("%H.%n(%p)", gen.method()); } - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR); - gen.emitCall(stub, stub.getCallingConvention(), false, Constant.forObject(where), gen.operand(format), gen.operand(value)); + HotSpotRuntime runtime = (HotSpotRuntime) gen.getRuntime(); + Constant whereArg = Constant.forObject(runtime.registerGCRoot(where)); + Value formatArg; + if (format.isConstant() && format.kind() == Kind.Object) { + formatArg = Constant.forObject(runtime.registerGCRoot(format.asConstant().asObject())); + } else { + formatArg = gen.operand(format); + } + + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR); + gen.emitCall(stub, stub.getCallingConvention(), false, whereArg, formatArg, gen.operand(value)); } @NodeIntrinsic diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -45,7 +45,7 @@ @Override public void generate(LIRGenerator gen) { - RuntimeCall stub = gen.getRuntime().lookupRuntimeCall(VerifyOopStubCall.VERIFY_OOP); + RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VerifyOopStubCall.VERIFY_OOP); gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object)); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.hotspot.phases; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.*; +import com.oracle.graal.api.code.RuntimeCallTarget.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Tue Dec 11 08:48:12 2012 +0100 @@ -1,333 +1,485 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot.snippets; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.Node.ConstantNodeParameter; -import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.hotspot.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.snippets.Snippet.Fold; -import com.oracle.graal.snippets.*; - -//JaCoCo Exclude - -/** - * A collection of methods used in HotSpot snippets. - */ -public class HotSpotSnippetUtils { - - @Fold - static boolean verifyOops() { - return HotSpotGraalRuntime.getInstance().getConfig().verifyOops; - } - - @Fold - static int threadTlabTopOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().threadTlabTopOffset; - } - - @Fold - static int threadTlabEndOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().threadTlabEndOffset; - } - - @Fold - static int threadObjectOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().threadObjectOffset; - } - - @Fold - static int osThreadOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().osThreadOffset; - } - - @Fold - static int osThreadInterruptedOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().osThreadInterruptedOffset; - } - - @Fold - static Kind wordKind() { - return HotSpotGraalRuntime.getInstance().getTarget().wordKind; - } - - @Fold - static Register threadRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); - } - - @Fold - static Register stackPointerRegister() { - return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister(); - } - - @Fold - static int wordSize() { - return HotSpotGraalRuntime.getInstance().getTarget().wordSize; - } - - @Fold - static int pageSize() { - return HotSpotGraalRuntime.getInstance().getTarget().pageSize; - } - - @Fold - static int prototypeMarkWordOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().prototypeMarkWordOffset; - } - - @Fold - static int klassOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().klassOffset; - } - - @Fold - static int klassModifierFlagsOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().klassModifierFlagsOffset; - } - - @Fold - static int klassAccessFlagsOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().klassAccessFlagsOffset; - } - - @Fold - static int klassLayoutHelperOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().klassLayoutHelperOffset; - } - - @Fold - static int arrayKlassLayoutHelperIdentifier() { - return HotSpotGraalRuntime.getInstance().getConfig().arrayKlassLayoutHelperIdentifier; - } - - @Fold - static int arrayKlassComponentMirrorOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().arrayKlassComponentMirrorOffset; - } - - @Fold - static int klassSuperKlassOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().klassSuperKlassOffset; - } - - @Fold - static int classMirrorOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().classMirrorOffset; - } - - @Fold - static int markOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().markOffset; - } - - @Fold - static int unlockedMask() { - return HotSpotGraalRuntime.getInstance().getConfig().unlockedMask; - } - - /** - * Mask for a biasable, locked or unlocked mark word. - *
-     * +----------------------------------+-+-+
-     * |                                 1|1|1|
-     * +----------------------------------+-+-+
-     * 
- * - */ - @Fold - static int biasedLockMaskInPlace() { - return HotSpotGraalRuntime.getInstance().getConfig().biasedLockMaskInPlace; - } - - @Fold - static int epochMaskInPlace() { - return HotSpotGraalRuntime.getInstance().getConfig().epochMaskInPlace; - } - - /** - * Pattern for a biasable, unlocked mark word. - *
-     * +----------------------------------+-+-+
-     * |                                 1|0|1|
-     * +----------------------------------+-+-+
-     * 
- * - */ - @Fold - static int biasedLockPattern() { - return HotSpotGraalRuntime.getInstance().getConfig().biasedLockPattern; - } - - @Fold - static int ageMaskInPlace() { - return HotSpotGraalRuntime.getInstance().getConfig().ageMaskInPlace; - } - - @Fold - static int hubOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().hubOffset; - } - - @Fold - static int metaspaceArrayLengthOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().metaspaceArrayLengthOffset; - } - - @Fold - static int metaspaceArrayBaseOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().metaspaceArrayBaseOffset; - } - - @Fold - static int arrayLengthOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().arrayLengthOffset; - } - - @Fold - static int arrayBaseOffset(Kind elementKind) { - return HotSpotRuntime.getArrayBaseOffset(elementKind); - } - - @Fold - static int arrayIndexScale(Kind elementKind) { - return HotSpotRuntime.getArrayIndexScale(elementKind); - } - - @Fold - static int cardTableShift() { - return HotSpotGraalRuntime.getInstance().getConfig().cardtableShift; - } - - @Fold - static long cardTableStart() { - return HotSpotGraalRuntime.getInstance().getConfig().cardtableStartAddress; - } - - @Fold - static int superCheckOffsetOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().superCheckOffsetOffset; - } - - @Fold - static int secondarySuperCacheOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().secondarySuperCacheOffset; - } - - @Fold - static int secondarySupersOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().secondarySupersOffset; - } - - @Fold - static int lockDisplacedMarkOffset() { - return HotSpotGraalRuntime.getInstance().getConfig().basicLockDisplacedHeaderOffset; - } - - @Fold - static boolean useBiasedLocking() { - return HotSpotGraalRuntime.getInstance().getConfig().useBiasedLocking; - } - - @Fold - static int uninitializedIdentityHashCodeValue() { - return HotSpotGraalRuntime.getInstance().getConfig().uninitializedIdentityHashCodeValue; - } - - @Fold - static int identityHashCodeShift() { - return HotSpotGraalRuntime.getInstance().getConfig().identityHashCodeShift; - } - - /** - * Loads the hub from a object, null checking it first. - */ - static Word loadHub(Object object) { - return loadHubIntrinsic(object, wordKind()); - } - - static Object verifyOop(Object object) { - if (verifyOops()) { - VerifyOopStubCall.call(object); - } - return object; - } - - /** - * Gets the value of the stack pointer register as a Word. - */ - static Word stackPointer() { - return HotSpotSnippetUtils.registerAsWord(stackPointerRegister()); - } - - /** - * Gets the value of the thread register as a Word. - */ - static Word thread() { - return HotSpotSnippetUtils.registerAsWord(threadRegister()); - } - - static int loadIntFromWord(Word address, int offset) { - Integer value = UnsafeLoadNode.load(address, 0, offset, Kind.Int); - return value; - } - - static Word loadWordFromWord(Word address, int offset) { - return loadWordFromWordIntrinsic(address, 0, offset, wordKind()); - } - - static Object loadObjectFromWord(Word address, int offset) { - return UnsafeLoadNode.load(address, 0, offset, Kind.Object); - } - - static Word loadWordFromObject(Object object, int offset) { - return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); - } - - @NodeIntrinsic(value = RegisterNode.class, setStampFromReturnType = true) - public static native Word registerAsWord(@ConstantNodeParameter Register register); - - @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) - private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); - - @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) - private static native Word loadWordFromWordIntrinsic(Word address, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); - - @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) - static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word); - - static { - assert arrayIndexScale(Kind.Byte) == 1; - assert arrayIndexScale(Kind.Boolean) == 1; - assert arrayIndexScale(Kind.Char) == 2; - assert arrayIndexScale(Kind.Short) == 2; - assert arrayIndexScale(Kind.Int) == 4; - assert arrayIndexScale(Kind.Long) == 8; - assert arrayIndexScale(Kind.Float) == 4; - assert arrayIndexScale(Kind.Double) == 8; - } -} +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.snippets; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.Node.ConstantNodeParameter; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.snippets.Snippet.Fold; +import com.oracle.graal.snippets.*; + +//JaCoCo Exclude + +/** + * A collection of methods used in HotSpot snippets. + */ +public class HotSpotSnippetUtils { + + public static HotSpotVMConfig config() { + return HotSpotGraalRuntime.getInstance().getConfig(); + } + + @Fold + public static boolean verifyOops() { + return config().verifyOops; + } + + @Fold + public static int threadTlabTopOffset() { + return config().threadTlabTopOffset; + } + + @Fold + public static int threadTlabEndOffset() { + return config().threadTlabEndOffset; + } + + @Fold + public static int threadObjectOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().threadObjectOffset; + } + + @Fold + public static int osThreadOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().osThreadOffset; + } + + @Fold + public static int osThreadInterruptedOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().osThreadInterruptedOffset; + } + + @Fold + public static Kind wordKind() { + return HotSpotGraalRuntime.getInstance().getTarget().wordKind; + } + + @Fold + public static Register threadRegister() { + return HotSpotGraalRuntime.getInstance().getRuntime().threadRegister(); + } + + @Fold + public static Register stackPointerRegister() { + return HotSpotGraalRuntime.getInstance().getRuntime().stackPointerRegister(); + } + + @Fold + public static int wordSize() { + return HotSpotGraalRuntime.getInstance().getTarget().wordSize; + } + + @Fold + public static int pageSize() { + return HotSpotGraalRuntime.getInstance().getTarget().pageSize; + } + + @Fold + public static int prototypeMarkWordOffset() { + return config().prototypeMarkWordOffset; + } + + @Fold + public static long arrayPrototypeMarkWord() { + return config().arrayPrototypeMarkWord; + } + + @Fold + public static int klassOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().klassOffset; + } + + @Fold + public static int klassModifierFlagsOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().klassModifierFlagsOffset; + } + + @Fold + public static int klassAccessFlagsOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().klassAccessFlagsOffset; + } + + @Fold + public static int klassLayoutHelperOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().klassLayoutHelperOffset; + } + + @Fold + public static int arrayKlassLayoutHelperIdentifier() { + return HotSpotGraalRuntime.getInstance().getConfig().arrayKlassLayoutHelperIdentifier; + } + + @Fold + public static int arrayKlassComponentMirrorOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().arrayKlassComponentMirrorOffset; + } + + @Fold + public static int klassSuperKlassOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().klassSuperKlassOffset; + } + + @Fold + public static int classMirrorOffset() { + return HotSpotGraalRuntime.getInstance().getConfig().classMirrorOffset; + } + + @Fold + public static int markOffset() { + return config().markOffset; + } + + @Fold + public static int unlockedMask() { + return config().unlockedMask; + } + + /** + * Mask for a biasable, locked or unlocked mark word. + *
+     * +----------------------------------+-+-+
+     * |                                 1|1|1|
+     * +----------------------------------+-+-+
+     * 
+ * + */ + @Fold + public static int biasedLockMaskInPlace() { + return config().biasedLockMaskInPlace; + } + + @Fold + public static int epochMaskInPlace() { + return config().epochMaskInPlace; + } + + /** + * Pattern for a biasable, unlocked mark word. + *
+     * +----------------------------------+-+-+
+     * |                                 1|0|1|
+     * +----------------------------------+-+-+
+     * 
+ * + */ + @Fold + public static int biasedLockPattern() { + return config().biasedLockPattern; + } + + @Fold + public static int ageMaskInPlace() { + return config().ageMaskInPlace; + } + + @Fold + public static int hubOffset() { + return config().hubOffset; + } + + @Fold + public static int metaspaceArrayLengthOffset() { + return config().metaspaceArrayLengthOffset; + } + + @Fold + public static int metaspaceArrayBaseOffset() { + return config().metaspaceArrayBaseOffset; + } + + @Fold + public static int arrayLengthOffset() { + return config().arrayLengthOffset; + } + + @Fold + public static int arrayBaseOffset(Kind elementKind) { + return HotSpotRuntime.getArrayBaseOffset(elementKind); + } + + @Fold + public static int arrayIndexScale(Kind elementKind) { + return HotSpotRuntime.getArrayIndexScale(elementKind); + } + + @Fold + public static int cardTableShift() { + return config().cardtableShift; + } + + @Fold + public static long cardTableStart() { + return config().cardtableStartAddress; + } + + @Fold + public static int superCheckOffsetOffset() { + return config().superCheckOffsetOffset; + } + + @Fold + public static int secondarySuperCacheOffset() { + return config().secondarySuperCacheOffset; + } + + @Fold + public static int secondarySupersOffset() { + return config().secondarySupersOffset; + } + + @Fold + public static int lockDisplacedMarkOffset() { + return config().basicLockDisplacedHeaderOffset; + } + + @Fold + public static boolean useBiasedLocking() { + return config().useBiasedLocking; + } + + @Fold + static int uninitializedIdentityHashCodeValue() { + return HotSpotGraalRuntime.getInstance().getConfig().uninitializedIdentityHashCodeValue; + } + + @Fold + static int identityHashCodeShift() { + return HotSpotGraalRuntime.getInstance().getConfig().identityHashCodeShift; + } + + /** + * Loads the hub from a object, null checking it first. + */ + public static Word loadHub(Object object) { + return loadHubIntrinsic(object, wordKind()); + } + + public static Object verifyOop(Object object) { + if (verifyOops()) { + VerifyOopStubCall.call(object); + } + return object; + } + + /** + * Gets the value of the stack pointer register as a Word. + */ + public static Word stackPointer() { + return HotSpotSnippetUtils.registerAsWord(stackPointerRegister()); + } + + /** + * Gets the value of the thread register as a Word. + */ + public static Word thread() { + return HotSpotSnippetUtils.registerAsWord(threadRegister()); + } + + public static int loadIntFromWord(Word address, int offset) { + Integer value = UnsafeLoadNode.load(address, 0, offset, Kind.Int); + return value; + } + + public static Word loadWordFromWord(Word address, int offset) { + return loadWordFromWordIntrinsic(address, 0, offset, wordKind()); + } + + static Object loadObjectFromWord(Word address, int offset) { + return UnsafeLoadNode.load(address, 0, offset, Kind.Object); + } + + public static Word loadWordFromObject(Object object, int offset) { + return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); + } + + @NodeIntrinsic(value = RegisterNode.class, setStampFromReturnType = true) + public static native Word registerAsWord(@ConstantNodeParameter Register register); + + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); + + @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) + private static native Word loadWordFromWordIntrinsic(Word address, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); + + @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) + static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word); + + @Fold + public + static int log2WordSize() { + return CodeUtil.log2(wordSize()); + } + + @Fold + public + static int klassStateOffset() { + return config().klassStateOffset; + } + + @Fold + public + static int klassInstanceSizeOffset() { + return config().klassInstanceSizeOffset; + } + + @Fold + public + static long heapTopAddress() { + return config().heapTopAddress; + } + + @Fold + public + static long heapEndAddress() { + return config().heapEndAddress; + } + + @Fold + public + static int threadTlabStartOffset() { + return config().threadTlabStartOffset; + } + + @Fold + public + static long tlabIntArrayMarkWord() { + return config().tlabIntArrayMarkWord; + } + + @Fold + public + static boolean inlineContiguousAllocationSupported() { + return config().inlineContiguousAllocationSupported; + } + + @Fold + public + static int tlabAlignmentReserveInHeapWords() { + return config().tlabAlignmentReserve; + } + + @Fold + public + static int threadTlabSizeOffset() { + return config().threadTlabSizeOffset; + } + + @Fold + public + static int threadAllocatedBytesOffset() { + return config().threadAllocatedBytesOffset; + } + + @Fold + public + static int klassStateFullyInitialized() { + return config().klassStateFullyInitialized; + } + + @Fold + public + static int tlabRefillWasteLimitOffset() { + return config().tlabRefillWasteLimitOffset; + } + + @Fold + public + static int tlabNumberOfRefillsOffset() { + return config().tlabNumberOfRefillsOffset; + } + + @Fold + public + static int tlabFastRefillWasteOffset() { + return config().tlabFastRefillWasteOffset; + } + + @Fold + public + static int tlabSlowAllocationsOffset() { + return config().tlabSlowAllocationsOffset; + } + + @Fold + public + static int tlabRefillWasteIncrement() { + return config().tlabRefillWasteIncrement; + } + + @Fold + public + static boolean tlabStats() { + return config().tlabStats; + } + + @Fold + public static int layoutHelperOffset() { + return config().layoutHelperOffset; + } + + @Fold + public static int layoutHelperHeaderSizeShift() { + return config().layoutHelperHeaderSizeShift; + } + + @Fold + public static int layoutHelperHeaderSizeMask() { + return config().layoutHelperHeaderSizeMask; + } + + @Fold + public static int layoutHelperLog2ElementSizeShift() { + return config().layoutHelperLog2ElementSizeShift; + } + + @Fold + public static int layoutHelperLog2ElementSizeMask() { + return config().layoutHelperLog2ElementSizeMask; + } + + @Fold + public static int layoutHelperElementTypeShift() { + return config().layoutHelperElementTypeShift; + } + + @Fold + public static int layoutHelperElementTypeMask() { + return config().layoutHelperElementTypeMask; + } + + static { + assert arrayIndexScale(Kind.Byte) == 1; + assert arrayIndexScale(Kind.Boolean) == 1; + assert arrayIndexScale(Kind.Char) == 2; + assert arrayIndexScale(Kind.Short) == 2; + assert arrayIndexScale(Kind.Int) == 4; + assert arrayIndexScale(Kind.Long) == 8; + assert arrayIndexScale(Kind.Float) == 4; + assert arrayIndexScale(Kind.Double) == 8; + } +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Tue Dec 11 08:48:12 2012 +0100 @@ -37,6 +37,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -520,7 +521,8 @@ List rets = graph.getNodes().filter(ReturnNode.class).snapshot(); for (ReturnNode ret : rets) { returnType = checkCounter.getSignature().getReturnType(checkCounter.getDeclaringClass()); - ConstantNode errMsg = ConstantNode.forObject("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d", runtime, graph); + Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"); + ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph); callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[] {errMsg}, returnType)); invoke = graph.add(new InvokeNode(callTarget, 0, -1)); List stack = Collections.emptyList(); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Tue Dec 11 08:48:12 2012 +0100 @@ -95,55 +95,30 @@ } @Snippet - public static Object initializeObjectArray( + public static Object initializeArray( @Parameter("memory") Word memory, @Parameter("hub") Word hub, @Parameter("length") int length, - @Parameter("size") int size, + @Parameter("allocationSize") int allocationSize, @Parameter("prototypeMarkWord") Word prototypeMarkWord, @ConstantParameter("headerSize") int headerSize, @ConstantParameter("fillContents") boolean fillContents, @ConstantParameter("locked") boolean locked) { if (locked) { - return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, true, fillContents); + return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents); } else { - return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, true, fillContents); + return initializeArray(memory, hub, length, allocationSize, prototypeMarkWord, headerSize, fillContents); } } - @Snippet - public static Object initializePrimitiveArray( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("length") int length, - @Parameter("size") int size, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { - if (locked) { - return initializeArray(memory, hub, length, size, thread().or(biasedLockPattern()), headerSize, false, fillContents); - } else { - return initializeArray(memory, hub, length, size, prototypeMarkWord, headerSize, false, fillContents); - } - } - - private static Object initializeArray(Word memory, Word hub, int length, int size, Word prototypeMarkWord, int headerSize, boolean isObjectArray, boolean fillContents) { + private static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, int headerSize, boolean fillContents) { Object result; if (memory == Word.zero()) { - if (isObjectArray) { - anewarray_stub.inc(); - } else { - newarray_stub.inc(); - } - result = NewArrayStubCall.call(isObjectArray, hub, length); + newarray_stub.inc(); + result = NewArrayStubCall.call(hub, length); } else { - if (isObjectArray) { - anewarray_loopInit.inc(); - } else { - newarray_loopInit.inc(); - } - formatArray(hub, size, length, headerSize, memory, prototypeMarkWord, fillContents); + newarray_loopInit.inc(); + formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents); result = memory.toObject(); } return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); @@ -152,7 +127,7 @@ /** * Maximum array length for which fast path allocation is used. */ - private static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; + public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; @Snippet public static Object allocateArrayAndInitialize( @@ -165,12 +140,21 @@ // This handles both negative array sizes and very large array sizes DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.RuntimeConstraint); } - int size = getArraySize(length, alignment, headerSize, log2ElementSize); - Word memory = TLABAllocateNode.allocateVariableSize(size); - return InitializeArrayNode.initialize(memory, length, size, type, true, false); + int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + Word memory = TLABAllocateNode.allocateVariableSize(allocationSize); + return InitializeArrayNode.initialize(memory, length, allocationSize, type, true, false); } - public static int getArraySize(int length, int alignment, int headerSize, int log2ElementSize) { + /** + * Computes the size of the memory chunk allocated for an array. This size accounts for the array + * header size, boy size and any padding after the last element to satisfy object alignment requirements. + * + * @param length the number of elements in the array + * @param alignment the object alignment requirement + * @param headerSize the size of the array header + * @param log2ElementSize log2 of the size of an element in the array + */ + public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { int size = (length << log2ElementSize) + headerSize + (alignment - 1); int mask = ~(alignment - 1); return size & mask; @@ -225,12 +209,13 @@ /** * Formats some allocated memory with an object header zeroes out the rest. */ - private static void formatArray(Word hub, int size, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { + public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { storeWord(memory, 0, markOffset(), prototypeMarkWord); + storeInt(memory, 0, arrayLengthOffset(), length); + // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null storeWord(memory, 0, hubOffset(), hub); - storeInt(memory, 0, arrayLengthOffset(), length); if (fillContents) { - for (int offset = headerSize; offset < size; offset += wordSize()) { + for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { storeWord(memory, 0, offset, Word.zero()); } } @@ -240,8 +225,7 @@ private final ResolvedJavaMethod allocate; private final ResolvedJavaMethod initializeObject; - private final ResolvedJavaMethod initializeObjectArray; - private final ResolvedJavaMethod initializePrimitiveArray; + private final ResolvedJavaMethod initializeArray; private final ResolvedJavaMethod allocateArrayAndInitialize; private final ResolvedJavaMethod newmultiarray; private final TargetDescription target; @@ -253,8 +237,7 @@ this.useTLAB = useTLAB; allocate = snippet("allocate", int.class); initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); - initializeObjectArray = snippet("initializeObjectArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - initializePrimitiveArray = snippet("initializePrimitiveArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); + initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, ResolvedJavaType.class); newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); } @@ -308,7 +291,7 @@ graph.replaceFixedWithFixed(newArrayNode, initializeNode); } else if (length != null && belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { // Calculate aligned size - int size = getArraySize(length, alignment, headerSize, log2ElementSize); + int size = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); ConstantNode sizeNode = ConstantNode.forInt(size, graph); tlabAllocateNode = graph.add(new TLABAllocateNode(sizeNode)); graph.addBeforeFixed(newArrayNode, tlabAllocateNode); @@ -364,11 +347,11 @@ ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); Kind elementKind = elementType.getKind(); final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); - Key key = new Key(elementKind == Kind.Object ? initializeObjectArray : initializePrimitiveArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); + Key key = new Key(initializeArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("size", initializeNode.size()).add("length", initializeNode.length()); + Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("allocationSize", initializeNode.allocationSize()).add("length", initializeNode.length()); SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeObjectArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); + Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); } @@ -394,11 +377,7 @@ private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub"); - private static final SnippetCounter.Group countersNewPrimitiveArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewPrimitiveArray") : null; - private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewPrimitiveArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewPrimitiveArray, "stub", "alloc and zeroing via stub"); - - private static final SnippetCounter.Group countersNewObjectArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewObjectArray") : null; - private static final SnippetCounter anewarray_loopInit = new SnippetCounter(countersNewObjectArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); - private static final SnippetCounter anewarray_stub = new SnippetCounter(countersNewObjectArray, "stub", "alloc and zeroing via stub"); + private static final SnippetCounter.Group countersNewArray = GraalOptions.SnippetCounters ? new SnippetCounter.Group("NewArray") : null; + private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop"); + private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub"); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSnippets.java Tue Dec 11 08:48:12 2012 +0100 @@ -22,9 +22,9 @@ */ package com.oracle.graal.hotspot.snippets; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.snippets.NewObjectSnippets.*; +import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.SnippetTemplate.Key; + +/** + * Stub implementing the fast path for TLAB refill during instance class allocation. + * This stub is called from the {@linkplain NewObjectSnippets inline} allocation + * code when TLAB allocation fails. If this stub fails to refill the TLAB + * or allocate the object, it calls out to the HotSpot C++ runtime for + * to complete the allocation. + */ +public class NewArrayStub extends Stub { + + public NewArrayStub(final HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, NewArrayStubCall.NEW_ARRAY); + } + + @Override + protected void populateKey(Key key) { + HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + Constant intArrayHub = intArrayType.klass(); + key.add("intArrayHub", intArrayHub); + } + + /** + * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to -XX:-UseTLAB). + * + * @param hub the hub of the object to be allocated + * @param length the length of the array + * @param intArrayHub the hub for {@code int[].class} + */ + @Snippet + private static Object newArray(@Parameter("hub") Word hub, @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub) { + int layoutHelper = loadIntFromWord(hub, layoutHelperOffset()); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); + int sizeInBytes = computeArrayAllocationSize(length, wordSize(), headerSize, log2ElementSize); + logf("newArray: element kind %d\n", elementKind); + logf("newArray: array length %d\n", length); + logf("newArray: array size %d\n", sizeInBytes); + logf("newArray: hub=%p\n", hub.toLong()); + + // check that array length is small enough for fast path. + if (length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) { + Word memory; + if (refillTLAB(intArrayHub, Word.fromLong(tlabIntArrayMarkWord()), tlabAlignmentReserveInHeapWords() * wordSize())) { + memory = allocate(sizeInBytes); + } else { + logf("newArray: allocating directly in eden\n", 0L); + memory = edenAllocate(Word.fromInt(sizeInBytes)); + } + if (memory != Word.zero()) { + logf("newArray: allocated new array at %p\n", memory.toLong()); + formatArray(hub, sizeInBytes, length, headerSize, memory, Word.fromLong(arrayPrototypeMarkWord()), true); + return verifyOop(memory.toObject()); + } + } + logf("newArray: calling new_array_slow", 0L); + return verifyOop(NewArraySlowStubCall.call(hub, length)); + } + + private static final boolean LOGGING_ENABLED = Boolean.getBoolean("graal.logNewArrayStub"); + + private static void logf(String format, long value) { + if (LOGGING_ENABLED) { + Log.printf(format, value); + } + } +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; +import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; +import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.hotspot.snippets.NewObjectSnippets.*; +import static com.oracle.graal.snippets.nodes.DirectObjectStoreNode.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.SnippetTemplate.Key; + +/** + * Stub implementing the fast path for TLAB refill during instance class allocation. + * This stub is called from the {@linkplain NewObjectSnippets inline} allocation + * code when TLAB allocation fails. If this stub fails to refill the TLAB + * or allocate the object, it calls out to the HotSpot C++ runtime for + * to complete the allocation. + */ +public class NewInstanceStub extends Stub { + + public NewInstanceStub(final HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target, NEW_INSTANCE); + } + + @Override + protected void populateKey(Key key) { + HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); + Constant intArrayHub = intArrayType.klass(); + key.add("intArrayHub", intArrayHub); + } + + /** + * Re-attempts allocation after an initial TLAB allocation failed or was skipped (e.g., due to -XX:-UseTLAB). + * + * @param hub the hub of the object to be allocated + * @param intArrayHub the hub for {@code int[].class} + */ + @Snippet + private static Object newInstance(@Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub) { + int sizeInBytes = loadIntFromWord(hub, klassInstanceSizeOffset()); + logf("newInstance: size %d\n", sizeInBytes); + if (inlineContiguousAllocationSupported()) { + if (loadIntFromWord(hub, klassStateOffset()) == klassStateFullyInitialized()) { + Word memory; + if (refillTLAB(intArrayHub, Word.fromLong(tlabIntArrayMarkWord()), tlabAlignmentReserveInHeapWords() * wordSize())) { + memory = allocate(sizeInBytes); + } else { + logf("newInstance: allocating directly in eden\n", 0L); + memory = edenAllocate(Word.fromInt(sizeInBytes)); + } + if (memory != Word.zero()) { + logf("newInstance: allocated new object at %p\n", memory.toLong()); + Word prototypeMarkWord = loadWordFromWord(hub, prototypeMarkWordOffset()); + storeWord(memory, 0, markOffset(), prototypeMarkWord); + storeWord(memory, 0, hubOffset(), hub); + for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { + storeWord(memory, 0, offset, Word.zero()); + } + return verifyOop(memory.toObject()); + } + } + } + logf("newInstance: calling new_instance_slow", 0L); + return verifyOop(NewInstanceSlowStubCall.call(hub)); + } + + /** + * Attempts to refill the current thread's TLAB. + * + * @param intArrayHub the hub for {@code int[].class} + * @param intArrayMarkWord the mark word for the int array placed in the left over TLAB space + * @param alignmentReserveInBytes the amount of extra bytes to reserve in a new TLAB + * @return whether or not a new TLAB was allocated + */ + static boolean refillTLAB(Word intArrayHub, Word intArrayMarkWord, int alignmentReserveInBytes) { + + Word thread = thread(); + Word top = loadWordFromWord(thread, threadTlabTopOffset()); + Word end = loadWordFromWord(thread, threadTlabEndOffset()); + + // calculate amount of free space + Word tlabFreeSpaceInBytes = end.minus(top); + + logf("refillTLAB: thread=%p\n", thread.toLong()); + logf("refillTLAB: top=%p\n", top.toLong()); + logf("refillTLAB: end=%p\n", end.toLong()); + logf("refillTLAB: tlabFreeSpaceInBytes=%d\n", tlabFreeSpaceInBytes.toLong()); + + // a DIV or SHR operations on Words would be handy here... + Word tlabFreeSpaceInWords = Word.fromLong(tlabFreeSpaceInBytes.toLong() >>> log2WordSize()); + + // Retain TLAB and allocate object in shared space if + // the amount free in the TLAB is too large to discard. + if (tlabFreeSpaceInWords.belowOrEqual(loadWordFromWord(thread, tlabRefillWasteLimitOffset()))) { + logf("refillTLAB: discarding TLAB\n", 0L); + + if (tlabStats()) { + // increment number of refills + storeInt(thread, 0, tlabNumberOfRefillsOffset(), loadIntFromWord(thread, tlabNumberOfRefillsOffset()) + 1); + // accumulate wastage + storeWord(thread, 0, tlabFastRefillWasteOffset(), loadWordFromWord(thread, tlabFastRefillWasteOffset()).plus(tlabFreeSpaceInWords)); + } + + // if TLAB is currently allocated (top or end != null) then + // fill [top, end + alignment_reserve) with array object + if (top != Word.zero()) { + int headerSize = arrayBaseOffset(Kind.Int); + // just like the HotSpot assembler stubs, assumes that tlabFreeSpaceInInts fits in an int + int tlabFreeSpaceInInts = (int) tlabFreeSpaceInBytes.toLong() >>> 2; + int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; + logf("refillTLAB: alignmentReserveInBytes %d\n", alignmentReserveInBytes); + logf("refillTLAB: headerSize %d\n", headerSize); + logf("refillTLAB: filler.length %d\n", length); + NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false); + + Word allocated = loadWordFromWord(thread, threadAllocatedBytesOffset()); + allocated = allocated.plus(top.minus(loadWordFromWord(thread, threadTlabStartOffset()))); + storeWord(thread, 0, threadAllocatedBytesOffset(), allocated); + } + + // refill the TLAB with an eden allocation + Word tlabRefillSizeInWords = loadWordFromWord(thread, threadTlabSizeOffset()); + Word tlabRefillSizeInBytes = Word.fromLong(tlabRefillSizeInWords.toLong() * wordSize()); + // allocate new TLAB, address returned in top + top = edenAllocate(tlabRefillSizeInBytes); + if (top != Word.zero()) { + storeWord(thread, 0, threadTlabStartOffset(), top); + storeWord(thread, 0, threadTlabTopOffset(), top); + + end = top.plus(tlabRefillSizeInBytes.minus(alignmentReserveInBytes)); + storeWord(thread, 0, threadTlabEndOffset(), end); + logf("refillTLAB: top'=%p\n", top.toLong()); + logf("refillTLAB: start'=%p\n", top.toLong()); + logf("refillTLAB: end'=%p\n", end.toLong()); + return true; + } else { + return false; + } + } else { + // Retain TLAB + Word newRefillWasteLimit = loadWordFromWord(thread, tlabRefillWasteLimitOffset()).plus(tlabRefillWasteIncrement()); + storeWord(thread, 0, tlabRefillWasteLimitOffset(), newRefillWasteLimit); + logf("refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.toLong()); + + if (tlabStats()) { + storeInt(thread, 0, tlabSlowAllocationsOffset(), loadIntFromWord(thread, tlabSlowAllocationsOffset()) + 1); + } + + return false; + } + } + + /** + * Attempts to allocate a chunk of memory from Eden space. + * + * @param sizeInBytes the size of the chunk to allocate + * @return the allocated chunk or {@link Word#zero()} if allocation fails + */ + static Word edenAllocate(Word sizeInBytes) { + Word heapTopAddress = Word.fromLong(heapTopAddress()); + Word heapEndAddress = Word.fromLong(heapEndAddress()); + logf("edenAllocate: heapTopAddress %p\n", heapTopAddress.toLong()); + logf("edenAllocate: heapEndAddress %p\n", heapEndAddress.toLong()); + + while (true) { + Word heapTop = loadWordFromWord(heapTopAddress, 0); + Word newHeapTop = heapTop.plus(sizeInBytes); + logf("edenAllocate: heapTop %p\n", heapTop.toLong()); + logf("edenAllocate: newHeapTop %p\n", newHeapTop.toLong()); + if (newHeapTop.belowOrEqual(heapTop)) { + logf("edenAllocate: fail 1\n", 0L); + return Word.zero(); + } + + Word heapEnd = loadWordFromWord(heapEndAddress, 0); + logf("edenAllocate: heapEnd %p\n", heapEnd.toLong()); + if (newHeapTop.above(heapEnd)) { + logf("edenAllocate: fail 2\n", 0L); + return Word.zero(); + } + + if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop) == heapTop) { + logf("edenAllocate: success %p\n", heapTop.toLong()); + return heapTop; + } + } + } + + private static final boolean LOGGING_ENABLED = Boolean.getBoolean("graal.logNewInstanceStub"); + + private static void logf(String format, long value) { + if (LOGGING_ENABLED) { + Log.printf(format, value); + } + } +} diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Tue Dec 11 08:48:12 2012 +0100 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot.stubs; + +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.PhasePlan.PhasePosition; +import com.oracle.graal.snippets.*; +import com.oracle.graal.snippets.Snippet.ConstantParameter; +import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.snippets.SnippetTemplate.Key; + +/** + * Base class for implementing some low level code providing the out-of-line slow path for a snippet. + * A concrete stub is defined a subclass of this class. + *

+ * Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s + * purely for convenience (e.g., can re-use the {@link SnippetInstaller}). + */ +public abstract class Stub extends AbstractTemplates implements SnippetsInterface { + + /** + * The method implementing the stub. + */ + protected final HotSpotResolvedJavaMethod stubMethod; + + /** + * The linkage information for the stub. + */ + protected final HotSpotRuntimeCallTarget linkage; + + /** + * The code installed for the stub. + */ + protected InstalledCode stubCode; + + /** + * Creates a new stub container. The new stub still needs to be {@linkplain #install(GraalCompiler) installed}. + * + * @param descriptor linkage details for a call to the stub + */ + @SuppressWarnings("unchecked") + public Stub(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target, Descriptor descriptor) { + super(runtime, assumptions, target, null); + stubMethod = findStubMethod(runtime, getClass()); + linkage = runtime.registerStub(descriptor, this); + assert linkage != null; + } + + /** + * Adds the {@linkplain ConstantParameter constant} arguments of this stub. + */ + protected abstract void populateKey(Key key); + + protected HotSpotRuntime runtime() { + return (HotSpotRuntime) runtime; + } + + /** + * Gets the method implementing this stub. + */ + public ResolvedJavaMethod getMethod() { + return stubMethod; + } + + public HotSpotRuntimeCallTarget getLinkage() { + return linkage; + } + + /** + * Compiles the code for this stub, installs it and initializes the address used for calls to it. + */ + public void install(GraalCompiler compiler) { + StructuredGraph graph = (StructuredGraph) stubMethod.getCompilerStorage().get(Graph.class); + + Key key = new Key(stubMethod); + populateKey(key); + SnippetTemplate template = cache.get(key, assumptions); + graph = template.copySpecializedGraph(); + + PhasePlan phasePlan = new PhasePlan(); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); + phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); + final CompilationResult compResult = compiler.compileMethod(stubMethod, graph, null, phasePlan, OptimisticOptimizations.ALL); + + final CodeInfo[] info = new CodeInfo[1]; + stubCode = Debug.scope("CodeInstall", new Object[] {compiler, stubMethod}, new Callable() { + @Override + public InstalledCode call() { + InstalledCode installedCode = runtime().addMethod(stubMethod, compResult, info); + assert installedCode != null : "error installing stub " + stubMethod; + if (Debug.isDumpEnabled()) { + Debug.dump(new Object[] {compResult, info[0]}, "After code installation"); + } + return installedCode; + } + }); + + assert stubCode != null : "error installing stub " + stubMethod; + linkage.setAddress(info[0].getStart()); + } + + /** + * Finds the static method annotated with {@link Snippet} in a given class of which there must be exactly one. + */ + private static HotSpotResolvedJavaMethod findStubMethod(HotSpotRuntime runtime, Class stubClass) { + HotSpotResolvedJavaMethod m = null; + for (Method candidate : stubClass.getDeclaredMethods()) { + if (isStatic(candidate.getModifiers()) && candidate.getAnnotation(Snippet.class) != null) { + assert m == null : "more than one method annotated with @" + Snippet.class.getSimpleName() + " in " + stubClass; + m = (HotSpotResolvedJavaMethod) runtime.lookupJavaMethod(candidate); + } + } + assert m != null : "no static method annotated with @" + Snippet.class.getSimpleName() + " in " + stubClass; + return m; + } +} diff -r fcae6d960acd -r 2ae3e26b7e9a 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 Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Tue Dec 11 08:48:12 2012 +0100 @@ -29,7 +29,7 @@ import java.util.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ProfilingInfo.ExceptionSeen; @@ -775,7 +775,7 @@ lastInstr = falseSucc; if (GraalOptions.OmitHotExceptionStacktrace) { - ValueNode exception = ConstantNode.forObject(new NullPointerException(), runtime, currentGraph); + ValueNode exception = ConstantNode.forObject(cachedNullPointerException, runtime, currentGraph); trueSucc.setNext(handleException(exception, bci())); } else { RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_NULL_POINTER_EXCEPTION)); @@ -785,6 +785,14 @@ } } + private static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException(); + private static final NullPointerException cachedNullPointerException = new NullPointerException(); + static { + cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]); + cachedNullPointerException.setStackTrace(new StackTraceElement[0]); + } + + private void emitBoundsCheck(ValueNode index, ValueNode length) { BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode()); BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode()); @@ -794,7 +802,7 @@ lastInstr = trueSucc; if (GraalOptions.OmitHotExceptionStacktrace) { - ValueNode exception = ConstantNode.forObject(new ArrayIndexOutOfBoundsException(), runtime, currentGraph); + ValueNode exception = ConstantNode.forObject(cachedArrayIndexOutOfBoundsException, runtime, currentGraph); falseSucc.setNext(handleException(exception, bci())); } else { RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CREATE_OUT_OF_BOUNDS_EXCEPTION, index)); @@ -963,7 +971,7 @@ Kind resultType = targetMethod.getSignature().getReturnKind(); if (GraalOptions.DeoptALot) { DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint, graphId)); - deoptimize.setMessage("invoke " + targetMethod.getName()); + deoptimize.setMessage(targetMethod.getName()); append(deoptimize); frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph)); return; diff -r fcae6d960acd -r 2ae3e26b7e9a 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 Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Tue Dec 11 08:48:12 2012 +0100 @@ -26,7 +26,7 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; @@ -44,10 +44,10 @@ @Temp protected Value[] temps; @State protected LIRFrameState state; - protected final Object targetMethod; + protected final Object callTarget; - public DirectCallOp(Object targetMethod, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - this.targetMethod = targetMethod; + public DirectCallOp(Object callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + this.callTarget = callTarget; this.result = result; this.parameters = parameters; this.state = state; @@ -58,7 +58,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { emitAlignmentForDirectCall(tasm, masm); - directCall(tasm, masm, targetMethod, state); + directCall(tasm, masm, callTarget, state); } protected void emitAlignmentForDirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { @@ -77,10 +77,10 @@ @Temp protected Value[] temps; @State protected LIRFrameState state; - protected final Object targetMethod; + protected final Object callTarget; - public IndirectCallOp(Object targetMethod, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { - this.targetMethod = targetMethod; + public IndirectCallOp(Object callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { + this.callTarget = callTarget; this.result = result; this.parameters = parameters; this.targetAddress = targetAddress; @@ -91,7 +91,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - indirectCall(tasm, masm, asRegister(targetAddress), targetMethod, state); + indirectCall(tasm, masm, asRegister(targetAddress), callTarget, state); } @Override @@ -101,10 +101,10 @@ } } - public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target, LIRFrameState info) { + public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object callTarget, LIRFrameState info) { int before = masm.codeBuffer.position(); - if (target instanceof RuntimeCall) { - long maxOffset = ((RuntimeCall) target).getMaxCallTargetOffset(); + if (callTarget instanceof RuntimeCallTarget) { + long maxOffset = ((RuntimeCallTarget) callTarget).getMaxCallTargetOffset(); if (maxOffset != (int) maxOffset) { // offset might not fit a 32-bit immediate, generate an // indirect call with a 64-bit immediate @@ -120,7 +120,7 @@ masm.call(); } int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, tasm.runtime.lookupCallTarget(target), info); + tasm.recordDirectCall(before, after, tasm.runtime.lookupCallTarget(callTarget), info); tasm.recordExceptionHandlers(after, info); masm.ensureUniquePC(); } @@ -133,11 +133,11 @@ masm.ensureUniquePC(); } - public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, Object target, LIRFrameState info) { + public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, Object callTarget, LIRFrameState info) { int before = masm.codeBuffer.position(); masm.call(dst); int after = masm.codeBuffer.position(); - tasm.recordIndirectCall(before, after, tasm.runtime.lookupCallTarget(target), info); + tasm.recordIndirectCall(before, after, tasm.runtime.lookupCallTarget(callTarget), info); tasm.recordExceptionHandlers(after, info); masm.ensureUniquePC(); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -25,7 +25,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -60,6 +59,22 @@ this.reason = deoptReason; } + public DeoptimizationReason getReason() { + return reason; + } + + public DeoptimizationAction getAction() { + return action; + } + + public boolean isNegated() { + return negated; + } + + public long getLeafGraphId() { + return leafGraphId; + } + @Override public String toString(Verbosity verbosity) { if (verbosity == Verbosity.Name && negated) { @@ -93,8 +108,7 @@ @Override public void lower(LoweringTool tool) { - ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(tool.createGuard(condition, reason, action, negated, leafGraphId))); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor); + tool.getRuntime().lower(this, tool); } @Override diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.nodes; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; @@ -50,7 +50,7 @@ @Override public void generate(LIRGeneratorTool gen) { - RuntimeCall call = gen.getRuntime().lookupRuntimeCall(UNWIND_EXCEPTION); + RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(UNWIND_EXCEPTION); gen.emitCall(call, call.getCallingConvention(), false, gen.operand(exception())); } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -40,7 +40,7 @@ } public LoadHubNode(ValueNode object, Kind kind) { - super(StampFactory.forKind(kind)); + super(kind == Kind.Object ? StampFactory.objectNonNull() : StampFactory.forKind(kind)); this.object = object; } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -22,7 +22,7 @@ */ package com.oracle.graal.nodes.extended; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; diff -r fcae6d960acd -r 2ae3e26b7e9a 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 Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -45,6 +45,10 @@ return dimensions.size(); } + public NodeList dimensions() { + return dimensions; + } + /** * Constructs a new NewMultiArrayNode. * @param type the element type of the array diff -r fcae6d960acd -r 2ae3e26b7e9a 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 Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Tue Dec 11 08:48:12 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.graal.nodes.java; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCall.*; +import com.oracle.graal.api.code.RuntimeCallTarget.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -49,7 +49,7 @@ @Override public void generate(LIRGeneratorTool gen) { - RuntimeCall call = gen.getRuntime().lookupRuntimeCall(REGISTER_FINALIZER); + RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(REGISTER_FINALIZER); gen.emitCall(call, call.getCallingConvention(), true, gen.operand(object())); } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Tue Dec 11 08:48:12 2012 +0100 @@ -85,7 +85,7 @@ public abstract void emitMembar(int barriers); public abstract void emitDeoptimizeOnOverflow(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo); public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo, long leafGraphId); - public abstract Value emitCall(Object target, CallingConvention cc, boolean canTrap, Value... args); + public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args); public abstract void emitIf(IfNode i); public abstract void emitConditional(ConditionalNode i); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Dec 11 08:48:12 2012 +0100 @@ -1001,7 +1001,7 @@ return getIntrinsicGraph(invoke, target, runtime) != null; } - private static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { + public static StructuredGraph getIntrinsicGraph(Invoke invoke, ResolvedJavaMethod target, GraalCodeCacheProvider runtime) { assert invoke.node().isAlive(); StructuredGraph intrinsicGraph = (StructuredGraph) target.getCompilerStorage().get(Graph.class); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Tue Dec 11 08:48:12 2012 +0100 @@ -104,6 +104,8 @@ private final GraalCodeCacheProvider runtime; private final Assumptions assumptions; + private boolean deferred; + public LoweringPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { this.runtime = runtime; this.assumptions = assumptions; @@ -127,11 +129,12 @@ final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph, false); + deferred = false; processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); Debug.dump(graph, "Lowering iteration %d", i++); new CanonicalizerPhase(null, runtime, assumptions, mark).apply(graph); - if (!containsLowerable(graph.getNewNodes(mark))) { + if (!deferred && !containsLowerable(graph.getNewNodes(mark))) { // No new lowerable nodes - done! break; } @@ -184,9 +187,14 @@ loweringTool.lastFixedNode = fixed; } - if (node.isAlive() && !processed.isMarked(node)) { - processed.mark(node); - if (node instanceof Lowerable) { + if (node.isAlive() && !processed.isMarked(node) && node instanceof Lowerable) { + if (loweringTool.lastFixedNode == null) { + // We cannot lower the node now because we don't have a fixed node to anchor the replacements. + // This can happen when previous lowerings in this lowering iteration deleted the BeginNode of this block. + // In the next iteration, we will have the new BeginNode available, and we can lower this node. + deferred = true; + } else { + processed.mark(node); ((Lowerable) node).lower(loweringTool); } } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Dec 11 08:48:12 2012 +0100 @@ -116,7 +116,7 @@ @Test public void test_fromObject() { - inliningPolicy.set(new DefaultSnippetInliningPolicy(new BoxingMethodPool(runtime())) { + inliningPolicy.set(new DefaultSnippetInliningPolicy(runtime(), new BoxingMethodPool(runtime())) { @Override public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { return super.shouldInline(method, caller) && !method.getName().equals("hashCode"); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Log.java Tue Dec 11 08:48:12 2012 +0100 @@ -24,7 +24,7 @@ import java.io.*; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/MathSnippetsX86.java Tue Dec 11 08:48:12 2012 +0100 @@ -22,7 +22,7 @@ */ package com.oracle.graal.snippets; -import com.oracle.graal.api.code.RuntimeCall.Descriptor; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java Tue Dec 11 08:48:12 2012 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.snippets; -import static com.oracle.graal.api.meta.MetaUtil.*; - import java.lang.annotation.*; import java.lang.reflect.*; @@ -73,9 +71,11 @@ * */ public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { + private final MetaAccessProvider metaAccess; private final BoxingMethodPool pool; - public DefaultSnippetInliningPolicy(BoxingMethodPool pool) { + public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { + this.metaAccess = metaAccess; this.pool = pool; } @@ -90,7 +90,7 @@ if (method.getAnnotation(NodeIntrinsic.class) != null) { return false; } - if (Throwable.class.isAssignableFrom(getMirrorOrFail(method.getDeclaringClass(), null))) { + if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { if (method.getName().equals("")) { return false; } diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Dec 11 08:48:12 2012 +0100 @@ -142,7 +142,7 @@ policyClass = snippet.inlining(); } if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(pool); + return new DefaultSnippetInliningPolicy(runtime, pool); } try { return policyClass.getConstructor().newInstance(); diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Tue Dec 11 08:48:12 2012 +0100 @@ -85,7 +85,7 @@ int count = signature.getParameterCount(false); Class[] result = new Class< ? >[count]; for (int i = 0; i < result.length; ++i) { - result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), null); + result[i] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); } return result; } @@ -126,7 +126,7 @@ } // Call the method - Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, null), target.getName(), parameterTypes, receiver, arguments); + Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, receiver, arguments); if (constant != null) { // Replace the invoke with the result of the call @@ -191,7 +191,7 @@ private static Class< ? > getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { Class< ? > result = intrinsic.value(); if (result == NodeIntrinsic.class) { - return getMirrorOrFail(target.getDeclaringClass(), null); + return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); } assert Node.class.isAssignableFrom(result); return result; diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Tue Dec 11 08:48:12 2012 +0100 @@ -185,12 +185,17 @@ protected final Cache cache; protected final MetaAccessProvider runtime; protected final Assumptions assumptions; - protected Class snippetsClass; + protected Class snippetsClass; public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { this.runtime = runtime; this.assumptions = assumptions; - this.snippetsClass = snippetsClass; + if (snippetsClass == null) { + assert this instanceof SnippetsInterface; + this.snippetsClass = getClass(); + } else { + this.snippetsClass = snippetsClass; + } this.cache = new Cache(runtime, target); } @@ -243,7 +248,13 @@ String name = c.value(); Object arg = key.get(name); Kind kind = signature.getParameterKind(i); - replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(Constant.forBoxed(kind, arg), runtime, snippetCopy)); + Constant constantArg; + if (arg instanceof Constant) { + constantArg = (Constant) arg; + } else { + constantArg = Constant.forBoxed(kind, arg); + } + replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); } else { VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); if (vp != null) { @@ -390,8 +401,12 @@ } private static boolean checkConstantArgument(final ResolvedJavaMethod method, Signature signature, int i, String name, Object arg, Kind kind) { + ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); + if (WordTypeRewriterPhase.isWord(type)) { + assert arg instanceof Constant : method + ": word constant parameters must be passed boxed in a Constant value: " + arg; + return true; + } if (kind == Kind.Object) { - ResolvedJavaType type = signature.getParameterType(i, method.getDeclaringClass()).resolve(method.getDeclaringClass()); assert arg == null || type.isInstance(Constant.forObject(arg)) : method + ": wrong value type for " + name + ": expected " + type.getName() + ", got " + arg.getClass().getName(); } else { @@ -581,6 +596,13 @@ } /** + * Gets a copy of the specialized graph. + */ + public StructuredGraph copySpecializedGraph() { + return snippet.copy(); + } + + /** * Replaces a given floating node with this specialized snippet. * * @param runtime diff -r fcae6d960acd -r 2ae3e26b7e9a graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Tue Dec 11 08:28:00 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Tue Dec 11 08:48:12 2012 +0100 @@ -43,7 +43,7 @@ */ public class WordTypeRewriterPhase extends Phase { - private static final String WordClassName = MetaUtil.toInternalName(Word.class.getName()); + public static final String WordClassName = MetaUtil.toInternalName(Word.class.getName()); private final Kind wordKind; @@ -290,6 +290,7 @@ } public static boolean isWord(ValueNode node) { + node.inferStamp(); if (node.stamp() == StampFactory.forWord()) { return true; } @@ -310,7 +311,7 @@ } private void changeToWord(ValueNode valueNode) { - assert !(valueNode instanceof ConstantNode); + assert !(valueNode instanceof ConstantNode) : "boxed Word constants should not appear in a snippet graph: " + valueNode + ", stamp: " + valueNode.stamp(); valueNode.setStamp(StampFactory.forKind(wordKind)); // Propagate word kind. diff -r fcae6d960acd -r 2ae3e26b7e9a src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Tue Dec 11 08:48:12 2012 +0100 @@ -804,44 +804,18 @@ break; - case graal_new_type_array_id: - case graal_new_object_array_id: + case graal_new_array_id: { Register length = rbx; // Incoming Register klass = rdx; // Incoming Register obj = rax; // Result - if (id == graal_new_type_array_id) { - __ set_info("new_type_array", dont_gc_arguments); - } else { - __ set_info("new_object_array", dont_gc_arguments); - } + __ set_info("new_array", dont_gc_arguments); -#ifdef ASSERT - // assert object type is really an array of the proper kind - { - Label ok; - Register t0 = obj; - __ movl(t0, Address(klass, Klass::layout_helper_offset())); - __ sarl(t0, Klass::_lh_array_tag_shift); - int tag = ((id == graal_new_type_array_id) - ? Klass::_lh_array_tag_type_value - : Klass::_lh_array_tag_obj_value); - __ cmpl(t0, tag); - __ jcc(Assembler::equal, ok); - __ stop("assert(is an array klass)"); - __ should_not_reach_here(); - __ bind(ok); - } -#endif // ASSERT __ enter(); OopMap* map = save_live_registers(sasm, 3); int call_offset; - if (id == graal_new_type_array_id) { - call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length); - } else { - call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length); - } + call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_array), klass, length); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/compiler/abstractCompiler.hpp --- a/src/share/vm/compiler/abstractCompiler.hpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/compiler/abstractCompiler.hpp Tue Dec 11 08:48:12 2012 +0100 @@ -47,8 +47,11 @@ // Name of this compiler virtual const char* name() = 0; - // Missing feature tests + // Should a native wrapper be generated by the runtime. This method + // does *not* answer the question "can this compiler generate code for + // a native method". virtual bool supports_native() { return true; } + virtual bool supports_osr () { return true; } #if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !defined(GRAAL)) virtual bool is_c1 () { return false; } diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Tue Dec 11 08:48:12 2012 +0100 @@ -538,8 +538,12 @@ // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); _debug_recorder->add_safepoint(pc_offset, -1, create_oop_map(_total_frame_size, _parameter_count, debug_info)); - oop code_pos = DebugInfo::bytecodePosition(debug_info); - record_scope(pc_offset, code_pos, new GrowableArray()); + oop frame = DebugInfo::bytecodePosition(debug_info); + if (frame != NULL) { + record_scope(pc_offset, frame, new GrowableArray()); + } else { + // Stubs do not record scope info, just oop maps + } _debug_recorder->end_safepoint(pc_offset); } @@ -595,8 +599,13 @@ if (debug_info != NULL) { oop frame = DebugInfo::bytecodePosition(debug_info); - _debug_recorder->add_safepoint(next_pc_offset, BytecodeFrame::leafGraphId(frame), create_oop_map(_total_frame_size, _parameter_count, debug_info)); - record_scope(next_pc_offset, frame, new GrowableArray()); + jlong leaf_graph_id = frame == NULL ? -1 : BytecodeFrame::leafGraphId(frame); + _debug_recorder->add_safepoint(next_pc_offset, leaf_graph_id, create_oop_map(_total_frame_size, _parameter_count, debug_info)); + if (frame != NULL) { + record_scope(next_pc_offset, frame, new GrowableArray()); + } else { + // Stubs do not record scope info, just oop maps + } } if (global_stub != NULL) { diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Tue Dec 11 08:48:12 2012 +0100 @@ -1,968 +1,984 @@ -/* - * 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. - */ - -#include "precompiled.hpp" -#include "runtime/fieldDescriptor.hpp" -#include "memory/oopFactory.hpp" -#include "oops/generateOopMap.hpp" -#include "oops/fieldStreams.hpp" -#include "runtime/javaCalls.hpp" -#include "graal/graalRuntime.hpp" -#include "compiler/compileBroker.hpp" -#include "compiler/compilerOracle.hpp" -#include "graal/graalCompilerToVM.hpp" -#include "graal/graalCompiler.hpp" -#include "graal/graalEnv.hpp" -#include "graal/graalJavaAccess.hpp" -#include "graal/graalCodeInstaller.hpp" -#include "graal/graalVMToCompiler.hpp" -#include "graal/graalVmIds.hpp" - - -Method* getMethodFromHotSpotMethod(oop hotspot_method) { - assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethod::klass()), "sanity"); - return asMethod(HotSpotResolvedJavaMethod::metaspaceMethod(hotspot_method)); -} - -// Entry to native method implementation that transitions current thread to '_thread_in_vm'. -#define C2V_VMENTRY(result_type, name, signature) \ - JNIEXPORT result_type JNICALL c2v_ ## name signature { \ - TRACE_graal_3("CompilerToVM::" #name); \ - GRAAL_VM_ENTRY_MARK; \ - -// Entry to native method implementation that calls a JNI function -// and hence cannot transition current thread to '_thread_in_vm'. -#define C2V_ENTRY(result_type, name, signature) \ - JNIEXPORT result_type JNICALL c2v_ ## name signature { \ - TRACE_graal_3("CompilerToVM::" #name); \ - -#define C2V_END } - -C2V_ENTRY(jbyteArray, initializeBytecode, (JNIEnv *env, jobject, jlong metaspace_method, jbyteArray result)) - methodHandle method = asMethod(metaspace_method); - ResourceMark rm; - - int code_size = method->code_size(); - jbyte* reconstituted_code = NULL; - - // replace all breakpoints - must be done before undoing any rewriting - if (method->number_of_breakpoints() > 0) { - reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size); - memcpy(reconstituted_code, (jbyte *) method->code_base(), code_size); - BreakpointInfo* bp = InstanceKlass::cast(method->method_holder())->breakpoints(); - for (; bp != NULL; bp = bp->next()) { - if (bp->match(method())) { - jbyte code = bp->orig_bytecode(); - reconstituted_code[bp->bci()] = code; - } - } - } - - // iterate over all bytecodes and replace non-Java bytecodes - if (RewriteBytecodes || RewriteFrequentPairs || InstanceKlass::cast(method->method_holder())->is_rewritten()) { - if (reconstituted_code == NULL) { - reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size); - memcpy(reconstituted_code, (jbyte *) method->code_base(), code_size); - } - BytecodeStream s(method); - while(!s.is_last_bytecode()) { - s.next(); - Bytecodes::Code opcode = s.raw_code(); - if (!Bytecodes::is_java_code(opcode)) { - jbyte original_opcode = Bytecodes::java_code(opcode); - int bci = s.bci(); - reconstituted_code[bci] = original_opcode; - if (opcode == Bytecodes::_fast_aldc_w) { - int cpci = Bytes::get_native_u2((address) reconstituted_code + bci + 1); - int i = method->constants()->object_to_cp_index(cpci); - assert(i < method->constants()->length(), "sanity check"); - Bytes::put_Java_u2((address) reconstituted_code + bci + 1, (u2)i); - } else if (opcode == Bytecodes::_fast_aldc) { - int cpci = reconstituted_code[bci + 1] & 0xff; - int i = method->constants()->object_to_cp_index(cpci); - assert(i < method->constants()->length(), "sanity check"); - reconstituted_code[bci + 1] = (jbyte)i; - } - } - } - } - - if (reconstituted_code == NULL) { - env->SetByteArrayRegion(result, 0, code_size, (jbyte *) method->code_base()); - } else { - env->SetByteArrayRegion(result, 0, code_size, reconstituted_code); - } - - return result; -C2V_END - -C2V_VMENTRY(jstring, getSignature, (JNIEnv *env, jobject, jlong metaspace_method)) - Method* method = asMethod(metaspace_method); - assert(method != NULL && method->signature() != NULL, "signature required"); - return VmIds::toString(method->signature(), THREAD); -C2V_END - -C2V_VMENTRY(jobjectArray, initializeExceptionHandlers, (JNIEnv *, jobject, jlong metaspace_method, jobjectArray java_handlers)) - ResourceMark rm; - methodHandle method = asMethod(metaspace_method); - int handler_count = method->exception_table_length(); - objArrayHandle array = (objArrayOop) JNIHandles::resolve(java_handlers); - assert(array->length() == handler_count, "wrong length"); - ExceptionTableElement* handlers = handler_count == 0 ? NULL : method->exception_table_start(); - - for (int i = 0; i < handler_count; i++) { - ExceptionTableElement* handler = handlers + i; - Handle entry = array->obj_at(i); - assert(!entry.is_null(), "entry should not be null"); - ExceptionHandler::set_startBCI(entry, handler->start_pc); - ExceptionHandler::set_endBCI(entry, handler->end_pc); - ExceptionHandler::set_handlerBCI(entry, handler->handler_pc); - int catch_class_index = handler->catch_type_index; - ExceptionHandler::set_catchTypeCPI(entry, catch_class_index); - - if (catch_class_index == 0) { - ExceptionHandler::set_catchType(entry, NULL); - } else { - ConstantPool* cp = InstanceKlass::cast(method->method_holder())->constants(); - KlassHandle loading_klass = method->method_holder(); - Handle catch_class = GraalCompiler::get_JavaType(cp, catch_class_index, loading_klass, CHECK_NULL); - if (catch_class->klass() == HotSpotResolvedObjectType::klass() && java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(catch_class)) == SystemDictionary::Throwable_klass()) { - ExceptionHandler::set_catchType(entry, NULL); - ExceptionHandler::set_catchTypeCPI(entry, 0); - } else { - ExceptionHandler::set_catchType(entry, catch_class()); - } - } - array->obj_at_put(i, entry()); - } - - return (jobjectArray) JNIHandles::make_local(array()); -C2V_END - -C2V_VMENTRY(jint, hasBalancedMonitors, (JNIEnv *, jobject, jlong metaspace_method)) - - // Analyze the method to see if monitors are used properly. - methodHandle method(THREAD, asMethod(metaspace_method)); - assert(method->has_monitor_bytecodes(), "should have checked this"); - - // Check to see if a previous compilation computed the monitor-matching analysis. - if (method->guaranteed_monitor_matching()) { - return true; - } - - { - EXCEPTION_MARK; - ResourceMark rm(THREAD); - GeneratePairingInfo gpi(method); - gpi.compute_map(CATCH); - if (!gpi.monitor_safe()) { - return false; - } - method->set_guaranteed_monitor_matching(); - } - return true; -C2V_END - -C2V_VMENTRY(jlong, getMetaspaceMethod, (JNIEnv *, jobject, jobject reflection_method_handle, jobject resultHolder)) - oop reflection_method = JNIHandles::resolve(reflection_method_handle); - oop reflection_holder = java_lang_reflect_Method::clazz(reflection_method); - int slot = java_lang_reflect_Method::slot(reflection_method); - Klass* holder = java_lang_Class::as_Klass(reflection_holder); - methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); - Handle type = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK_0); - objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); - return (jlong) (address) method(); -} - -C2V_VMENTRY(jlong, getMetaspaceConstructor, (JNIEnv *, jobject, jobject reflection_ctor_handle, jobject resultHolder)) - oop reflection_ctor = JNIHandles::resolve(reflection_ctor_handle); - oop reflection_holder = java_lang_reflect_Constructor::clazz(reflection_ctor); - int slot = java_lang_reflect_Constructor::slot(reflection_ctor); - Klass* holder = java_lang_Class::as_Klass(reflection_holder); - methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); - Handle type = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK_0); - objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); - return (jlong) (address) method(); -} - -C2V_VMENTRY(jobject, getJavaField, (JNIEnv *, jobject, jobject reflection_field_handle)) - oop reflection_field = JNIHandles::resolve(reflection_field_handle); - oop reflection_holder = java_lang_reflect_Field::clazz(reflection_field); - int slot = java_lang_reflect_Field::slot(reflection_field); - InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(reflection_holder)); - - int offset = holder->field_offset(slot); - int flags = holder->field_access_flags(slot); - Symbol* field_name = holder->field_name(slot); - Handle field_holder = GraalCompiler::get_JavaTypeFromClass(reflection_holder, CHECK_NULL); - Handle field_type = GraalCompiler::get_JavaTypeFromClass(java_lang_reflect_Field::type(reflection_field), CHECK_NULL); - - Handle ret = GraalCompiler::get_JavaField(offset, flags, field_name, field_holder, field_type, CHECK_NULL); - return JNIHandles::make_local(THREAD, ret()); -} - -C2V_VMENTRY(jlong, getUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_method, jobject resultHolder)) - methodHandle method = asMethod(metaspace_method); - KlassHandle holder = method->method_holder(); - if (holder->is_interface()) { - // Cannot trust interfaces. Because of: - // interface I { void foo(); } - // class A { public void foo() {} } - // class B extends A implements I { } - // class C extends B { public void foo() { } } - // class D extends B { } - // Would lead to identify C.foo() as the unique concrete method for I.foo() without seeing A.foo(). - return 0L; - } - methodHandle ucm; - { - ResourceMark rm; - MutexLocker locker(Compile_lock); - ucm = Dependencies::find_unique_concrete_method(holder(), method()); - } - - if (ucm.is_null()) { - return 0L; - } - - Handle type = GraalCompiler::createHotSpotResolvedObjectType(ucm(), CHECK_0); - objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); - return (jlong) (address) ucm(); -C2V_END - -C2V_ENTRY(jint, getInvocationCount, (JNIEnv *, jobject, jlong metaspace_method)) - Method* method = asMethod(metaspace_method); - return method->invocation_count(); -C2V_END - -C2V_VMENTRY(void, initializeMethod,(JNIEnv *, jobject, jlong metaspace_method, jobject hotspot_method)) - methodHandle method = asMethod(metaspace_method); - Handle name = VmIds::toString(method->name(), CHECK); - InstanceKlass::cast(HotSpotResolvedJavaMethod::klass())->initialize(CHECK); - HotSpotResolvedJavaMethod::set_name(hotspot_method, name()); - HotSpotResolvedJavaMethod::set_codeSize(hotspot_method, method->code_size()); - HotSpotResolvedJavaMethod::set_exceptionHandlerCount(hotspot_method, method->exception_table_length()); -C2V_END - -C2V_VMENTRY(jboolean, isMethodCompilable,(JNIEnv *, jobject, jlong metaspace_method)) - methodHandle method = asMethod(metaspace_method); - return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method); -C2V_END - -C2V_VMENTRY(void, initializeMethodData,(JNIEnv *, jobject, jlong metaspace_method_data, jobject hotspot_method_data)) - MethodData* method_data = asMethodData(metaspace_method_data); - HotSpotMethodData::set_normalDataSize(hotspot_method_data, method_data->data_size()); - HotSpotMethodData::set_extraDataSize(hotspot_method_data, method_data->extra_data_size()); -C2V_END - -// ------------------------------------------------------------------ -// Adjust a CounterData count to be commensurate with -// interpreter_invocation_count. If the MDO exists for -// only 25% of the time the method exists, then the -// counts in the MDO should be scaled by 4X, so that -// they can be usefully and stably compared against the -// invocation counts in methods. -int scale_count(MethodData* method_data, int count) { - if (count > 0) { - int counter_life; - int method_life = method_data->method()->interpreter_invocation_count(); - int current_mileage = MethodData::mileage_of(method_data->method()); - int creation_mileage = method_data->creation_mileage(); - counter_life = current_mileage - creation_mileage; - - // counter_life due to backedge_counter could be > method_life - if (counter_life > method_life) - counter_life = method_life; - if (0 < counter_life && counter_life <= method_life) { - count = (int)((double)count * method_life / counter_life + 0.5); - count = (count > 0) ? count : 1; - } - } - return count; -} - -C2V_ENTRY(jint, getCompiledCodeSize, (JNIEnv *env, jobject, jlong metaspace_method)) - nmethod* code = (asMethod(metaspace_method))->code(); - return code == NULL ? 0 : code->insts_size(); -C2V_END - -C2V_VMENTRY(jobject, lookupType, (JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve)) - ResourceMark rm; - - Symbol* nameSymbol = VmIds::toSymbol(jname); - Handle name = JNIHandles::resolve(jname); - assert(nameSymbol != NULL, "name to symbol creation failed"); - - oop result = NULL; - if (nameSymbol == vmSymbols::int_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_INT, THREAD); - } else if (nameSymbol == vmSymbols::long_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_LONG, THREAD); - } else if (nameSymbol == vmSymbols::bool_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_BOOLEAN, THREAD); - } else if (nameSymbol == vmSymbols::char_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_CHAR, THREAD); - } else if (nameSymbol == vmSymbols::short_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_SHORT, THREAD); - } else if (nameSymbol == vmSymbols::byte_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_BYTE, THREAD); - } else if (nameSymbol == vmSymbols::double_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_DOUBLE, THREAD); - } else if (nameSymbol == vmSymbols::float_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_FLOAT, THREAD); - } else if (nameSymbol == vmSymbols::void_signature()) { - result = VMToCompiler::createPrimitiveJavaType((int) T_VOID, THREAD); - } else { - Klass* resolved_type = NULL; - Handle classloader; - Handle protectionDomain; - if (JNIHandles::resolve(accessingClass) != NULL) { - classloader = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(accessingClass))->class_loader(); - protectionDomain = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(accessingClass))->protection_domain(); - } - - if (eagerResolve) { - resolved_type = SystemDictionary::resolve_or_fail(nameSymbol, classloader, protectionDomain, true, THREAD); - } else { - resolved_type = SystemDictionary::resolve_or_null(nameSymbol, classloader, protectionDomain, THREAD); - } - - if (!HAS_PENDING_EXCEPTION) { - if (resolved_type == NULL) { - assert(!eagerResolve, "failed eager resolution should have caused an exception"); - Handle type = VMToCompiler::createUnresolvedJavaType(name, THREAD); - result = type(); - } else { - Handle type = GraalCompiler::createHotSpotResolvedObjectType(resolved_type, name, CHECK_NULL); - result = type(); - } - } - } - - return JNIHandles::make_local(THREAD, result); -C2V_END - -C2V_VMENTRY(jobject, lookupConstantInPool, (JNIEnv *env, jobject, jobject type, jint index)) - - ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); - - oop result = NULL; - constantTag tag = cp->tag_at(index); - if (tag.is_int()) { - result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_0); - } else if (tag.is_long()) { - result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_0); - } else if (tag.is_float()) { - result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_0); - } else if (tag.is_double()) { - result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_0); - } else if (tag.is_string()) { - oop string = NULL; - if (cp->is_pseudo_string_at(index)) { - int obj_index = cp->cp_to_object_index(index); - string = cp->pseudo_string_at(index, obj_index); - } else { - string = cp->string_at(index, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - // TODO: Gracefully exit compilation. - fatal("out of memory during compilation!"); - return NULL; - } - } - result = VMToCompiler::createConstantObject(string, CHECK_0); - } else if (tag.is_klass() || tag.is_unresolved_klass()) { - Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); - result = type(); - } else if (tag.is_object()) { - oop obj = cp->object_at(index); - assert(obj->is_instance(), "must be an instance"); - result = VMToCompiler::createConstantObject(obj, CHECK_NULL); - } else { - tty->print("unknown constant pool tag (%s) at cpi %d in %s: ", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string()); - ShouldNotReachHere(); - } - - return JNIHandles::make_local(THREAD, result); -C2V_END - -C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte opcode)) - index = GraalCompiler::to_cp_index_u2(index); - constantPoolHandle cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); - instanceKlassHandle pool_holder(cp->pool_holder()); - - Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); - methodHandle method = GraalEnv::get_method_by_index(cp, index, bc, pool_holder); - if (!method.is_null()) { - Handle holder = GraalCompiler::get_JavaType(method->method_holder(), CHECK_NULL); - return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); - } else { - // Get the method's name and signature. - Handle name = VmIds::toString(cp->name_ref_at(index), CHECK_NULL); - Handle signature = VmIds::toString(cp->signature_ref_at(index), CHECK_NULL); - int holder_index = cp->klass_ref_index_at(index); - Handle type = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); - return JNIHandles::make_local(THREAD, VMToCompiler::createUnresolvedJavaMethod(name, signature, type, THREAD)); - } -C2V_END - -C2V_VMENTRY(jobject, lookupTypeInPool, (JNIEnv *env, jobject, jobject type, jint index)) - - ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); - Handle result = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); - return JNIHandles::make_local(THREAD, result()); -C2V_END - -C2V_VMENTRY(void, lookupReferencedTypeInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte op)) - ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); - int opcode = (op & 0xFF); - if (opcode != Bytecodes::_checkcast && opcode != Bytecodes::_instanceof && opcode != Bytecodes::_new && opcode != Bytecodes::_anewarray - && opcode != Bytecodes::_multianewarray && opcode != Bytecodes::_ldc && opcode != Bytecodes::_ldc_w && opcode != Bytecodes::_ldc2_w) - { - index = cp->remap_instruction_operand_from_cache(GraalCompiler::to_cp_index_u2(index)); - } - constantTag tag = cp->tag_at(index); - if (tag.is_field_or_method()) { - index = cp->uncached_klass_ref_index_at(index); - tag = cp->tag_at(index); - } - - if (tag.is_unresolved_klass() || tag.is_klass()) { - Klass* klass = cp->klass_at(index, CHECK); - if (klass->oop_is_instance()) { - InstanceKlass::cast(klass)->initialize(CHECK); - } - } -C2V_END - -C2V_VMENTRY(jobject, lookupFieldInPool, (JNIEnv *env, jobject, jobject constantPoolHolder, jint index, jbyte opcode)) - ResourceMark rm; - - index = GraalCompiler::to_cp_index_u2(index); - constantPoolHandle cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(constantPoolHolder)))->constants(); - - int nt_index = cp->name_and_type_ref_index_at(index); - int sig_index = cp->signature_ref_index_at(nt_index); - Symbol* signature = cp->symbol_at(sig_index); - int name_index = cp->name_ref_index_at(nt_index); - Symbol* name = cp->symbol_at(name_index); - int holder_index = cp->klass_ref_index_at(index); - Handle holder = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); - instanceKlassHandle holder_klass; - - Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); - int offset = -1; - AccessFlags flags; - BasicType basic_type; - if (holder->klass() == SystemDictionary::HotSpotResolvedObjectType_klass()) { - FieldAccessInfo result; - LinkResolver::resolve_field(result, cp, index, - Bytecodes::java_code(code), - true, false, Thread::current()); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - } else { - offset = result.field_offset(); - flags = result.access_flags(); - holder_klass = result.klass()(); - basic_type = result.field_type(); - holder = GraalCompiler::get_JavaType(holder_klass, CHECK_NULL); - } - } - - Handle type = GraalCompiler::get_JavaTypeFromSignature(signature, cp->pool_holder(), CHECK_NULL); - Handle field_handle = GraalCompiler::get_JavaField(offset, flags.as_int(), name, holder, type, THREAD); - - return JNIHandles::make_local(THREAD, field_handle()); -C2V_END - -C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject resolved_type, jstring name, jstring signature)) - - assert(JNIHandles::resolve(resolved_type) != NULL, ""); - Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(resolved_type)); - Symbol* name_symbol = VmIds::toSymbol(name); - Symbol* signature_symbol = VmIds::toSymbol(signature); - methodHandle method = klass->lookup_method(name_symbol, signature_symbol); - if (method.is_null()) { - if (TraceGraal >= 3) { - ResourceMark rm; - tty->print_cr("Could not resolve method %s %s on klass %s", name_symbol->as_C_string(), signature_symbol->as_C_string(), klass->name()->as_C_string()); - } - return NULL; - } - Handle holder = GraalCompiler::get_JavaType(method->method_holder(), CHECK_NULL); - return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); -C2V_END - -C2V_VMENTRY(jlong, getPrototypeMarkWord, (JNIEnv *, jobject, jobject klass)) - KlassHandle klass_handle(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(klass))); - if (klass_handle->oop_is_array()) { - return (int32_t)(intptr_t) markOopDesc::prototype(); - } else { - return (jlong) (intptr_t) klass_handle->prototype_header(); - } -C2V_END - -C2V_VMENTRY(jboolean, isTypeInitialized,(JNIEnv *, jobject, jobject hotspot_klass)) - Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(hotspot_klass)); - assert(klass != NULL, "method must not be called for primitive types"); - return InstanceKlass::cast(klass)->is_initialized(); -C2V_END - -C2V_VMENTRY(void, initializeType, (JNIEnv *, jobject, jobject hotspot_klass)) - Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(hotspot_klass)); - assert(klass != NULL, "method must not be called for primitive types"); - InstanceKlass::cast(klass)->initialize(JavaThread::current()); -C2V_END - -C2V_VMENTRY(jobject, getInstanceFields, (JNIEnv *, jobject, jobject klass)) - ResourceMark rm; - - instanceKlassHandle k = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(klass)); - GrowableArray fields(k->java_fields_count()); - - for (AllFieldStream fs(k()); !fs.done(); fs.next()) { - if (!fs.access_flags().is_static()) { - Handle type = GraalCompiler::get_JavaTypeFromSignature(fs.signature(), k, Thread::current()); - int flags = fs.access_flags().as_int(); - bool internal = fs.access_flags().is_internal(); - Handle name = VmIds::toString(fs.name(), Thread::current()); - Handle field = VMToCompiler::createJavaField(JNIHandles::resolve(klass), name, type, fs.offset(), flags, internal, Thread::current()); - fields.append(field()); - } - } - objArrayHandle field_array = oopFactory::new_objArray(SystemDictionary::HotSpotResolvedJavaField_klass(), fields.length(), CHECK_NULL); - for (int i = 0; i < fields.length(); ++i) { - field_array->obj_at_put(i, fields.at(i)()); - } - return JNIHandles::make_local(field_array()); -C2V_END - -C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong stub)) - address target_addr = (address) stub; - if (target_addr != 0x0) { - int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); - int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); - return MAX2(ABS(off_low), ABS(off_high)); - } - return -1; -C2V_END - -C2V_VMENTRY(jobject, getResolvedType, (JNIEnv *env, jobject, jobject javaClass)) - oop java_mirror = JNIHandles::resolve(javaClass); - assert(java_mirror != NULL, "argument to CompilerToVM.getResolvedType must not be NULL"); - Handle type = GraalCompiler::get_JavaTypeFromClass(java_mirror, CHECK_NULL); - return JNIHandles::make_local(THREAD, type()); -C2V_END - - -// helpers used to set fields in the HotSpotVMConfig object -jfieldID getFieldID(JNIEnv* env, jobject obj, const char* name, const char* sig) { - jfieldID id = env->GetFieldID(env->GetObjectClass(obj), name, sig); - if (id == NULL) { - fatal(err_msg("field not found: %s (%s)", name, sig)); - } - return id; -} - -void set_boolean(JNIEnv* env, jobject obj, const char* name, bool value) { env->SetBooleanField(obj, getFieldID(env, obj, name, "Z"), value); } -void set_int(JNIEnv* env, jobject obj, const char* name, int value) { env->SetIntField(obj, getFieldID(env, obj, name, "I"), value); } -void set_long(JNIEnv* env, jobject obj, const char* name, jlong value) { env->SetLongField(obj, getFieldID(env, obj, name, "J"), value); } -void set_object(JNIEnv* env, jobject obj, const char* name, jobject value) { env->SetObjectField(obj, getFieldID(env, obj, name, "Ljava/lang/Object;"), value); } -void set_int_array(JNIEnv* env, jobject obj, const char* name, jarray value) { env->SetObjectField(obj, getFieldID(env, obj, name, "[I"), value); } - -jboolean get_boolean(JNIEnv* env, jobject obj, const char* name) { return env->GetBooleanField(obj, getFieldID(env, obj, name, "Z")); } -jint get_int(JNIEnv* env, jobject obj, const char* name) { return env->GetIntField(obj, getFieldID(env, obj, name, "I")); } -jlong get_long(JNIEnv* env, jobject obj, const char* name) { return env->GetLongField(obj, getFieldID(env, obj, name, "J")); } -jobject get_object(JNIEnv* env, jobject obj, const char* name) { return env->GetObjectField(obj, getFieldID(env, obj, name, "Ljava/lang/Object;")); } -jobject get_object(JNIEnv* env, jobject obj, const char* name, const char* sig) { return env->GetObjectField(obj, getFieldID(env, obj, name, sig)); } - - -BasicType basicTypes[] = { T_BOOLEAN, T_BYTE, T_SHORT, T_CHAR, T_INT, T_FLOAT, T_LONG, T_DOUBLE, T_OBJECT }; -int basicTypeCount = sizeof(basicTypes) / sizeof(BasicType); - -C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config)) -#ifdef _WIN64 - set_boolean(env, config, "windowsOs", true); -#else - set_boolean(env, config, "windowsOs", false); -#endif - set_boolean(env, config, "verifyOops", VerifyOops); - set_boolean(env, config, "useFastLocking", UseFastLocking); - set_boolean(env, config, "useFastNewObjectArray", UseFastNewObjectArray); - set_boolean(env, config, "useBiasedLocking", UseBiasedLocking); - set_boolean(env, config, "useFastNewTypeArray", UseFastNewTypeArray); - set_boolean(env, config, "useTLAB", UseTLAB); - set_int(env, config, "codeEntryAlignment", CodeEntryAlignment); - set_int(env, config, "vmPageSize", os::vm_page_size()); - set_int(env, config, "stackShadowPages", StackShadowPages); - set_int(env, config, "hubOffset", oopDesc::klass_offset_in_bytes()); - set_int(env, config, "markOffset", oopDesc::mark_offset_in_bytes()); - set_int(env, config, "prototypeMarkWordOffset", in_bytes(Klass::prototype_header_offset())); - set_int(env, config, "superCheckOffsetOffset", in_bytes(Klass::super_check_offset_offset())); - set_int(env, config, "secondarySuperCacheOffset", in_bytes(Klass::secondary_super_cache_offset())); - set_int(env, config, "secondarySupersOffset", in_bytes(Klass::secondary_supers_offset())); - set_int(env, config, "subklassOffset", in_bytes(Klass::subklass_offset())); - set_int(env, config, "nextSiblingOffset", in_bytes(Klass::next_sibling_offset())); - set_int(env, config, "arrayLengthOffset", arrayOopDesc::length_offset_in_bytes()); - set_int(env, config, "klassStateOffset", in_bytes(InstanceKlass::init_state_offset())); - set_int(env, config, "klassStateFullyInitialized", (int)InstanceKlass::fully_initialized); - set_int(env, config, "threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset())); - set_int(env, config, "threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset())); - set_int(env, config, "threadObjectOffset", in_bytes(JavaThread::threadObj_offset())); - set_int(env, config, "osThreadOffset", in_bytes(JavaThread::osthread_offset())); - set_int(env, config, "osThreadInterruptedOffset", in_bytes(OSThread::interrupted_offset())); - set_int(env, config, "unlockedMask", (int) markOopDesc::unlocked_value); - set_int(env, config, "biasedLockMaskInPlace", (int) markOopDesc::biased_lock_mask_in_place); - set_int(env, config, "ageMaskInPlace", (int) markOopDesc::age_mask_in_place); - set_int(env, config, "epochMaskInPlace", (int) markOopDesc::epoch_mask_in_place); - set_int(env, config, "biasedLockPattern", (int) markOopDesc::biased_lock_pattern); - set_int(env, config, "methodMaxLocalsOffset", in_bytes(Method::size_of_locals_offset())); - set_int(env, config, "methodMaxStackOffset", in_bytes(Method::max_stack_offset())); - set_int(env, config, "extraStackEntries", Method::extra_stack_entries()); - set_int(env, config, "methodAccessFlagsOffset", in_bytes(Method::access_flags_offset())); - set_int(env, config, "klassHasFinalizerFlag", JVM_ACC_HAS_FINALIZER); - set_int(env, config, "threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset())); - set_int(env, config, "threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); - set_long(env, config, "safepointPollingAddress", (jlong)(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()))); - set_boolean(env, config, "isPollingPageFar", Assembler::is_polling_page_far()); - set_int(env, config, "classMirrorOffset", in_bytes(Klass::java_mirror_offset())); - set_int(env, config, "runtimeCallStackSize", (jint)frame::arg_reg_save_area_bytes); - set_int(env, config, "klassModifierFlagsOffset", in_bytes(Klass::modifier_flags_offset())); - set_int(env, config, "klassAccessFlagsOffset", in_bytes(Klass::access_flags_offset())); - set_int(env, config, "klassLayoutHelperOffset", in_bytes(Klass::layout_helper_offset())); - set_int(env, config, "klassSuperKlassOffset", in_bytes(Klass::super_offset())); - set_int(env, config, "klassOffset", java_lang_Class::klass_offset_in_bytes()); - set_int(env, config, "graalMirrorInClassOffset", java_lang_Class::graal_mirror_offset_in_bytes()); - set_int(env, config, "methodDataOffset", in_bytes(Method::method_data_offset())); - set_int(env, config, "nmethodEntryOffset", nmethod::verified_entry_point_offset()); - set_int(env, config, "methodCompiledEntryOffset", in_bytes(Method::from_compiled_offset())); - set_int(env, config, "basicLockSize", sizeof(BasicLock)); - set_int(env, config, "basicLockDisplacedHeaderOffset", BasicLock::displaced_header_offset_in_bytes()); - set_int(env, config, "uninitializedIdentityHashCodeValue", markOopDesc::no_hash); - set_int(env, config, "identityHashCodeShift", markOopDesc::hash_shift); - - set_int(env, config, "arrayKlassLayoutHelperIdentifier", 0x80000000); - assert((Klass::_lh_array_tag_obj_value & Klass::_lh_array_tag_type_value & 0x80000000) != 0, "obj_array and type_array must have first bit set"); - set_int(env, config, "arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset())); - - set_int(env, config, "metaspaceArrayLengthOffset", Array::length_offset_in_bytes()); - set_int(env, config, "metaspaceArrayBaseOffset", Array::base_offset_in_bytes()); - set_int(env, config, "methodDataOopDataOffset", in_bytes(MethodData::data_offset())); - set_int(env, config, "methodDataOopTrapHistoryOffset", in_bytes(MethodData::trap_history_offset())); - set_int(env, config, "dataLayoutHeaderSize", DataLayout::header_size_in_bytes()); - set_int(env, config, "dataLayoutTagOffset", in_bytes(DataLayout::tag_offset())); - set_int(env, config, "dataLayoutFlagsOffset", in_bytes(DataLayout::flags_offset())); - set_int(env, config, "dataLayoutBCIOffset", in_bytes(DataLayout::bci_offset())); - set_int(env, config, "dataLayoutCellsOffset", in_bytes(DataLayout::cell_offset(0))); - set_int(env, config, "dataLayoutCellSize", DataLayout::cell_size); - set_int(env, config, "bciProfileWidth", BciProfileWidth); - set_int(env, config, "typeProfileWidth", TypeProfileWidth); - - set_long(env, config, "debugStub", VmIds::addStub((address)warning)); - set_long(env, config, "instanceofStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_slow_subtype_check_id))); - set_long(env, config, "newInstanceStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_instance_id))); - set_long(env, config, "newTypeArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_type_array_id))); - set_long(env, config, "newObjectArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_object_array_id))); - set_long(env, config, "newMultiArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_multi_array_id))); - set_long(env, config, "inlineCacheMissStub", VmIds::addStub(SharedRuntime::get_ic_miss_stub())); - set_long(env, config, "handleExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_handle_exception_nofpu_id))); - set_long(env, config, "handleDeoptStub", VmIds::addStub(SharedRuntime::deopt_blob()->unpack())); - set_long(env, config, "monitorEnterStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorenter_id))); - set_long(env, config, "monitorExitStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorexit_id))); - set_long(env, config, "verifyOopStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_verify_oop_id))); - set_long(env, config, "vmErrorStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_vm_error_id))); - set_long(env, config, "deoptimizeStub", VmIds::addStub(SharedRuntime::deopt_blob()->uncommon_trap())); - set_long(env, config, "unwindExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_unwind_exception_call_id))); - set_long(env, config, "osrMigrationEndStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_OSR_migration_end_id))); - set_long(env, config, "registerFinalizerStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_register_finalizer_id))); - set_long(env, config, "setDeoptInfoStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_set_deopt_info_id))); - set_long(env, config, "createNullPointerExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_null_pointer_exception_id))); - set_long(env, config, "createOutOfBoundsExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_out_of_bounds_exception_id))); - set_long(env, config, "javaTimeMillisStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeMillis))); - set_long(env, config, "javaTimeNanosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeNanos))); - set_long(env, config, "arithmeticFremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_frem_id))); - set_long(env, config, "arithmeticDremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_drem_id))); - set_long(env, config, "arithmeticSinStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dsin))); - set_long(env, config, "arithmeticCosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dcos))); - set_long(env, config, "arithmeticTanStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dtan))); - set_long(env, config, "logPrimitiveStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_primitive_id))); - set_long(env, config, "logObjectStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_object_id))); - set_long(env, config, "logPrintfStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_printf_id))); - set_long(env, config, "identityHashCodeStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_identity_hash_code_id))); - set_long(env, config, "threadIsInterruptedStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_thread_is_interrupted_id))); - - - BarrierSet* bs = Universe::heap()->barrier_set(); - switch (bs->kind()) { - case BarrierSet::CardTableModRef: - case BarrierSet::CardTableExtension: { - jlong base = (jlong)((CardTableModRefBS*)bs)->byte_map_base; - assert(base != 0, "unexpected byte_map_base"); - set_long(env, config, "cardtableStartAddress", base); - set_int(env, config, "cardtableShift", CardTableModRefBS::card_shift); - break; - } - case BarrierSet::ModRef: - case BarrierSet::Other: - set_long(env, config, "cardtableStartAddress", 0); - set_int(env, config, "cardtableShift", 0); - // No post barriers - break; -#ifndef SERIALGC - case BarrierSet::G1SATBCT: - case BarrierSet::G1SATBCTLogging: -#endif // SERIALGC - default: - ShouldNotReachHere(); - break; - } - - set_int(env, config, "arrayClassElementOffset", in_bytes(ObjArrayKlass::element_klass_offset())); -C2V_END - -C2V_VMENTRY(jint, installCode0, (JNIEnv *jniEnv, jobject, jobject compResult, jobject installed_code, jobject info)) - ResourceMark rm; - HandleMark hm; - Handle compResultHandle = JNIHandles::resolve(compResult); - nmethod* nm = NULL; - methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult)); - Handle installed_code_handle = JNIHandles::resolve(installed_code); - GraalEnv::CodeInstallResult result; - CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle); - - if (result != GraalEnv::ok) { - assert(nm == NULL, "should be"); - } else { - if (info != NULL) { - arrayOop codeCopy = oopFactory::new_byteArray(nm->code_size(), CHECK_0); - memcpy(codeCopy->base(T_BYTE), nm->code_begin(), nm->code_size()); - HotSpotCodeInfo::set_code(info, codeCopy); - HotSpotCodeInfo::set_start(info, (jlong) nm->code_begin()); - } - - if (!installed_code_handle.is_null()) { - assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type"); - HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm); - HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult)); - assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable"); - } - } - return result; -C2V_END - -C2V_VMENTRY(jobject, disassembleNative, (JNIEnv *jniEnv, jobject, jbyteArray code, jlong start_address)) - ResourceMark rm; - HandleMark hm; - - stringStream(st); - arrayOop code_oop = (arrayOop) JNIHandles::resolve(code); - int len = code_oop->length(); - address begin = (address) code_oop->base(T_BYTE); - address end = begin + len; - Disassembler::decode(begin, end, &st); - - Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(result()); -C2V_END - -C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv *env, jobject, jlong metaspace_method, int bci)) - ResourceMark rm; - HandleMark hm; - - methodHandle method = asMethod(metaspace_method); - oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); - return JNIHandles::make_local(element); -C2V_END - -C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject args)) - ResourceMark rm; - HandleMark hm; - - assert(metaspace_method != 0, "just checking"); - methodHandle mh = asMethod(metaspace_method); - Symbol* signature = mh->signature(); - JavaCallArguments jca; - - JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); - JavaValue result(jap.get_ret_type()); - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - THROW_0(vmSymbols::MethodInvalidatedException()); - } - - JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL); - - if (jap.get_ret_type() == T_VOID) { - return NULL; - } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { - return JNIHandles::make_local((oop) result.get_jobject()); - } else { - oop o = java_lang_boxing_object::create(jap.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL); - return JNIHandles::make_local(o); - } -C2V_END - -C2V_VMENTRY(jobject, executeCompiledMethod, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject arg1, jobject arg2, jobject arg3)) - ResourceMark rm; - HandleMark hm; - - methodHandle method = asMethod(metaspace_method); - assert(!method.is_null(), "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(JNIHandles::resolve(arg1)); - args.push_oop(JNIHandles::resolve(arg2)); - args.push_oop(JNIHandles::resolve(arg3)); - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - THROW_0(vmSymbols::MethodInvalidatedException()); - } - - JavaCalls::call(&result, method, nm, &args, CHECK_NULL); - - return JNIHandles::make_local((oop) result.get_jobject()); -C2V_END - -C2V_VMENTRY(jint, getVtableEntryOffset, (JNIEnv *, jobject, jlong metaspace_method)) - - Method* method = asMethod(metaspace_method); - assert(!InstanceKlass::cast(method->method_holder())->is_interface(), "vtableEntryOffset cannot be called for interface methods"); - assert(InstanceKlass::cast(method->method_holder())->is_linked(), "vtableEntryOffset cannot be called is holder is not linked"); - - // get entry offset in words - int vtable_entry_offset = InstanceKlass::vtable_start_offset() + method->vtable_index() * vtableEntry::size(); - // convert to bytes - vtable_entry_offset = vtable_entry_offset * wordSize + vtableEntry::method_offset_in_bytes(); - - return vtable_entry_offset; -C2V_END - -C2V_VMENTRY(jobject, getDeoptedLeafGraphIds, (JNIEnv *, jobject)) - - // the contract for this method is as follows: - // returning null: no deopted leaf graphs - // returning array (size > 0): the ids of the deopted leaf graphs - // returning array (size == 0): there was an overflow, the compiler needs to clear its cache completely - - oop array = GraalCompiler::instance()->dump_deopted_leaf_graphs(CHECK_NULL); - return JNIHandles::make_local(array); -C2V_END - -C2V_VMENTRY(jobject, decodePC, (JNIEnv *, jobject, jlong pc)) - stringStream(st); - CodeBlob* blob = CodeCache::find_blob_unsafe((void*) pc); - if (blob == NULL) { - st.print("[unidentified pc]"); - } else { - st.print(blob->name()); - - nmethod* nm = blob->as_nmethod_or_null(); - if (nm != NULL && nm->method() != NULL) { - st.print(" %s.", nm->method()->method_holder()->external_name()); - nm->method()->name()->print_symbol_on(&st); - st.print(" @ %d", pc - (jlong) nm->entry_point()); - } - } - Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(result()); -C2V_END - - -#define CC (char*) /*cast a literal from (const char*)*/ -#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) - -#define RESOLVED_TYPE "Lcom/oracle/graal/api/meta/ResolvedJavaType;" -#define TYPE "Lcom/oracle/graal/api/meta/JavaType;" -#define METHOD "Lcom/oracle/graal/api/meta/JavaMethod;" -#define FIELD "Lcom/oracle/graal/api/meta/JavaField;" -#define SIGNATURE "Lcom/oracle/graal/api/meta/Signature;" -#define CONSTANT_POOL "Lcom/oracle/graal/api/meta/ConstantPool;" -#define CONSTANT "Lcom/oracle/graal/api/meta/Constant;" -#define KIND "Lcom/oracle/graal/api/meta/Kind;" -#define RUNTIME_CALL "Lcom/oracle/graal/api/code/RuntimeCall;" -#define EXCEPTION_HANDLERS "[Lcom/oracle/graal/api/meta/ExceptionHandler;" -#define REFLECT_METHOD "Ljava/lang/reflect/Method;" -#define REFLECT_CONSTRUCTOR "Ljava/lang/reflect/Constructor;" -#define REFLECT_FIELD "Ljava/lang/reflect/Field;" -#define STRING "Ljava/lang/String;" -#define OBJECT "Ljava/lang/Object;" -#define CLASS "Ljava/lang/Class;" -#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" -#define HS_RESOLVED_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;" -#define HS_RESOLVED_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;" -#define HS_RESOLVED_FIELD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;" -#define HS_COMP_RESULT "Lcom/oracle/graal/hotspot/HotSpotCompilationResult;" -#define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" -#define HS_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;" -#define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" -#define HS_CODE_INFO "Lcom/oracle/graal/hotspot/meta/HotSpotCodeInfo;" -#define METHOD_DATA "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;" -#define METASPACE_METHOD "J" -#define METASPACE_METHOD_DATA "J" -#define NMETHOD "J" - -JNINativeMethod CompilerToVM_methods[] = { - {CC"initializeBytecode", CC"("METASPACE_METHOD"[B)[B", FN_PTR(initializeBytecode)}, - {CC"getSignature", CC"("METASPACE_METHOD")"STRING, FN_PTR(getSignature)}, - {CC"initializeExceptionHandlers", CC"("METASPACE_METHOD EXCEPTION_HANDLERS")"EXCEPTION_HANDLERS, FN_PTR(initializeExceptionHandlers)}, - {CC"hasBalancedMonitors", CC"("METASPACE_METHOD")Z", FN_PTR(hasBalancedMonitors)}, - {CC"getUniqueConcreteMethod", CC"("METASPACE_METHOD"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getUniqueConcreteMethod)}, - {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, - {CC"initializeMethod", CC"("METASPACE_METHOD HS_RESOLVED_METHOD")V", FN_PTR(initializeMethod)}, - {CC"initializeMethodData", CC"("METASPACE_METHOD_DATA METHOD_DATA")V", FN_PTR(initializeMethodData)}, - {CC"isMethodCompilable", CC"("METASPACE_METHOD")Z", FN_PTR(isMethodCompilable)}, - {CC"getInvocationCount", CC"("METASPACE_METHOD")I", FN_PTR(getInvocationCount)}, - {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, - {CC"getVtableEntryOffset", CC"("METASPACE_METHOD")I", FN_PTR(getVtableEntryOffset)}, - {CC"lookupType", CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE, FN_PTR(lookupType)}, - {CC"lookupConstantInPool", CC"("HS_RESOLVED_TYPE"I)"OBJECT, FN_PTR(lookupConstantInPool)}, - {CC"lookupMethodInPool", CC"("HS_RESOLVED_TYPE"IB)"METHOD, FN_PTR(lookupMethodInPool)}, - {CC"lookupTypeInPool", CC"("HS_RESOLVED_TYPE"I)"TYPE, FN_PTR(lookupTypeInPool)}, - {CC"lookupReferencedTypeInPool", CC"("HS_RESOLVED_TYPE"IB)V", FN_PTR(lookupReferencedTypeInPool)}, - {CC"lookupFieldInPool", CC"("HS_RESOLVED_TYPE"IB)"FIELD, FN_PTR(lookupFieldInPool)}, - {CC"resolveMethod", CC"("HS_RESOLVED_TYPE STRING STRING")"METHOD, FN_PTR(resolveMethod)}, - {CC"getPrototypeMarkWord", CC"("HS_RESOLVED_TYPE")J", FN_PTR(getPrototypeMarkWord)}, - {CC"getInstanceFields", CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD, FN_PTR(getInstanceFields)}, - {CC"isTypeInitialized", CC"("HS_RESOLVED_TYPE")Z", FN_PTR(isTypeInitialized)}, - {CC"initializeType", CC"("HS_RESOLVED_TYPE")V", FN_PTR(initializeType)}, - {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, - {CC"getResolvedType", CC"("CLASS")"RESOLVED_TYPE, FN_PTR(getResolvedType)}, - {CC"getMetaspaceMethod", CC"("REFLECT_METHOD"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getMetaspaceMethod)}, - {CC"getMetaspaceConstructor", CC"("REFLECT_CONSTRUCTOR"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getMetaspaceConstructor)}, - {CC"getJavaField", CC"("REFLECT_FIELD")"HS_RESOLVED_FIELD, FN_PTR(getJavaField)}, - {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)}, - {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE HS_CODE_INFO")I", FN_PTR(installCode0)}, - {CC"disassembleNative", CC"([BJ)"STRING, FN_PTR(disassembleNative)}, - {CC"executeCompiledMethod", CC"("METASPACE_METHOD NMETHOD OBJECT OBJECT OBJECT")"OBJECT, FN_PTR(executeCompiledMethod)}, - {CC"executeCompiledMethodVarargs", CC"("METASPACE_METHOD NMETHOD "["OBJECT")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, - {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, - {CC"decodePC", CC"(J)"STRING, FN_PTR(decodePC)}, -}; - -int CompilerToVM_methods_count() { - return sizeof(CompilerToVM_methods) / sizeof(JNINativeMethod); -} - +/* + * 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. + */ + +#include "precompiled.hpp" +#include "runtime/fieldDescriptor.hpp" +#include "memory/oopFactory.hpp" +#include "oops/generateOopMap.hpp" +#include "oops/fieldStreams.hpp" +#include "runtime/javaCalls.hpp" +#include "graal/graalRuntime.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compilerOracle.hpp" +#include "graal/graalCompilerToVM.hpp" +#include "graal/graalCompiler.hpp" +#include "graal/graalEnv.hpp" +#include "graal/graalJavaAccess.hpp" +#include "graal/graalCodeInstaller.hpp" +#include "graal/graalVMToCompiler.hpp" +#include "graal/graalVmIds.hpp" + + +Method* getMethodFromHotSpotMethod(oop hotspot_method) { + assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethod::klass()), "sanity"); + return asMethod(HotSpotResolvedJavaMethod::metaspaceMethod(hotspot_method)); +} + +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_graal_3("CompilerToVM::" #name); \ + GRAAL_VM_ENTRY_MARK; \ + +// Entry to native method implementation that calls a JNI function +// and hence cannot transition current thread to '_thread_in_vm'. +#define C2V_ENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_graal_3("CompilerToVM::" #name); \ + +#define C2V_END } + +C2V_ENTRY(jbyteArray, initializeBytecode, (JNIEnv *env, jobject, jlong metaspace_method, jbyteArray result)) + methodHandle method = asMethod(metaspace_method); + ResourceMark rm; + + int code_size = method->code_size(); + jbyte* reconstituted_code = NULL; + + // replace all breakpoints - must be done before undoing any rewriting + if (method->number_of_breakpoints() > 0) { + reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size); + memcpy(reconstituted_code, (jbyte *) method->code_base(), code_size); + BreakpointInfo* bp = InstanceKlass::cast(method->method_holder())->breakpoints(); + for (; bp != NULL; bp = bp->next()) { + if (bp->match(method())) { + jbyte code = bp->orig_bytecode(); + reconstituted_code[bp->bci()] = code; + } + } + } + + // iterate over all bytecodes and replace non-Java bytecodes + if (RewriteBytecodes || RewriteFrequentPairs || InstanceKlass::cast(method->method_holder())->is_rewritten()) { + if (reconstituted_code == NULL) { + reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size); + memcpy(reconstituted_code, (jbyte *) method->code_base(), code_size); + } + BytecodeStream s(method); + while(!s.is_last_bytecode()) { + s.next(); + Bytecodes::Code opcode = s.raw_code(); + if (!Bytecodes::is_java_code(opcode)) { + jbyte original_opcode = Bytecodes::java_code(opcode); + int bci = s.bci(); + reconstituted_code[bci] = original_opcode; + if (opcode == Bytecodes::_fast_aldc_w) { + int cpci = Bytes::get_native_u2((address) reconstituted_code + bci + 1); + int i = method->constants()->object_to_cp_index(cpci); + assert(i < method->constants()->length(), "sanity check"); + Bytes::put_Java_u2((address) reconstituted_code + bci + 1, (u2)i); + } else if (opcode == Bytecodes::_fast_aldc) { + int cpci = reconstituted_code[bci + 1] & 0xff; + int i = method->constants()->object_to_cp_index(cpci); + assert(i < method->constants()->length(), "sanity check"); + reconstituted_code[bci + 1] = (jbyte)i; + } + } + } + } + + if (reconstituted_code == NULL) { + env->SetByteArrayRegion(result, 0, code_size, (jbyte *) method->code_base()); + } else { + env->SetByteArrayRegion(result, 0, code_size, reconstituted_code); + } + + return result; +C2V_END + +C2V_VMENTRY(jstring, getSignature, (JNIEnv *env, jobject, jlong metaspace_method)) + Method* method = asMethod(metaspace_method); + assert(method != NULL && method->signature() != NULL, "signature required"); + return VmIds::toString(method->signature(), THREAD); +C2V_END + +C2V_VMENTRY(jobjectArray, initializeExceptionHandlers, (JNIEnv *, jobject, jlong metaspace_method, jobjectArray java_handlers)) + ResourceMark rm; + methodHandle method = asMethod(metaspace_method); + int handler_count = method->exception_table_length(); + objArrayHandle array = (objArrayOop) JNIHandles::resolve(java_handlers); + assert(array->length() == handler_count, "wrong length"); + ExceptionTableElement* handlers = handler_count == 0 ? NULL : method->exception_table_start(); + + for (int i = 0; i < handler_count; i++) { + ExceptionTableElement* handler = handlers + i; + Handle entry = array->obj_at(i); + assert(!entry.is_null(), "entry should not be null"); + ExceptionHandler::set_startBCI(entry, handler->start_pc); + ExceptionHandler::set_endBCI(entry, handler->end_pc); + ExceptionHandler::set_handlerBCI(entry, handler->handler_pc); + int catch_class_index = handler->catch_type_index; + ExceptionHandler::set_catchTypeCPI(entry, catch_class_index); + + if (catch_class_index == 0) { + ExceptionHandler::set_catchType(entry, NULL); + } else { + ConstantPool* cp = InstanceKlass::cast(method->method_holder())->constants(); + KlassHandle loading_klass = method->method_holder(); + Handle catch_class = GraalCompiler::get_JavaType(cp, catch_class_index, loading_klass, CHECK_NULL); + if (catch_class->klass() == HotSpotResolvedObjectType::klass() && java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(catch_class)) == SystemDictionary::Throwable_klass()) { + ExceptionHandler::set_catchType(entry, NULL); + ExceptionHandler::set_catchTypeCPI(entry, 0); + } else { + ExceptionHandler::set_catchType(entry, catch_class()); + } + } + array->obj_at_put(i, entry()); + } + + return (jobjectArray) JNIHandles::make_local(array()); +C2V_END + +C2V_VMENTRY(jint, hasBalancedMonitors, (JNIEnv *, jobject, jlong metaspace_method)) + + // Analyze the method to see if monitors are used properly. + methodHandle method(THREAD, asMethod(metaspace_method)); + assert(method->has_monitor_bytecodes(), "should have checked this"); + + // Check to see if a previous compilation computed the monitor-matching analysis. + if (method->guaranteed_monitor_matching()) { + return true; + } + + { + EXCEPTION_MARK; + ResourceMark rm(THREAD); + GeneratePairingInfo gpi(method); + gpi.compute_map(CATCH); + if (!gpi.monitor_safe()) { + return false; + } + method->set_guaranteed_monitor_matching(); + } + return true; +C2V_END + +C2V_VMENTRY(jlong, getMetaspaceMethod, (JNIEnv *, jobject, jobject reflection_method_handle, jobject resultHolder)) + oop reflection_method = JNIHandles::resolve(reflection_method_handle); + oop reflection_holder = java_lang_reflect_Method::clazz(reflection_method); + int slot = java_lang_reflect_Method::slot(reflection_method); + Klass* holder = java_lang_Class::as_Klass(reflection_holder); + methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); + Handle type = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK_0); + objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); + return (jlong) (address) method(); +} + +C2V_VMENTRY(jlong, getMetaspaceConstructor, (JNIEnv *, jobject, jobject reflection_ctor_handle, jobject resultHolder)) + oop reflection_ctor = JNIHandles::resolve(reflection_ctor_handle); + oop reflection_holder = java_lang_reflect_Constructor::clazz(reflection_ctor); + int slot = java_lang_reflect_Constructor::slot(reflection_ctor); + Klass* holder = java_lang_Class::as_Klass(reflection_holder); + methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); + Handle type = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK_0); + objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); + return (jlong) (address) method(); +} + +C2V_VMENTRY(jobject, getJavaField, (JNIEnv *, jobject, jobject reflection_field_handle)) + oop reflection_field = JNIHandles::resolve(reflection_field_handle); + oop reflection_holder = java_lang_reflect_Field::clazz(reflection_field); + int slot = java_lang_reflect_Field::slot(reflection_field); + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(reflection_holder)); + + int offset = holder->field_offset(slot); + int flags = holder->field_access_flags(slot); + Symbol* field_name = holder->field_name(slot); + Handle field_holder = GraalCompiler::get_JavaTypeFromClass(reflection_holder, CHECK_NULL); + Handle field_type = GraalCompiler::get_JavaTypeFromClass(java_lang_reflect_Field::type(reflection_field), CHECK_NULL); + + Handle ret = GraalCompiler::get_JavaField(offset, flags, field_name, field_holder, field_type, CHECK_NULL); + return JNIHandles::make_local(THREAD, ret()); +} + +C2V_VMENTRY(jlong, getUniqueConcreteMethod, (JNIEnv *, jobject, jlong metaspace_method, jobject resultHolder)) + methodHandle method = asMethod(metaspace_method); + KlassHandle holder = method->method_holder(); + if (holder->is_interface()) { + // Cannot trust interfaces. Because of: + // interface I { void foo(); } + // class A { public void foo() {} } + // class B extends A implements I { } + // class C extends B { public void foo() { } } + // class D extends B { } + // Would lead to identify C.foo() as the unique concrete method for I.foo() without seeing A.foo(). + return 0L; + } + methodHandle ucm; + { + ResourceMark rm; + MutexLocker locker(Compile_lock); + ucm = Dependencies::find_unique_concrete_method(holder(), method()); + } + + if (ucm.is_null()) { + return 0L; + } + + Handle type = GraalCompiler::createHotSpotResolvedObjectType(ucm(), CHECK_0); + objArrayOop(JNIHandles::resolve(resultHolder))->obj_at_put(0, type()); + return (jlong) (address) ucm(); +C2V_END + +C2V_ENTRY(jint, getInvocationCount, (JNIEnv *, jobject, jlong metaspace_method)) + Method* method = asMethod(metaspace_method); + return method->invocation_count(); +C2V_END + +C2V_VMENTRY(void, initializeMethod,(JNIEnv *, jobject, jlong metaspace_method, jobject hotspot_method)) + methodHandle method = asMethod(metaspace_method); + Handle name = VmIds::toString(method->name(), CHECK); + InstanceKlass::cast(HotSpotResolvedJavaMethod::klass())->initialize(CHECK); + HotSpotResolvedJavaMethod::set_name(hotspot_method, name()); + HotSpotResolvedJavaMethod::set_codeSize(hotspot_method, method->code_size()); + HotSpotResolvedJavaMethod::set_exceptionHandlerCount(hotspot_method, method->exception_table_length()); +C2V_END + +C2V_VMENTRY(jboolean, isMethodCompilable,(JNIEnv *, jobject, jlong metaspace_method)) + methodHandle method = asMethod(metaspace_method); + return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method); +C2V_END + +C2V_VMENTRY(void, initializeMethodData,(JNIEnv *, jobject, jlong metaspace_method_data, jobject hotspot_method_data)) + MethodData* method_data = asMethodData(metaspace_method_data); + HotSpotMethodData::set_normalDataSize(hotspot_method_data, method_data->data_size()); + HotSpotMethodData::set_extraDataSize(hotspot_method_data, method_data->extra_data_size()); +C2V_END + +// ------------------------------------------------------------------ +// Adjust a CounterData count to be commensurate with +// interpreter_invocation_count. If the MDO exists for +// only 25% of the time the method exists, then the +// counts in the MDO should be scaled by 4X, so that +// they can be usefully and stably compared against the +// invocation counts in methods. +int scale_count(MethodData* method_data, int count) { + if (count > 0) { + int counter_life; + int method_life = method_data->method()->interpreter_invocation_count(); + int current_mileage = MethodData::mileage_of(method_data->method()); + int creation_mileage = method_data->creation_mileage(); + counter_life = current_mileage - creation_mileage; + + // counter_life due to backedge_counter could be > method_life + if (counter_life > method_life) + counter_life = method_life; + if (0 < counter_life && counter_life <= method_life) { + count = (int)((double)count * method_life / counter_life + 0.5); + count = (count > 0) ? count : 1; + } + } + return count; +} + +C2V_ENTRY(jint, getCompiledCodeSize, (JNIEnv *env, jobject, jlong metaspace_method)) + nmethod* code = (asMethod(metaspace_method))->code(); + return code == NULL ? 0 : code->insts_size(); +C2V_END + +C2V_VMENTRY(jobject, lookupType, (JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve)) + ResourceMark rm; + + Symbol* nameSymbol = VmIds::toSymbol(jname); + Handle name = JNIHandles::resolve(jname); + assert(nameSymbol != NULL, "name to symbol creation failed"); + + oop result = NULL; + if (nameSymbol == vmSymbols::int_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_INT, THREAD); + } else if (nameSymbol == vmSymbols::long_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_LONG, THREAD); + } else if (nameSymbol == vmSymbols::bool_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_BOOLEAN, THREAD); + } else if (nameSymbol == vmSymbols::char_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_CHAR, THREAD); + } else if (nameSymbol == vmSymbols::short_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_SHORT, THREAD); + } else if (nameSymbol == vmSymbols::byte_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_BYTE, THREAD); + } else if (nameSymbol == vmSymbols::double_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_DOUBLE, THREAD); + } else if (nameSymbol == vmSymbols::float_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_FLOAT, THREAD); + } else if (nameSymbol == vmSymbols::void_signature()) { + result = VMToCompiler::createPrimitiveJavaType((int) T_VOID, THREAD); + } else { + Klass* resolved_type = NULL; + Handle classloader; + Handle protectionDomain; + if (JNIHandles::resolve(accessingClass) != NULL) { + classloader = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(accessingClass))->class_loader(); + protectionDomain = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(accessingClass))->protection_domain(); + } + + if (eagerResolve) { + resolved_type = SystemDictionary::resolve_or_fail(nameSymbol, classloader, protectionDomain, true, THREAD); + } else { + resolved_type = SystemDictionary::resolve_or_null(nameSymbol, classloader, protectionDomain, THREAD); + } + + if (!HAS_PENDING_EXCEPTION) { + if (resolved_type == NULL) { + assert(!eagerResolve, "failed eager resolution should have caused an exception"); + Handle type = VMToCompiler::createUnresolvedJavaType(name, THREAD); + result = type(); + } else { + Handle type = GraalCompiler::createHotSpotResolvedObjectType(resolved_type, name, CHECK_NULL); + result = type(); + } + } + } + + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, lookupConstantInPool, (JNIEnv *env, jobject, jobject type, jint index)) + + ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + + oop result = NULL; + constantTag tag = cp->tag_at(index); + if (tag.is_int()) { + result = VMToCompiler::createConstant(Kind::Int(), cp->int_at(index), CHECK_0); + } else if (tag.is_long()) { + result = VMToCompiler::createConstant(Kind::Long(), cp->long_at(index), CHECK_0); + } else if (tag.is_float()) { + result = VMToCompiler::createConstantFloat(cp->float_at(index), CHECK_0); + } else if (tag.is_double()) { + result = VMToCompiler::createConstantDouble(cp->double_at(index), CHECK_0); + } else if (tag.is_string()) { + oop string = NULL; + if (cp->is_pseudo_string_at(index)) { + int obj_index = cp->cp_to_object_index(index); + string = cp->pseudo_string_at(index, obj_index); + } else { + string = cp->string_at(index, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + // TODO: Gracefully exit compilation. + fatal("out of memory during compilation!"); + return NULL; + } + } + result = VMToCompiler::createConstantObject(string, CHECK_0); + } else if (tag.is_klass() || tag.is_unresolved_klass()) { + Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); + result = type(); + } else if (tag.is_object()) { + oop obj = cp->object_at(index); + assert(obj->is_instance(), "must be an instance"); + result = VMToCompiler::createConstantObject(obj, CHECK_NULL); + } else { + tty->print("unknown constant pool tag (%s) at cpi %d in %s: ", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string()); + ShouldNotReachHere(); + } + + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte opcode)) + index = GraalCompiler::to_cp_index_u2(index); + constantPoolHandle cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + instanceKlassHandle pool_holder(cp->pool_holder()); + + Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + methodHandle method = GraalEnv::get_method_by_index(cp, index, bc, pool_holder); + if (!method.is_null()) { + Handle holder = GraalCompiler::get_JavaType(method->method_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); + } else { + // Get the method's name and signature. + Handle name = VmIds::toString(cp->name_ref_at(index), CHECK_NULL); + Handle signature = VmIds::toString(cp->signature_ref_at(index), CHECK_NULL); + int holder_index = cp->klass_ref_index_at(index); + Handle type = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, VMToCompiler::createUnresolvedJavaMethod(name, signature, type, THREAD)); + } +C2V_END + +C2V_VMENTRY(jobject, lookupTypeInPool, (JNIEnv *env, jobject, jobject type, jint index)) + + ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + Handle result = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(void, lookupReferencedTypeInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte op)) + ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + int opcode = (op & 0xFF); + if (opcode != Bytecodes::_checkcast && opcode != Bytecodes::_instanceof && opcode != Bytecodes::_new && opcode != Bytecodes::_anewarray + && opcode != Bytecodes::_multianewarray && opcode != Bytecodes::_ldc && opcode != Bytecodes::_ldc_w && opcode != Bytecodes::_ldc2_w) + { + index = cp->remap_instruction_operand_from_cache(GraalCompiler::to_cp_index_u2(index)); + } + constantTag tag = cp->tag_at(index); + if (tag.is_field_or_method()) { + index = cp->uncached_klass_ref_index_at(index); + tag = cp->tag_at(index); + } + + if (tag.is_unresolved_klass() || tag.is_klass()) { + Klass* klass = cp->klass_at(index, CHECK); + if (klass->oop_is_instance()) { + InstanceKlass::cast(klass)->initialize(CHECK); + } + } +C2V_END + +C2V_VMENTRY(jobject, lookupFieldInPool, (JNIEnv *env, jobject, jobject constantPoolHolder, jint index, jbyte opcode)) + ResourceMark rm; + + index = GraalCompiler::to_cp_index_u2(index); + constantPoolHandle cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(constantPoolHolder)))->constants(); + + int nt_index = cp->name_and_type_ref_index_at(index); + int sig_index = cp->signature_ref_index_at(nt_index); + Symbol* signature = cp->symbol_at(sig_index); + int name_index = cp->name_ref_index_at(nt_index); + Symbol* name = cp->symbol_at(name_index); + int holder_index = cp->klass_ref_index_at(index); + Handle holder = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); + instanceKlassHandle holder_klass; + + Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); + int offset = -1; + AccessFlags flags; + BasicType basic_type; + if (holder->klass() == SystemDictionary::HotSpotResolvedObjectType_klass()) { + FieldAccessInfo result; + LinkResolver::resolve_field(result, cp, index, + Bytecodes::java_code(code), + true, false, Thread::current()); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } else { + offset = result.field_offset(); + flags = result.access_flags(); + holder_klass = result.klass()(); + basic_type = result.field_type(); + holder = GraalCompiler::get_JavaType(holder_klass, CHECK_NULL); + } + } + + Handle type = GraalCompiler::get_JavaTypeFromSignature(signature, cp->pool_holder(), CHECK_NULL); + Handle field_handle = GraalCompiler::get_JavaField(offset, flags.as_int(), name, holder, type, THREAD); + + return JNIHandles::make_local(THREAD, field_handle()); +C2V_END + +C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject resolved_type, jstring name, jstring signature)) + + assert(JNIHandles::resolve(resolved_type) != NULL, ""); + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(resolved_type)); + Symbol* name_symbol = VmIds::toSymbol(name); + Symbol* signature_symbol = VmIds::toSymbol(signature); + methodHandle method = klass->lookup_method(name_symbol, signature_symbol); + if (method.is_null()) { + if (TraceGraal >= 3) { + ResourceMark rm; + tty->print_cr("Could not resolve method %s %s on klass %s", name_symbol->as_C_string(), signature_symbol->as_C_string(), klass->name()->as_C_string()); + } + return NULL; + } + Handle holder = GraalCompiler::get_JavaType(method->method_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); +C2V_END + +C2V_VMENTRY(jboolean, isTypeInitialized,(JNIEnv *, jobject, jobject hotspot_klass)) + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(hotspot_klass)); + assert(klass != NULL, "method must not be called for primitive types"); + return InstanceKlass::cast(klass)->is_initialized(); +C2V_END + +C2V_VMENTRY(void, initializeType, (JNIEnv *, jobject, jobject hotspot_klass)) + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(hotspot_klass)); + assert(klass != NULL, "method must not be called for primitive types"); + InstanceKlass::cast(klass)->initialize(JavaThread::current()); +C2V_END + +C2V_VMENTRY(jobject, getInstanceFields, (JNIEnv *, jobject, jobject klass)) + ResourceMark rm; + + instanceKlassHandle k = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(klass)); + GrowableArray fields(k->java_fields_count()); + + for (AllFieldStream fs(k()); !fs.done(); fs.next()) { + if (!fs.access_flags().is_static()) { + Handle type = GraalCompiler::get_JavaTypeFromSignature(fs.signature(), k, Thread::current()); + int flags = fs.access_flags().as_int(); + bool internal = fs.access_flags().is_internal(); + Handle name = VmIds::toString(fs.name(), Thread::current()); + Handle field = VMToCompiler::createJavaField(JNIHandles::resolve(klass), name, type, fs.offset(), flags, internal, Thread::current()); + fields.append(field()); + } + } + objArrayHandle field_array = oopFactory::new_objArray(SystemDictionary::HotSpotResolvedJavaField_klass(), fields.length(), CHECK_NULL); + for (int i = 0; i < fields.length(); ++i) { + field_array->obj_at_put(i, fields.at(i)()); + } + return JNIHandles::make_local(field_array()); +C2V_END + +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong stub)) + address target_addr = (address) stub; + if (target_addr != 0x0) { + int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); + int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); + return MAX2(ABS(off_low), ABS(off_high)); + } + return -1; +C2V_END + +C2V_VMENTRY(jobject, getResolvedType, (JNIEnv *env, jobject, jobject javaClass)) + oop java_mirror = JNIHandles::resolve(javaClass); + assert(java_mirror != NULL, "argument to CompilerToVM.getResolvedType must not be NULL"); + Handle type = GraalCompiler::get_JavaTypeFromClass(java_mirror, CHECK_NULL); + return JNIHandles::make_local(THREAD, type()); +C2V_END + + +// helpers used to set fields in the HotSpotVMConfig object +jfieldID getFieldID(JNIEnv* env, jobject obj, const char* name, const char* sig) { + jfieldID id = env->GetFieldID(env->GetObjectClass(obj), name, sig); + if (id == NULL) { + fatal(err_msg("field not found: %s (%s)", name, sig)); + } + return id; +} + +BasicType basicTypes[] = { T_BOOLEAN, T_BYTE, T_SHORT, T_CHAR, T_INT, T_FLOAT, T_LONG, T_DOUBLE, T_OBJECT }; +int basicTypeCount = sizeof(basicTypes) / sizeof(BasicType); + +C2V_ENTRY(void, initializeConfiguration, (JNIEnv *env, jobject, jobject config)) + +#define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0) +#define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0) +#define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0) +#define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0) +#define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0) + + guarantee(HeapWordSize == sizeof(char*), "Graal assumption that HeadWordSize == machine word size is wrong"); +#ifdef _WIN64 + set_boolean(env, config, "windowsOs", true); +#else + set_boolean("windowsOs", false); +#endif + set_boolean("verifyOops", VerifyOops); + set_boolean("useFastLocking", UseFastLocking); + set_boolean("useFastNewObjectArray", UseFastNewObjectArray); + set_boolean("useBiasedLocking", UseBiasedLocking); + set_boolean("useFastNewTypeArray", UseFastNewTypeArray); + set_boolean("useTLAB", UseTLAB); + set_int("codeEntryAlignment", CodeEntryAlignment); + set_int("vmPageSize", os::vm_page_size()); + set_int("stackShadowPages", StackShadowPages); + set_int("hubOffset", oopDesc::klass_offset_in_bytes()); + set_int("markOffset", oopDesc::mark_offset_in_bytes()); + set_int("prototypeMarkWordOffset", in_bytes(Klass::prototype_header_offset())); + set_int("superCheckOffsetOffset", in_bytes(Klass::super_check_offset_offset())); + set_int("secondarySuperCacheOffset", in_bytes(Klass::secondary_super_cache_offset())); + set_int("secondarySupersOffset", in_bytes(Klass::secondary_supers_offset())); + set_int("subklassOffset", in_bytes(Klass::subklass_offset())); + set_int("nextSiblingOffset", in_bytes(Klass::next_sibling_offset())); + set_int("arrayLengthOffset", arrayOopDesc::length_offset_in_bytes()); + set_int("klassStateOffset", in_bytes(InstanceKlass::init_state_offset())); + set_int("klassStateFullyInitialized", (int)InstanceKlass::fully_initialized); + set_int("threadTlabTopOffset", in_bytes(JavaThread::tlab_top_offset())); + set_int("threadTlabEndOffset", in_bytes(JavaThread::tlab_end_offset())); + set_int("threadObjectOffset", in_bytes(JavaThread::threadObj_offset())); + set_int("osThreadOffset", in_bytes(JavaThread::osthread_offset())); + set_int("osThreadInterruptedOffset", in_bytes(OSThread::interrupted_offset())); + set_int("unlockedMask", (int) markOopDesc::unlocked_value); + set_int("biasedLockMaskInPlace", (int) markOopDesc::biased_lock_mask_in_place); + set_int("ageMaskInPlace", (int) markOopDesc::age_mask_in_place); + set_int("epochMaskInPlace", (int) markOopDesc::epoch_mask_in_place); + set_int("biasedLockPattern", (int) markOopDesc::biased_lock_pattern); + set_int("methodMaxLocalsOffset", in_bytes(Method::size_of_locals_offset())); + set_int("methodMaxStackOffset", in_bytes(Method::max_stack_offset())); + set_int("extraStackEntries", Method::extra_stack_entries()); + set_int("methodAccessFlagsOffset", in_bytes(Method::access_flags_offset())); + set_int("klassHasFinalizerFlag", JVM_ACC_HAS_FINALIZER); + set_int("threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset())); + set_int("threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); + set_long("safepointPollingAddress", (jlong)(os::get_polling_page() + (SafepointPollOffset % os::vm_page_size()))); + set_boolean("isPollingPageFar", Assembler::is_polling_page_far()); + set_int("classMirrorOffset", in_bytes(Klass::java_mirror_offset())); + set_int("runtimeCallStackSize", (jint)frame::arg_reg_save_area_bytes); + set_int("klassModifierFlagsOffset", in_bytes(Klass::modifier_flags_offset())); + set_int("klassAccessFlagsOffset", in_bytes(Klass::access_flags_offset())); + set_int("klassOffset", java_lang_Class::klass_offset_in_bytes()); + set_int("graalMirrorInClassOffset", java_lang_Class::graal_mirror_offset_in_bytes()); + set_int("klassLayoutHelperOffset", in_bytes(Klass::layout_helper_offset())); + set_int("klassSuperKlassOffset", in_bytes(Klass::super_offset())); + set_int("methodDataOffset", in_bytes(Method::method_data_offset())); + set_int("nmethodEntryOffset", nmethod::verified_entry_point_offset()); + set_int("methodCompiledEntryOffset", in_bytes(Method::from_compiled_offset())); + set_int("basicLockSize", sizeof(BasicLock)); + set_int("basicLockDisplacedHeaderOffset", BasicLock::displaced_header_offset_in_bytes()); + set_int("uninitializedIdentityHashCodeValue", markOopDesc::no_hash); + set_int("identityHashCodeShift", markOopDesc::hash_shift); + + set_int("arrayKlassLayoutHelperIdentifier", 0x80000000); + assert((Klass::_lh_array_tag_obj_value & Klass::_lh_array_tag_type_value & 0x80000000) != 0, "obj_array and type_array must have first bit set"); + set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset())); + + set_int("metaspaceArrayLengthOffset", Array::length_offset_in_bytes()); + set_int("metaspaceArrayBaseOffset", Array::base_offset_in_bytes()); + set_int("methodDataOopDataOffset", in_bytes(MethodData::data_offset())); + set_int("methodDataOopTrapHistoryOffset", in_bytes(MethodData::trap_history_offset())); + set_int("dataLayoutHeaderSize", DataLayout::header_size_in_bytes()); + set_int("dataLayoutTagOffset", in_bytes(DataLayout::tag_offset())); + set_int("dataLayoutFlagsOffset", in_bytes(DataLayout::flags_offset())); + set_int("dataLayoutBCIOffset", in_bytes(DataLayout::bci_offset())); + set_int("dataLayoutCellsOffset", in_bytes(DataLayout::cell_offset(0))); + set_int("dataLayoutCellSize", DataLayout::cell_size); + set_int("bciProfileWidth", BciProfileWidth); + set_int("typeProfileWidth", TypeProfileWidth); + + set_int("tlabAlignmentReserve", (int32_t)ThreadLocalAllocBuffer::alignment_reserve()); + set_long("tlabIntArrayMarkWord", (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2)); + set_long("heapTopAddress", (jlong)(address) Universe::heap()->top_addr()); + set_long("heapEndAddress", (jlong)(address) Universe::heap()->end_addr()); + set_int("threadTlabStartOffset", in_bytes(JavaThread::tlab_start_offset())); + set_int("threadTlabSizeOffset", in_bytes(JavaThread::tlab_size_offset())); + set_int("threadAllocatedBytesOffset", in_bytes(JavaThread::allocated_bytes_offset())); + set_int("tlabSlowAllocationsOffset", in_bytes(JavaThread::tlab_slow_allocations_offset())); + set_int("tlabFastRefillWasteOffset", in_bytes(JavaThread::tlab_fast_refill_waste_offset())); + set_int("tlabNumberOfRefillsOffset", in_bytes(JavaThread::tlab_number_of_refills_offset())); + set_int("tlabRefillWasteLimitOffset", in_bytes(JavaThread::tlab_refill_waste_limit_offset())); + set_int("tlabRefillWasteIncrement", (int32_t) ThreadLocalAllocBuffer::refill_waste_limit_increment()); + set_int("klassInstanceSizeOffset", in_bytes(Klass::layout_helper_offset())); + set_boolean("tlabStats", TLABStats); + set_boolean("inlineContiguousAllocationSupported", !CMSIncrementalMode && Universe::heap()->supports_inline_contig_alloc()); + + set_long("arrayPrototypeMarkWord", (intptr_t)markOopDesc::prototype()); + set_int("layoutHelperLog2ElementSizeShift", Klass::_lh_log2_element_size_shift); + set_int("layoutHelperLog2ElementSizeMask", Klass::_lh_log2_element_size_mask); + set_int("layoutHelperElementTypeShift", Klass::_lh_element_type_shift); + set_int("layoutHelperElementTypeMask", Klass::_lh_element_type_mask); + set_int("layoutHelperHeaderSizeShift", Klass::_lh_header_size_shift); + set_int("layoutHelperHeaderSizeMask", Klass::_lh_header_size_mask); + set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset())); + + set_long("debugStub", VmIds::addStub((address)warning)); + set_long("instanceofStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_slow_subtype_check_id))); + set_long("newInstanceStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_instance_id))); + set_long("newArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_array_id))); + set_long("newMultiArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_multi_array_id))); + set_long("identityHashCodeStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_identity_hash_code_id))); + set_long("threadIsInterruptedStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_thread_is_interrupted_id))); + set_long("inlineCacheMissStub", VmIds::addStub(SharedRuntime::get_ic_miss_stub())); + set_long("handleExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_handle_exception_nofpu_id))); + set_long("handleDeoptStub", VmIds::addStub(SharedRuntime::deopt_blob()->unpack())); + set_long("monitorEnterStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorenter_id))); + set_long("monitorExitStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorexit_id))); + set_long("verifyOopStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_verify_oop_id))); + set_long("vmErrorStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_vm_error_id))); + set_long("deoptimizeStub", VmIds::addStub(SharedRuntime::deopt_blob()->uncommon_trap())); + set_long("unwindExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_unwind_exception_call_id))); + set_long("osrMigrationEndStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_OSR_migration_end_id))); + set_long("registerFinalizerStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_register_finalizer_id))); + set_long("setDeoptInfoStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_set_deopt_info_id))); + set_long("createNullPointerExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_null_pointer_exception_id))); + set_long("createOutOfBoundsExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_out_of_bounds_exception_id))); + set_long("javaTimeMillisStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeMillis))); + set_long("javaTimeNanosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeNanos))); + set_long("arithmeticFremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_frem_id))); + set_long("arithmeticDremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_drem_id))); + set_long("arithmeticSinStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dsin))); + set_long("arithmeticCosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dcos))); + set_long("arithmeticTanStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dtan))); + set_long("logPrimitiveStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_primitive_id))); + set_long("logObjectStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_object_id))); + set_long("logPrintfStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_printf_id))); + + + BarrierSet* bs = Universe::heap()->barrier_set(); + switch (bs->kind()) { + case BarrierSet::CardTableModRef: + case BarrierSet::CardTableExtension: { + jlong base = (jlong)((CardTableModRefBS*)bs)->byte_map_base; + assert(base != 0, "unexpected byte_map_base"); + set_long("cardtableStartAddress", base); + set_int("cardtableShift", CardTableModRefBS::card_shift); + break; + } + case BarrierSet::ModRef: + case BarrierSet::Other: + set_long("cardtableStartAddress", 0); + set_int("cardtableShift", 0); + // No post barriers + break; +#ifndef SERIALGC + case BarrierSet::G1SATBCT: + case BarrierSet::G1SATBCTLogging: +#endif // SERIALGC + default: + ShouldNotReachHere(); + break; + } + + set_int("arrayClassElementOffset", in_bytes(ObjArrayKlass::element_klass_offset())); + +#undef set_boolean +#undef set_int +#undef set_long +#undef set_object +#undef set_int_array + +C2V_END + +C2V_VMENTRY(jint, installCode0, (JNIEnv *jniEnv, jobject, jobject compResult, jobject installed_code, jobject info)) + ResourceMark rm; + HandleMark hm; + Handle compResultHandle = JNIHandles::resolve(compResult); + nmethod* nm = NULL; + methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult)); + Handle installed_code_handle = JNIHandles::resolve(installed_code); + GraalEnv::CodeInstallResult result; + CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle); + + if (result != GraalEnv::ok) { + assert(nm == NULL, "should be"); + } else { + if (info != NULL) { + arrayOop codeCopy = oopFactory::new_byteArray(nm->code_size(), CHECK_0); + memcpy(codeCopy->base(T_BYTE), nm->code_begin(), nm->code_size()); + HotSpotCodeInfo::set_code(info, codeCopy); + HotSpotCodeInfo::set_start(info, (jlong) nm->code_begin()); + } + + if (!installed_code_handle.is_null()) { + assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type"); + HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm); + HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult)); + assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable"); + } + } + return result; +C2V_END + +C2V_VMENTRY(jobject, disassembleNative, (JNIEnv *jniEnv, jobject, jbyteArray code, jlong start_address)) + ResourceMark rm; + HandleMark hm; + + stringStream(st); + arrayOop code_oop = (arrayOop) JNIHandles::resolve(code); + int len = code_oop->length(); + address begin = (address) code_oop->base(T_BYTE); + address end = begin + len; + Disassembler::decode(begin, end, &st); + + Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); + return JNIHandles::make_local(result()); +C2V_END + +C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv *env, jobject, jlong metaspace_method, int bci)) + ResourceMark rm; + HandleMark hm; + + methodHandle method = asMethod(metaspace_method); + oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); + return JNIHandles::make_local(element); +C2V_END + +C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject args)) + ResourceMark rm; + HandleMark hm; + + assert(metaspace_method != 0, "just checking"); + methodHandle mh = asMethod(metaspace_method); + Symbol* signature = mh->signature(); + JavaCallArguments jca; + + JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + JavaValue result(jap.get_ret_type()); + + nmethod* nm = (nmethod*) (address) metaspace_nmethod; + if (nm == NULL || !nm->is_alive()) { + THROW_0(vmSymbols::MethodInvalidatedException()); + } + + JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL); + + if (jap.get_ret_type() == T_VOID) { + return NULL; + } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { + return JNIHandles::make_local((oop) result.get_jobject()); + } else { + oop o = java_lang_boxing_object::create(jap.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL); + return JNIHandles::make_local(o); + } +C2V_END + +C2V_VMENTRY(jobject, executeCompiledMethod, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject arg1, jobject arg2, jobject arg3)) + ResourceMark rm; + HandleMark hm; + + methodHandle method = asMethod(metaspace_method); + assert(!method.is_null(), "just checking"); + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(JNIHandles::resolve(arg1)); + args.push_oop(JNIHandles::resolve(arg2)); + args.push_oop(JNIHandles::resolve(arg3)); + + nmethod* nm = (nmethod*) (address) metaspace_nmethod; + if (nm == NULL || !nm->is_alive()) { + THROW_0(vmSymbols::MethodInvalidatedException()); + } + + JavaCalls::call(&result, method, nm, &args, CHECK_NULL); + + return JNIHandles::make_local((oop) result.get_jobject()); +C2V_END + +C2V_VMENTRY(jint, getVtableEntryOffset, (JNIEnv *, jobject, jlong metaspace_method)) + + Method* method = asMethod(metaspace_method); + assert(!InstanceKlass::cast(method->method_holder())->is_interface(), "vtableEntryOffset cannot be called for interface methods"); + assert(InstanceKlass::cast(method->method_holder())->is_linked(), "vtableEntryOffset cannot be called is holder is not linked"); + + // get entry offset in words + int vtable_entry_offset = InstanceKlass::vtable_start_offset() + method->vtable_index() * vtableEntry::size(); + // convert to bytes + vtable_entry_offset = vtable_entry_offset * wordSize + vtableEntry::method_offset_in_bytes(); + + return vtable_entry_offset; +C2V_END + +C2V_VMENTRY(jobject, getDeoptedLeafGraphIds, (JNIEnv *, jobject)) + + // the contract for this method is as follows: + // returning null: no deopted leaf graphs + // returning array (size > 0): the ids of the deopted leaf graphs + // returning array (size == 0): there was an overflow, the compiler needs to clear its cache completely + + oop array = GraalCompiler::instance()->dump_deopted_leaf_graphs(CHECK_NULL); + return JNIHandles::make_local(array); +C2V_END + +C2V_VMENTRY(jobject, decodePC, (JNIEnv *, jobject, jlong pc)) + stringStream(st); + CodeBlob* blob = CodeCache::find_blob_unsafe((void*) pc); + if (blob == NULL) { + st.print("[unidentified pc]"); + } else { + st.print(blob->name()); + + nmethod* nm = blob->as_nmethod_or_null(); + if (nm != NULL && nm->method() != NULL) { + st.print(" %s.", nm->method()->method_holder()->external_name()); + nm->method()->name()->print_symbol_on(&st); + st.print(" @ %d", pc - (jlong) nm->entry_point()); + } + } + Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); + return JNIHandles::make_local(result()); +C2V_END + + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) + +#define RESOLVED_TYPE "Lcom/oracle/graal/api/meta/ResolvedJavaType;" +#define TYPE "Lcom/oracle/graal/api/meta/JavaType;" +#define METHOD "Lcom/oracle/graal/api/meta/JavaMethod;" +#define FIELD "Lcom/oracle/graal/api/meta/JavaField;" +#define SIGNATURE "Lcom/oracle/graal/api/meta/Signature;" +#define CONSTANT_POOL "Lcom/oracle/graal/api/meta/ConstantPool;" +#define CONSTANT "Lcom/oracle/graal/api/meta/Constant;" +#define KIND "Lcom/oracle/graal/api/meta/Kind;" +#define RUNTIME_CALL "Lcom/oracle/graal/api/code/RuntimeCall;" +#define EXCEPTION_HANDLERS "[Lcom/oracle/graal/api/meta/ExceptionHandler;" +#define REFLECT_METHOD "Ljava/lang/reflect/Method;" +#define REFLECT_CONSTRUCTOR "Ljava/lang/reflect/Constructor;" +#define REFLECT_FIELD "Ljava/lang/reflect/Field;" +#define STRING "Ljava/lang/String;" +#define OBJECT "Ljava/lang/Object;" +#define CLASS "Ljava/lang/Class;" +#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" +#define HS_RESOLVED_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;" +#define HS_RESOLVED_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;" +#define HS_RESOLVED_FIELD "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;" +#define HS_COMP_RESULT "Lcom/oracle/graal/hotspot/HotSpotCompilationResult;" +#define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" +#define HS_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;" +#define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" +#define HS_CODE_INFO "Lcom/oracle/graal/hotspot/meta/HotSpotCodeInfo;" +#define METHOD_DATA "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;" +#define METASPACE_METHOD "J" +#define METASPACE_METHOD_DATA "J" +#define NMETHOD "J" + +JNINativeMethod CompilerToVM_methods[] = { + {CC"initializeBytecode", CC"("METASPACE_METHOD"[B)[B", FN_PTR(initializeBytecode)}, + {CC"getSignature", CC"("METASPACE_METHOD")"STRING, FN_PTR(getSignature)}, + {CC"initializeExceptionHandlers", CC"("METASPACE_METHOD EXCEPTION_HANDLERS")"EXCEPTION_HANDLERS, FN_PTR(initializeExceptionHandlers)}, + {CC"hasBalancedMonitors", CC"("METASPACE_METHOD")Z", FN_PTR(hasBalancedMonitors)}, + {CC"getUniqueConcreteMethod", CC"("METASPACE_METHOD"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getUniqueConcreteMethod)}, + {CC"getStackTraceElement", CC"("METASPACE_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC"initializeMethod", CC"("METASPACE_METHOD HS_RESOLVED_METHOD")V", FN_PTR(initializeMethod)}, + {CC"initializeMethodData", CC"("METASPACE_METHOD_DATA METHOD_DATA")V", FN_PTR(initializeMethodData)}, + {CC"isMethodCompilable", CC"("METASPACE_METHOD")Z", FN_PTR(isMethodCompilable)}, + {CC"getInvocationCount", CC"("METASPACE_METHOD")I", FN_PTR(getInvocationCount)}, + {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, + {CC"getVtableEntryOffset", CC"("METASPACE_METHOD")I", FN_PTR(getVtableEntryOffset)}, + {CC"lookupType", CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE, FN_PTR(lookupType)}, + {CC"lookupConstantInPool", CC"("HS_RESOLVED_TYPE"I)"OBJECT, FN_PTR(lookupConstantInPool)}, + {CC"lookupMethodInPool", CC"("HS_RESOLVED_TYPE"IB)"METHOD, FN_PTR(lookupMethodInPool)}, + {CC"lookupTypeInPool", CC"("HS_RESOLVED_TYPE"I)"TYPE, FN_PTR(lookupTypeInPool)}, + {CC"lookupReferencedTypeInPool", CC"("HS_RESOLVED_TYPE"IB)V", FN_PTR(lookupReferencedTypeInPool)}, + {CC"lookupFieldInPool", CC"("HS_RESOLVED_TYPE"IB)"FIELD, FN_PTR(lookupFieldInPool)}, + {CC"resolveMethod", CC"("HS_RESOLVED_TYPE STRING STRING")"METHOD, FN_PTR(resolveMethod)}, + {CC"getInstanceFields", CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD, FN_PTR(getInstanceFields)}, + {CC"isTypeInitialized", CC"("HS_RESOLVED_TYPE")Z", FN_PTR(isTypeInitialized)}, + {CC"initializeType", CC"("HS_RESOLVED_TYPE")V", FN_PTR(initializeType)}, + {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, + {CC"getResolvedType", CC"("CLASS")"RESOLVED_TYPE, FN_PTR(getResolvedType)}, + {CC"getMetaspaceMethod", CC"("REFLECT_METHOD"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getMetaspaceMethod)}, + {CC"getMetaspaceConstructor", CC"("REFLECT_CONSTRUCTOR"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getMetaspaceConstructor)}, + {CC"getJavaField", CC"("REFLECT_FIELD")"HS_RESOLVED_FIELD, FN_PTR(getJavaField)}, + {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)}, + {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE HS_CODE_INFO")I", FN_PTR(installCode0)}, + {CC"disassembleNative", CC"([BJ)"STRING, FN_PTR(disassembleNative)}, + {CC"executeCompiledMethod", CC"("METASPACE_METHOD NMETHOD OBJECT OBJECT OBJECT")"OBJECT, FN_PTR(executeCompiledMethod)}, + {CC"executeCompiledMethodVarargs", CC"("METASPACE_METHOD NMETHOD "["OBJECT")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, + {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, + {CC"decodePC", CC"(J)"STRING, FN_PTR(decodePC)}, +}; + +int CompilerToVM_methods_count() { + return sizeof(CompilerToVM_methods) / sizeof(JNINativeMethod); +} + diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Tue Dec 11 08:48:12 2012 +0100 @@ -1,618 +1,606 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "runtime/interfaceSupport.hpp" -#include "prims/jvm.h" -#include "graal/graalRuntime.hpp" -#include "graal/graalVMToCompiler.hpp" -#include "asm/codeBuffer.hpp" -#include "runtime/biasedLocking.hpp" - -// Implementation of GraalStubAssembler - -GraalStubAssembler::GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id) : MacroAssembler(code) { - _name = name; - _must_gc_arguments = false; - _frame_size = no_frame_size; - _num_rt_args = 0; - _stub_id = stub_id; -} - - -void GraalStubAssembler::set_info(const char* name, bool must_gc_arguments) { - _name = name; - _must_gc_arguments = must_gc_arguments; -} - - -void GraalStubAssembler::set_frame_size(int size) { - if (_frame_size == no_frame_size) { - _frame_size = size; - } - assert(_frame_size == size, "can't change the frame size"); -} - - -void GraalStubAssembler::set_num_rt_args(int args) { - if (_num_rt_args == 0) { - _num_rt_args = args; - } - assert(_num_rt_args == args, "can't change the number of args"); -} - -// Implementation of GraalRuntime - -CodeBlob* GraalRuntime::_blobs[GraalRuntime::number_of_ids]; -const char *GraalRuntime::_blob_names[] = { - GRAAL_STUBS(STUB_NAME, LAST_STUB_NAME) -}; - -// Simple helper to see if the caller of a runtime stub which -// entered the VM has been deoptimized - -static bool caller_is_deopted() { - JavaThread* thread = JavaThread::current(); - RegisterMap reg_map(thread, false); - frame runtime_frame = thread->last_frame(); - frame caller_frame = runtime_frame.sender(®_map); - assert(caller_frame.is_compiled_frame(), "must be compiled"); - return caller_frame.is_deoptimized_frame(); -} - -// Stress deoptimization -static void deopt_caller() { - if ( !caller_is_deopted()) { - JavaThread* thread = JavaThread::current(); - RegisterMap reg_map(thread, false); - frame runtime_frame = thread->last_frame(); - frame caller_frame = runtime_frame.sender(®_map); - Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); - assert(caller_is_deopted(), "Must be deoptimized"); - } -} - -static bool setup_code_buffer(CodeBuffer* code) { - // Preinitialize the consts section to some large size: - int locs_buffer_size = 1 * (relocInfo::length_limit + sizeof(relocInfo)); - char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size); - code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, - locs_buffer_size / sizeof(relocInfo)); - - // Global stubs have neither constants nor local stubs - code->initialize_consts_size(0); - code->initialize_stubs_size(0); - - return true; -} - -void GraalRuntime::generate_blob_for(BufferBlob* buffer_blob, StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - ResourceMark rm; - // create code buffer for code storage - CodeBuffer code(buffer_blob); - - setup_code_buffer(&code); - - // create assembler for code generation - GraalStubAssembler* sasm = new GraalStubAssembler(&code, name_for(id), id); - // generate code for runtime stub - OopMapSet* oop_maps; - oop_maps = generate_code_for(id, sasm); - assert(oop_maps == NULL || sasm->frame_size() != no_frame_size, - "if stub has an oop map it must have a valid frame size"); - -#ifdef ASSERT - // Make sure that stubs that need oopmaps have them - switch (id) { - // These stubs don't need to have an oopmap - case graal_slow_subtype_check_id: -#if defined(SPARC) || defined(PPC) - case handle_exception_nofpu_id: // Unused on sparc -#endif -#ifdef GRAAL - case graal_verify_oop_id: - case graal_unwind_exception_call_id: - case graal_OSR_migration_end_id: - case graal_arithmetic_frem_id: - case graal_arithmetic_drem_id: - case graal_set_deopt_info_id: -#endif - break; - - // All other stubs should have oopmaps - default: - assert(oop_maps != NULL, "must have an oopmap"); - } -#endif - - // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned) - sasm->align(BytesPerWord); - // make sure all code is in code buffer - sasm->flush(); - // create blob - distinguish a few special cases - CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id), - &code, - CodeOffsets::frame_never_safe, - sasm->frame_size(), - oop_maps, - sasm->must_gc_arguments()); - // install blob - assert(blob != NULL, "blob must exist"); - _blobs[id] = blob; -} - - -void GraalRuntime::initialize(BufferBlob* blob) { - // generate stubs - for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id); - // printing -#ifndef PRODUCT - if (PrintSimpleStubs) { - ResourceMark rm; - for (int id = 0; id < number_of_ids; id++) { - _blobs[id]->print(); - if (_blobs[id]->oop_maps() != NULL) { - _blobs[id]->oop_maps()->print(); - } - } - } -#endif -} - - -CodeBlob* GraalRuntime::blob_for(StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - return _blobs[id]; -} - - -const char* GraalRuntime::name_for(StubID id) { - assert(0 <= id && id < number_of_ids, "illegal stub id"); - return _blob_names[id]; -} - -const char* GraalRuntime::name_for_address(address entry) { - for (int id = 0; id < number_of_ids; id++) { - if (entry == entry_for((StubID)id)) return name_for((StubID)id); - } - -#define FUNCTION_CASE(a, f) \ - if ((intptr_t)a == CAST_FROM_FN_PTR(intptr_t, f)) return #f - - FUNCTION_CASE(entry, os::javaTimeMillis); - FUNCTION_CASE(entry, os::javaTimeNanos); - FUNCTION_CASE(entry, SharedRuntime::OSR_migration_end); - FUNCTION_CASE(entry, SharedRuntime::d2f); - FUNCTION_CASE(entry, SharedRuntime::d2i); - FUNCTION_CASE(entry, SharedRuntime::d2l); - FUNCTION_CASE(entry, SharedRuntime::dcos); - FUNCTION_CASE(entry, SharedRuntime::dexp); - FUNCTION_CASE(entry, SharedRuntime::dlog); - FUNCTION_CASE(entry, SharedRuntime::dlog10); - FUNCTION_CASE(entry, SharedRuntime::dpow); - FUNCTION_CASE(entry, SharedRuntime::drem); - FUNCTION_CASE(entry, SharedRuntime::dsin); - FUNCTION_CASE(entry, SharedRuntime::dtan); - FUNCTION_CASE(entry, SharedRuntime::f2i); - FUNCTION_CASE(entry, SharedRuntime::f2l); - FUNCTION_CASE(entry, SharedRuntime::frem); - FUNCTION_CASE(entry, SharedRuntime::l2d); - FUNCTION_CASE(entry, SharedRuntime::l2f); - FUNCTION_CASE(entry, SharedRuntime::ldiv); - FUNCTION_CASE(entry, SharedRuntime::lmul); - FUNCTION_CASE(entry, SharedRuntime::lrem); - FUNCTION_CASE(entry, SharedRuntime::lrem); - FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry); - FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit); -#ifdef TRACE_HAVE_INTRINSICS - FUNCTION_CASE(entry, TRACE_TIME_METHOD); -#endif - - ShouldNotReachHere(); - return NULL; - -#undef FUNCTION_CASE -} - - -JRT_ENTRY(void, GraalRuntime::new_instance(JavaThread* thread, Klass* klass)) - assert(klass->is_klass(), "not a class"); - instanceKlassHandle h(thread, klass); - h->check_valid_for_instantiation(true, CHECK); - // make sure klass is initialized - h->initialize(CHECK); - // allocate instance and return via TLS - oop obj = h->allocate_instance(CHECK); - thread->set_vm_result(obj); -JRT_END - - -JRT_ENTRY(void, GraalRuntime::new_type_array(JavaThread* thread, Klass* klass, jint length)) - // Note: no handle for klass needed since they are not used - // anymore after new_typeArray() and no GC can happen before. - // (This may have to change if this code changes!) - assert(klass->is_klass(), "not a class"); - BasicType elt_type = TypeArrayKlass::cast(klass)->element_type(); - oop obj = oopFactory::new_typeArray(elt_type, length, CHECK); - thread->set_vm_result(obj); - // This is pretty rare but this runtime patch is stressful to deoptimization - // if we deoptimize here so force a deopt to stress the path. - if (DeoptimizeALot) { - deopt_caller(); - } - -JRT_END - - -JRT_ENTRY(void, GraalRuntime::new_object_array(JavaThread* thread, Klass* array_klass, jint length)) - // Note: no handle for klass needed since they are not used - // anymore after new_objArray() and no GC can happen before. - // (This may have to change if this code changes!) - assert(array_klass->is_klass(), "not a class"); - Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); - objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK); - thread->set_vm_result(obj); - // This is pretty rare but this runtime patch is stressful to deoptimization - // if we deoptimize here so force a deopt to stress the path. - if (DeoptimizeALot) { - deopt_caller(); - } -JRT_END - - -JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) - assert(klass->is_klass(), "not a class"); - assert(rank >= 1, "rank must be nonzero"); - oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); - thread->set_vm_result(obj); -JRT_END - -JRT_ENTRY(void, GraalRuntime::unimplemented_entry(JavaThread* thread, StubID id)) - tty->print_cr("GraalRuntime::entry_for(%d) returned unimplemented entry point", id); -JRT_END - -extern void vm_exit(int code); - -// Enter this method from compiled code handler below. This is where we transition -// to VM mode. This is done as a helper routine so that the method called directly -// from compiled code does not have to transition to VM. This allows the entry -// method to see if the nmethod that we have just looked up a handler for has -// been deoptimized while we were in the vm. This simplifies the assembly code -// cpu directories. -// -// We are entering here from exception stub (via the entry method below) -// If there is a compiled exception handler in this method, we will continue there; -// otherwise we will unwind the stack and continue at the caller of top frame method -// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to -// control the area where we can allow a safepoint. After we exit the safepoint area we can -// check to see if the handler we are going to return is now in a nmethod that has -// been deoptimized. If that is the case we return the deopt blob -// unpack_with_exception entry instead. This makes life for the exception blob easier -// because making that same check and diverting is painful from assembly language. -JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) - // Reset method handle flag. - thread->set_is_method_handle_return(false); - - Handle exception(thread, ex); - nm = CodeCache::find_nmethod(pc); - assert(nm != NULL, "this is not an nmethod"); - // Adjust the pc as needed/ - if (nm->is_deopt_pc(pc)) { - RegisterMap map(thread, false); - frame exception_frame = thread->last_frame().sender(&map); - // if the frame isn't deopted then pc must not correspond to the caller of last_frame - assert(exception_frame.is_deoptimized_frame(), "must be deopted"); - pc = exception_frame.pc(); - } -#ifdef ASSERT - assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); - assert(exception->is_oop(), "just checking"); - // Check that exception is a subclass of Throwable, otherwise we have a VerifyError - if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { - if (ExitVMOnVerifyError) vm_exit(-1); - ShouldNotReachHere(); - } -#endif - - // Check the stack guard pages and reenable them if necessary and there is - // enough space on the stack to do so. Use fast exceptions only if the guard - // pages are enabled. - bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); - if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); - - if (JvmtiExport::can_post_on_exceptions()) { - // To ensure correct notification of exception catches and throws - // we have to deoptimize here. If we attempted to notify the - // catches and throws during this exception lookup it's possible - // we could deoptimize on the way out of the VM and end back in - // the interpreter at the throw site. This would result in double - // notifications since the interpreter would also notify about - // these same catches and throws as it unwound the frame. - - RegisterMap reg_map(thread); - frame stub_frame = thread->last_frame(); - frame caller_frame = stub_frame.sender(®_map); - - // We don't really want to deoptimize the nmethod itself since we - // can actually continue in the exception handler ourselves but I - // don't see an easy way to have the desired effect. - Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); - assert(caller_is_deopted(), "Must be deoptimized"); - - return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); - } - - // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions - if (guard_pages_enabled) { - address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); - if (fast_continuation != NULL) { - // Set flag if return address is a method handle call site. - thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); - return fast_continuation; - } - } - - // If the stack guard pages are enabled, check whether there is a handler in - // the current method. Otherwise (guard pages disabled), force an unwind and - // skip the exception cache update (i.e., just leave continuation==NULL). - address continuation = NULL; - if (guard_pages_enabled) { - - // New exception handling mechanism can support inlined methods - // with exception handlers since the mappings are from PC to PC - - // debugging support - // tracing - if (TraceExceptions) { - ttyLocker ttyl; - ResourceMark rm; - int offset = pc - nm->code_begin(); - tty->print_cr("Exception <%s> (0x%x) thrown in compiled method <%s> at PC " PTR_FORMAT " [" PTR_FORMAT "+%d] for thread 0x%x", - exception->print_value_string(), (address)exception(), nm->method()->print_value_string(), pc, nm->code_begin(), offset, thread); - } - // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(exception)); - - // Clear out the exception oop and pc since looking up an - // exception handler can cause class loading, which might throw an - // exception and those fields are expected to be clear during - // normal bytecode execution. - thread->set_exception_oop(NULL); - thread->set_exception_pc(NULL); - - continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); - // If an exception was thrown during exception dispatch, the exception oop may have changed - thread->set_exception_oop(exception()); - thread->set_exception_pc(pc); - - // the exception cache is used only by non-implicit exceptions - if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { - nm->add_handler_for_exception_and_pc(exception, pc, continuation); - } - } - - thread->set_vm_result(exception()); - // Set flag if return address is a method handle call site. - thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); - - if (TraceExceptions) { - ttyLocker ttyl; - ResourceMark rm; - tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, - thread, continuation, pc); - } - - return continuation; -JRT_END - -// Enter this method from compiled code only if there is a Java exception handler -// in the method handling the exception. -// We are entering here from exception stub. We don't do a normal VM transition here. -// We do it in a helper. This is so we can check to see if the nmethod we have just -// searched for an exception handler has been deoptimized in the meantime. -address GraalRuntime::exception_handler_for_pc(JavaThread* thread) { - oop exception = thread->exception_oop(); - address pc = thread->exception_pc(); - // Still in Java mode - DEBUG_ONLY(ResetNoHandleMark rnhm); - nmethod* nm = NULL; - address continuation = NULL; - { - // Enter VM mode by calling the helper - ResetNoHandleMark rnhm; - continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); - } - // Back in JAVA, use no oops DON'T safepoint - - // Now check to see if the nmethod we were called from is now deoptimized. - // If so we must return to the deopt blob and deoptimize the nmethod - if (nm != NULL && caller_is_deopted()) { - continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); - } - - assert(continuation != NULL, "no handler found"); - return continuation; -} - -JRT_ENTRY(void, GraalRuntime::graal_create_null_exception(JavaThread* thread)) - thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); -JRT_END - -JRT_ENTRY(void, GraalRuntime::graal_create_out_of_bounds_exception(JavaThread* thread, jint index)) - char message[jintAsStringSize]; - sprintf(message, "%d", index); - thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message)()); -JRT_END - -JRT_ENTRY_NO_ASYNC(void, GraalRuntime::graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) - if (TraceGraal >= 3) { - char type[O_BUFLEN]; - obj->klass()->name()->as_C_string(type, O_BUFLEN); - markOop mark = obj->mark(); - tty->print_cr("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), obj, type, mark, lock); - tty->flush(); - } -#ifdef ASSERT - if (PrintBiasedLockingStatistics) { - Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); - } -#endif - Handle h_obj(thread, obj); - assert(h_obj()->is_oop(), "must be NULL or an object"); - if (UseBiasedLocking) { - // Retry fast entry if bias is revoked to avoid unnecessary inflation - ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); - } else { - if (UseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); - } else { - ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); - } - } - if (TraceGraal >= 3) { - tty->print_cr("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), obj); - } -JRT_END - - -JRT_LEAF(void, GraalRuntime::graal_monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) - assert(thread == JavaThread::current(), "threads must correspond"); - assert(thread->last_Java_sp(), "last_Java_sp must be set"); - // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown - EXCEPTION_MARK; - -#ifdef DEBUG - if (!obj->is_oop()) { - ResetNoHandleMark rhm; - nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); - if (method != NULL) { - tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), obj); - } - thread->print_stack_on(tty); - assert(false, "invalid lock object pointer dected"); - } -#endif - - if (UseFastLocking) { - // When using fast locking, the compiled code has already tried the fast case - ObjectSynchronizer::slow_exit(obj, lock, THREAD); - } else { - ObjectSynchronizer::fast_exit(obj, lock, THREAD); - } - if (TraceGraal >= 3) { - char type[O_BUFLEN]; - obj->klass()->name()->as_C_string(type, O_BUFLEN); - tty->print_cr("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), obj, type, obj->mark(), lock); - tty->flush(); - } -JRT_END - -JRT_ENTRY(void, GraalRuntime::graal_log_object(JavaThread* thread, oop obj, jint flags)) - bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); - bool address = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); - bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); - if (!string) { - if (!address && obj->is_oop_or_null(true)) { - char buf[O_BUFLEN]; - tty->print("%s@%p", obj->klass()->name()->as_C_string(buf, O_BUFLEN), obj); - } else { - tty->print("%p", obj); - } - } else { - ResourceMark rm; - assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); - char *buf = java_lang_String::as_utf8_string(obj); - tty->print(buf); - } - if (newline) { - tty->cr(); - } -JRT_END - -JRT_ENTRY(void, GraalRuntime::graal_vm_error(JavaThread* thread, oop where, oop format, jlong value)) - ResourceMark rm; - assert(where == NULL || java_lang_String::is_instance(where), "must be"); - const char *error_msg = where == NULL ? "" : java_lang_String::as_utf8_string(where); - char *detail_msg = NULL; - if (format != NULL) { - const char* buf = java_lang_String::as_utf8_string(format); - size_t detail_msg_length = strlen(buf) * 2; - detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); - jio_snprintf(detail_msg, detail_msg_length, buf, value); - } - report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); -JRT_END - -JRT_ENTRY(void, GraalRuntime::graal_log_printf(JavaThread* thread, oop format, jlong val)) - ResourceMark rm; - assert(format != NULL && java_lang_String::is_instance(format), "must be"); - char *buf = java_lang_String::as_utf8_string(format); - tty->print(buf, val); -JRT_END - -JRT_ENTRY(void, GraalRuntime::graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) - union { - jlong l; - jdouble d; - jfloat f; - } uu; - uu.l = value; - switch (typeChar) { - case 'z': tty->print(value == 0 ? "false" : "true"); break; - case 'b': tty->print("%d", (jbyte) value); break; - case 'c': tty->print("%c", (jchar) value); break; - case 's': tty->print("%d", (jshort) value); break; - case 'i': tty->print("%d", (jint) value); break; - case 'f': tty->print("%f", uu.f); break; - case 'j': tty->print(INT64_FORMAT, value); break; - case 'd': tty->print("%lf", uu.d); break; - default: assert(false, "unknown typeChar"); break; - } - if (newline) { - tty->cr(); - } -JRT_END - -JRT_ENTRY(jint, GraalRuntime::graal_identity_hash_code(JavaThread* thread, oop obj)) - return (jint) obj->identity_hash(); -JRT_END - -JRT_ENTRY(jboolean, GraalRuntime::graal_thread_is_interrupted(JavaThread* thread, oop receiver, jboolean clear_interrupted)) - // TEMP: - tty->print_cr("ThreadIsInterruptedSlowCase"); - +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "runtime/interfaceSupport.hpp" +#include "prims/jvm.h" +#include "graal/graalRuntime.hpp" +#include "graal/graalVMToCompiler.hpp" +#include "asm/codeBuffer.hpp" +#include "runtime/biasedLocking.hpp" + +// Implementation of GraalStubAssembler + +GraalStubAssembler::GraalStubAssembler(CodeBuffer* code, const char * name, int stub_id) : MacroAssembler(code) { + _name = name; + _must_gc_arguments = false; + _frame_size = no_frame_size; + _num_rt_args = 0; + _stub_id = stub_id; +} + + +void GraalStubAssembler::set_info(const char* name, bool must_gc_arguments) { + _name = name; + _must_gc_arguments = must_gc_arguments; +} + + +void GraalStubAssembler::set_frame_size(int size) { + if (_frame_size == no_frame_size) { + _frame_size = size; + } + assert(_frame_size == size, "can't change the frame size"); +} + + +void GraalStubAssembler::set_num_rt_args(int args) { + if (_num_rt_args == 0) { + _num_rt_args = args; + } + assert(_num_rt_args == args, "can't change the number of args"); +} + +// Implementation of GraalRuntime + +CodeBlob* GraalRuntime::_blobs[GraalRuntime::number_of_ids]; +const char *GraalRuntime::_blob_names[] = { + GRAAL_STUBS(STUB_NAME, LAST_STUB_NAME) +}; + +// Simple helper to see if the caller of a runtime stub which +// entered the VM has been deoptimized + +static bool caller_is_deopted() { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + assert(caller_frame.is_compiled_frame(), "must be compiled"); + return caller_frame.is_deoptimized_frame(); +} + +// Stress deoptimization +static void deopt_caller() { + if ( !caller_is_deopted()) { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + } +} + +static bool setup_code_buffer(CodeBuffer* code) { + // Preinitialize the consts section to some large size: + int locs_buffer_size = 1 * (relocInfo::length_limit + sizeof(relocInfo)); + char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size); + code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, + locs_buffer_size / sizeof(relocInfo)); + + // Global stubs have neither constants nor local stubs + code->initialize_consts_size(0); + code->initialize_stubs_size(0); + + return true; +} + +void GraalRuntime::generate_blob_for(BufferBlob* buffer_blob, StubID id) { + assert(0 <= id && id < number_of_ids, "illegal stub id"); + ResourceMark rm; + // create code buffer for code storage + CodeBuffer code(buffer_blob); + + setup_code_buffer(&code); + + // create assembler for code generation + GraalStubAssembler* sasm = new GraalStubAssembler(&code, name_for(id), id); + // generate code for runtime stub + OopMapSet* oop_maps; + oop_maps = generate_code_for(id, sasm); + assert(oop_maps == NULL || sasm->frame_size() != no_frame_size, + "if stub has an oop map it must have a valid frame size"); + +#ifdef ASSERT + // Make sure that stubs that need oopmaps have them + switch (id) { + // These stubs don't need to have an oopmap + case graal_slow_subtype_check_id: +#if defined(SPARC) || defined(PPC) + case handle_exception_nofpu_id: // Unused on sparc +#endif +#ifdef GRAAL + case graal_verify_oop_id: + case graal_unwind_exception_call_id: + case graal_OSR_migration_end_id: + case graal_arithmetic_frem_id: + case graal_arithmetic_drem_id: + case graal_set_deopt_info_id: +#endif + break; + + // All other stubs should have oopmaps + default: + assert(oop_maps != NULL, "must have an oopmap"); + } +#endif + + // align so printing shows nop's instead of random code at the end (SimpleStubs are aligned) + sasm->align(BytesPerWord); + // make sure all code is in code buffer + sasm->flush(); + // create blob - distinguish a few special cases + CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id), + &code, + CodeOffsets::frame_never_safe, + sasm->frame_size(), + oop_maps, + sasm->must_gc_arguments()); + // install blob + assert(blob != NULL, "blob must exist"); + _blobs[id] = blob; +} + + +void GraalRuntime::initialize(BufferBlob* blob) { + // generate stubs + for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id); + // printing +#ifndef PRODUCT + if (PrintSimpleStubs) { + ResourceMark rm; + for (int id = 0; id < number_of_ids; id++) { + _blobs[id]->print(); + if (_blobs[id]->oop_maps() != NULL) { + _blobs[id]->oop_maps()->print(); + } + } + } +#endif +} + + +CodeBlob* GraalRuntime::blob_for(StubID id) { + assert(0 <= id && id < number_of_ids, "illegal stub id"); + return _blobs[id]; +} + + +const char* GraalRuntime::name_for(StubID id) { + assert(0 <= id && id < number_of_ids, "illegal stub id"); + return _blob_names[id]; +} + +const char* GraalRuntime::name_for_address(address entry) { + for (int id = 0; id < number_of_ids; id++) { + if (entry == entry_for((StubID)id)) return name_for((StubID)id); + } + +#define FUNCTION_CASE(a, f) \ + if ((intptr_t)a == CAST_FROM_FN_PTR(intptr_t, f)) return #f + + FUNCTION_CASE(entry, os::javaTimeMillis); + FUNCTION_CASE(entry, os::javaTimeNanos); + FUNCTION_CASE(entry, SharedRuntime::OSR_migration_end); + FUNCTION_CASE(entry, SharedRuntime::d2f); + FUNCTION_CASE(entry, SharedRuntime::d2i); + FUNCTION_CASE(entry, SharedRuntime::d2l); + FUNCTION_CASE(entry, SharedRuntime::dcos); + FUNCTION_CASE(entry, SharedRuntime::dexp); + FUNCTION_CASE(entry, SharedRuntime::dlog); + FUNCTION_CASE(entry, SharedRuntime::dlog10); + FUNCTION_CASE(entry, SharedRuntime::dpow); + FUNCTION_CASE(entry, SharedRuntime::drem); + FUNCTION_CASE(entry, SharedRuntime::dsin); + FUNCTION_CASE(entry, SharedRuntime::dtan); + FUNCTION_CASE(entry, SharedRuntime::f2i); + FUNCTION_CASE(entry, SharedRuntime::f2l); + FUNCTION_CASE(entry, SharedRuntime::frem); + FUNCTION_CASE(entry, SharedRuntime::l2d); + FUNCTION_CASE(entry, SharedRuntime::l2f); + FUNCTION_CASE(entry, SharedRuntime::ldiv); + FUNCTION_CASE(entry, SharedRuntime::lmul); + FUNCTION_CASE(entry, SharedRuntime::lrem); + FUNCTION_CASE(entry, SharedRuntime::lrem); + FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry); + FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit); +#ifdef TRACE_HAVE_INTRINSICS + FUNCTION_CASE(entry, TRACE_TIME_METHOD); +#endif + + ShouldNotReachHere(); + return NULL; + +#undef FUNCTION_CASE +} + + +JRT_ENTRY(void, GraalRuntime::new_instance(JavaThread* thread, Klass* klass)) + assert(klass->is_klass(), "not a class"); + instanceKlassHandle h(thread, klass); + h->check_valid_for_instantiation(true, CHECK); + // make sure klass is initialized + h->initialize(CHECK); + // allocate instance and return via TLS + oop obj = h->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, GraalRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length)) + // Note: no handle for klass needed since they are not used + // anymore after new_objArray() and no GC can happen before. + // (This may have to change if this code changes!) + assert(array_klass->is_klass(), "not a class"); + oop obj; + if (array_klass->oop_is_typeArray()) { + BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); + obj = oopFactory::new_typeArray(elt_type, length, CHECK); + } else { + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); + obj = oopFactory::new_objArray(elem_klass, length, CHECK); + } + thread->set_vm_result(obj); + // This is pretty rare but this runtime patch is stressful to deoptimization + // if we deoptimize here so force a deopt to stress the path. + if (DeoptimizeALot) { + deopt_caller(); + } +JRT_END + + +JRT_ENTRY(void, GraalRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) + assert(klass->is_klass(), "not a class"); + assert(rank >= 1, "rank must be nonzero"); + oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, GraalRuntime::unimplemented_entry(JavaThread* thread, StubID id)) + tty->print_cr("GraalRuntime::entry_for(%d) returned unimplemented entry point", id); +JRT_END + +extern void vm_exit(int code); + +// Enter this method from compiled code handler below. This is where we transition +// to VM mode. This is done as a helper routine so that the method called directly +// from compiled code does not have to transition to VM. This allows the entry +// method to see if the nmethod that we have just looked up a handler for has +// been deoptimized while we were in the vm. This simplifies the assembly code +// cpu directories. +// +// We are entering here from exception stub (via the entry method below) +// If there is a compiled exception handler in this method, we will continue there; +// otherwise we will unwind the stack and continue at the caller of top frame method +// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to +// control the area where we can allow a safepoint. After we exit the safepoint area we can +// check to see if the handler we are going to return is now in a nmethod that has +// been deoptimized. If that is the case we return the deopt blob +// unpack_with_exception entry instead. This makes life for the exception blob easier +// because making that same check and diverting is painful from assembly language. +JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) + // Reset method handle flag. + thread->set_is_method_handle_return(false); + + Handle exception(thread, ex); + nm = CodeCache::find_nmethod(pc); + assert(nm != NULL, "this is not an nmethod"); + // Adjust the pc as needed/ + if (nm->is_deopt_pc(pc)) { + RegisterMap map(thread, false); + frame exception_frame = thread->last_frame().sender(&map); + // if the frame isn't deopted then pc must not correspond to the caller of last_frame + assert(exception_frame.is_deoptimized_frame(), "must be deopted"); + pc = exception_frame.pc(); + } +#ifdef ASSERT + assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); + assert(exception->is_oop(), "just checking"); + // Check that exception is a subclass of Throwable, otherwise we have a VerifyError + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { + if (ExitVMOnVerifyError) vm_exit(-1); + ShouldNotReachHere(); + } +#endif + + // Check the stack guard pages and reenable them if necessary and there is + // enough space on the stack to do so. Use fast exceptions only if the guard + // pages are enabled. + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + + if (JvmtiExport::can_post_on_exceptions()) { + // To ensure correct notification of exception catches and throws + // we have to deoptimize here. If we attempted to notify the + // catches and throws during this exception lookup it's possible + // we could deoptimize on the way out of the VM and end back in + // the interpreter at the throw site. This would result in double + // notifications since the interpreter would also notify about + // these same catches and throws as it unwound the frame. + + RegisterMap reg_map(thread); + frame stub_frame = thread->last_frame(); + frame caller_frame = stub_frame.sender(®_map); + + // We don't really want to deoptimize the nmethod itself since we + // can actually continue in the exception handler ourselves but I + // don't see an easy way to have the desired effect. + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions + if (guard_pages_enabled) { + address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); + if (fast_continuation != NULL) { + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + return fast_continuation; + } + } + + // If the stack guard pages are enabled, check whether there is a handler in + // the current method. Otherwise (guard pages disabled), force an unwind and + // skip the exception cache update (i.e., just leave continuation==NULL). + address continuation = NULL; + if (guard_pages_enabled) { + + // New exception handling mechanism can support inlined methods + // with exception handlers since the mappings are from PC to PC + + // debugging support + // tracing + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + int offset = pc - nm->code_begin(); + tty->print_cr("Exception <%s> (0x%x) thrown in compiled method <%s> at PC " PTR_FORMAT " [" PTR_FORMAT "+%d] for thread 0x%x", + exception->print_value_string(), (address)exception(), nm->method()->print_value_string(), pc, nm->code_begin(), offset, thread); + } + // for AbortVMOnException flag + NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + + // Clear out the exception oop and pc since looking up an + // exception handler can cause class loading, which might throw an + // exception and those fields are expected to be clear during + // normal bytecode execution. + thread->set_exception_oop(NULL); + thread->set_exception_pc(NULL); + + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); + // If an exception was thrown during exception dispatch, the exception oop may have changed + thread->set_exception_oop(exception()); + thread->set_exception_pc(pc); + + // the exception cache is used only by non-implicit exceptions + if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { + nm->add_handler_for_exception_and_pc(exception, pc, continuation); + } + } + + thread->set_vm_result(exception()); + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, + thread, continuation, pc); + } + + return continuation; +JRT_END + +// Enter this method from compiled code only if there is a Java exception handler +// in the method handling the exception. +// We are entering here from exception stub. We don't do a normal VM transition here. +// We do it in a helper. This is so we can check to see if the nmethod we have just +// searched for an exception handler has been deoptimized in the meantime. +address GraalRuntime::exception_handler_for_pc(JavaThread* thread) { + oop exception = thread->exception_oop(); + address pc = thread->exception_pc(); + // Still in Java mode + DEBUG_ONLY(ResetNoHandleMark rnhm); + nmethod* nm = NULL; + address continuation = NULL; + { + // Enter VM mode by calling the helper + ResetNoHandleMark rnhm; + continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); + } + // Back in JAVA, use no oops DON'T safepoint + + // Now check to see if the nmethod we were called from is now deoptimized. + // If so we must return to the deopt blob and deoptimize the nmethod + if (nm != NULL && caller_is_deopted()) { + continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + assert(continuation != NULL, "no handler found"); + return continuation; +} + +JRT_ENTRY(void, GraalRuntime::graal_create_null_exception(JavaThread* thread)) + thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); +JRT_END + +JRT_ENTRY(void, GraalRuntime::graal_create_out_of_bounds_exception(JavaThread* thread, jint index)) + char message[jintAsStringSize]; + sprintf(message, "%d", index); + thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message)()); +JRT_END + +JRT_ENTRY_NO_ASYNC(void, GraalRuntime::graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + if (TraceGraal >= 3) { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + markOop mark = obj->mark(); + tty->print_cr("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), obj, type, mark, lock); + tty->flush(); + } +#ifdef ASSERT + if (PrintBiasedLockingStatistics) { + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + } +#endif + Handle h_obj(thread, obj); + assert(h_obj()->is_oop(), "must be NULL or an object"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); + } else { + if (UseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); + } + } + if (TraceGraal >= 3) { + tty->print_cr("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), obj); + } +JRT_END + + +JRT_LEAF(void, GraalRuntime::graal_monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + assert(thread == JavaThread::current(), "threads must correspond"); + assert(thread->last_Java_sp(), "last_Java_sp must be set"); + // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown + EXCEPTION_MARK; + +#ifdef DEBUG + if (!obj->is_oop()) { + ResetNoHandleMark rhm; + nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); + if (method != NULL) { + tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), obj); + } + thread->print_stack_on(tty); + assert(false, "invalid lock object pointer dected"); + } +#endif + + if (UseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_exit(obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_exit(obj, lock, THREAD); + } + if (TraceGraal >= 3) { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + tty->print_cr("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), obj, type, obj->mark(), lock); + tty->flush(); + } +JRT_END + +JRT_ENTRY(void, GraalRuntime::graal_log_object(JavaThread* thread, oop obj, jint flags)) + bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); + bool address = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); + bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); + if (!string) { + if (!address && obj->is_oop_or_null(true)) { + char buf[O_BUFLEN]; + tty->print("%s@%p", obj->klass()->name()->as_C_string(buf, O_BUFLEN), obj); + } else { + tty->print("%p", obj); + } + } else { + ResourceMark rm; + assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); + char *buf = java_lang_String::as_utf8_string(obj); + tty->print(buf); + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(void, GraalRuntime::graal_vm_error(JavaThread* thread, oop where, oop format, jlong value)) + ResourceMark rm; + assert(where == NULL || java_lang_String::is_instance(where), "must be"); + const char *error_msg = where == NULL ? "" : java_lang_String::as_utf8_string(where); + char *detail_msg = NULL; + if (format != NULL) { + const char* buf = java_lang_String::as_utf8_string(format); + size_t detail_msg_length = strlen(buf) * 2; + detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); + jio_snprintf(detail_msg, detail_msg_length, buf, value); + } + report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); +JRT_END + +JRT_ENTRY(void, GraalRuntime::graal_log_printf(JavaThread* thread, oop format, jlong val)) + ResourceMark rm; + assert(format != NULL && java_lang_String::is_instance(format), "must be"); + char *buf = java_lang_String::as_utf8_string(format); + tty->print(buf, val); +JRT_END + +JRT_ENTRY(void, GraalRuntime::graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) + union { + jlong l; + jdouble d; + jfloat f; + } uu; + uu.l = value; + switch (typeChar) { + case 'z': tty->print(value == 0 ? "false" : "true"); break; + case 'b': tty->print("%d", (jbyte) value); break; + case 'c': tty->print("%c", (jchar) value); break; + case 's': tty->print("%d", (jshort) value); break; + case 'i': tty->print("%d", (jint) value); break; + case 'f': tty->print("%f", uu.f); break; + case 'j': tty->print(INT64_FORMAT, value); break; + case 'd': tty->print("%lf", uu.d); break; + default: assert(false, "unknown typeChar"); break; + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(jint, GraalRuntime::graal_identity_hash_code(JavaThread* thread, oop obj)) + return (jint) obj->identity_hash(); +JRT_END + +JRT_ENTRY(jboolean, GraalRuntime::graal_thread_is_interrupted(JavaThread* thread, oop receiver, jboolean clear_interrupted)) + // TEMP: + tty->print_cr("ThreadIsInterruptedSlowCase"); + // Ensure that the C++ Thread and OSThread structures aren't freed before we operate Handle receiverHandle(thread, receiver); JRT_BLOCK MutexLockerEx ml(thread->threadObj() == receiver ? NULL : Threads_lock); JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); - JRT_BLOCK_END -JRT_END - -// JVM_InitializeGraalRuntime -JVM_ENTRY(jobject, JVM_InitializeGraalRuntime(JNIEnv *env, jclass graalclass)) - return VMToCompiler::graalRuntimePermObject(); -JVM_END + JRT_BLOCK_END +JRT_END + +// JVM_InitializeGraalRuntime +JVM_ENTRY(jobject, JVM_InitializeGraalRuntime(JNIEnv *env, jclass graalclass)) + return VMToCompiler::graalRuntimePermObject(); +JVM_END diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Tue Dec 11 08:48:12 2012 +0100 @@ -80,8 +80,7 @@ #define GRAAL_STUBS(stub, last_entry) \ stub(graal_register_finalizer) \ stub(graal_new_instance) \ - stub(graal_new_type_array) \ - stub(graal_new_object_array) \ + stub(graal_new_array) \ stub(graal_new_multi_array) \ stub(graal_handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ stub(graal_slow_subtype_check) \ @@ -130,12 +129,11 @@ Register arg1 = noreg, Register arg2 = noreg, Register arg3 = noreg); // runtime entry points - static void new_instance (JavaThread* thread, Klass* klass); - static void new_type_array (JavaThread* thread, Klass* klass, jint length); - static void new_object_array(JavaThread* thread, Klass* klass, jint length); - static void new_multi_array (JavaThread* thread, Klass* klass, int rank, jint* dims); + static void new_instance(JavaThread* thread, Klass* klass); + static void new_array(JavaThread* thread, Klass* klass, jint length); + static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); - static void unimplemented_entry (JavaThread* thread, StubID id); + static void unimplemented_entry(JavaThread* thread, StubID id); static address exception_handler_for_pc(JavaThread* thread); diff -r fcae6d960acd -r 2ae3e26b7e9a src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Tue Dec 11 08:28:00 2012 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Tue Dec 11 08:48:12 2012 +0100 @@ -36,9 +36,7 @@ #include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" -#ifdef GRAAL #include "oops/fieldStreams.hpp" -#endif #include "prims/jvmtiThreadState.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/compilationPolicy.hpp" @@ -809,77 +807,6 @@ return true; } -// This assumes that the fields are stored in ObjectValue in the same order -// they are yielded by do_nonstatic_fields. -class FieldReassigner: public FieldClosure { - frame* _fr; - RegisterMap* _reg_map; - ObjectValue* _sv; - InstanceKlass* _ik; - oop _obj; - - int _i; -public: - FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) : - _fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {} - - int i() const { return _i; } - - - void do_field(fieldDescriptor* fd) { - intptr_t val; - StackValue* value = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); - int offset = fd->offset(); - switch (fd->field_type()) { - case T_OBJECT: case T_ARRAY: - assert(value->type() == T_OBJECT, "Agreement."); - _obj->obj_field_put(offset, value->get_obj()()); - break; - - case T_LONG: case T_DOUBLE: { - assert(value->type() == T_INT, "Agreement."); - StackValue* low = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); -#ifdef _LP64 - jlong res = (jlong)low->get_int(); -#else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else - jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC -#endif - _obj->long_field_put(offset, res); - break; - } - // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->int_field_put(offset, (jint)*((jint*)&val)); - break; - - case T_SHORT: case T_CHAR: // 2 bytes - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->short_field_put(offset, (jshort)*((jint*)&val)); - break; - - case T_BOOLEAN: case T_BYTE: // 1 byte - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->bool_field_put(offset, (jboolean)*((jint*)&val)); - break; - - default: - ShouldNotReachHere(); - } - _i++; - } -}; - // restore elements of an eliminated type array void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { int index = 0; @@ -932,7 +859,6 @@ } } - // restore fields of an eliminated object array void Deoptimization::reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj) { for (int i = 0; i < sv->field_size(); i++) { @@ -942,7 +868,15 @@ } } -#ifdef GRAAL +typedef struct { + int offset; + BasicType type; +} ReassignedField; + +int compare(ReassignedField* left, ReassignedField* right) { + return left->offset - right->offset; +} + // Restore fields of an eliminated instance object using the same field order // returned by HotSpotResolvedObjectType.getInstanceFields(true) static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj) { @@ -950,14 +884,21 @@ svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj); } + GrowableArray* fields = new GrowableArray(); for (AllFieldStream fs(klass); !fs.done(); fs.next()) { - if (fs.access_flags().is_static()) { - continue; + if (!fs.access_flags().is_static()) { + ReassignedField field; + field.offset = fs.offset(); + field.type = FieldType::basic_type(fs.signature()); + fields->append(field); } + } + fields->sort(compare); + for (int i = 0; i < fields->length(); i++) { intptr_t val; StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(svIndex)); - int offset = fs.offset(); - BasicType type = FieldType::basic_type(fs.signature()); + int offset = fields->at(i).offset; + BasicType type = fields->at(i).type; switch (type) { case T_OBJECT: case T_ARRAY: assert(value->type() == T_OBJECT, "Agreement."); @@ -1006,8 +947,6 @@ } return svIndex; } -#endif - // restore fields of all eliminated objects and arrays void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects) { @@ -1022,12 +961,7 @@ if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); -#ifndef GRAAL - FieldReassigner reassign(fr, reg_map, sv, obj()); - ik->do_nonstatic_fields(&reassign); -#else reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj()); -#endif } else if (k->oop_is_typeArray()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k()); reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type());