diff --git a/make/linux/makefiles/mapfile-vers-debug b/make/linux/makefiles/mapfile-vers-debug index 3f73de30725ea2d3dd6a62f1d93180d304651782..b36259c8d06f24dfad68fc272f939167e3318354 100644 --- a/make/linux/makefiles/mapfile-vers-debug +++ b/make/linux/makefiles/mapfile-vers-debug @@ -1,4 +1,6 @@ # +# @(#)mapfile-vers-debug 1.18 07/10/25 16:47:35 +# # # Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. @@ -75,6 +77,11 @@ SUNWprivate_1.1 { JVM_DesiredAssertionStatus; JVM_DisableCompiler; JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; JVM_DumpAllStacks; JVM_DumpThreads; JVM_EnableCompiler; diff --git a/make/linux/makefiles/mapfile-vers-product b/make/linux/makefiles/mapfile-vers-product index df2994fcd495bcfb6b8f2450b0572f8420daa2c5..eaffd6a582a2c80adf6adb38f16cefb11c0bbcd2 100644 --- a/make/linux/makefiles/mapfile-vers-product +++ b/make/linux/makefiles/mapfile-vers-product @@ -1,4 +1,6 @@ # +# @(#)mapfile-vers-product 1.19 08/02/12 10:56:37 +# # # Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. @@ -75,6 +77,11 @@ SUNWprivate_1.1 { JVM_DesiredAssertionStatus; JVM_DisableCompiler; JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; JVM_DumpAllStacks; JVM_DumpThreads; JVM_EnableCompiler; diff --git a/make/solaris/makefiles/dtrace.make b/make/solaris/makefiles/dtrace.make index 4c974ede21280b1ae791af22fe335c07f3a4c46d..f4f7edf934d1da135345238fa68b0d5533a9bfdb 100644 --- a/make/solaris/makefiles/dtrace.make +++ b/make/solaris/makefiles/dtrace.make @@ -193,10 +193,16 @@ $(DTRACE.o): $(DTRACE).d $(JVMOFFS).h $(JVMOFFS)Index.h $(DTraced_Files) .PHONY: dtraceCheck +SYSTEM_DTRACE_H = /usr/include/dtrace.h SYSTEM_DTRACE_PROG = /usr/sbin/dtrace PATCH_DTRACE_PROG = /opt/SUNWdtrd/sbin/dtrace systemDtraceFound := $(wildcard ${SYSTEM_DTRACE_PROG}) patchDtraceFound := $(wildcard ${PATCH_DTRACE_PROG}) +systemDtraceHdrFound := $(wildcard $(SYSTEM_DTRACE_H)) + +ifneq ("$(systemDtraceHdrFound)", "") +CFLAGS += -DHAVE_DTRACE_H +endif ifneq ("$(patchDtraceFound)", "") DTRACE_PROG=$(PATCH_DTRACE_PROG) diff --git a/make/solaris/makefiles/mapfile-vers b/make/solaris/makefiles/mapfile-vers index 7b1a1743e7918320694b1aa8a6337c3062679804..f7ed56e5f1079871b361fd5a2017b4860c00d97d 100644 --- a/make/solaris/makefiles/mapfile-vers +++ b/make/solaris/makefiles/mapfile-vers @@ -1,4 +1,6 @@ # +# @(#)mapfile-vers 1.32 07/10/25 16:47:36 +# # # Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. @@ -75,6 +77,11 @@ SUNWprivate_1.1 { JVM_DesiredAssertionStatus; JVM_DisableCompiler; JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; JVM_DumpAllStacks; JVM_DumpThreads; JVM_EnableCompiler; diff --git a/src/cpu/sparc/vm/nativeInst_sparc.cpp b/src/cpu/sparc/vm/nativeInst_sparc.cpp index 331675102a830a28f27c7682fae00f1d1cd25505..3deee97da7523f39e9b6e83cd154030dfb525c79 100644 --- a/src/cpu/sparc/vm/nativeInst_sparc.cpp +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp @@ -26,6 +26,10 @@ # include "incls/_nativeInst_sparc.cpp.incl" +bool NativeInstruction::is_dtrace_trap() { + return !is_nop(); +} + void NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) { ResourceMark rm; CodeBuffer buf(instaddr, 10 * BytesPerInstWord ); diff --git a/src/cpu/sparc/vm/nativeInst_sparc.hpp b/src/cpu/sparc/vm/nativeInst_sparc.hpp index ff0913515c747c90e3e584398fd67f1949db08c5..1e7263b41efd2dd6a6361b6dc8eb382b9fd033cf 100644 --- a/src/cpu/sparc/vm/nativeInst_sparc.hpp +++ b/src/cpu/sparc/vm/nativeInst_sparc.hpp @@ -43,6 +43,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { nop_instruction_size = 4 }; + bool is_dtrace_trap(); bool is_nop() { return long_at(0) == nop_instruction(); } bool is_call() { return is_op(long_at(0), Assembler::call_op); } bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) diff --git a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index ab10c809d0fc15f8016d47891b5c781503794b8b..7f5c4f814070d35d8a16cd783050abbc85b5c6f9 100644 --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1637,7 +1637,7 @@ static void long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { } } else if (dst.is_single_phys_reg()) { if (src.is_adjacent_aligned_on_stack(2)) { - __ ldd(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); + __ ld_long(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); } else { // dst is a single reg. // Remember lo is low address not msb for stack slots @@ -2501,6 +2501,551 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm, } +#ifdef HAVE_DTRACE_H +// --------------------------------------------------------------------------- +// Generate a dtrace nmethod for a given signature. The method takes arguments +// in the Java compiled code convention, marshals them to the native +// abi and then leaves nops at the position you would expect to call a native +// function. When the probe is enabled the nops are replaced with a trap +// instruction that dtrace inserts and the trace will cause a notification +// to dtrace. +// +// The probes are only able to take primitive types and java/lang/String as +// arguments. No other java types are allowed. Strings are converted to utf8 +// strings so that from dtrace point of view java strings are converted to C +// strings. There is an arbitrary fixed limit on the total space that a method +// can use for converting the strings. (256 chars per string in the signature). +// So any java string larger then this is truncated. + +static int fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 }; +static bool offsets_initialized = false; + +static VMRegPair reg64_to_VMRegPair(Register r) { + VMRegPair ret; + if (wordSize == 8) { + ret.set2(r->as_VMReg()); + } else { + ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg()); + } + return ret; +} + + +nmethod *SharedRuntime::generate_dtrace_nmethod( + MacroAssembler *masm, methodHandle method) { + + + // generate_dtrace_nmethod is guarded by a mutex so we are sure to + // be single threaded in this method. + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); + + // Fill in the signature array, for the calling-convention call. + int total_args_passed = method->size_of_parameters(); + + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); + + // The signature we are going to use for the trap that dtrace will see + // java/lang/String is converted. We drop "this" and any other object + // is converted to NULL. (A one-slot java/lang/Long object reference + // is converted to a two-slot long, which is why we double the allocation). + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); + + int i=0; + int total_strings = 0; + int first_arg_to_pass = 0; + int total_c_args = 0; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); + + // Skip the receiver as dtrace doesn't want to see it + if( !method->is_static() ) { + in_sig_bt[i++] = T_OBJECT; + first_arg_to_pass = 1; + } + + SignatureStream ss(method->signature()); + for ( ; !ss.at_return_type(); ss.next()) { + BasicType bt = ss.type(); + in_sig_bt[i++] = bt; // Collect remaining bits of signature + out_sig_bt[total_c_args++] = bt; + if( bt == T_OBJECT) { + symbolOop s = ss.as_symbol_or_null(); + if (s == vmSymbols::java_lang_String()) { + total_strings++; + out_sig_bt[total_c_args-1] = T_ADDRESS; + } else if (s == vmSymbols::java_lang_Boolean() || + s == vmSymbols::java_lang_Byte()) { + out_sig_bt[total_c_args-1] = T_BYTE; + } else if (s == vmSymbols::java_lang_Character() || + s == vmSymbols::java_lang_Short()) { + out_sig_bt[total_c_args-1] = T_SHORT; + } else if (s == vmSymbols::java_lang_Integer() || + s == vmSymbols::java_lang_Float()) { + out_sig_bt[total_c_args-1] = T_INT; + } else if (s == vmSymbols::java_lang_Long() || + s == vmSymbols::java_lang_Double()) { + out_sig_bt[total_c_args-1] = T_LONG; + out_sig_bt[total_c_args++] = T_VOID; + } + } else if ( bt == T_LONG || bt == T_DOUBLE ) { + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + // We convert double to long + out_sig_bt[total_c_args-1] = T_LONG; + out_sig_bt[total_c_args++] = T_VOID; + } else if ( bt == T_FLOAT) { + // We convert float to int + out_sig_bt[total_c_args-1] = T_INT; + } + } + + assert(i==total_args_passed, "validly parsed signature"); + + // Now get the compiled-Java layout as input arguments + int comp_args_on_stack; + comp_args_on_stack = SharedRuntime::java_calling_convention( + in_sig_bt, in_regs, total_args_passed, false); + + // We have received a description of where all the java arg are located + // on entry to the wrapper. We need to convert these args to where + // the a native (non-jni) function would expect them. To figure out + // where they go we convert the java signature to a C signature and remove + // T_VOID for any long/double we might have received. + + + // Now figure out where the args must be stored and how much stack space + // they require (neglecting out_preserve_stack_slots but space for storing + // the 1st six register arguments). It's weird see int_stk_helper. + // + int out_arg_slots; + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); + + // Calculate the total number of stack slots we will need. + + // First count the abi requirement plus all of the outgoing args + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; + + // Plus a temp for possible converion of float/double/long register args + + int conversion_temp = stack_slots; + stack_slots += 2; + + + // Now space for the string(s) we must convert + + int string_locs = stack_slots; + stack_slots += total_strings * + (max_dtrace_string_size / VMRegImpl::stack_slot_size); + + // Ok The space we have allocated will look like: + // + // + // FP-> | | + // |---------------------| + // | string[n] | + // |---------------------| <- string_locs[n] + // | string[n-1] | + // |---------------------| <- string_locs[n-1] + // | ... | + // | ... | + // |---------------------| <- string_locs[1] + // | string[0] | + // |---------------------| <- string_locs[0] + // | temp | + // |---------------------| <- conversion_temp + // | outbound memory | + // | based arguments | + // | | + // |---------------------| + // | | + // SP-> | out_preserved_slots | + // + // + + // Now compute actual number of stack words we need rounding to make + // stack properly aligned. + stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word); + + int stack_size = stack_slots * VMRegImpl::stack_slot_size; + + intptr_t start = (intptr_t)__ pc(); + + // First thing make an ic check to see if we should even be here + + { + Label L; + const Register temp_reg = G3_scratch; + Address ic_miss(temp_reg, SharedRuntime::get_ic_miss_stub()); + __ verify_oop(O0); + __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), temp_reg); + __ cmp(temp_reg, G5_inline_cache_reg); + __ brx(Assembler::equal, true, Assembler::pt, L); + __ delayed()->nop(); + + __ jump_to(ic_miss, 0); + __ delayed()->nop(); + __ align(CodeEntryAlignment); + __ bind(L); + } + + int vep_offset = ((intptr_t)__ pc()) - start; + + + // The instruction at the verified entry point must be 5 bytes or longer + // because it can be patched on the fly by make_non_entrant. The stack bang + // instruction fits that requirement. + + // Generate stack overflow check before creating frame + __ generate_stack_overflow_check(stack_size); + + assert(((intptr_t)__ pc() - start - vep_offset) >= 5, + "valid size for make_non_entrant"); + + // Generate a new frame for the wrapper. + __ save(SP, -stack_size, SP); + + // Frame is now completed as far a size and linkage. + + int frame_complete = ((intptr_t)__ pc()) - start; + +#ifdef ASSERT + bool reg_destroyed[RegisterImpl::number_of_registers]; + bool freg_destroyed[FloatRegisterImpl::number_of_registers]; + for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) { + reg_destroyed[r] = false; + } + for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) { + freg_destroyed[f] = false; + } + +#endif /* ASSERT */ + + VMRegPair zero; + zero.set2(G0->as_VMReg()); + + int c_arg, j_arg; + + Register conversion_off = noreg; + + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + + VMRegPair src = in_regs[j_arg]; + VMRegPair dst = out_regs[c_arg]; + +#ifdef ASSERT + if (src.first()->is_Register()) { + assert(!reg_destroyed[src.first()->as_Register()->encoding()], "ack!"); + } else if (src.first()->is_FloatRegister()) { + assert(!freg_destroyed[src.first()->as_FloatRegister()->encoding( + FloatRegisterImpl::S)], "ack!"); + } + if (dst.first()->is_Register()) { + reg_destroyed[dst.first()->as_Register()->encoding()] = true; + } else if (dst.first()->is_FloatRegister()) { + freg_destroyed[dst.first()->as_FloatRegister()->encoding( + FloatRegisterImpl::S)] = true; + } +#endif /* ASSERT */ + + switch (in_sig_bt[j_arg]) { + case T_ARRAY: + case T_OBJECT: + { + if (out_sig_bt[c_arg] == T_BYTE || out_sig_bt[c_arg] == T_SHORT || + out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { + // need to unbox a one-slot value + Register in_reg = L0; + Register tmp = L2; + if ( src.first()->is_reg() ) { + in_reg = src.first()->as_Register(); + } else { + assert(Assembler::is_simm13(reg2offset(src.first()) + STACK_BIAS), + "must be"); + __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, in_reg); + } + // If the final destination is an acceptable register + if ( dst.first()->is_reg() ) { + if ( dst.is_single_phys_reg() || out_sig_bt[c_arg] != T_LONG ) { + tmp = dst.first()->as_Register(); + } + } + + Label skipUnbox; + if ( wordSize == 4 && out_sig_bt[c_arg] == T_LONG ) { + __ mov(G0, tmp->successor()); + } + __ br_null(in_reg, true, Assembler::pn, skipUnbox); + __ delayed()->mov(G0, tmp); + + switch (out_sig_bt[c_arg]) { + case T_BYTE: + __ ldub(in_reg, box_offset, tmp); break; + case T_SHORT: + __ lduh(in_reg, box_offset, tmp); break; + case T_INT: + __ ld(in_reg, box_offset, tmp); break; + case T_LONG: + __ ld_long(in_reg, box_offset, tmp); break; + default: ShouldNotReachHere(); + } + + __ bind(skipUnbox); + // If tmp wasn't final destination copy to final destination + if (tmp == L2) { + VMRegPair tmp_as_VM = reg64_to_VMRegPair(L2); + if (out_sig_bt[c_arg] == T_LONG) { + long_move(masm, tmp_as_VM, dst); + } else { + move32_64(masm, tmp_as_VM, out_regs[c_arg]); + } + } + if (out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // move over the T_VOID to keep the loop indices in sync + } + } else if (out_sig_bt[c_arg] == T_ADDRESS) { + Register s = + src.first()->is_reg() ? src.first()->as_Register() : L2; + Register d = + dst.first()->is_reg() ? dst.first()->as_Register() : L2; + + // We store the oop now so that the conversion pass can reach + // while in the inner frame. This will be the only store if + // the oop is NULL. + if (s != L2) { + // src is register + if (d != L2) { + // dst is register + __ mov(s, d); + } else { + assert(Assembler::is_simm13(reg2offset(dst.first()) + + STACK_BIAS), "must be"); + __ st_ptr(s, SP, reg2offset(dst.first()) + STACK_BIAS); + } + } else { + // src not a register + assert(Assembler::is_simm13(reg2offset(src.first()) + + STACK_BIAS), "must be"); + __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, d); + if (d == L2) { + assert(Assembler::is_simm13(reg2offset(dst.first()) + + STACK_BIAS), "must be"); + __ st_ptr(d, SP, reg2offset(dst.first()) + STACK_BIAS); + } + } + } else if (out_sig_bt[c_arg] != T_VOID) { + // Convert the arg to NULL + if (dst.first()->is_reg()) { + __ mov(G0, dst.first()->as_Register()); + } else { + assert(Assembler::is_simm13(reg2offset(dst.first()) + + STACK_BIAS), "must be"); + __ st_ptr(G0, SP, reg2offset(dst.first()) + STACK_BIAS); + } + } + } + break; + case T_VOID: + break; + + case T_FLOAT: + if (src.first()->is_stack()) { + // Stack to stack/reg is simple + move32_64(masm, src, dst); + } else { + if (dst.first()->is_reg()) { + // freg -> reg + int off = + STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; + Register d = dst.first()->as_Register(); + if (Assembler::is_simm13(off)) { + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), + SP, off); + __ ld(SP, off, d); + } else { + if (conversion_off == noreg) { + __ set(off, L6); + conversion_off = L6; + } + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), + SP, conversion_off); + __ ld(SP, conversion_off , d); + } + } else { + // freg -> mem + int off = STACK_BIAS + reg2offset(dst.first()); + if (Assembler::is_simm13(off)) { + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), + SP, off); + } else { + if (conversion_off == noreg) { + __ set(off, L6); + conversion_off = L6; + } + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), + SP, conversion_off); + } + } + } + break; + + case T_DOUBLE: + assert( j_arg + 1 < total_args_passed && + in_sig_bt[j_arg + 1] == T_VOID && + out_sig_bt[c_arg+1] == T_VOID, "bad arg list"); + if (src.first()->is_stack()) { + // Stack to stack/reg is simple + long_move(masm, src, dst); + } else { + Register d = dst.first()->is_reg() ? dst.first()->as_Register() : L2; + + // Destination could be an odd reg on 32bit in which case + // we can't load direct to the destination. + + if (!d->is_even() && wordSize == 4) { + d = L2; + } + int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; + if (Assembler::is_simm13(off)) { + __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), + SP, off); + __ ld_long(SP, off, d); + } else { + if (conversion_off == noreg) { + __ set(off, L6); + conversion_off = L6; + } + __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), + SP, conversion_off); + __ ld_long(SP, conversion_off, d); + } + if (d == L2) { + long_move(masm, reg64_to_VMRegPair(L2), dst); + } + } + break; + + case T_LONG : + // 32bit can't do a split move of something like g1 -> O0, O1 + // so use a memory temp + if (src.is_single_phys_reg() && wordSize == 4) { + Register tmp = L2; + if (dst.first()->is_reg() && + (wordSize == 8 || dst.first()->as_Register()->is_even())) { + tmp = dst.first()->as_Register(); + } + + int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; + if (Assembler::is_simm13(off)) { + __ stx(src.first()->as_Register(), SP, off); + __ ld_long(SP, off, tmp); + } else { + if (conversion_off == noreg) { + __ set(off, L6); + conversion_off = L6; + } + __ stx(src.first()->as_Register(), SP, conversion_off); + __ ld_long(SP, conversion_off, tmp); + } + + if (tmp == L2) { + long_move(masm, reg64_to_VMRegPair(L2), dst); + } + } else { + long_move(masm, src, dst); + } + break; + + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); + + default: + move32_64(masm, src, dst); + } + } + + + // If we have any strings we must store any register based arg to the stack + // This includes any still live xmm registers too. + + if (total_strings > 0 ) { + + // protect all the arg registers + __ save_frame(0); + __ mov(G2_thread, L7_thread_cache); + const Register L2_string_off = L2; + + // Get first string offset + __ set(string_locs * VMRegImpl::stack_slot_size, L2_string_off); + + for (c_arg = 0 ; c_arg < total_c_args ; c_arg++ ) { + if (out_sig_bt[c_arg] == T_ADDRESS) { + + VMRegPair dst = out_regs[c_arg]; + const Register d = dst.first()->is_reg() ? + dst.first()->as_Register()->after_save() : noreg; + + // It's a string the oop and it was already copied to the out arg + // position + if (d != noreg) { + __ mov(d, O0); + } else { + assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), + "must be"); + __ ld_ptr(FP, reg2offset(dst.first()) + STACK_BIAS, O0); + } + Label skip; + + __ br_null(O0, false, Assembler::pn, skip); + __ delayed()->add(FP, L2_string_off, O1); + + if (d != noreg) { + __ mov(O1, d); + } else { + assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), + "must be"); + __ st_ptr(O1, FP, reg2offset(dst.first()) + STACK_BIAS); + } + + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::get_utf), + relocInfo::runtime_call_type); + __ delayed()->add(L2_string_off, max_dtrace_string_size, L2_string_off); + + __ bind(skip); + + } + + } + __ mov(L7_thread_cache, G2_thread); + __ restore(); + + } + + + // Ok now we are done. Need to place the nop that dtrace wants in order to + // patch in the trap + + int patch_offset = ((intptr_t)__ pc()) - start; + + __ nop(); + + + // Return + + __ ret(); + __ delayed()->restore(); + + __ flush(); + + nmethod *nm = nmethod::new_dtrace_nmethod( + method, masm->code(), vep_offset, patch_offset, frame_complete, + stack_slots / VMRegImpl::slots_per_word); + return nm; + +} + +#endif // HAVE_DTRACE_H + // this function returns the adjust size (in number of words) to a c2i adapter // activation for use during deoptimization int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { diff --git a/src/cpu/x86/vm/nativeInst_x86.cpp b/src/cpu/x86/vm/nativeInst_x86.cpp index a501aef8fa2abb85568c343512c7ba5f3c1b542a..9133af54123f808e41fe9a215bd857cd01b97674 100644 --- a/src/cpu/x86/vm/nativeInst_x86.cpp +++ b/src/cpu/x86/vm/nativeInst_x86.cpp @@ -472,3 +472,7 @@ address NativeGeneralJump::jump_destination() const { else return addr_at(0) + length + sbyte_at(offset); } + +bool NativeInstruction::is_dtrace_trap() { + return (*(int32_t*)this & 0xff) == 0xcc; +} diff --git a/src/cpu/x86/vm/nativeInst_x86.hpp b/src/cpu/x86/vm/nativeInst_x86.hpp index 12b7b0f548666950e3a0a142ed3f23ef3af4dba9..f4115bcf9859819bc61323412444357a5e612fd5 100644 --- a/src/cpu/x86/vm/nativeInst_x86.hpp +++ b/src/cpu/x86/vm/nativeInst_x86.hpp @@ -50,6 +50,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { }; bool is_nop() { return ubyte_at(0) == nop_instruction_code; } + bool is_dtrace_trap(); inline bool is_call(); inline bool is_illegal(); inline bool is_return(); diff --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 3d30eb251ed486acef36ecc765056f60ae790891..7dc635d0c3406667088027a2b96625c92afde3f8 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1880,6 +1880,379 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, } +#ifdef HAVE_DTRACE_H +// --------------------------------------------------------------------------- +// Generate a dtrace nmethod for a given signature. The method takes arguments +// in the Java compiled code convention, marshals them to the native +// abi and then leaves nops at the position you would expect to call a native +// function. When the probe is enabled the nops are replaced with a trap +// instruction that dtrace inserts and the trace will cause a notification +// to dtrace. +// +// The probes are only able to take primitive types and java/lang/String as +// arguments. No other java types are allowed. Strings are converted to utf8 +// strings so that from dtrace point of view java strings are converted to C +// strings. There is an arbitrary fixed limit on the total space that a method +// can use for converting the strings. (256 chars per string in the signature). +// So any java string larger then this is truncated. + +nmethod *SharedRuntime::generate_dtrace_nmethod( + MacroAssembler *masm, methodHandle method) { + + // generate_dtrace_nmethod is guarded by a mutex so we are sure to + // be single threaded in this method. + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); + + // Fill in the signature array, for the calling-convention call. + int total_args_passed = method->size_of_parameters(); + + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); + + // The signature we are going to use for the trap that dtrace will see + // java/lang/String is converted. We drop "this" and any other object + // is converted to NULL. (A one-slot java/lang/Long object reference + // is converted to a two-slot long, which is why we double the allocation). + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); + + int i=0; + int total_strings = 0; + int first_arg_to_pass = 0; + int total_c_args = 0; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); + + if( !method->is_static() ) { // Pass in receiver first + in_sig_bt[i++] = T_OBJECT; + first_arg_to_pass = 1; + } + + // We need to convert the java args to where a native (non-jni) function + // would expect them. To figure out where they go we convert the java + // signature to a C signature. + + SignatureStream ss(method->signature()); + for ( ; !ss.at_return_type(); ss.next()) { + BasicType bt = ss.type(); + in_sig_bt[i++] = bt; // Collect remaining bits of signature + out_sig_bt[total_c_args++] = bt; + if( bt == T_OBJECT) { + symbolOop s = ss.as_symbol_or_null(); + if (s == vmSymbols::java_lang_String()) { + total_strings++; + out_sig_bt[total_c_args-1] = T_ADDRESS; + } else if (s == vmSymbols::java_lang_Boolean() || + s == vmSymbols::java_lang_Character() || + s == vmSymbols::java_lang_Byte() || + s == vmSymbols::java_lang_Short() || + s == vmSymbols::java_lang_Integer() || + s == vmSymbols::java_lang_Float()) { + out_sig_bt[total_c_args-1] = T_INT; + } else if (s == vmSymbols::java_lang_Long() || + s == vmSymbols::java_lang_Double()) { + out_sig_bt[total_c_args-1] = T_LONG; + out_sig_bt[total_c_args++] = T_VOID; + } + } else if ( bt == T_LONG || bt == T_DOUBLE ) { + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + out_sig_bt[total_c_args++] = T_VOID; + } + } + + assert(i==total_args_passed, "validly parsed signature"); + + // Now get the compiled-Java layout as input arguments + int comp_args_on_stack; + comp_args_on_stack = SharedRuntime::java_calling_convention( + in_sig_bt, in_regs, total_args_passed, false); + + // Now figure out where the args must be stored and how much stack space + // they require (neglecting out_preserve_stack_slots). + + int out_arg_slots; + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); + + // Calculate the total number of stack slots we will need. + + // First count the abi requirement plus all of the outgoing args + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; + + // Now space for the string(s) we must convert + + int* string_locs = NEW_RESOURCE_ARRAY(int, total_strings + 1); + for (i = 0; i < total_strings ; i++) { + string_locs[i] = stack_slots; + stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size; + } + + // + 2 for return address (which we own) and saved rbp, + + stack_slots += 2; + + // Ok The space we have allocated will look like: + // + // + // FP-> | | + // |---------------------| + // | string[n] | + // |---------------------| <- string_locs[n] + // | string[n-1] | + // |---------------------| <- string_locs[n-1] + // | ... | + // | ... | + // |---------------------| <- string_locs[1] + // | string[0] | + // |---------------------| <- string_locs[0] + // | outbound memory | + // | based arguments | + // | | + // |---------------------| + // | | + // SP-> | out_preserved_slots | + // + // + + // Now compute actual number of stack words we need rounding to make + // stack properly aligned. + stack_slots = round_to(stack_slots, 2 * VMRegImpl::slots_per_word); + + int stack_size = stack_slots * VMRegImpl::stack_slot_size; + + intptr_t start = (intptr_t)__ pc(); + + // First thing make an ic check to see if we should even be here + + // We are free to use all registers as temps without saving them and + // restoring them except rbp. rbp, is the only callee save register + // as far as the interpreter and the compiler(s) are concerned. + + const Register ic_reg = rax; + const Register receiver = rcx; + Label hit; + Label exception_pending; + + + __ verify_oop(receiver); + __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); + __ jcc(Assembler::equal, hit); + + __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + + // verified entry must be aligned for code patching. + // and the first 5 bytes must be in the same cache line + // if we align at 8 then we will be sure 5 bytes are in the same line + __ align(8); + + __ bind(hit); + + int vep_offset = ((intptr_t)__ pc()) - start; + + + // The instruction at the verified entry point must be 5 bytes or longer + // because it can be patched on the fly by make_non_entrant. The stack bang + // instruction fits that requirement. + + // Generate stack overflow check + + + if (UseStackBanging) { + if (stack_size <= StackShadowPages*os::vm_page_size()) { + __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); + } else { + __ movl(rax, stack_size); + __ bang_stack_size(rax, rbx); + } + } else { + // need a 5 byte instruction to allow MT safe patching to non-entrant + __ fat_nop(); + } + + assert(((int)__ pc() - start - vep_offset) >= 5, + "valid size for make_non_entrant"); + + // Generate a new frame for the wrapper. + __ enter(); + + // -2 because return address is already present and so is saved rbp, + if (stack_size - 2*wordSize != 0) { + __ subl(rsp, stack_size - 2*wordSize); + } + + // Frame is now completed as far a size and linkage. + + int frame_complete = ((intptr_t)__ pc()) - start; + + // First thing we do store all the args as if we are doing the call. + // Since the C calling convention is stack based that ensures that + // all the Java register args are stored before we need to convert any + // string we might have. + + int sid = 0; + int c_arg, j_arg; + int string_reg = 0; + + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + + VMRegPair src = in_regs[j_arg]; + VMRegPair dst = out_regs[c_arg]; + assert(dst.first()->is_stack() || in_sig_bt[j_arg] == T_VOID, + "stack based abi assumed"); + + switch (in_sig_bt[j_arg]) { + + case T_ARRAY: + case T_OBJECT: + if (out_sig_bt[c_arg] == T_ADDRESS) { + // Any register based arg for a java string after the first + // will be destroyed by the call to get_utf so we store + // the original value in the location the utf string address + // will eventually be stored. + if (src.first()->is_reg()) { + if (string_reg++ != 0) { + simple_move32(masm, src, dst); + } + } + } else if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { + // need to unbox a one-word value + Register in_reg = rax; + if ( src.first()->is_reg() ) { + in_reg = src.first()->as_Register(); + } else { + simple_move32(masm, src, in_reg->as_VMReg()); + } + Label skipUnbox; + __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD); + if ( out_sig_bt[c_arg] == T_LONG ) { + __ movl(Address(rsp, reg2offset_out(dst.second())), NULL_WORD); + } + __ testl(in_reg, in_reg); + __ jcc(Assembler::zero, skipUnbox); + assert(dst.first()->is_stack() && + (!dst.second()->is_valid() || dst.second()->is_stack()), + "value(s) must go into stack slots"); + if ( out_sig_bt[c_arg] == T_LONG ) { + __ movl(rbx, Address(in_reg, + box_offset + VMRegImpl::stack_slot_size)); + __ movl(Address(rsp, reg2offset_out(dst.second())), rbx); + } + __ movl(in_reg, Address(in_reg, box_offset)); + __ movl(Address(rsp, reg2offset_out(dst.first())), in_reg); + __ bind(skipUnbox); + } else { + // Convert the arg to NULL + __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD); + } + if (out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // Move over the T_VOID To keep the loop indices in sync + } + break; + + case T_VOID: + break; + + case T_FLOAT: + float_move(masm, src, dst); + break; + + case T_DOUBLE: + assert( j_arg + 1 < total_args_passed && + in_sig_bt[j_arg + 1] == T_VOID, "bad arg list"); + double_move(masm, src, dst); + break; + + case T_LONG : + long_move(masm, src, dst); + break; + + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); + + default: + simple_move32(masm, src, dst); + } + } + + // Now we must convert any string we have to utf8 + // + + for (sid = 0, j_arg = first_arg_to_pass, c_arg = 0 ; + sid < total_strings ; j_arg++, c_arg++ ) { + + if (out_sig_bt[c_arg] == T_ADDRESS) { + + Address utf8_addr = Address( + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); + __ leal(rax, utf8_addr); + + // The first string we find might still be in the original java arg + // register + VMReg orig_loc = in_regs[j_arg].first(); + Register string_oop; + + // This is where the argument will eventually reside + Address dest = Address(rsp, reg2offset_out(out_regs[c_arg].first())); + + if (sid == 1 && orig_loc->is_reg()) { + string_oop = orig_loc->as_Register(); + assert(string_oop != rax, "smashed arg"); + } else { + + if (orig_loc->is_reg()) { + // Get the copy of the jls object + __ movl(rcx, dest); + } else { + // arg is still in the original location + __ movl(rcx, Address(rbp, reg2offset_in(orig_loc))); + } + string_oop = rcx; + + } + Label nullString; + __ movl(dest, NULL_WORD); + __ testl(string_oop, string_oop); + __ jcc(Assembler::zero, nullString); + + // Now we can store the address of the utf string as the argument + __ movl(dest, rax); + + // And do the conversion + __ call_VM_leaf(CAST_FROM_FN_PTR( + address, SharedRuntime::get_utf), string_oop, rax); + __ bind(nullString); + } + + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // Move over the T_VOID To keep the loop indices in sync + } + } + + + // Ok now we are done. Need to place the nop that dtrace wants in order to + // patch in the trap + + int patch_offset = ((intptr_t)__ pc()) - start; + + __ nop(); + + + // Return + + __ leave(); + __ ret(0); + + __ flush(); + + nmethod *nm = nmethod::new_dtrace_nmethod( + method, masm->code(), vep_offset, patch_offset, frame_complete, + stack_slots / VMRegImpl::slots_per_word); + return nm; + +} + +#endif // HAVE_DTRACE_H + // this function returns the adjust size (in number of words) to a c2i adapter // activation for use during deoptimization int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) { diff --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index aa3e0493a4ca6e85845965f760c2381ec3a42c80..8fa458680d3e708f81d125e39b191efb147989fb 100644 --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -1886,6 +1886,627 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, } +#ifdef HAVE_DTRACE_H +// --------------------------------------------------------------------------- +// Generate a dtrace nmethod for a given signature. The method takes arguments +// in the Java compiled code convention, marshals them to the native +// abi and then leaves nops at the position you would expect to call a native +// function. When the probe is enabled the nops are replaced with a trap +// instruction that dtrace inserts and the trace will cause a notification +// to dtrace. +// +// The probes are only able to take primitive types and java/lang/String as +// arguments. No other java types are allowed. Strings are converted to utf8 +// strings so that from dtrace point of view java strings are converted to C +// strings. There is an arbitrary fixed limit on the total space that a method +// can use for converting the strings. (256 chars per string in the signature). +// So any java string larger then this is truncated. + +static int fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 }; +static bool offsets_initialized = false; + + +nmethod *SharedRuntime::generate_dtrace_nmethod(MacroAssembler *masm, + methodHandle method) { + + + // generate_dtrace_nmethod is guarded by a mutex so we are sure to + // be single threaded in this method. + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); + + if (!offsets_initialized) { + fp_offset[c_rarg0->as_VMReg()->value()] = -1 * wordSize; + fp_offset[c_rarg1->as_VMReg()->value()] = -2 * wordSize; + fp_offset[c_rarg2->as_VMReg()->value()] = -3 * wordSize; + fp_offset[c_rarg3->as_VMReg()->value()] = -4 * wordSize; + fp_offset[c_rarg4->as_VMReg()->value()] = -5 * wordSize; + fp_offset[c_rarg5->as_VMReg()->value()] = -6 * wordSize; + + fp_offset[c_farg0->as_VMReg()->value()] = -7 * wordSize; + fp_offset[c_farg1->as_VMReg()->value()] = -8 * wordSize; + fp_offset[c_farg2->as_VMReg()->value()] = -9 * wordSize; + fp_offset[c_farg3->as_VMReg()->value()] = -10 * wordSize; + fp_offset[c_farg4->as_VMReg()->value()] = -11 * wordSize; + fp_offset[c_farg5->as_VMReg()->value()] = -12 * wordSize; + fp_offset[c_farg6->as_VMReg()->value()] = -13 * wordSize; + fp_offset[c_farg7->as_VMReg()->value()] = -14 * wordSize; + + offsets_initialized = true; + } + // Fill in the signature array, for the calling-convention call. + int total_args_passed = method->size_of_parameters(); + + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); + + // The signature we are going to use for the trap that dtrace will see + // java/lang/String is converted. We drop "this" and any other object + // is converted to NULL. (A one-slot java/lang/Long object reference + // is converted to a two-slot long, which is why we double the allocation). + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); + + int i=0; + int total_strings = 0; + int first_arg_to_pass = 0; + int total_c_args = 0; + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); + + // Skip the receiver as dtrace doesn't want to see it + if( !method->is_static() ) { + in_sig_bt[i++] = T_OBJECT; + first_arg_to_pass = 1; + } + + // We need to convert the java args to where a native (non-jni) function + // would expect them. To figure out where they go we convert the java + // signature to a C signature. + + SignatureStream ss(method->signature()); + for ( ; !ss.at_return_type(); ss.next()) { + BasicType bt = ss.type(); + in_sig_bt[i++] = bt; // Collect remaining bits of signature + out_sig_bt[total_c_args++] = bt; + if( bt == T_OBJECT) { + symbolOop s = ss.as_symbol_or_null(); + if (s == vmSymbols::java_lang_String()) { + total_strings++; + out_sig_bt[total_c_args-1] = T_ADDRESS; + } else if (s == vmSymbols::java_lang_Boolean() || + s == vmSymbols::java_lang_Character() || + s == vmSymbols::java_lang_Byte() || + s == vmSymbols::java_lang_Short() || + s == vmSymbols::java_lang_Integer() || + s == vmSymbols::java_lang_Float()) { + out_sig_bt[total_c_args-1] = T_INT; + } else if (s == vmSymbols::java_lang_Long() || + s == vmSymbols::java_lang_Double()) { + out_sig_bt[total_c_args-1] = T_LONG; + out_sig_bt[total_c_args++] = T_VOID; + } + } else if ( bt == T_LONG || bt == T_DOUBLE ) { + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots + // We convert double to long + out_sig_bt[total_c_args-1] = T_LONG; + out_sig_bt[total_c_args++] = T_VOID; + } else if ( bt == T_FLOAT) { + // We convert float to int + out_sig_bt[total_c_args-1] = T_INT; + } + } + + assert(i==total_args_passed, "validly parsed signature"); + + // Now get the compiled-Java layout as input arguments + int comp_args_on_stack; + comp_args_on_stack = SharedRuntime::java_calling_convention( + in_sig_bt, in_regs, total_args_passed, false); + + // Now figure out where the args must be stored and how much stack space + // they require (neglecting out_preserve_stack_slots but space for storing + // the 1st six register arguments). It's weird see int_stk_helper. + + int out_arg_slots; + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); + + // Calculate the total number of stack slots we will need. + + // First count the abi requirement plus all of the outgoing args + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; + + // Now space for the string(s) we must convert + int* string_locs = NEW_RESOURCE_ARRAY(int, total_strings + 1); + for (i = 0; i < total_strings ; i++) { + string_locs[i] = stack_slots; + stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size; + } + + // Plus the temps we might need to juggle register args + // regs take two slots each + stack_slots += (Argument::n_int_register_parameters_c + + Argument::n_float_register_parameters_c) * 2; + + + // + 4 for return address (which we own) and saved rbp, + + stack_slots += 4; + + // Ok The space we have allocated will look like: + // + // + // FP-> | | + // |---------------------| + // | string[n] | + // |---------------------| <- string_locs[n] + // | string[n-1] | + // |---------------------| <- string_locs[n-1] + // | ... | + // | ... | + // |---------------------| <- string_locs[1] + // | string[0] | + // |---------------------| <- string_locs[0] + // | outbound memory | + // | based arguments | + // | | + // |---------------------| + // | | + // SP-> | out_preserved_slots | + // + // + + // Now compute actual number of stack words we need rounding to make + // stack properly aligned. + stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word); + + int stack_size = stack_slots * VMRegImpl::stack_slot_size; + + intptr_t start = (intptr_t)__ pc(); + + // First thing make an ic check to see if we should even be here + + // We are free to use all registers as temps without saving them and + // restoring them except rbp. rbp, is the only callee save register + // as far as the interpreter and the compiler(s) are concerned. + + const Register ic_reg = rax; + const Register receiver = rcx; + Label hit; + Label exception_pending; + + + __ verify_oop(receiver); + __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); + __ jcc(Assembler::equal, hit); + + __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + + // verified entry must be aligned for code patching. + // and the first 5 bytes must be in the same cache line + // if we align at 8 then we will be sure 5 bytes are in the same line + __ align(8); + + __ bind(hit); + + int vep_offset = ((intptr_t)__ pc()) - start; + + + // The instruction at the verified entry point must be 5 bytes or longer + // because it can be patched on the fly by make_non_entrant. The stack bang + // instruction fits that requirement. + + // Generate stack overflow check + + if (UseStackBanging) { + if (stack_size <= StackShadowPages*os::vm_page_size()) { + __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); + } else { + __ movl(rax, stack_size); + __ bang_stack_size(rax, rbx); + } + } else { + // need a 5 byte instruction to allow MT safe patching to non-entrant + __ fat_nop(); + } + + assert(((uintptr_t)__ pc() - start - vep_offset) >= 5, + "valid size for make_non_entrant"); + + // Generate a new frame for the wrapper. + __ enter(); + + // -4 because return address is already present and so is saved rbp, + if (stack_size - 2*wordSize != 0) { + __ subq(rsp, stack_size - 2*wordSize); + } + + // Frame is now completed as far a size and linkage. + + int frame_complete = ((intptr_t)__ pc()) - start; + + int c_arg, j_arg; + + // State of input register args + + bool live[ConcreteRegisterImpl::number_of_registers]; + + live[j_rarg0->as_VMReg()->value()] = false; + live[j_rarg1->as_VMReg()->value()] = false; + live[j_rarg2->as_VMReg()->value()] = false; + live[j_rarg3->as_VMReg()->value()] = false; + live[j_rarg4->as_VMReg()->value()] = false; + live[j_rarg5->as_VMReg()->value()] = false; + + live[j_farg0->as_VMReg()->value()] = false; + live[j_farg1->as_VMReg()->value()] = false; + live[j_farg2->as_VMReg()->value()] = false; + live[j_farg3->as_VMReg()->value()] = false; + live[j_farg4->as_VMReg()->value()] = false; + live[j_farg5->as_VMReg()->value()] = false; + live[j_farg6->as_VMReg()->value()] = false; + live[j_farg7->as_VMReg()->value()] = false; + + + bool rax_is_zero = false; + + // All args (except strings) destined for the stack are moved first + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + VMRegPair src = in_regs[j_arg]; + VMRegPair dst = out_regs[c_arg]; + + // Get the real reg value or a dummy (rsp) + + int src_reg = src.first()->is_reg() ? + src.first()->value() : + rsp->as_VMReg()->value(); + + bool useless = in_sig_bt[j_arg] == T_ARRAY || + (in_sig_bt[j_arg] == T_OBJECT && + out_sig_bt[c_arg] != T_INT && + out_sig_bt[c_arg] != T_ADDRESS && + out_sig_bt[c_arg] != T_LONG); + + live[src_reg] = !useless; + + if (dst.first()->is_stack()) { + + // Even though a string arg in a register is still live after this loop + // after the string conversion loop (next) it will be dead so we take + // advantage of that now for simpler code to manage live. + + live[src_reg] = false; + switch (in_sig_bt[j_arg]) { + + case T_ARRAY: + case T_OBJECT: + { + Address stack_dst(rsp, reg2offset_out(dst.first())); + + if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { + // need to unbox a one-word value + Register in_reg = rax; + if ( src.first()->is_reg() ) { + in_reg = src.first()->as_Register(); + } else { + __ movq(rax, Address(rbp, reg2offset_in(src.first()))); + rax_is_zero = false; + } + Label skipUnbox; + __ movptr(Address(rsp, reg2offset_out(dst.first())), + (int32_t)NULL_WORD); + __ testq(in_reg, in_reg); + __ jcc(Assembler::zero, skipUnbox); + + Address src1(in_reg, box_offset); + if ( out_sig_bt[c_arg] == T_LONG ) { + __ movq(in_reg, src1); + __ movq(stack_dst, in_reg); + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // skip over T_VOID to keep the loop indices in sync + } else { + __ movl(in_reg, src1); + __ movl(stack_dst, in_reg); + } + + __ bind(skipUnbox); + } else if (out_sig_bt[c_arg] != T_ADDRESS) { + // Convert the arg to NULL + if (!rax_is_zero) { + __ xorq(rax, rax); + rax_is_zero = true; + } + __ movq(stack_dst, rax); + } + } + break; + + case T_VOID: + break; + + case T_FLOAT: + // This does the right thing since we know it is destined for the + // stack + float_move(masm, src, dst); + break; + + case T_DOUBLE: + // This does the right thing since we know it is destined for the + // stack + double_move(masm, src, dst); + break; + + case T_LONG : + long_move(masm, src, dst); + break; + + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); + + default: + move32_64(masm, src, dst); + } + } + + } + + // If we have any strings we must store any register based arg to the stack + // This includes any still live xmm registers too. + + int sid = 0; + + if (total_strings > 0 ) { + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + VMRegPair src = in_regs[j_arg]; + VMRegPair dst = out_regs[c_arg]; + + if (src.first()->is_reg()) { + Address src_tmp(rbp, fp_offset[src.first()->value()]); + + // string oops were left untouched by the previous loop even if the + // eventual (converted) arg is destined for the stack so park them + // away now (except for first) + + if (out_sig_bt[c_arg] == T_ADDRESS) { + Address utf8_addr = Address( + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); + if (sid != 1) { + // The first string arg won't be killed until after the utf8 + // conversion + __ movq(utf8_addr, src.first()->as_Register()); + } + } else if (dst.first()->is_reg()) { + if (in_sig_bt[j_arg] == T_FLOAT || in_sig_bt[j_arg] == T_DOUBLE) { + + // Convert the xmm register to an int and store it in the reserved + // location for the eventual c register arg + XMMRegister f = src.first()->as_XMMRegister(); + if (in_sig_bt[j_arg] == T_FLOAT) { + __ movflt(src_tmp, f); + } else { + __ movdbl(src_tmp, f); + } + } else { + // If the arg is an oop type we don't support don't bother to store + // it remember string was handled above. + bool useless = in_sig_bt[j_arg] == T_ARRAY || + (in_sig_bt[j_arg] == T_OBJECT && + out_sig_bt[c_arg] != T_INT && + out_sig_bt[c_arg] != T_LONG); + + if (!useless) { + __ movq(src_tmp, src.first()->as_Register()); + } + } + } + } + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // skip over T_VOID to keep the loop indices in sync + } + } + + // Now that the volatile registers are safe, convert all the strings + sid = 0; + + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + if (out_sig_bt[c_arg] == T_ADDRESS) { + // It's a string + Address utf8_addr = Address( + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); + // The first string we find might still be in the original java arg + // register + + VMReg src = in_regs[j_arg].first(); + + // We will need to eventually save the final argument to the trap + // in the von-volatile location dedicated to src. This is the offset + // from fp we will use. + int src_off = src->is_reg() ? + fp_offset[src->value()] : reg2offset_in(src); + + // This is where the argument will eventually reside + VMRegPair dst = out_regs[c_arg]; + + if (src->is_reg()) { + if (sid == 1) { + __ movq(c_rarg0, src->as_Register()); + } else { + __ movq(c_rarg0, utf8_addr); + } + } else { + // arg is still in the original location + __ movq(c_rarg0, Address(rbp, reg2offset_in(src))); + } + Label done, convert; + + // see if the oop is NULL + __ testq(c_rarg0, c_rarg0); + __ jcc(Assembler::notEqual, convert); + + if (dst.first()->is_reg()) { + // Save the ptr to utf string in the origina src loc or the tmp + // dedicated to it + __ movq(Address(rbp, src_off), c_rarg0); + } else { + __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg0); + } + __ jmp(done); + + __ bind(convert); + + __ lea(c_rarg1, utf8_addr); + if (dst.first()->is_reg()) { + __ movq(Address(rbp, src_off), c_rarg1); + } else { + __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg1); + } + // And do the conversion + __ call(RuntimeAddress( + CAST_FROM_FN_PTR(address, SharedRuntime::get_utf))); + + __ bind(done); + } + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // skip over T_VOID to keep the loop indices in sync + } + } + // The get_utf call killed all the c_arg registers + live[c_rarg0->as_VMReg()->value()] = false; + live[c_rarg1->as_VMReg()->value()] = false; + live[c_rarg2->as_VMReg()->value()] = false; + live[c_rarg3->as_VMReg()->value()] = false; + live[c_rarg4->as_VMReg()->value()] = false; + live[c_rarg5->as_VMReg()->value()] = false; + + live[c_farg0->as_VMReg()->value()] = false; + live[c_farg1->as_VMReg()->value()] = false; + live[c_farg2->as_VMReg()->value()] = false; + live[c_farg3->as_VMReg()->value()] = false; + live[c_farg4->as_VMReg()->value()] = false; + live[c_farg5->as_VMReg()->value()] = false; + live[c_farg6->as_VMReg()->value()] = false; + live[c_farg7->as_VMReg()->value()] = false; + } + + // Now we can finally move the register args to their desired locations + + rax_is_zero = false; + + for (j_arg = first_arg_to_pass, c_arg = 0 ; + j_arg < total_args_passed ; j_arg++, c_arg++ ) { + + VMRegPair src = in_regs[j_arg]; + VMRegPair dst = out_regs[c_arg]; + + // Only need to look for args destined for the interger registers (since we + // convert float/double args to look like int/long outbound) + if (dst.first()->is_reg()) { + Register r = dst.first()->as_Register(); + + // Check if the java arg is unsupported and thereofre useless + bool useless = in_sig_bt[j_arg] == T_ARRAY || + (in_sig_bt[j_arg] == T_OBJECT && + out_sig_bt[c_arg] != T_INT && + out_sig_bt[c_arg] != T_ADDRESS && + out_sig_bt[c_arg] != T_LONG); + + + // If we're going to kill an existing arg save it first + if (live[dst.first()->value()]) { + // you can't kill yourself + if (src.first() != dst.first()) { + __ movq(Address(rbp, fp_offset[dst.first()->value()]), r); + } + } + if (src.first()->is_reg()) { + if (live[src.first()->value()] ) { + if (in_sig_bt[j_arg] == T_FLOAT) { + __ movdl(r, src.first()->as_XMMRegister()); + } else if (in_sig_bt[j_arg] == T_DOUBLE) { + __ movdq(r, src.first()->as_XMMRegister()); + } else if (r != src.first()->as_Register()) { + if (!useless) { + __ movq(r, src.first()->as_Register()); + } + } + } else { + // If the arg is an oop type we don't support don't bother to store + // it + if (!useless) { + if (in_sig_bt[j_arg] == T_DOUBLE || + in_sig_bt[j_arg] == T_LONG || + in_sig_bt[j_arg] == T_OBJECT ) { + __ movq(r, Address(rbp, fp_offset[src.first()->value()])); + } else { + __ movl(r, Address(rbp, fp_offset[src.first()->value()])); + } + } + } + live[src.first()->value()] = false; + } else if (!useless) { + // full sized move even for int should be ok + __ movq(r, Address(rbp, reg2offset_in(src.first()))); + } + + // At this point r has the original java arg in the final location + // (assuming it wasn't useless). If the java arg was an oop + // we have a bit more to do + + if (in_sig_bt[j_arg] == T_ARRAY || in_sig_bt[j_arg] == T_OBJECT ) { + if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { + // need to unbox a one-word value + Label skip; + __ testq(r, r); + __ jcc(Assembler::equal, skip); + Address src1(r, box_offset); + if ( out_sig_bt[c_arg] == T_LONG ) { + __ movq(r, src1); + } else { + __ movl(r, src1); + } + __ bind(skip); + + } else if (out_sig_bt[c_arg] != T_ADDRESS) { + // Convert the arg to NULL + __ xorq(r, r); + } + } + + // dst can longer be holding an input value + live[dst.first()->value()] = false; + } + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); + ++c_arg; // skip over T_VOID to keep the loop indices in sync + } + } + + + // Ok now we are done. Need to place the nop that dtrace wants in order to + // patch in the trap + int patch_offset = ((intptr_t)__ pc()) - start; + + __ nop(); + + + // Return + + __ leave(); + __ ret(0); + + __ flush(); + + nmethod *nm = nmethod::new_dtrace_nmethod( + method, masm->code(), vep_offset, patch_offset, frame_complete, + stack_slots / VMRegImpl::slots_per_word); + return nm; + +} + +#endif // HAVE_DTRACE_H + // this function returns the adjust size (in number of words) to a c2i adapter // activation for use during deoptimization int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) { diff --git a/src/os/linux/vm/dtraceJSDT_linux.cpp b/src/os/linux/vm/dtraceJSDT_linux.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea0eab9b975b18bfa826e818e31a8d19d521f402 --- /dev/null +++ b/src/os/linux/vm/dtraceJSDT_linux.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_dtraceJSDT_linux.cpp.incl" + +int DTraceJSDT::pd_activate( + void* baseAddress, jstring module, + jint providers_count, JVM_DTraceProvider* providers) { + return -1; +} + +void DTraceJSDT::pd_dispose(int handle) { +} + +jboolean DTraceJSDT::pd_is_supported() { + return false; +} diff --git a/src/os/solaris/vm/dtraceJSDT_solaris.cpp b/src/os/solaris/vm/dtraceJSDT_solaris.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49f74216f16deea3947cb303e2f2682dcfb81a96 --- /dev/null +++ b/src/os/solaris/vm/dtraceJSDT_solaris.cpp @@ -0,0 +1,685 @@ +/* + * Copyright 2005-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_dtraceJSDT_solaris.cpp.incl" + +#ifdef HAVE_DTRACE_H + +#include +#include +#include +#include +#include + +static const char* devname = "/dev/dtrace/helper"; +static const char* olddevname = "/devices/pseudo/dtrace@0:helper"; + +static const char* string_sig = "uintptr_t"; +static const char* int_sig = "long"; +static const char* long_sig = "long long"; + +static void printDOFHelper(dof_helper_t* helper); + +static int dofhelper_open() { + int fd; + if ((fd = open64(devname, O_RDWR)) < 0) { + // Optimize next calls + devname = olddevname; + if ((fd = open64(devname, O_RDWR)) < 0) { + return -1; + } + } + return fd; +} + +static jint dof_register(jstring module, uint8_t* dof, void* modaddr) { + int probe; + dof_helper_t dh; + int fd; + + memset(&dh, 0, sizeof(dh)); + + char* module_name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(module)); + jio_snprintf(dh.dofhp_mod, sizeof(dh.dofhp_mod), "%s", module_name); + dh.dofhp_dof = (uint64_t)dof; + dh.dofhp_addr = (uint64_t)modaddr; + + fd = dofhelper_open(); + if (fd < 0) + return -1; + probe = ioctl(fd, DTRACEHIOC_ADDDOF, &dh); + close(fd); + if (PrintDTraceDOF) { + printDOFHelper(&dh); + tty->print_cr("DOF helper id = %d", probe); + } + return probe; +} + +int DTraceJSDT::pd_activate( + void* moduleBaseAddress, jstring module, + jint providers_count, JVM_DTraceProvider* providers) { + + // We need sections: + // (1) STRTAB + // ( + // (2) PROVIDER + // (3) PROBES + // (4) PROBOFFS + // (5) PROBARGS + // ) * Number of Providers + + // Type of sections we create + enum { + STRTAB = 0, + PROVIDERS = 1, + PROBES = 2, + PROBE_OFFSETS = 3, + ARG_OFFSETS = 4, + NUM_SECTIONS = 5 + }; + + static int alignment_for[NUM_SECTIONS] = { 1, 4, 8, 4, 1 }; + + ResourceMark rm; + + uint32_t num_sections = 1 + 4 * providers_count; + uint32_t offset = sizeof(dof_hdr_t) + (num_sections * sizeof(dof_sec_t)); + uint32_t* secoffs = NEW_RESOURCE_ARRAY(uint32_t, num_sections); + uint32_t* secsize = NEW_RESOURCE_ARRAY(uint32_t, num_sections); + + // Store offsets of all strings here in such order: + // zero-string (always 0) + // provider1-name + // probe1-function + // probe1-name + // arg-1 + // arg-2 + // ... + // probe2-function + // probe2-name + // arg-1 + // arg-2 + // provider2-name + // ... + + uint32_t strcount = 0; + // Count the number of strings we'll need + for(int prvc = 0; prvc < providers_count; ++prvc) { + JVM_DTraceProvider* provider = &providers[prvc]; + // Provider name + ++strcount; + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* p = &(provider->probes[prbc]); + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); + // function + name + one per argument + strcount += 2 + ArgumentCount(sig).size(); + } + } + + // Create place for string offsets + uint32_t* stroffs = NEW_RESOURCE_ARRAY(uint32_t, strcount + 1); + uint32_t string_index = 0; + uint32_t curstr = 0; + + // First we need an empty string: "" + stroffs[curstr++] = string_index; + string_index += strlen("") + 1; + + for(int prvc = 0; prvc < providers_count; ++prvc) { + JVM_DTraceProvider* provider = &providers[prvc]; + char* provider_name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(provider->name)); + stroffs[curstr++] = string_index; + string_index += strlen(provider_name) + 1; + + // All probes + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* p = &(provider->probes[prbc]); + + char* function = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(p->function)); + stroffs[curstr++] = string_index; + string_index += strlen(function) + 1; + + char* name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(p->name)); + stroffs[curstr++] = string_index; + string_index += strlen(name) + 1; + + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); + SignatureStream ss(sig); + for ( ; !ss.at_return_type(); ss.next()) { + BasicType bt = ss.type(); + const char* t = NULL; + if (bt == T_OBJECT && + ss.as_symbol_or_null() == vmSymbols::java_lang_String()) { + t = string_sig; + } else if (bt == T_LONG) { + t = long_sig; + } else { + t = int_sig; + } + stroffs[curstr++] = string_index; + string_index += strlen(t) + 1; + } + } + } + secoffs[STRTAB] = offset; + secsize[STRTAB] = string_index; + offset += string_index; + + // Calculate the size of the rest + for(int prvc = 0; prvc < providers_count; ++prvc) { + JVM_DTraceProvider* provider = &providers[prvc]; + size_t provider_sec = PROVIDERS + prvc * 4; + size_t probe_sec = PROBES + prvc * 4; + size_t probeoffs_sec = PROBE_OFFSETS + prvc * 4; + size_t argoffs_sec = ARG_OFFSETS + prvc * 4; + + // Allocate space for the provider data struction + secoffs[provider_sec] = align_size_up(offset, alignment_for[PROVIDERS]); + secsize[provider_sec] = sizeof(dof_provider_t); + offset = secoffs[provider_sec] + secsize[provider_sec]; + + // Allocate space for all the probes + secoffs[probe_sec] = align_size_up(offset, alignment_for[PROBES]); + secsize[probe_sec] = sizeof(dof_probe_t) * provider->probe_count; + offset = secoffs[probe_sec] + secsize[probe_sec]; + + // Allocate space for the probe offsets + secoffs[probeoffs_sec] = align_size_up(offset, alignment_for[PROBE_OFFSETS]); + secsize[probeoffs_sec] = sizeof(uint32_t) * provider->probe_count; + offset = secoffs[probeoffs_sec] + secsize[probeoffs_sec]; + + // We need number of arguments argoffs + uint32_t argscount = 0; + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* p = &(provider->probes[prbc]); + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); + argscount += ArgumentCount(sig).size(); + } + secoffs[argoffs_sec] = align_size_up(offset, alignment_for[ARG_OFFSETS]); + secsize[argoffs_sec] = sizeof(uint8_t) * argscount; + offset = secoffs[argoffs_sec] + secsize[argoffs_sec]; + } + + uint32_t size = offset; + + uint8_t* dof = NEW_RESOURCE_ARRAY(uint8_t, size); + if (!dof) { + return -1; + } + memset((void*)dof, 0, size); + + // Fill memory with proper values + dof_hdr_t* hdr = (dof_hdr_t*)dof; + hdr->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; + hdr->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; + hdr->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; + hdr->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; + hdr->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; // No variants + hdr->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; // No variants + hdr->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; // No variants + hdr->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION_2; // No variants + // all other fields of ident to zero + + hdr->dofh_flags = 0; + hdr->dofh_hdrsize = sizeof(dof_hdr_t); + hdr->dofh_secsize = sizeof(dof_sec_t); + hdr->dofh_secnum = num_sections; + hdr->dofh_secoff = sizeof(dof_hdr_t); + hdr->dofh_loadsz = size; + hdr->dofh_filesz = size; + + // First section: STRTAB + dof_sec_t* sec = (dof_sec_t*)(dof + sizeof(dof_hdr_t)); + sec->dofs_type = DOF_SECT_STRTAB; + sec->dofs_align = alignment_for[STRTAB]; + sec->dofs_flags = DOF_SECF_LOAD; + sec->dofs_entsize = 0; + sec->dofs_offset = secoffs[STRTAB]; + sec->dofs_size = secsize[STRTAB]; + // Make data for this section + char* str = (char*)(dof + sec->dofs_offset); + + *str = 0; str += 1; // "" + + // Run through all strings again + for(int prvc = 0; prvc < providers_count; ++prvc) { + JVM_DTraceProvider* provider = &providers[prvc]; + char* provider_name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(provider->name)); + strcpy(str, provider_name); + str += strlen(provider_name) + 1; + + // All probes + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* p = &(provider->probes[prbc]); + + char* function = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(p->function)); + strcpy(str, function); + str += strlen(str) + 1; + + char* name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(p->name)); + strcpy(str, name); + str += strlen(name) + 1; + + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); + SignatureStream ss(sig); + for ( ; !ss.at_return_type(); ss.next()) { + BasicType bt = ss.type(); + const char* t; + if (bt == T_OBJECT && + ss.as_symbol_or_null() == vmSymbols::java_lang_String()) { + t = string_sig; + } else if (bt == T_LONG) { + t = long_sig; + } else { + t = int_sig; + } + strcpy(str, t); + str += strlen(t) + 1; + } + } + } + + curstr = 1; + for(int prvc = 0; prvc < providers_count; ++prvc) { + JVM_DTraceProvider* provider = &providers[prvc]; + size_t provider_sec = PROVIDERS + prvc * 4; + size_t probe_sec = PROBES + prvc * 4; + size_t probeoffs_sec = PROBE_OFFSETS + prvc * 4; + size_t argoffs_sec = ARG_OFFSETS + prvc * 4; + + // PROVIDER /////////////////////////////////////////////////////////////// + // Section header + sec = (dof_sec_t*) + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * provider_sec); + sec->dofs_type = DOF_SECT_PROVIDER; + sec->dofs_align = alignment_for[PROVIDERS]; + sec->dofs_flags = DOF_SECF_LOAD; + sec->dofs_entsize = 0; + sec->dofs_offset = secoffs[provider_sec]; + sec->dofs_size = secsize[provider_sec]; + // Make provider decriiption + dof_provider_t* prv = (dof_provider_t*)(dof + sec->dofs_offset); + prv->dofpv_strtab = STRTAB; + prv->dofpv_probes = probe_sec; + prv->dofpv_prargs = argoffs_sec; + prv->dofpv_proffs = probeoffs_sec; + prv->dofpv_name = stroffs[curstr++]; // Index in string table + prv->dofpv_provattr = DOF_ATTR( + provider->providerAttributes.nameStability, + provider->providerAttributes.dataStability, + provider->providerAttributes.dependencyClass); + prv->dofpv_modattr = DOF_ATTR( + provider->moduleAttributes.nameStability, + provider->moduleAttributes.dataStability, + provider->moduleAttributes.dependencyClass); + prv->dofpv_funcattr = DOF_ATTR( + provider->functionAttributes.nameStability, + provider->functionAttributes.dataStability, + provider->functionAttributes.dependencyClass); + prv->dofpv_nameattr = DOF_ATTR( + provider->nameAttributes.nameStability, + provider->nameAttributes.dataStability, + provider->nameAttributes.dependencyClass); + prv->dofpv_argsattr = DOF_ATTR( + provider->argsAttributes.nameStability, + provider->argsAttributes.dataStability, + provider->argsAttributes.dependencyClass); + + // PROBES ///////////////////////////////////////////////////////////////// + // Section header + sec = (dof_sec_t*) + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * probe_sec); + sec->dofs_type = DOF_SECT_PROBES; + sec->dofs_align = alignment_for[PROBES]; + sec->dofs_flags = DOF_SECF_LOAD; + sec->dofs_entsize = sizeof(dof_probe_t); + sec->dofs_offset = secoffs[probe_sec]; + sec->dofs_size = secsize[probe_sec]; + // Make probes descriptions + uint32_t argsoffs = 0; + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* probe = &(provider->probes[prbc]); + methodOop m = JNIHandles::resolve_jmethod_id(probe->method); + int arg_count = ArgumentCount(m->signature()).size(); + assert(m->code() != NULL, "must have an nmethod"); + + dof_probe_t* prb = + (dof_probe_t*)(dof + sec->dofs_offset + prbc * sizeof(dof_probe_t)); + + prb->dofpr_addr = (uint64_t)m->code()->entry_point(); + prb->dofpr_func = stroffs[curstr++]; // Index in string table + prb->dofpr_name = stroffs[curstr++]; // Index in string table + prb->dofpr_nargv = stroffs[curstr ]; // Index in string table + // We spent siglen strings here + curstr += arg_count; + prb->dofpr_xargv = prb->dofpr_nargv; // Same bunch of strings + prb->dofpr_argidx = argsoffs; + prb->dofpr_offidx = prbc; + prb->dofpr_nargc = arg_count; + prb->dofpr_xargc = arg_count; + prb->dofpr_noffs = 1; // Number of offsets + // Next bunch of offsets + argsoffs += arg_count; + } + + // PROFFS ///////////////////////////////////////////////////////////////// + // Section header + sec = (dof_sec_t*) + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * probeoffs_sec); + sec->dofs_type = DOF_SECT_PROFFS; + sec->dofs_align = alignment_for[PROBE_OFFSETS]; + sec->dofs_flags = DOF_SECF_LOAD; + sec->dofs_entsize = sizeof(uint32_t); + sec->dofs_offset = secoffs[probeoffs_sec]; + sec->dofs_size = secsize[probeoffs_sec]; + // Make offsets + for (int prbc = 0; prbc < provider->probe_count; ++prbc) { + uint32_t* pof = + (uint32_t*)(dof + sec->dofs_offset + sizeof(uint32_t) * prbc); + JVM_DTraceProbe* probe = &(provider->probes[prbc]); + methodOop m = JNIHandles::resolve_jmethod_id(probe->method); + *pof = m->code()->trap_offset(); + } + + // PRARGS ///////////////////////////////////////////////////////////////// + // Section header + sec = (dof_sec_t*) + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * argoffs_sec); + sec->dofs_type = DOF_SECT_PRARGS; + sec->dofs_align = alignment_for[ARG_OFFSETS]; + sec->dofs_flags = DOF_SECF_LOAD; + sec->dofs_entsize = sizeof(uint8_t); + sec->dofs_offset = secoffs[argoffs_sec]; + sec->dofs_size = secsize[argoffs_sec]; + // Make arguments + uint8_t* par = (uint8_t*)(dof + sec->dofs_offset); + for (int prbc = 0; prbc < provider->probe_count; ++prbc) { + JVM_DTraceProbe* p = &(provider->probes[prbc]); + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); + uint8_t count = (uint8_t)ArgumentCount(sig).size(); + for (uint8_t i = 0; i < count; ++i) { + *par++ = i; + } + } + } + + // Register module + return dof_register(module, dof, moduleBaseAddress); +} + + +void DTraceJSDT::pd_dispose(int handle) { + int fd; + if (handle == -1) { + return; + } + fd = dofhelper_open(); + if (fd < 0) + return; + ioctl(fd, DTRACEHIOC_REMOVE, handle); + close(fd); +} + +jboolean DTraceJSDT::pd_is_supported() { + int fd = dofhelper_open(); + if (fd < 0) { + return false; + } + close(fd); + return true; +} + +static const char* dofSecTypeFor(uint32_t type) { + switch (type) { + case 0: return "DOF_SECT_NONE"; + case 1: return "DOF_SECT_COMMENTS"; + case 2: return "DOF_SECT_SOURCE"; + case 3: return "DOF_SECT_ECBDESC"; + case 4: return "DOF_SECT_PROBEDESC"; + case 5: return "DOF_SECT_ACTDESC"; + case 6: return "DOF_SECT_DIFOHDR"; + case 7: return "DOF_SECT_DIF"; + case 8: return "DOF_SECT_STRTAB"; + case 9: return "DOF_SECT_VARTAB"; + case 10: return "DOF_SECT_RELTAB"; + case 11: return "DOF_SECT_TYPETAB"; + case 12: return "DOF_SECT_URELHDR"; + case 13: return "DOF_SECT_KRELHDR"; + case 14: return "DOF_SECT_OPTDESC"; + case 15: return "DOF_SECT_PROVIDER"; + case 16: return "DOF_SECT_PROBES"; + case 17: return "DOF_SECT_PRARGS"; + case 18: return "DOF_SECT_PROFFS"; + case 19: return "DOF_SECT_INTTAB"; + case 20: return "DOF_SECT_UTSNAME"; + case 21: return "DOF_SECT_XLTAB"; + case 22: return "DOF_SECT_XLMEMBERS"; + case 23: return "DOF_SECT_XLIMPORT"; + case 24: return "DOF_SECT_XLEXPORT"; + case 25: return "DOF_SECT_PREXPORT"; + case 26: return "DOF_SECT_PRENOFFS"; + default: return ""; + } +} + +static void printDOFStringTabSec(void* dof, dof_sec_t* sec) { + size_t tab = sec->dofs_offset; + size_t limit = sec->dofs_size; + tty->print_cr("// String Table:"); + for (size_t idx = 0; idx < limit; /*empty*/) { + char* str = ((char*)dof) + tab + idx; + tty->print_cr("// [0x%x + 0x%x] '%s'", tab, idx, str); + idx += strlen(str) + 1; + } +} + +static void printDOFProviderSec(void* dof, dof_sec_t* sec) { + dof_provider_t* prov = (dof_provider_t*)((char*)dof + sec->dofs_offset); + tty->print_cr("// dof_provider_t {"); + tty->print_cr("// dofpv_strtab = %d", prov->dofpv_strtab); + tty->print_cr("// dofpv_probes = %d", prov->dofpv_probes); + tty->print_cr("// dofpv_prargs = %d", prov->dofpv_prargs); + tty->print_cr("// dofpv_proffs = %d", prov->dofpv_proffs); + tty->print_cr("// dofpv_name = 0x%x", prov->dofpv_name); + tty->print_cr("// dofpv_provattr = 0x%08x", prov->dofpv_provattr); + tty->print_cr("// dofpv_modattr = 0x%08x", prov->dofpv_modattr); + tty->print_cr("// dofpv_funcattr = 0x%08x", prov->dofpv_funcattr); + tty->print_cr("// dofpv_nameattr = 0x%08x", prov->dofpv_nameattr); + tty->print_cr("// dofpv_argsattr = 0x%08x", prov->dofpv_argsattr); + tty->print_cr("// }"); +} + +static void printDOFProbesSec(void* dof, dof_sec_t* sec) { + size_t idx = sec->dofs_offset; + size_t limit = idx + sec->dofs_size; + for (size_t idx = sec->dofs_offset; idx < limit; idx += sec->dofs_entsize) { + dof_probe_t* prb = (dof_probe_t*)((char*)dof + idx); + tty->print_cr("// dof_probe_t {"); + tty->print_cr("// dofpr_addr = 0x%016llx", prb->dofpr_addr); + tty->print_cr("// dofpr_func = 0x%x", prb->dofpr_func); + tty->print_cr("// dofpr_name = 0x%x", prb->dofpr_name); + tty->print_cr("// dofpr_nargv = 0x%x", prb->dofpr_nargv); + tty->print_cr("// dofpr_xargv = 0x%x", prb->dofpr_xargv); + tty->print_cr("// dofpr_argidx = 0x%x", prb->dofpr_argidx); + tty->print_cr("// dofpr_offidx = 0x%x", prb->dofpr_offidx); + tty->print_cr("// dofpr_nargc = %d", prb->dofpr_nargc); + tty->print_cr("// dofpr_xargc = %d", prb->dofpr_xargc); + tty->print_cr("// dofpr_noffs = %d", prb->dofpr_noffs); + tty->print_cr("// }"); + } +} + +static void printDOFOffsetsSec(void* dof, dof_sec_t* sec) { + size_t tab = sec->dofs_offset; + size_t limit = sec->dofs_size; + tty->print_cr("// Offsets:"); + for (size_t idx = 0; idx < limit; idx += sec->dofs_entsize) { + uint32_t* off = (uint32_t*)((char*)dof + tab + idx); + tty->print_cr("// [0x%x + 0x%x]: %d", tab, idx, *off); + } +} + +static void printDOFArgsSec(void* dof, dof_sec_t* sec) { + size_t tab = sec->dofs_offset; + size_t limit = sec->dofs_size; + tty->print_cr("// Arguments:"); + for (size_t idx = 0; idx < limit; idx += sec->dofs_entsize) { + uint8_t* arg = (uint8_t*)((char*)dof + tab + idx); + tty->print_cr("// [0x%x + 0x%x]: %d", tab, idx, *arg); + } +} + +static void printDOFSection(void* dof, dof_sec_t* sec) { + tty->print_cr("// dof_sec_t {"); + tty->print_cr("// dofs_type = 0x%x /* %s */", + sec->dofs_type, dofSecTypeFor(sec->dofs_type)); + tty->print_cr("// dofs_align = %d", sec->dofs_align); + tty->print_cr("// dofs_flags = 0x%x", sec->dofs_flags); + tty->print_cr("// dofs_entsize = %d", sec->dofs_entsize); + tty->print_cr("// dofs_offset = 0x%llx", sec->dofs_offset); + tty->print_cr("// dofs_size = %lld", sec->dofs_size); + tty->print_cr("// }"); + switch (sec->dofs_type) { + case DOF_SECT_STRTAB: printDOFStringTabSec(dof, sec); break; + case DOF_SECT_PROVIDER: printDOFProviderSec(dof, sec); break; + case DOF_SECT_PROBES: printDOFProbesSec(dof, sec); break; + case DOF_SECT_PROFFS: printDOFOffsetsSec(dof, sec); break; + case DOF_SECT_PRARGS: printDOFArgsSec(dof, sec); break; + default: tty->print_cr("//
"); + } +} + +static void printDOFHeader(dof_hdr_t* hdr) { + tty->print_cr("// dof_hdr_t {"); + tty->print_cr("// dofh_ident[DOF_ID_MAG0] = 0x%x", + hdr->dofh_ident[DOF_ID_MAG0]); + tty->print_cr("// dofh_ident[DOF_ID_MAG1] = 0x%x", + hdr->dofh_ident[DOF_ID_MAG1]); + tty->print_cr("// dofh_ident[DOF_ID_MAG2] = 0x%x", + hdr->dofh_ident[DOF_ID_MAG2]); + tty->print_cr("// dofh_ident[DOF_ID_MAG3] = 0x%x", + hdr->dofh_ident[DOF_ID_MAG3]); + tty->print_cr("// dofh_ident[DOF_ID_MODEL] = 0x%x", + hdr->dofh_ident[DOF_ID_MODEL]); + tty->print_cr("// dofh_ident[DOF_ID_ENCODING] = 0x%x", + hdr->dofh_ident[DOF_ID_ENCODING]); + tty->print_cr("// dofh_ident[DOF_ID_VERSION] = 0x%x", + hdr->dofh_ident[DOF_ID_VERSION]); + tty->print_cr("// dofh_ident[DOF_ID_DIFVERS] = 0x%x", + hdr->dofh_ident[DOF_ID_DIFVERS]); + tty->print_cr("// dofh_flags = 0x%x", hdr->dofh_flags); + tty->print_cr("// dofh_hdrsize = %d", hdr->dofh_hdrsize); + tty->print_cr("// dofh_secsize = %d", hdr->dofh_secsize); + tty->print_cr("// dofh_secnum = %d", hdr->dofh_secnum); + tty->print_cr("// dofh_secoff = %lld", hdr->dofh_secoff); + tty->print_cr("// dofh_loadsz = %lld", hdr->dofh_loadsz); + tty->print_cr("// dofh_filesz = %lld", hdr->dofh_filesz); + tty->print_cr("// }"); +} + +static void printDOF(void* dof) { + dof_hdr_t* hdr = (dof_hdr_t*)dof; + printDOFHeader(hdr); + for (int i = 0; i < hdr->dofh_secnum; ++i) { + dof_sec_t* sec = + (dof_sec_t*)((char*)dof + sizeof(dof_hdr_t) + i * sizeof(dof_sec_t)); + tty->print_cr("// [Section #%d]", i); + printDOFSection(dof, sec); + } +} + +/** + * This prints out hex data in a 'windbg' or 'xxd' form, where each line is: + * : 8 * + * example: + * 0000000: 7f44 4f46 0102 0102 0000 0000 0000 0000 .DOF............ + * 0000010: 0000 0000 0000 0040 0000 0020 0000 0005 .......@... .... + * 0000020: 0000 0000 0000 0040 0000 0000 0000 015d .......@.......] + * ... + */ +static void printDOFRawData(void* dof) { + size_t size = ((dof_hdr_t*)dof)->dofh_loadsz; + size_t limit = (size + 16) / 16 * 16; + for (size_t i = 0; i < limit; ++i) { + if (i % 16 == 0) { + tty->print("%07x:", i); + } + if (i % 2 == 0) { + tty->print(" "); + } + if (i < size) { + tty->print("%02x", ((unsigned char*)dof)[i]); + } else { + tty->print(" "); + } + if ((i + 1) % 16 == 0) { + tty->print(" "); + for (size_t j = 0; j < 16; ++j) { + size_t idx = i + j - 15; + char c = ((char*)dof)[idx]; + if (idx < size) { + tty->print("%c", c >= 32 && c <= 126 ? c : '.'); + } + } + tty->print_cr(""); + } + } + tty->print_cr(""); +} + +static void printDOFHelper(dof_helper_t* helper) { + tty->print_cr("// dof_helper_t {"); + tty->print_cr("// dofhp_mod = \"%s\"", helper->dofhp_mod); + tty->print_cr("// dofhp_addr = 0x%016llx", helper->dofhp_addr); + tty->print_cr("// dofhp_dof = 0x%016llx", helper->dofhp_dof); + printDOF((void*)helper->dofhp_dof); + tty->print_cr("// }"); + printDOFRawData((void*)helper->dofhp_dof); +} + +#else // ndef HAVE_DTRACE_H + +// Get here if we're not building on at least Solaris 10 +int DTraceJSDT::pd_activate( + void* baseAddress, jstring module, + jint provider_count, JVM_DTraceProvider* providers) { + return -1; +} + +void DTraceJSDT::pd_dispose(int handle) { +} + +jboolean DTraceJSDT::pd_is_supported() { + return false; +} +#endif diff --git a/src/os/windows/vm/dtraceJSDT_windows.cpp b/src/os/windows/vm/dtraceJSDT_windows.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f8986a98a2dbd19a44612cff1f0952664c7cc29 --- /dev/null +++ b/src/os/windows/vm/dtraceJSDT_windows.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_dtraceJSDT_windows.cpp.incl" + +int DTraceJSDT::pd_activate( + void* baseAddress, jstring module, + jint providers_count, JVM_DTraceProvider* providers) { + return -1; +} + +void DTraceJSDT::pd_dispose(int handle) { +} + +jboolean DTraceJSDT::pd_is_supported() { + return false; +} diff --git a/src/share/vm/asm/codeBuffer.hpp b/src/share/vm/asm/codeBuffer.hpp index 96a983c300c5839d618ce68e1e41e11f9a65f8ed..87f02215d97aa70e188063e0e1730683ff928681 100644 --- a/src/share/vm/asm/codeBuffer.hpp +++ b/src/share/vm/asm/codeBuffer.hpp @@ -36,6 +36,7 @@ public: Verified_Entry, Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete OSR_Entry, + Dtrace_trap = OSR_Entry, // dtrace probes can never have an OSR entry so reuse it Exceptions, // Offset where exception handler lives Deopt, // Offset where deopt handler lives max_Entries }; diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp index f09e8a244c0e4342f0fd37815bd486cfddb33c2d..14b10ea410c19827dc89b0d34cfc07d6034be63f 100644 --- a/src/share/vm/code/nmethod.cpp +++ b/src/share/vm/code/nmethod.cpp @@ -27,7 +27,6 @@ #ifdef DTRACE_ENABLED - // Only bother with this argument setup if dtrace is available HS_DTRACE_PROBE_DECL8(hotspot, compiled__method__load, @@ -438,7 +437,6 @@ nmethod* nmethod::new_native_nmethod(methodHandle method, { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int native_nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); - const int dummy = -1; // Flag to force proper "operator new" CodeOffsets offsets; offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); @@ -461,6 +459,41 @@ nmethod* nmethod::new_native_nmethod(methodHandle method, return nm; } +#ifdef HAVE_DTRACE_H +nmethod* nmethod::new_dtrace_nmethod(methodHandle method, + CodeBuffer *code_buffer, + int vep_offset, + int trap_offset, + int frame_complete, + int frame_size) { + // create nmethod + nmethod* nm = NULL; + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + int nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); + CodeOffsets offsets; + offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); + offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset); + offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); + + nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size); + + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); + if (PrintAssembly && nm != NULL) + Disassembler::decode(nm); + } + // verify nmethod + debug_only(if (nm) nm->verify();) // might block + + if (nm != NULL) { + nm->log_new_nmethod(); + } + + return nm; +} + +#endif // def HAVE_DTRACE_H + nmethod* nmethod::new_nmethod(methodHandle method, int compile_id, int entry_bci, @@ -558,6 +591,9 @@ nmethod::nmethod( _exception_offset = 0; _deoptimize_offset = 0; _orig_pc_offset = 0; +#ifdef HAVE_DTRACE_H + _trap_offset = 0; +#endif // def HAVE_DTRACE_H _stub_offset = data_offset(); _consts_offset = data_offset(); _scopes_data_offset = data_offset(); @@ -615,6 +651,90 @@ nmethod::nmethod( Events::log("Create nmethod " INTPTR_FORMAT, this); } +// For dtrace wrappers +#ifdef HAVE_DTRACE_H +nmethod::nmethod( + methodOop method, + int nmethod_size, + CodeOffsets* offsets, + CodeBuffer* code_buffer, + int frame_size) + : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod), + nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL), + _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), + _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) +{ + { + debug_only(No_Safepoint_Verifier nsv;) + assert_locked_or_safepoint(CodeCache_lock); + + NOT_PRODUCT(_has_debug_info = false; ) + _method = method; + _entry_bci = InvocationEntryBci; + _link = NULL; + _compiler = NULL; + // We have no exception handler or deopt handler make the + // values something that will never match a pc like the nmethod vtable entry + _exception_offset = 0; + _deoptimize_offset = 0; + _trap_offset = offsets->value(CodeOffsets::Dtrace_trap); + _orig_pc_offset = 0; + _stub_offset = data_offset(); + _consts_offset = data_offset(); + _scopes_data_offset = data_offset(); + _scopes_pcs_offset = _scopes_data_offset; + _dependencies_offset = _scopes_pcs_offset; + _handler_table_offset = _dependencies_offset; + _nul_chk_table_offset = _handler_table_offset; + _nmethod_end_offset = _nul_chk_table_offset; + _compile_id = 0; // default + _comp_level = CompLevel_none; + _entry_point = instructions_begin(); + _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry); + _osr_entry_point = NULL; + _exception_cache = NULL; + _pc_desc_cache.reset_to(NULL); + + flags.clear(); + flags.state = alive; + _markedForDeoptimization = 0; + + _lock_count = 0; + _stack_traversal_mark = 0; + + code_buffer->copy_oops_to(this); + debug_only(check_store();) + CodeCache::commit(this); + VTune::create_nmethod(this); + } + + if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { + ttyLocker ttyl; // keep the following output all in one block + // This output goes directly to the tty, not the compiler log. + // To enable tools to match it up with the compilation activity, + // be sure to tag this tty output with the compile ID. + if (xtty != NULL) { + xtty->begin_head("print_dtrace_nmethod"); + xtty->method(_method); + xtty->stamp(); + xtty->end_head(" address='" INTPTR_FORMAT "'", (intptr_t) this); + } + // print the header part first + print(); + // then print the requested information + if (PrintNMethods) { + print_code(); + } + if (PrintRelocations) { + print_relocations(); + } + if (xtty != NULL) { + xtty->tail("print_dtrace_nmethod"); + } + } + Events::log("Create nmethod " INTPTR_FORMAT, this); +} +#endif // def HAVE_DTRACE_H void* nmethod::operator new(size_t size, int nmethod_size) { // Always leave some room in the CodeCache for I2C/C2I adapters @@ -658,6 +778,9 @@ nmethod::nmethod( _link = NULL; _compiler = compiler; _orig_pc_offset = orig_pc_offset; +#ifdef HAVE_DTRACE_H + _trap_offset = 0; +#endif // def HAVE_DTRACE_H _stub_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start()); // Exception handler and deopt handler are in the stub section @@ -1885,7 +2008,6 @@ void nmethod::print() const { } else if (is_compiled_by_c2()) { tty->print("(c2) "); } else { - assert(is_native_method(), "Who else?"); tty->print("(nm) "); } diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp index f03ec5434d8ef51730eb8c399868754ad2b710da..4cfb4b9c3f5b472aff5dd13821b511f70b719aaa 100644 --- a/src/share/vm/code/nmethod.hpp +++ b/src/share/vm/code/nmethod.hpp @@ -140,6 +140,9 @@ class nmethod : public CodeBlob { int _exception_offset; // All deoptee's will resume execution at this location described by this offset int _deoptimize_offset; +#ifdef HAVE_DTRACE_H + int _trap_offset; +#endif // def HAVE_DTRACE_H int _stub_offset; int _consts_offset; int _scopes_data_offset; @@ -211,6 +214,15 @@ class nmethod : public CodeBlob { ByteSize basic_lock_sp_offset, /* synchronized natives only */ OopMapSet* oop_maps); +#ifdef HAVE_DTRACE_H + // For native wrappers + nmethod(methodOop method, + int nmethod_size, + CodeOffsets* offsets, + CodeBuffer *code_buffer, + int frame_size); +#endif // def HAVE_DTRACE_H + // Creation support nmethod(methodOop method, int nmethod_size, @@ -272,6 +284,22 @@ class nmethod : public CodeBlob { ByteSize basic_lock_sp_offset, OopMapSet* oop_maps); +#ifdef HAVE_DTRACE_H + // The method we generate for a dtrace probe has to look + // like an nmethod as far as the rest of the system is concerned + // which is somewhat unfortunate. + static nmethod* new_dtrace_nmethod(methodHandle method, + CodeBuffer *code_buffer, + int vep_offset, + int trap_offset, + int frame_complete, + int frame_size); + + int trap_offset() const { return _trap_offset; } + address trap_address() const { return code_begin() + _trap_offset; } + +#endif // def HAVE_DTRACE_H + // accessors methodOop method() const { return _method; } AbstractCompiler* compiler() const { return _compiler; } diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core index f7da6aa3f54ea8aa5d09a24081dae63bded9cacc..036cc46150f2b19db32830c6730961c5e9dc0e48 100644 --- a/src/share/vm/includeDB_core +++ b/src/share/vm/includeDB_core @@ -1497,6 +1497,30 @@ dtraceAttacher.cpp resourceArea.hpp dtraceAttacher.cpp vmThread.hpp dtraceAttacher.cpp vm_operations.hpp +dtraceJSDT.cpp allocation.hpp +dtraceJSDT.cpp codeBlob.hpp +dtraceJSDT.cpp dtraceJSDT.hpp +dtraceJSDT.cpp exceptions.hpp +dtraceJSDT.cpp globalDefinitions.hpp +dtraceJSDT.cpp javaClasses.hpp +dtraceJSDT.cpp jniHandles.hpp +dtraceJSDT.cpp jvm.h +dtraceJSDT.cpp os.hpp +dtraceJSDT.cpp utf8.hpp + +dtraceJSDT.hpp nativeInst_.hpp +dtraceJSDT.hpp nmethod.hpp + +dtraceJSDT_.cpp allocation.hpp +dtraceJSDT_.cpp codeBlob.hpp +dtraceJSDT_.cpp dtraceJSDT.hpp +dtraceJSDT_.cpp globalDefinitions.hpp +dtraceJSDT_.cpp javaClasses.hpp +dtraceJSDT_.cpp jniHandles.hpp +dtraceJSDT_.cpp jvm.h +dtraceJSDT_.cpp os.hpp +dtraceJSDT_.cpp signature.hpp + // dump is jck optional, put cpp deps in includeDB_features events.cpp allocation.inline.hpp @@ -2400,6 +2424,7 @@ jvm.cpp classLoader.hpp jvm.cpp collectedHeap.inline.hpp jvm.cpp copy.hpp jvm.cpp defaultStream.hpp +jvm.cpp dtraceJSDT.hpp jvm.cpp events.hpp jvm.cpp handles.inline.hpp jvm.cpp histogram.hpp diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp index 83543fee24270fe0d9a6241ac2c3054062629d0a..cb1ad91807e2110dba8ffb16f9e3ed4d7f0f5167 100644 --- a/src/share/vm/oops/methodOop.cpp +++ b/src/share/vm/oops/methodOop.cpp @@ -672,9 +672,6 @@ void methodOopDesc::link_method(methodHandle h_method, TRAPS) { } address methodOopDesc::make_adapters(methodHandle mh, TRAPS) { - // If running -Xint we need no adapters. - if (Arguments::mode() == Arguments::_int) return NULL; - // Adapters for compiled code are made eagerly here. They are fairly // small (generally < 100 bytes) and quick to make (and cached and shared) // so making them eagerly shouldn't be too expensive. diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp index 9a2cbf3676cce9c852e69a023a45b746dc875e07..deaba3a9ed74957de23b6d7ca85f626e3919e8f9 100644 --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp @@ -4168,6 +4168,36 @@ JVM_ENTRY(jboolean, JVM_CX8Field(JNIEnv *env, jobject obj, jfieldID fid, jlong o return res == oldVal; JVM_END +// DTrace /////////////////////////////////////////////////////////////////// + +JVM_ENTRY(jint, JVM_DTraceGetVersion(JNIEnv* env)) + JVMWrapper("JVM_DTraceGetVersion"); + return (jint)JVM_TRACING_DTRACE_VERSION; +JVM_END + +JVM_ENTRY(jlong,JVM_DTraceActivate( + JNIEnv* env, jint version, jstring module_name, jint providers_count, + JVM_DTraceProvider* providers)) + JVMWrapper("JVM_DTraceActivate"); + return DTraceJSDT::activate( + version, module_name, providers_count, providers, CHECK_0); +JVM_END + +JVM_ENTRY(jboolean,JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method)) + JVMWrapper("JVM_DTraceIsProbeEnabled"); + return DTraceJSDT::is_probe_enabled(method); +JVM_END + +JVM_ENTRY(void,JVM_DTraceDispose(JNIEnv* env, jlong handle)) + JVMWrapper("JVM_DTraceDispose"); + DTraceJSDT::dispose(handle); +JVM_END + +JVM_ENTRY(jboolean,JVM_DTraceIsSupported(JNIEnv* env)) + JVMWrapper("JVM_DTraceIsSupported"); + return DTraceJSDT::is_supported(); +JVM_END + // Returns an array of all live Thread objects (VM internal JavaThreads, // jvmti agent threads, and JNI attaching threads are skipped) // See CR 6404306 regarding JNI attaching threads @@ -4496,3 +4526,4 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i #endif // KERNEL } JVM_END + diff --git a/src/share/vm/prims/jvm.h b/src/share/vm/prims/jvm.h index a8012ce8b547e4efdb305681b3d456988316ccc1..feaf0d4a13fa2abe1504dc9bf439c75559b4c76c 100644 --- a/src/share/vm/prims/jvm.h +++ b/src/share/vm/prims/jvm.h @@ -606,6 +606,83 @@ JVM_SupportsCX8(void); JNIEXPORT jboolean JNICALL JVM_CX8Field(JNIEnv *env, jobject obj, jfieldID fldID, jlong oldVal, jlong newVal); +/* + * com.sun.dtrace.jsdt support + */ + +#define JVM_TRACING_DTRACE_VERSION 1 + +/* + * Structure to pass one probe description to JVM. + * + * The VM will overwrite the definition of the referenced method with + * code that will fire the probe. + */ +typedef struct { + jmethodID method; + jstring function; + jstring name; + void* reserved[4]; // for future use +} JVM_DTraceProbe; + +/** + * Encapsulates the stability ratings for a DTrace provider field + */ +typedef struct { + jint nameStability; + jint dataStability; + jint dependencyClass; +} JVM_DTraceInterfaceAttributes; + +/* + * Structure to pass one provider description to JVM + */ +typedef struct { + jstring name; + JVM_DTraceProbe* probes; + jint probe_count; + JVM_DTraceInterfaceAttributes providerAttributes; + JVM_DTraceInterfaceAttributes moduleAttributes; + JVM_DTraceInterfaceAttributes functionAttributes; + JVM_DTraceInterfaceAttributes nameAttributes; + JVM_DTraceInterfaceAttributes argsAttributes; + void* reserved[4]; // for future use +} JVM_DTraceProvider; + +/* + * Get the version number the JVM was built with + */ +JNIEXPORT jint JNICALL +JVM_DTraceGetVersion(JNIEnv* env); + +/* + * Register new probe with given signature, return global handle + * + * The version passed in is the version that the library code was + * built with. + */ +JNIEXPORT jlong JNICALL +JVM_DTraceActivate(JNIEnv* env, jint version, jstring module_name, + jint providers_count, JVM_DTraceProvider* providers); + +/* + * Check JSDT probe + */ +JNIEXPORT jboolean JNICALL +JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method); + +/* + * Destroy custom DOF + */ +JNIEXPORT void JNICALL +JVM_DTraceDispose(JNIEnv* env, jlong handle); + +/* + * Check to see if DTrace is supported by OS + */ +JNIEXPORT jboolean JNICALL +JVM_DTraceIsSupported(JNIEnv* env); + /************************************************************************* PART 2: Support for the Verifier and Class File Format Checker ************************************************************************/ diff --git a/src/share/vm/runtime/dtraceJSDT.cpp b/src/share/vm/runtime/dtraceJSDT.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57095dec4ed6ca77bff6094e2a391c07b250a472 --- /dev/null +++ b/src/share/vm/runtime/dtraceJSDT.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_dtraceJSDT.cpp.incl" + +#ifdef HAVE_DTRACE_H + +jlong DTraceJSDT::activate( + jint version, jstring module_name, jint providers_count, + JVM_DTraceProvider* providers, TRAPS) { + + size_t count = 0; + RegisteredProbes* probes = NULL; + + if (!is_supported()) { + return 0; + } + + assert(module_name != NULL, "valid module name"); + assert(providers != NULL, "valid provider array"); + + for (int i = 0; i < providers_count; ++i) { + count += providers[i].probe_count; + } + probes = new RegisteredProbes(count); + count = 0; + + for (int i = 0; i < providers_count; ++i) { + assert(providers[i].name != NULL, "valid provider name"); + assert(providers[i].probe_count == 0 || providers[i].probes != NULL, + "valid probe count"); + for (int j = 0; j < providers[i].probe_count; ++j) { + JVM_DTraceProbe* probe = &(providers[i].probes[j]); + assert(probe != NULL, "valid probe"); + assert(probe->method != NULL, "valid method"); + assert(probe->name != NULL, "valid probe name"); + assert(probe->function != NULL, "valid probe function spec"); + methodHandle h_method = + methodHandle(THREAD, JNIHandles::resolve_jmethod_id(probe->method)); + nmethod* nm = AdapterHandlerLibrary::create_dtrace_nmethod(h_method); + h_method()->set_not_compilable(CompLevel_highest_tier); + h_method()->set_code(h_method, nm); + probes->nmethod_at_put(count++, nm); + } + } + + int handle = pd_activate((void*)probes, + module_name, providers_count, providers); + if (handle <= 0) { + delete probes; + THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), + "Unable to register DTrace probes (internal error)."); + } + probes->set_helper_handle(handle); + return RegisteredProbes::toOpaqueProbes(probes); +} + +jboolean DTraceJSDT::is_probe_enabled(jmethodID method) { + methodOop m = JNIHandles::resolve_jmethod_id(method); + return nativeInstruction_at(m->code()->trap_address())->is_dtrace_trap(); +} + +void DTraceJSDT::dispose(OpaqueProbes probes) { + RegisteredProbes* p = RegisteredProbes::toRegisteredProbes(probes); + if (probes != -1 && p != NULL) { + pd_dispose(p->helper_handle()); + delete p; + } +} + +jboolean DTraceJSDT::is_supported() { + return pd_is_supported(); +} + +#else // HAVE_DTRACE_H + +jlong DTraceJSDT::activate( + jint version, jstring module_name, jint providers_count, + JVM_DTraceProvider* providers, TRAPS) { + return 0; +} + +jboolean DTraceJSDT::is_probe_enabled(jmethodID method) { + return false; +} + +void DTraceJSDT::dispose(OpaqueProbes probes) { + return; +} + +jboolean DTraceJSDT::is_supported() { + return false; +} + +#endif // ndef HAVE_DTRACE_H diff --git a/src/share/vm/runtime/dtraceJSDT.hpp b/src/share/vm/runtime/dtraceJSDT.hpp new file mode 100644 index 0000000000000000000000000000000000000000..37b18b04f00215aca7aa2b55ccc621e705e97615 --- /dev/null +++ b/src/share/vm/runtime/dtraceJSDT.hpp @@ -0,0 +1,89 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class RegisteredProbes; +typedef jlong OpaqueProbes; + +class DTraceJSDT : AllStatic { + private: + + static int pd_activate(void* moduleBaseAddress, jstring module, + jint providers_count, JVM_DTraceProvider* providers); + static void pd_dispose(int handle); + static jboolean pd_is_supported(); + + public: + + static OpaqueProbes activate( + jint version, jstring module_name, jint providers_count, + JVM_DTraceProvider* providers, TRAPS); + static jboolean is_probe_enabled(jmethodID method); + static void dispose(OpaqueProbes handle); + static jboolean is_supported(); +}; + +class RegisteredProbes : public CHeapObj { + private: + nmethod** _nmethods; // all the probe methods + size_t _count; // number of probe methods + int _helper_handle; // DTrace-assigned identifier + + public: + RegisteredProbes(size_t count) { + _count = count; + _nmethods = NEW_C_HEAP_ARRAY(nmethod*, count); + } + + ~RegisteredProbes() { + for (size_t i = 0; i < _count; ++i) { + // Let the sweeper reclaim it + _nmethods[i]->make_not_entrant(); + _nmethods[i]->method()->clear_code(); + } + FREE_C_HEAP_ARRAY(nmethod*, _nmethods); + _nmethods = NULL; + _count = 0; + } + + static RegisteredProbes* toRegisteredProbes(OpaqueProbes p) { + return (RegisteredProbes*)(intptr_t)p; + } + + static OpaqueProbes toOpaqueProbes(RegisteredProbes* p) { + return (OpaqueProbes)(intptr_t)p; + } + + void set_helper_handle(int handle) { _helper_handle = handle; } + int helper_handle() const { return _helper_handle; } + + nmethod* nmethod_at(size_t i) { + assert(i >= 0 && i < _count, "bad nmethod index"); + return _nmethods[i]; + } + + void nmethod_at_put(size_t i, nmethod* nm) { + assert(i >= 0 && i < _count, "bad nmethod index"); + _nmethods[i] = nm; + } +}; diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index d25dd756e4e1bcf166ef7f6408357a531aa6bf06..ae59b5bdab03dbd97b6705f19f650ec0ede0583a 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -3188,6 +3188,9 @@ class CommandLineFlags { product(bool, RelaxAccessControlCheck, false, \ "Relax the access control checks in the verifier") \ \ + diagnostic(bool, PrintDTraceDOF, false, \ + "Print the DTrace DOF passed to the system for JSDT probes") \ + \ product(bool, UseVMInterruptibleIO, true, \ "(Unstable, Solaris-specific) Thread interrupt before or with " \ "EINTR for I/O operations results in OS_INTRPT") diff --git a/src/share/vm/runtime/reflection.cpp b/src/share/vm/runtime/reflection.cpp index b0e8a9968221bbc2bf9e3dfe4f827cf85a3ecd0c..ebe0899a1485c1cd27b8ff1a738a830ecad2cbd2 100644 --- a/src/share/vm/runtime/reflection.cpp +++ b/src/share/vm/runtime/reflection.cpp @@ -500,7 +500,8 @@ bool Reflection::verify_field_access(klassOop current_class, if (!protected_restriction) { // See if current_class is a subclass of field_class if (Klass::cast(current_class)->is_subclass_of(field_class)) { - if (current_class == resolved_class || + if (access.is_static() || // static fields are ok, see 6622385 + current_class == resolved_class || field_class == resolved_class || Klass::cast(current_class)->is_subclass_of(resolved_class) || Klass::cast(resolved_class)->is_subclass_of(current_class)) { diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp index 6f2fa5be969b273ba881d73e603fa6d661df4adb..cb8eeb121495fb20583f4918702da15bedf2a720 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp @@ -1748,11 +1748,6 @@ int AdapterHandlerLibrary::get_create_adapter_index(methodHandle method) { // _fingerprints array (it is not safe for concurrent readers and a single // writer: this can be fixed if it becomes a problem). - // Shouldn't be here if running -Xint - if (Arguments::mode() == Arguments::_int) { - ShouldNotReachHere(); - } - // Get the address of the ic_miss handlers before we grab the // AdapterHandlerLibrary_lock. This fixes bug 6236259 which // was caused by the initialization of the stubs happening @@ -1997,6 +1992,64 @@ nmethod *AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { return nm; } +#ifdef HAVE_DTRACE_H +// Create a dtrace nmethod for this method. The wrapper converts the +// java compiled calling convention to the native convention, makes a dummy call +// (actually nops for the size of the call instruction, which become a trap if +// probe is enabled). The returns to the caller. Since this all looks like a +// leaf no thread transition is needed. + +nmethod *AdapterHandlerLibrary::create_dtrace_nmethod(methodHandle method) { + ResourceMark rm; + nmethod* nm = NULL; + + if (PrintCompilation) { + ttyLocker ttyl; + tty->print("--- n%s "); + method->print_short_name(tty); + if (method->is_static()) { + tty->print(" (static)"); + } + tty->cr(); + } + + { + // perform the work while holding the lock, but perform any printing + // outside the lock + MutexLocker mu(AdapterHandlerLibrary_lock); + // See if somebody beat us to it + nm = method->code(); + if (nm) { + return nm; + } + + // Improve alignment slightly + u_char* buf = (u_char*) + (((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1)); + CodeBuffer buffer(buf, AdapterHandlerLibrary_size); + // Need a few relocation entries + double locs_buf[20]; + buffer.insts()->initialize_shared_locs( + (relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); + MacroAssembler _masm(&buffer); + + // Generate the compiled-to-native wrapper code + nm = SharedRuntime::generate_dtrace_nmethod(&_masm, method); + } + return nm; +} + +// the dtrace method needs to convert java lang string to utf8 string. +void SharedRuntime::get_utf(oopDesc* src, address dst) { + typeArrayOop jlsValue = java_lang_String::value(src); + int jlsOffset = java_lang_String::offset(src); + int jlsLen = java_lang_String::length(src); + jchar* jlsPos = (jlsLen == 0) ? NULL : + jlsValue->char_at_addr(jlsOffset); + (void) UNICODE::as_utf8(jlsPos, jlsLen, (char *)dst, max_dtrace_string_size); +} +#endif // ndef HAVE_DTRACE_H + // ------------------------------------------------------------------------- // Java-Java calling convention // (what you use when Java calls Java) diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp index b2138d0a7034bf35f4b0e4fa394d2b54f24e0159..22bb552ddc99fdc63de0a1bd3c71dc4b739ce288 100644 --- a/src/share/vm/runtime/sharedRuntime.hpp +++ b/src/share/vm/runtime/sharedRuntime.hpp @@ -59,6 +59,10 @@ class SharedRuntime: AllStatic { #endif // !PRODUCT public: + + // max bytes for each dtrace string parameter + enum { max_dtrace_string_size = 256 }; + // The following arithmetic routines are used on platforms that do // not have machine instructions to implement their functionality. // Do not remove these. @@ -258,9 +262,6 @@ class SharedRuntime: AllStatic { public: - - static void create_native_wrapper (JavaThread* thread, methodOop method); - // Read the array of BasicTypes from a Java signature, and compute where // compiled Java code would like to put the results. Values in reg_lo and // reg_hi refer to 4-byte quantities. Values less than SharedInfo::stack0 are @@ -354,6 +355,19 @@ class SharedRuntime: AllStatic { VMRegPair *regs, BasicType ret_type ); +#ifdef HAVE_DTRACE_H + // Generate a dtrace wrapper for a given method. The method takes arguments + // in the Java compiled code convention, marshals them to the native + // convention (handlizes oops, etc), transitions to native, makes the call, + // returns to java state (possibly blocking), unhandlizes any result and + // returns. + static nmethod *generate_dtrace_nmethod(MacroAssembler* masm, + methodHandle method); + + // dtrace support to convert a Java string to utf8 + static void get_utf(oopDesc* src, address dst); +#endif // def HAVE_DTRACE_H + // A compiled caller has just called the interpreter, but compiled code // exists. Patch the caller so he no longer calls into the interpreter. static void fixup_callers_callsite(methodOopDesc* moop, address ret_pc); @@ -492,42 +506,55 @@ class AdapterHandlerEntry : public CHeapObj { address _c2i_unverified_entry; public: + + // The name we give all buffer blobs + static const char* name; + AdapterHandlerEntry(address i2c_entry, address c2i_entry, address c2i_unverified_entry): _i2c_entry(i2c_entry), _c2i_entry(c2i_entry), _c2i_unverified_entry(c2i_unverified_entry) { } - // The name we give all buffer blobs - static const char* name; address get_i2c_entry() { return _i2c_entry; } address get_c2i_entry() { return _c2i_entry; } address get_c2i_unverified_entry() { return _c2i_unverified_entry; } + void relocate(address new_base); #ifndef PRODUCT void print(); #endif /* PRODUCT */ }; - class AdapterHandlerLibrary: public AllStatic { private: + static u_char _buffer[]; // the temporary code buffer + static GrowableArray* _fingerprints; // the fingerprint collection + static GrowableArray * _handlers; // the corresponding handlers enum { AbstractMethodHandler = 1 // special handler for abstract methods }; - static GrowableArray* _fingerprints; // the fingerprint collection - static GrowableArray * _handlers; // the corresponding handlers - static u_char _buffer[]; // the temporary code buffer static void initialize(); - static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); } static int get_create_adapter_index(methodHandle method); - static address get_i2c_entry( int index ) { return get_entry(index)->get_i2c_entry(); } - static address get_c2i_entry( int index ) { return get_entry(index)->get_c2i_entry(); } - static address get_c2i_unverified_entry( int index ) { return get_entry(index)->get_c2i_unverified_entry(); } + static address get_i2c_entry( int index ) { + return get_entry(index)->get_i2c_entry(); + } + static address get_c2i_entry( int index ) { + return get_entry(index)->get_c2i_entry(); + } + static address get_c2i_unverified_entry( int index ) { + return get_entry(index)->get_c2i_unverified_entry(); + } public: + static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); } static nmethod* create_native_wrapper(methodHandle method); - static AdapterHandlerEntry* get_adapter(methodHandle method) { return get_entry(get_create_adapter_index(method)); } + static AdapterHandlerEntry* get_adapter(methodHandle method) { + return get_entry(get_create_adapter_index(method)); + } +#ifdef HAVE_DTRACE_H + static nmethod* create_dtrace_nmethod (methodHandle method); +#endif // HAVE_DTRACE_H #ifndef PRODUCT static void print_handler(CodeBlob* b);