# HG changeset patch # User Thomas Wuerthinger # Date 1365724432 -7200 # Node ID ff5a32117e026a800c623192a0e5574cad2adc18 # Parent 2b840ae76df1479f7f26b45a1aa673f8ae6bcb88 Implement fast invocation of installed code (direct tail call to the target machine code address). diff -r 2b840ae76df1 -r ff5a32117e02 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotInstalledCodeTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotInstalledCodeTest.java Thu Apr 11 17:48:30 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotInstalledCodeTest.java Fri Apr 12 01:53:52 2013 +0200 @@ -24,6 +24,7 @@ import org.junit.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.hotspot.meta.*; @@ -36,11 +37,23 @@ final ResolvedJavaMethod testJavaMethod = runtime.lookupJavaMethod(getMethod("foo")); final StructuredGraph graph = parse("otherFoo"); final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(testJavaMethod, graph); - Object result = installedCode.execute(null, null, null); - assertEquals(43, result); + Assert.assertTrue(installedCode.isValid()); + Object result; + try { + result = installedCode.execute("a", "b", "c"); + assertEquals(43, result); + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + Assert.assertTrue(installedCode.isValid()); installedCode.invalidate(); - result = installedCode.execute(null, null, null); - System.out.println(result); + Assert.assertFalse(installedCode.isValid()); + try { + result = installedCode.execute(null, null, null); + Assert.fail("Code was not invalidated"); + } catch (InvalidInstalledCodeException e) { + } + Assert.assertFalse(installedCode.isValid()); } @SuppressWarnings("unused") diff -r 2b840ae76df1 -r ff5a32117e02 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java Thu Apr 11 17:48:30 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java Fri Apr 12 01:53:52 2013 +0200 @@ -24,6 +24,7 @@ import java.lang.reflect.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.test.*; @@ -36,7 +37,7 @@ // TODO this is not a test, move it somewhere else // CheckStyle: stop system..print check - public void test1() throws NoSuchMethodException, SecurityException { + public void test1() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { final Method benchrMethod = InstalledCodeExecuteHelperTest.class.getMethod("bench", long.class, long.class); final ResolvedJavaMethod benchJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(benchrMethod); @@ -63,7 +64,7 @@ // CheckStyle: resume system..print check - public static Long bench(long nmethod, long metaspacemethod) { + public static Long bench(long nmethod, long metaspacemethod) throws InvalidInstalledCodeException { long start = System.currentTimeMillis(); for (int i = 0; i < ITERATIONS; i++) { @@ -78,7 +79,7 @@ return 42; } - public static Object executeWrapper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { + public static Object executeWrapper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { return HotSpotInstalledCode.executeHelper(nmethod, metaspaceMethod, arg1, arg2, arg3); } diff -r 2b840ae76df1 -r ff5a32117e02 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 Thu Apr 11 17:48:30 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Fri Apr 12 01:53:52 2013 +0200 @@ -199,9 +199,9 @@ StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); - Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod); + Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException; - Object executeCompiledMethodVarargs(Object[] args, long nativeMethod); + Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException; int getVtableEntryOffset(long metaspaceMethod); diff -r 2b840ae76df1 -r ff5a32117e02 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 Thu Apr 11 17:48:30 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Fri Apr 12 01:53:52 2013 +0200 @@ -133,9 +133,6 @@ public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @Override - public native Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod); - - @Override public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod); @Override @@ -167,4 +164,11 @@ @Override public native boolean isInstalledCodeValid(long nativeMethod); + + @Override + public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException { + return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod); + } + + private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod); } diff -r 2b840ae76df1 -r ff5a32117e02 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 Thu Apr 11 17:48:30 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Fri Apr 12 01:53:52 2013 +0200 @@ -76,7 +76,7 @@ } @Override - public Object execute(Object arg1, Object arg2, Object arg3) { + public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3; assert method.getSignature().getParameterKind(0) == Kind.Object; assert method.getSignature().getParameterKind(1) == Kind.Object; @@ -99,7 +99,7 @@ } @Override - public Object executeVarargs(Object... args) { + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { assert checkArgs(args); return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod); } @@ -114,7 +114,8 @@ return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod); } - public static Object executeHelper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { + @SuppressWarnings("unused") + public static Object executeHelper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod); } } diff -r 2b840ae76df1 -r ff5a32117e02 src/cpu/sparc/vm/interpreter_sparc.cpp --- a/src/cpu/sparc/vm/interpreter_sparc.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/cpu/sparc/vm/interpreter_sparc.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -381,6 +381,7 @@ case Interpreter::zerolocals_synchronized: synchronized = true; break; case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; + case Interpreter::execute_compiled_method: entry_point = ((InterpreterGenerator*)this)->generate_execute_compiled_method_entry(); break; case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break; diff -r 2b840ae76df1 -r ff5a32117e02 src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -1917,6 +1917,7 @@ BasicType* in_sig_bt, VMRegPair* in_regs, BasicType ret_type) { + assert (method->intrinsic_id() != vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod, "not yet ported"); if (method->is_method_handle_intrinsic()) { vmIntrinsics::ID iid = method->intrinsic_id(); intptr_t start = (intptr_t)__ pc(); diff -r 2b840ae76df1 -r ff5a32117e02 src/cpu/x86/vm/interpreterGenerator_x86.hpp --- a/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/cpu/x86/vm/interpreterGenerator_x86.hpp Fri Apr 12 01:53:52 2013 +0200 @@ -36,6 +36,7 @@ address generate_normal_entry(bool synchronized); address generate_native_entry(bool synchronized); + address generate_execute_compiled_method_entry(); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); address generate_empty_entry(void); diff -r 2b840ae76df1 -r ff5a32117e02 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -1670,6 +1670,11 @@ verify_oop_args(masm, method, sig_bt, regs); vmIntrinsics::ID iid = method->intrinsic_id(); + if (iid == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod) { + __ jmp(Address(j_rarg3, nmethod::verified_entry_point_offset())); + return; + } + // Now write the args into the outgoing interpreter space bool has_receiver = false; Register receiver_reg = noreg; diff -r 2b840ae76df1 -r ff5a32117e02 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -873,6 +873,31 @@ return generate_accessor_entry(); } +// Interpreter stub for calling a compiled method with 3 object arguments +address InterpreterGenerator::generate_execute_compiled_method_entry() { + address entry_point = __ pc(); + + // Pick up the return address + __ movptr(rax, Address(rsp, 0)); + + // Must preserve original SP for loading incoming arguments because + // we need to align the outgoing SP for compiled code. + __ movptr(r11, rsp); + + // Ensure compiled code always sees stack at proper alignment + __ andptr(rsp, -16); + + // push the return address and misalign the stack that youngest frame always sees + // as far as the placement of the call instruction + __ push(rax); + + __ movq(j_rarg0, Address(r11, Interpreter::stackElementSize*5)); + __ movq(j_rarg1, Address(r11, Interpreter::stackElementSize*4)); + __ movq(j_rarg2, Address(r11, Interpreter::stackElementSize*3)); + __ movq(j_rarg3, Address(r11, Interpreter::stackElementSize)); + __ jmp(Address(j_rarg3, nmethod::verified_entry_point_offset())); + return entry_point; +} // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the @@ -1561,6 +1586,7 @@ switch (kind) { case Interpreter::zerolocals : break; case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::execute_compiled_method: entry_point = ((InterpreterGenerator*)this)->generate_execute_compiled_method_entry(); break; case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Apr 12 01:53:52 2013 +0200 @@ -299,6 +299,7 @@ template(com_oracle_graal_hotspot_HotSpotCompilationResult, "com/oracle/graal/hotspot/HotSpotCompilationResult") \ template(com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, "com/oracle/graal/hotspot/HotSpotRuntimeCallTarget") \ template(com_oracle_graal_hotspot_bridge_VMToCompiler, "com/oracle/graal/hotspot/bridge/VMToCompiler") \ + template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl, "com/oracle/graal/hotspot/bridge/CompilerToVMImpl") \ template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo, "com/oracle/graal/hotspot/meta/HotSpotCodeInfo") \ template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode, "com/oracle/graal/hotspot/meta/HotSpotInstalledCode") \ template(com_oracle_graal_hotspot_meta_HotSpotJavaType, "com/oracle/graal/hotspot/meta/HotSpotJavaType") \ @@ -1127,6 +1128,9 @@ do_intrinsic(_Double_valueOf, java_lang_Double, valueOf_name, Double_valueOf_signature, F_S) \ do_name( Double_valueOf_signature, "(D)Ljava/lang/Double;") \ \ + do_intrinsic(_CompilerToVMImpl_executeCompiledMethod, com_oracle_graal_hotspot_bridge_CompilerToVMImpl, executeCompiledMethod_name, CompilerToVMImpl_executeCompiledMethod_signature, F_SN)\ + do_name( CompilerToVMImpl_executeCompiledMethod_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;J)Ljava/lang/Object;") \ + do_name( executeCompiledMethod_name, "executeCompiledMethodIntrinsic") \ /*end*/ diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -898,12 +898,10 @@ return JNIHandles::make_local(element); C2V_END -C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject args, jlong nativeMethod)) +C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod)) ResourceMark rm; HandleMark hm; - assert(metaspace_method != 0, "just checking"); - nmethod* nm = (nmethod*) (address) nativeMethod; methodHandle mh = nm->method(); Symbol* signature = mh->signature(); @@ -924,24 +922,6 @@ } C2V_END -C2V_VMENTRY(jobject, executeCompiledMethod, (JNIEnv *env, jobject, jobject arg1, jobject arg2, jobject arg3, jlong nativeMethod)) - ResourceMark rm; - HandleMark hm; - - nmethod* nm = (nmethod*) (address) nativeMethod; - methodHandle method = nm->method(); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(JNIHandles::resolve(arg1)); - args.push_oop(JNIHandles::resolve(arg2)); - args.push_oop(JNIHandles::resolve(arg3)); - - args.set_alternative_target(nm); - JavaCalls::call(&result, method, &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); @@ -1062,15 +1042,17 @@ C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv *env, jobject, jlong nativeMethod)) nmethod* m = (nmethod*)nativeMethod; - m->mark_for_deoptimization(); - VM_Deoptimize op; - VMThread::execute(&op); + if (!m->is_not_entrant()) { + m->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } C2V_END C2V_VMENTRY(jboolean, isInstalledCodeValid, (JNIEnv *env, jobject, jlong nativeMethod)) nmethod* m = (nmethod*)nativeMethod; - return m->is_alive(); + return m->is_alive() && !m->is_not_entrant(); C2V_END #define CC (char*) /*cast a literal from (const char*)*/ @@ -1141,7 +1123,6 @@ {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I", FN_PTR(installCode0)}, {CC"getCode", CC"(J)[B", FN_PTR(getCode)}, {CC"disassembleNMethod", CC"(J)"STRING, FN_PTR(disassembleNMethod)}, - {CC"executeCompiledMethod", CC"("OBJECT OBJECT OBJECT NMETHOD")"OBJECT, FN_PTR(executeCompiledMethod)}, {CC"executeCompiledMethodVarargs", CC"(["OBJECT NMETHOD")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/interpreter/abstractInterpreter.hpp --- a/src/share/vm/interpreter/abstractInterpreter.hpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Fri Apr 12 01:53:52 2013 +0200 @@ -85,6 +85,7 @@ zerolocals_synchronized, // method needs locals initialization & is synchronized native, // native method native_synchronized, // native method & is synchronized + execute_compiled_method, // direct call to compiled method address empty, // empty method (code: _return) accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return) abstract, // abstract method (throws an AbstractMethodException) diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/interpreter/interpreter.cpp --- a/src/share/vm/interpreter/interpreter.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/interpreter/interpreter.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -188,6 +188,9 @@ // Method handle primitive? if (m->is_method_handle_intrinsic()) { vmIntrinsics::ID id = m->intrinsic_id(); + if (id == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod) { + return AbstractInterpreter::execute_compiled_method; + } assert(MethodHandles::is_signature_polymorphic(id), "must match an intrinsic"); MethodKind kind = (MethodKind)( method_handle_invoke_FIRST + ((int)id - vmIntrinsics::FIRST_MH_SIG_POLY) ); @@ -287,6 +290,7 @@ case zerolocals_synchronized: tty->print("zerolocals_synchronized"); break; case native : tty->print("native" ); break; case native_synchronized : tty->print("native_synchronized" ); break; + case execute_compiled_method: tty->print("execute_compiled_method"); break; case empty : tty->print("empty" ); break; case accessor : tty->print("accessor" ); break; case abstract : tty->print("abstract" ); break; diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/interpreter/templateInterpreter.cpp --- a/src/share/vm/interpreter/templateInterpreter.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -360,6 +360,7 @@ method_entry(zerolocals) method_entry(zerolocals_synchronized) method_entry(empty) + method_entry(execute_compiled_method) method_entry(accessor) method_entry(abstract) method_entry(java_lang_math_sin ) diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/oops/method.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -1014,8 +1014,8 @@ // Test if this method is an internal MH primitive method. bool Method::is_method_handle_intrinsic() const { vmIntrinsics::ID iid = intrinsic_id(); - return (MethodHandles::is_signature_polymorphic(iid) && - MethodHandles::is_signature_polymorphic_intrinsic(iid)); + return ((MethodHandles::is_signature_polymorphic(iid) && + MethodHandles::is_signature_polymorphic_intrinsic(iid))) || iid == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod; } bool Method::has_member_arg() const { diff -r 2b840ae76df1 -r ff5a32117e02 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 11 17:48:30 2013 +0200 +++ b/src/share/vm/runtime/sharedRuntime.cpp Fri Apr 12 01:53:52 2013 +0200 @@ -1355,7 +1355,8 @@ // Installed code has been deoptimized JRT_BLOCK_ENTRY(address, SharedRuntime::handle_deoptimized_installed_code(JavaThread* thread)) JavaThread* THREAD = thread; - THROW_(vmSymbols::java_lang_NullPointerException(), NULL); + ThreadInVMfromJava tiv(THREAD); + THROW_(vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL); JRT_END // Handle call site that has been made non-entrant