# HG changeset patch # User Peter Hofer # Date 1314795340 -7200 # Node ID 8780fa370aabb00122d52c4573efcfcf3dfc1c99 # Parent 549b9bcb8db6e57ed3c119bf6c474aab1b566c7f Support runtime calls to targets that don't fit in a 32-bit immediate: allow to query the maximum offset of a CiRuntimeCall target to determine the required immediate size and patch call sites with a mov/call instruction pair for indirect calls diff -r 549b9bcb8db6 -r 8780fa370aab src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Tue Aug 30 11:08:56 2011 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Wed Aug 31 14:55:40 2011 +0200 @@ -586,8 +586,21 @@ assert((runtime_call ? 1 : 0) + (hotspot_method ? 1 : 0) + (global_stub ? 1 : 0) == 1, "Call site needs exactly one type"); - assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size)"); - jint next_pc_offset = pc_offset + NativeCall::instruction_size; + NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); + jint next_pc_offset = 0x0; + if (inst->is_call() || inst->is_jump()) { + assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); + next_pc_offset = pc_offset + NativeCall::instruction_size; + } else if (inst->is_mov_literal64()) { + // mov+call instruction pair + next_pc_offset = pc_offset + NativeMovConstReg::instruction_size; + u_char* call = (u_char*) (_instructions->start() + next_pc_offset); + assert((call[0] == 0x40 || call[0] == 0x41) && call[1] == 0xFF, "expected call with rex/rexb prefix byte"); + next_pc_offset += 3; /* prefix byte + opcode byte + modrm byte */ + } else { + runtime_call->print(); + fatal("unsupported type of instruction for call site"); + } if (debug_info != NULL) { _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(_frame_size, _parameter_count, debug_info)); @@ -596,69 +609,69 @@ } if (runtime_call != NULL) { - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + address target_addr = 0x0; if (runtime_call == CiRuntimeCall::Debug()) { TRACE_graal_3("CiRuntimeCall::Debug()"); } else if (runtime_call == CiRuntimeCall::UnwindException()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_unwind_exception_call_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_unwind_exception_call_id); TRACE_graal_3("CiRuntimeCall::UnwindException()"); } else if (runtime_call == CiRuntimeCall::HandleException()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_handle_exception_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_handle_exception_id); TRACE_graal_3("CiRuntimeCall::HandleException()"); } else if (runtime_call == CiRuntimeCall::SetDeoptInfo()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_set_deopt_info_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_set_deopt_info_id); TRACE_graal_3("CiRuntimeCall::SetDeoptInfo()"); } else if (runtime_call == CiRuntimeCall::CreateNullPointerException()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_create_null_pointer_exception_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_create_null_pointer_exception_id); TRACE_graal_3("CiRuntimeCall::CreateNullPointerException()"); } else if (runtime_call == CiRuntimeCall::CreateOutOfBoundsException()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_create_out_of_bounds_exception_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_create_out_of_bounds_exception_id); TRACE_graal_3("CiRuntimeCall::CreateOutOfBoundsException()"); } else if (runtime_call == CiRuntimeCall::JavaTimeMillis()) { - call->set_destination(CAST_FROM_FN_PTR(address, os::javaTimeMillis)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = CAST_FROM_FN_PTR(address, os::javaTimeMillis); TRACE_graal_3("CiRuntimeCall::JavaTimeMillis()"); } else if (runtime_call == CiRuntimeCall::JavaTimeNanos()) { - call->set_destination(CAST_FROM_FN_PTR(address, os::javaTimeNanos)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = CAST_FROM_FN_PTR(address, os::javaTimeNanos); TRACE_graal_3("CiRuntimeCall::JavaTimeNanos()"); } else if (runtime_call == CiRuntimeCall::ArithmeticFrem()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_arithmetic_frem_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_arithmetic_frem_id); TRACE_graal_3("CiRuntimeCall::ArithmeticFrem()"); } else if (runtime_call == CiRuntimeCall::ArithmeticDrem()) { - call->set_destination(Runtime1::entry_for(Runtime1::graal_arithmetic_drem_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::graal_arithmetic_drem_id); TRACE_graal_3("CiRuntimeCall::ArithmeticDrem()"); } else if (runtime_call == CiRuntimeCall::ArithmeticSin()) { - call->set_destination(CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); TRACE_graal_3("CiRuntimeCall::ArithmeticSin()"); } else if (runtime_call == CiRuntimeCall::ArithmeticCos()) { - call->set_destination(CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); TRACE_graal_3("CiRuntimeCall::ArithmeticCos()"); } else if (runtime_call == CiRuntimeCall::ArithmeticTan()) { - call->set_destination(CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); TRACE_graal_3("CiRuntimeCall::ArithmeticTan()"); } else if (runtime_call == CiRuntimeCall::RegisterFinalizer()) { - call->set_destination(Runtime1::entry_for(Runtime1::register_finalizer_id)); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = Runtime1::entry_for(Runtime1::register_finalizer_id); } else if (runtime_call == CiRuntimeCall::Deoptimize()) { - call->set_destination(SharedRuntime::deopt_blob()->uncommon_trap()); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + target_addr = SharedRuntime::deopt_blob()->uncommon_trap(); } else { runtime_call->print(); fatal("runtime_call not implemented"); } + + if (inst->is_call()) { + // NOTE: for call without a mov, the offset must fit a 32-bit immediate + // see also VMEntries.getMaxCallTargetOffset() + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(target_addr); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_mov_literal64()) { + NativeMovConstReg* mov = nativeMovConstReg_at(_instructions->start() + pc_offset); + mov->set_data((intptr_t) target_addr); + _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); + } else { + runtime_call->print(); + fatal("unknown type of instruction for runtime call"); + } } else if (global_stub != NULL) { - NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); assert(java_lang_boxing_object::is_instance(global_stub, T_LONG), "global_stub needs to be of type Long"); if (inst->is_call()) { diff -r 549b9bcb8db6 -r 8780fa370aab src/share/vm/graal/graalVMEntries.cpp --- a/src/share/vm/graal/graalVMEntries.cpp Tue Aug 30 11:08:56 2011 +0200 +++ b/src/share/vm/graal/graalVMEntries.cpp Wed Aug 31 14:55:40 2011 +0200 @@ -749,6 +749,31 @@ return JNIHandles::make_local(THREAD, GraalCompiler::get_RiType(klass, KlassHandle(), THREAD)); } +// public long getMaxCallTargetOffset(CiRuntimeCall rtcall); +JNIEXPORT jlong JNICALL Java_com_oracle_graal_runtime_VMEntries_getMaxCallTargetOffset(JNIEnv *env, jobject, jobject rtcall) { + TRACE_graal_3("VMEntries::VMEntries_getMaxCallTargetOffset"); + VM_ENTRY_MARK; + oop call = JNIHandles::resolve(rtcall); + address target_addr = 0x0; + if (call == CiRuntimeCall::ArithmeticSin()) { + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); + } else if (call == CiRuntimeCall::ArithmeticCos()) { + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); + } else if (call == CiRuntimeCall::ArithmeticTan()) { + target_addr = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); + } else if (call == CiRuntimeCall::JavaTimeMillis()) { + target_addr = CAST_FROM_FN_PTR(address, os::javaTimeMillis); + } else if (call == CiRuntimeCall::JavaTimeNanos()) { + target_addr = CAST_FROM_FN_PTR(address, os::javaTimeNanos); + } + 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; +} + // public RiType getType(Class javaClass); JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_getType(JNIEnv *env, jobject, jobject javaClass) { TRACE_graal_3("VMEntries::VMEntries_getType"); @@ -941,6 +966,7 @@ #define HS_METHOD "Lcom/oracle/max/graal/runtime/HotSpotMethod;" #define CI_CONSTANT "Lcom/sun/cri/ci/CiConstant;" #define CI_KIND "Lcom/sun/cri/ci/CiKind;" +#define CI_RUNTIME_CALL "Lcom/sun/cri/ci/CiRuntimeCall;" #define STRING "Ljava/lang/String;" #define OBJECT "Ljava/lang/Object;" #define CLASS "Ljava/lang/Class;" @@ -975,6 +1001,7 @@ {CC"RiType_fields", CC"("RESOLVED_TYPE")["FIELD, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1fields)}, {CC"RiType_isInitialized", CC"("RESOLVED_TYPE")Z", FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1isInitialized)}, {CC"getPrimitiveArrayType", CC"("CI_KIND")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getPrimitiveArrayType)}, + {CC"getMaxCallTargetOffset", CC"("CI_RUNTIME_CALL")J", FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getMaxCallTargetOffset)}, {CC"getType", CC"("CLASS")"TYPE, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getType)}, {CC"getConfiguration", CC"()"CONFIG, FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getConfiguration)}, {CC"installMethod", CC"("TARGET_METHOD")V", FN_PTR(Java_com_oracle_graal_runtime_VMEntries_installMethod)},