Thu, 17 Apr 2008 22:18:15 -0400
6537506: Provide a mechanism for specifying Java-level USDT-like dtrace probes
Summary: Initial checkin of JSDT code
Reviewed-by: acorn, sbohne
1.1 --- a/make/linux/makefiles/mapfile-vers-debug Wed Apr 16 17:36:29 2008 -0400 1.2 +++ b/make/linux/makefiles/mapfile-vers-debug Thu Apr 17 22:18:15 2008 -0400 1.3 @@ -1,3 +1,5 @@ 1.4 +# 1.5 +# @(#)mapfile-vers-debug 1.18 07/10/25 16:47:35 1.6 # 1.7 1.8 # 1.9 @@ -75,6 +77,11 @@ 1.10 JVM_DesiredAssertionStatus; 1.11 JVM_DisableCompiler; 1.12 JVM_DoPrivileged; 1.13 + JVM_DTraceGetVersion; 1.14 + JVM_DTraceActivate; 1.15 + JVM_DTraceIsProbeEnabled; 1.16 + JVM_DTraceIsSupported; 1.17 + JVM_DTraceDispose; 1.18 JVM_DumpAllStacks; 1.19 JVM_DumpThreads; 1.20 JVM_EnableCompiler;
2.1 --- a/make/linux/makefiles/mapfile-vers-product Wed Apr 16 17:36:29 2008 -0400 2.2 +++ b/make/linux/makefiles/mapfile-vers-product Thu Apr 17 22:18:15 2008 -0400 2.3 @@ -1,3 +1,5 @@ 2.4 +# 2.5 +# @(#)mapfile-vers-product 1.19 08/02/12 10:56:37 2.6 # 2.7 2.8 # 2.9 @@ -75,6 +77,11 @@ 2.10 JVM_DesiredAssertionStatus; 2.11 JVM_DisableCompiler; 2.12 JVM_DoPrivileged; 2.13 + JVM_DTraceGetVersion; 2.14 + JVM_DTraceActivate; 2.15 + JVM_DTraceIsProbeEnabled; 2.16 + JVM_DTraceIsSupported; 2.17 + JVM_DTraceDispose; 2.18 JVM_DumpAllStacks; 2.19 JVM_DumpThreads; 2.20 JVM_EnableCompiler;
3.1 --- a/make/solaris/makefiles/dtrace.make Wed Apr 16 17:36:29 2008 -0400 3.2 +++ b/make/solaris/makefiles/dtrace.make Thu Apr 17 22:18:15 2008 -0400 3.3 @@ -193,10 +193,16 @@ 3.4 3.5 .PHONY: dtraceCheck 3.6 3.7 +SYSTEM_DTRACE_H = /usr/include/dtrace.h 3.8 SYSTEM_DTRACE_PROG = /usr/sbin/dtrace 3.9 PATCH_DTRACE_PROG = /opt/SUNWdtrd/sbin/dtrace 3.10 systemDtraceFound := $(wildcard ${SYSTEM_DTRACE_PROG}) 3.11 patchDtraceFound := $(wildcard ${PATCH_DTRACE_PROG}) 3.12 +systemDtraceHdrFound := $(wildcard $(SYSTEM_DTRACE_H)) 3.13 + 3.14 +ifneq ("$(systemDtraceHdrFound)", "") 3.15 +CFLAGS += -DHAVE_DTRACE_H 3.16 +endif 3.17 3.18 ifneq ("$(patchDtraceFound)", "") 3.19 DTRACE_PROG=$(PATCH_DTRACE_PROG)
4.1 --- a/make/solaris/makefiles/mapfile-vers Wed Apr 16 17:36:29 2008 -0400 4.2 +++ b/make/solaris/makefiles/mapfile-vers Thu Apr 17 22:18:15 2008 -0400 4.3 @@ -1,3 +1,5 @@ 4.4 +# 4.5 +# @(#)mapfile-vers 1.32 07/10/25 16:47:36 4.6 # 4.7 4.8 # 4.9 @@ -75,6 +77,11 @@ 4.10 JVM_DesiredAssertionStatus; 4.11 JVM_DisableCompiler; 4.12 JVM_DoPrivileged; 4.13 + JVM_DTraceGetVersion; 4.14 + JVM_DTraceActivate; 4.15 + JVM_DTraceIsProbeEnabled; 4.16 + JVM_DTraceIsSupported; 4.17 + JVM_DTraceDispose; 4.18 JVM_DumpAllStacks; 4.19 JVM_DumpThreads; 4.20 JVM_EnableCompiler;
5.1 --- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Wed Apr 16 17:36:29 2008 -0400 5.2 +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Apr 17 22:18:15 2008 -0400 5.3 @@ -26,6 +26,10 @@ 5.4 # include "incls/_nativeInst_sparc.cpp.incl" 5.5 5.6 5.7 +bool NativeInstruction::is_dtrace_trap() { 5.8 + return !is_nop(); 5.9 +} 5.10 + 5.11 void NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) { 5.12 ResourceMark rm; 5.13 CodeBuffer buf(instaddr, 10 * BytesPerInstWord );
6.1 --- a/src/cpu/sparc/vm/nativeInst_sparc.hpp Wed Apr 16 17:36:29 2008 -0400 6.2 +++ b/src/cpu/sparc/vm/nativeInst_sparc.hpp Thu Apr 17 22:18:15 2008 -0400 6.3 @@ -43,6 +43,7 @@ 6.4 nop_instruction_size = 4 6.5 }; 6.6 6.7 + bool is_dtrace_trap(); 6.8 bool is_nop() { return long_at(0) == nop_instruction(); } 6.9 bool is_call() { return is_op(long_at(0), Assembler::call_op); } 6.10 bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2)
7.1 --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Apr 16 17:36:29 2008 -0400 7.2 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Apr 17 22:18:15 2008 -0400 7.3 @@ -1637,7 +1637,7 @@ 7.4 } 7.5 } else if (dst.is_single_phys_reg()) { 7.6 if (src.is_adjacent_aligned_on_stack(2)) { 7.7 - __ ldd(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); 7.8 + __ ld_long(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); 7.9 } else { 7.10 // dst is a single reg. 7.11 // Remember lo is low address not msb for stack slots 7.12 @@ -2501,6 +2501,551 @@ 7.13 7.14 } 7.15 7.16 +#ifdef HAVE_DTRACE_H 7.17 +// --------------------------------------------------------------------------- 7.18 +// Generate a dtrace nmethod for a given signature. The method takes arguments 7.19 +// in the Java compiled code convention, marshals them to the native 7.20 +// abi and then leaves nops at the position you would expect to call a native 7.21 +// function. When the probe is enabled the nops are replaced with a trap 7.22 +// instruction that dtrace inserts and the trace will cause a notification 7.23 +// to dtrace. 7.24 +// 7.25 +// The probes are only able to take primitive types and java/lang/String as 7.26 +// arguments. No other java types are allowed. Strings are converted to utf8 7.27 +// strings so that from dtrace point of view java strings are converted to C 7.28 +// strings. There is an arbitrary fixed limit on the total space that a method 7.29 +// can use for converting the strings. (256 chars per string in the signature). 7.30 +// So any java string larger then this is truncated. 7.31 + 7.32 +static int fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 }; 7.33 +static bool offsets_initialized = false; 7.34 + 7.35 +static VMRegPair reg64_to_VMRegPair(Register r) { 7.36 + VMRegPair ret; 7.37 + if (wordSize == 8) { 7.38 + ret.set2(r->as_VMReg()); 7.39 + } else { 7.40 + ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg()); 7.41 + } 7.42 + return ret; 7.43 +} 7.44 + 7.45 + 7.46 +nmethod *SharedRuntime::generate_dtrace_nmethod( 7.47 + MacroAssembler *masm, methodHandle method) { 7.48 + 7.49 + 7.50 + // generate_dtrace_nmethod is guarded by a mutex so we are sure to 7.51 + // be single threaded in this method. 7.52 + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); 7.53 + 7.54 + // Fill in the signature array, for the calling-convention call. 7.55 + int total_args_passed = method->size_of_parameters(); 7.56 + 7.57 + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); 7.58 + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); 7.59 + 7.60 + // The signature we are going to use for the trap that dtrace will see 7.61 + // java/lang/String is converted. We drop "this" and any other object 7.62 + // is converted to NULL. (A one-slot java/lang/Long object reference 7.63 + // is converted to a two-slot long, which is why we double the allocation). 7.64 + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); 7.65 + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); 7.66 + 7.67 + int i=0; 7.68 + int total_strings = 0; 7.69 + int first_arg_to_pass = 0; 7.70 + int total_c_args = 0; 7.71 + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); 7.72 + 7.73 + // Skip the receiver as dtrace doesn't want to see it 7.74 + if( !method->is_static() ) { 7.75 + in_sig_bt[i++] = T_OBJECT; 7.76 + first_arg_to_pass = 1; 7.77 + } 7.78 + 7.79 + SignatureStream ss(method->signature()); 7.80 + for ( ; !ss.at_return_type(); ss.next()) { 7.81 + BasicType bt = ss.type(); 7.82 + in_sig_bt[i++] = bt; // Collect remaining bits of signature 7.83 + out_sig_bt[total_c_args++] = bt; 7.84 + if( bt == T_OBJECT) { 7.85 + symbolOop s = ss.as_symbol_or_null(); 7.86 + if (s == vmSymbols::java_lang_String()) { 7.87 + total_strings++; 7.88 + out_sig_bt[total_c_args-1] = T_ADDRESS; 7.89 + } else if (s == vmSymbols::java_lang_Boolean() || 7.90 + s == vmSymbols::java_lang_Byte()) { 7.91 + out_sig_bt[total_c_args-1] = T_BYTE; 7.92 + } else if (s == vmSymbols::java_lang_Character() || 7.93 + s == vmSymbols::java_lang_Short()) { 7.94 + out_sig_bt[total_c_args-1] = T_SHORT; 7.95 + } else if (s == vmSymbols::java_lang_Integer() || 7.96 + s == vmSymbols::java_lang_Float()) { 7.97 + out_sig_bt[total_c_args-1] = T_INT; 7.98 + } else if (s == vmSymbols::java_lang_Long() || 7.99 + s == vmSymbols::java_lang_Double()) { 7.100 + out_sig_bt[total_c_args-1] = T_LONG; 7.101 + out_sig_bt[total_c_args++] = T_VOID; 7.102 + } 7.103 + } else if ( bt == T_LONG || bt == T_DOUBLE ) { 7.104 + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots 7.105 + // We convert double to long 7.106 + out_sig_bt[total_c_args-1] = T_LONG; 7.107 + out_sig_bt[total_c_args++] = T_VOID; 7.108 + } else if ( bt == T_FLOAT) { 7.109 + // We convert float to int 7.110 + out_sig_bt[total_c_args-1] = T_INT; 7.111 + } 7.112 + } 7.113 + 7.114 + assert(i==total_args_passed, "validly parsed signature"); 7.115 + 7.116 + // Now get the compiled-Java layout as input arguments 7.117 + int comp_args_on_stack; 7.118 + comp_args_on_stack = SharedRuntime::java_calling_convention( 7.119 + in_sig_bt, in_regs, total_args_passed, false); 7.120 + 7.121 + // We have received a description of where all the java arg are located 7.122 + // on entry to the wrapper. We need to convert these args to where 7.123 + // the a native (non-jni) function would expect them. To figure out 7.124 + // where they go we convert the java signature to a C signature and remove 7.125 + // T_VOID for any long/double we might have received. 7.126 + 7.127 + 7.128 + // Now figure out where the args must be stored and how much stack space 7.129 + // they require (neglecting out_preserve_stack_slots but space for storing 7.130 + // the 1st six register arguments). It's weird see int_stk_helper. 7.131 + // 7.132 + int out_arg_slots; 7.133 + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); 7.134 + 7.135 + // Calculate the total number of stack slots we will need. 7.136 + 7.137 + // First count the abi requirement plus all of the outgoing args 7.138 + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; 7.139 + 7.140 + // Plus a temp for possible converion of float/double/long register args 7.141 + 7.142 + int conversion_temp = stack_slots; 7.143 + stack_slots += 2; 7.144 + 7.145 + 7.146 + // Now space for the string(s) we must convert 7.147 + 7.148 + int string_locs = stack_slots; 7.149 + stack_slots += total_strings * 7.150 + (max_dtrace_string_size / VMRegImpl::stack_slot_size); 7.151 + 7.152 + // Ok The space we have allocated will look like: 7.153 + // 7.154 + // 7.155 + // FP-> | | 7.156 + // |---------------------| 7.157 + // | string[n] | 7.158 + // |---------------------| <- string_locs[n] 7.159 + // | string[n-1] | 7.160 + // |---------------------| <- string_locs[n-1] 7.161 + // | ... | 7.162 + // | ... | 7.163 + // |---------------------| <- string_locs[1] 7.164 + // | string[0] | 7.165 + // |---------------------| <- string_locs[0] 7.166 + // | temp | 7.167 + // |---------------------| <- conversion_temp 7.168 + // | outbound memory | 7.169 + // | based arguments | 7.170 + // | | 7.171 + // |---------------------| 7.172 + // | | 7.173 + // SP-> | out_preserved_slots | 7.174 + // 7.175 + // 7.176 + 7.177 + // Now compute actual number of stack words we need rounding to make 7.178 + // stack properly aligned. 7.179 + stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word); 7.180 + 7.181 + int stack_size = stack_slots * VMRegImpl::stack_slot_size; 7.182 + 7.183 + intptr_t start = (intptr_t)__ pc(); 7.184 + 7.185 + // First thing make an ic check to see if we should even be here 7.186 + 7.187 + { 7.188 + Label L; 7.189 + const Register temp_reg = G3_scratch; 7.190 + Address ic_miss(temp_reg, SharedRuntime::get_ic_miss_stub()); 7.191 + __ verify_oop(O0); 7.192 + __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), temp_reg); 7.193 + __ cmp(temp_reg, G5_inline_cache_reg); 7.194 + __ brx(Assembler::equal, true, Assembler::pt, L); 7.195 + __ delayed()->nop(); 7.196 + 7.197 + __ jump_to(ic_miss, 0); 7.198 + __ delayed()->nop(); 7.199 + __ align(CodeEntryAlignment); 7.200 + __ bind(L); 7.201 + } 7.202 + 7.203 + int vep_offset = ((intptr_t)__ pc()) - start; 7.204 + 7.205 + 7.206 + // The instruction at the verified entry point must be 5 bytes or longer 7.207 + // because it can be patched on the fly by make_non_entrant. The stack bang 7.208 + // instruction fits that requirement. 7.209 + 7.210 + // Generate stack overflow check before creating frame 7.211 + __ generate_stack_overflow_check(stack_size); 7.212 + 7.213 + assert(((intptr_t)__ pc() - start - vep_offset) >= 5, 7.214 + "valid size for make_non_entrant"); 7.215 + 7.216 + // Generate a new frame for the wrapper. 7.217 + __ save(SP, -stack_size, SP); 7.218 + 7.219 + // Frame is now completed as far a size and linkage. 7.220 + 7.221 + int frame_complete = ((intptr_t)__ pc()) - start; 7.222 + 7.223 +#ifdef ASSERT 7.224 + bool reg_destroyed[RegisterImpl::number_of_registers]; 7.225 + bool freg_destroyed[FloatRegisterImpl::number_of_registers]; 7.226 + for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) { 7.227 + reg_destroyed[r] = false; 7.228 + } 7.229 + for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) { 7.230 + freg_destroyed[f] = false; 7.231 + } 7.232 + 7.233 +#endif /* ASSERT */ 7.234 + 7.235 + VMRegPair zero; 7.236 + zero.set2(G0->as_VMReg()); 7.237 + 7.238 + int c_arg, j_arg; 7.239 + 7.240 + Register conversion_off = noreg; 7.241 + 7.242 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 7.243 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 7.244 + 7.245 + VMRegPair src = in_regs[j_arg]; 7.246 + VMRegPair dst = out_regs[c_arg]; 7.247 + 7.248 +#ifdef ASSERT 7.249 + if (src.first()->is_Register()) { 7.250 + assert(!reg_destroyed[src.first()->as_Register()->encoding()], "ack!"); 7.251 + } else if (src.first()->is_FloatRegister()) { 7.252 + assert(!freg_destroyed[src.first()->as_FloatRegister()->encoding( 7.253 + FloatRegisterImpl::S)], "ack!"); 7.254 + } 7.255 + if (dst.first()->is_Register()) { 7.256 + reg_destroyed[dst.first()->as_Register()->encoding()] = true; 7.257 + } else if (dst.first()->is_FloatRegister()) { 7.258 + freg_destroyed[dst.first()->as_FloatRegister()->encoding( 7.259 + FloatRegisterImpl::S)] = true; 7.260 + } 7.261 +#endif /* ASSERT */ 7.262 + 7.263 + switch (in_sig_bt[j_arg]) { 7.264 + case T_ARRAY: 7.265 + case T_OBJECT: 7.266 + { 7.267 + if (out_sig_bt[c_arg] == T_BYTE || out_sig_bt[c_arg] == T_SHORT || 7.268 + out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { 7.269 + // need to unbox a one-slot value 7.270 + Register in_reg = L0; 7.271 + Register tmp = L2; 7.272 + if ( src.first()->is_reg() ) { 7.273 + in_reg = src.first()->as_Register(); 7.274 + } else { 7.275 + assert(Assembler::is_simm13(reg2offset(src.first()) + STACK_BIAS), 7.276 + "must be"); 7.277 + __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, in_reg); 7.278 + } 7.279 + // If the final destination is an acceptable register 7.280 + if ( dst.first()->is_reg() ) { 7.281 + if ( dst.is_single_phys_reg() || out_sig_bt[c_arg] != T_LONG ) { 7.282 + tmp = dst.first()->as_Register(); 7.283 + } 7.284 + } 7.285 + 7.286 + Label skipUnbox; 7.287 + if ( wordSize == 4 && out_sig_bt[c_arg] == T_LONG ) { 7.288 + __ mov(G0, tmp->successor()); 7.289 + } 7.290 + __ br_null(in_reg, true, Assembler::pn, skipUnbox); 7.291 + __ delayed()->mov(G0, tmp); 7.292 + 7.293 + switch (out_sig_bt[c_arg]) { 7.294 + case T_BYTE: 7.295 + __ ldub(in_reg, box_offset, tmp); break; 7.296 + case T_SHORT: 7.297 + __ lduh(in_reg, box_offset, tmp); break; 7.298 + case T_INT: 7.299 + __ ld(in_reg, box_offset, tmp); break; 7.300 + case T_LONG: 7.301 + __ ld_long(in_reg, box_offset, tmp); break; 7.302 + default: ShouldNotReachHere(); 7.303 + } 7.304 + 7.305 + __ bind(skipUnbox); 7.306 + // If tmp wasn't final destination copy to final destination 7.307 + if (tmp == L2) { 7.308 + VMRegPair tmp_as_VM = reg64_to_VMRegPair(L2); 7.309 + if (out_sig_bt[c_arg] == T_LONG) { 7.310 + long_move(masm, tmp_as_VM, dst); 7.311 + } else { 7.312 + move32_64(masm, tmp_as_VM, out_regs[c_arg]); 7.313 + } 7.314 + } 7.315 + if (out_sig_bt[c_arg] == T_LONG) { 7.316 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 7.317 + ++c_arg; // move over the T_VOID to keep the loop indices in sync 7.318 + } 7.319 + } else if (out_sig_bt[c_arg] == T_ADDRESS) { 7.320 + Register s = 7.321 + src.first()->is_reg() ? src.first()->as_Register() : L2; 7.322 + Register d = 7.323 + dst.first()->is_reg() ? dst.first()->as_Register() : L2; 7.324 + 7.325 + // We store the oop now so that the conversion pass can reach 7.326 + // while in the inner frame. This will be the only store if 7.327 + // the oop is NULL. 7.328 + if (s != L2) { 7.329 + // src is register 7.330 + if (d != L2) { 7.331 + // dst is register 7.332 + __ mov(s, d); 7.333 + } else { 7.334 + assert(Assembler::is_simm13(reg2offset(dst.first()) + 7.335 + STACK_BIAS), "must be"); 7.336 + __ st_ptr(s, SP, reg2offset(dst.first()) + STACK_BIAS); 7.337 + } 7.338 + } else { 7.339 + // src not a register 7.340 + assert(Assembler::is_simm13(reg2offset(src.first()) + 7.341 + STACK_BIAS), "must be"); 7.342 + __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, d); 7.343 + if (d == L2) { 7.344 + assert(Assembler::is_simm13(reg2offset(dst.first()) + 7.345 + STACK_BIAS), "must be"); 7.346 + __ st_ptr(d, SP, reg2offset(dst.first()) + STACK_BIAS); 7.347 + } 7.348 + } 7.349 + } else if (out_sig_bt[c_arg] != T_VOID) { 7.350 + // Convert the arg to NULL 7.351 + if (dst.first()->is_reg()) { 7.352 + __ mov(G0, dst.first()->as_Register()); 7.353 + } else { 7.354 + assert(Assembler::is_simm13(reg2offset(dst.first()) + 7.355 + STACK_BIAS), "must be"); 7.356 + __ st_ptr(G0, SP, reg2offset(dst.first()) + STACK_BIAS); 7.357 + } 7.358 + } 7.359 + } 7.360 + break; 7.361 + case T_VOID: 7.362 + break; 7.363 + 7.364 + case T_FLOAT: 7.365 + if (src.first()->is_stack()) { 7.366 + // Stack to stack/reg is simple 7.367 + move32_64(masm, src, dst); 7.368 + } else { 7.369 + if (dst.first()->is_reg()) { 7.370 + // freg -> reg 7.371 + int off = 7.372 + STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; 7.373 + Register d = dst.first()->as_Register(); 7.374 + if (Assembler::is_simm13(off)) { 7.375 + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), 7.376 + SP, off); 7.377 + __ ld(SP, off, d); 7.378 + } else { 7.379 + if (conversion_off == noreg) { 7.380 + __ set(off, L6); 7.381 + conversion_off = L6; 7.382 + } 7.383 + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), 7.384 + SP, conversion_off); 7.385 + __ ld(SP, conversion_off , d); 7.386 + } 7.387 + } else { 7.388 + // freg -> mem 7.389 + int off = STACK_BIAS + reg2offset(dst.first()); 7.390 + if (Assembler::is_simm13(off)) { 7.391 + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), 7.392 + SP, off); 7.393 + } else { 7.394 + if (conversion_off == noreg) { 7.395 + __ set(off, L6); 7.396 + conversion_off = L6; 7.397 + } 7.398 + __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), 7.399 + SP, conversion_off); 7.400 + } 7.401 + } 7.402 + } 7.403 + break; 7.404 + 7.405 + case T_DOUBLE: 7.406 + assert( j_arg + 1 < total_args_passed && 7.407 + in_sig_bt[j_arg + 1] == T_VOID && 7.408 + out_sig_bt[c_arg+1] == T_VOID, "bad arg list"); 7.409 + if (src.first()->is_stack()) { 7.410 + // Stack to stack/reg is simple 7.411 + long_move(masm, src, dst); 7.412 + } else { 7.413 + Register d = dst.first()->is_reg() ? dst.first()->as_Register() : L2; 7.414 + 7.415 + // Destination could be an odd reg on 32bit in which case 7.416 + // we can't load direct to the destination. 7.417 + 7.418 + if (!d->is_even() && wordSize == 4) { 7.419 + d = L2; 7.420 + } 7.421 + int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; 7.422 + if (Assembler::is_simm13(off)) { 7.423 + __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), 7.424 + SP, off); 7.425 + __ ld_long(SP, off, d); 7.426 + } else { 7.427 + if (conversion_off == noreg) { 7.428 + __ set(off, L6); 7.429 + conversion_off = L6; 7.430 + } 7.431 + __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), 7.432 + SP, conversion_off); 7.433 + __ ld_long(SP, conversion_off, d); 7.434 + } 7.435 + if (d == L2) { 7.436 + long_move(masm, reg64_to_VMRegPair(L2), dst); 7.437 + } 7.438 + } 7.439 + break; 7.440 + 7.441 + case T_LONG : 7.442 + // 32bit can't do a split move of something like g1 -> O0, O1 7.443 + // so use a memory temp 7.444 + if (src.is_single_phys_reg() && wordSize == 4) { 7.445 + Register tmp = L2; 7.446 + if (dst.first()->is_reg() && 7.447 + (wordSize == 8 || dst.first()->as_Register()->is_even())) { 7.448 + tmp = dst.first()->as_Register(); 7.449 + } 7.450 + 7.451 + int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size; 7.452 + if (Assembler::is_simm13(off)) { 7.453 + __ stx(src.first()->as_Register(), SP, off); 7.454 + __ ld_long(SP, off, tmp); 7.455 + } else { 7.456 + if (conversion_off == noreg) { 7.457 + __ set(off, L6); 7.458 + conversion_off = L6; 7.459 + } 7.460 + __ stx(src.first()->as_Register(), SP, conversion_off); 7.461 + __ ld_long(SP, conversion_off, tmp); 7.462 + } 7.463 + 7.464 + if (tmp == L2) { 7.465 + long_move(masm, reg64_to_VMRegPair(L2), dst); 7.466 + } 7.467 + } else { 7.468 + long_move(masm, src, dst); 7.469 + } 7.470 + break; 7.471 + 7.472 + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); 7.473 + 7.474 + default: 7.475 + move32_64(masm, src, dst); 7.476 + } 7.477 + } 7.478 + 7.479 + 7.480 + // If we have any strings we must store any register based arg to the stack 7.481 + // This includes any still live xmm registers too. 7.482 + 7.483 + if (total_strings > 0 ) { 7.484 + 7.485 + // protect all the arg registers 7.486 + __ save_frame(0); 7.487 + __ mov(G2_thread, L7_thread_cache); 7.488 + const Register L2_string_off = L2; 7.489 + 7.490 + // Get first string offset 7.491 + __ set(string_locs * VMRegImpl::stack_slot_size, L2_string_off); 7.492 + 7.493 + for (c_arg = 0 ; c_arg < total_c_args ; c_arg++ ) { 7.494 + if (out_sig_bt[c_arg] == T_ADDRESS) { 7.495 + 7.496 + VMRegPair dst = out_regs[c_arg]; 7.497 + const Register d = dst.first()->is_reg() ? 7.498 + dst.first()->as_Register()->after_save() : noreg; 7.499 + 7.500 + // It's a string the oop and it was already copied to the out arg 7.501 + // position 7.502 + if (d != noreg) { 7.503 + __ mov(d, O0); 7.504 + } else { 7.505 + assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), 7.506 + "must be"); 7.507 + __ ld_ptr(FP, reg2offset(dst.first()) + STACK_BIAS, O0); 7.508 + } 7.509 + Label skip; 7.510 + 7.511 + __ br_null(O0, false, Assembler::pn, skip); 7.512 + __ delayed()->add(FP, L2_string_off, O1); 7.513 + 7.514 + if (d != noreg) { 7.515 + __ mov(O1, d); 7.516 + } else { 7.517 + assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS), 7.518 + "must be"); 7.519 + __ st_ptr(O1, FP, reg2offset(dst.first()) + STACK_BIAS); 7.520 + } 7.521 + 7.522 + __ call(CAST_FROM_FN_PTR(address, SharedRuntime::get_utf), 7.523 + relocInfo::runtime_call_type); 7.524 + __ delayed()->add(L2_string_off, max_dtrace_string_size, L2_string_off); 7.525 + 7.526 + __ bind(skip); 7.527 + 7.528 + } 7.529 + 7.530 + } 7.531 + __ mov(L7_thread_cache, G2_thread); 7.532 + __ restore(); 7.533 + 7.534 + } 7.535 + 7.536 + 7.537 + // Ok now we are done. Need to place the nop that dtrace wants in order to 7.538 + // patch in the trap 7.539 + 7.540 + int patch_offset = ((intptr_t)__ pc()) - start; 7.541 + 7.542 + __ nop(); 7.543 + 7.544 + 7.545 + // Return 7.546 + 7.547 + __ ret(); 7.548 + __ delayed()->restore(); 7.549 + 7.550 + __ flush(); 7.551 + 7.552 + nmethod *nm = nmethod::new_dtrace_nmethod( 7.553 + method, masm->code(), vep_offset, patch_offset, frame_complete, 7.554 + stack_slots / VMRegImpl::slots_per_word); 7.555 + return nm; 7.556 + 7.557 +} 7.558 + 7.559 +#endif // HAVE_DTRACE_H 7.560 + 7.561 // this function returns the adjust size (in number of words) to a c2i adapter 7.562 // activation for use during deoptimization 7.563 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) {
8.1 --- a/src/cpu/x86/vm/nativeInst_x86.cpp Wed Apr 16 17:36:29 2008 -0400 8.2 +++ b/src/cpu/x86/vm/nativeInst_x86.cpp Thu Apr 17 22:18:15 2008 -0400 8.3 @@ -472,3 +472,7 @@ 8.4 else 8.5 return addr_at(0) + length + sbyte_at(offset); 8.6 } 8.7 + 8.8 +bool NativeInstruction::is_dtrace_trap() { 8.9 + return (*(int32_t*)this & 0xff) == 0xcc; 8.10 +}
9.1 --- a/src/cpu/x86/vm/nativeInst_x86.hpp Wed Apr 16 17:36:29 2008 -0400 9.2 +++ b/src/cpu/x86/vm/nativeInst_x86.hpp Thu Apr 17 22:18:15 2008 -0400 9.3 @@ -50,6 +50,7 @@ 9.4 }; 9.5 9.6 bool is_nop() { return ubyte_at(0) == nop_instruction_code; } 9.7 + bool is_dtrace_trap(); 9.8 inline bool is_call(); 9.9 inline bool is_illegal(); 9.10 inline bool is_return();
10.1 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Wed Apr 16 17:36:29 2008 -0400 10.2 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Apr 17 22:18:15 2008 -0400 10.3 @@ -1880,6 +1880,379 @@ 10.4 10.5 } 10.6 10.7 +#ifdef HAVE_DTRACE_H 10.8 +// --------------------------------------------------------------------------- 10.9 +// Generate a dtrace nmethod for a given signature. The method takes arguments 10.10 +// in the Java compiled code convention, marshals them to the native 10.11 +// abi and then leaves nops at the position you would expect to call a native 10.12 +// function. When the probe is enabled the nops are replaced with a trap 10.13 +// instruction that dtrace inserts and the trace will cause a notification 10.14 +// to dtrace. 10.15 +// 10.16 +// The probes are only able to take primitive types and java/lang/String as 10.17 +// arguments. No other java types are allowed. Strings are converted to utf8 10.18 +// strings so that from dtrace point of view java strings are converted to C 10.19 +// strings. There is an arbitrary fixed limit on the total space that a method 10.20 +// can use for converting the strings. (256 chars per string in the signature). 10.21 +// So any java string larger then this is truncated. 10.22 + 10.23 +nmethod *SharedRuntime::generate_dtrace_nmethod( 10.24 + MacroAssembler *masm, methodHandle method) { 10.25 + 10.26 + // generate_dtrace_nmethod is guarded by a mutex so we are sure to 10.27 + // be single threaded in this method. 10.28 + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); 10.29 + 10.30 + // Fill in the signature array, for the calling-convention call. 10.31 + int total_args_passed = method->size_of_parameters(); 10.32 + 10.33 + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); 10.34 + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); 10.35 + 10.36 + // The signature we are going to use for the trap that dtrace will see 10.37 + // java/lang/String is converted. We drop "this" and any other object 10.38 + // is converted to NULL. (A one-slot java/lang/Long object reference 10.39 + // is converted to a two-slot long, which is why we double the allocation). 10.40 + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); 10.41 + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); 10.42 + 10.43 + int i=0; 10.44 + int total_strings = 0; 10.45 + int first_arg_to_pass = 0; 10.46 + int total_c_args = 0; 10.47 + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); 10.48 + 10.49 + if( !method->is_static() ) { // Pass in receiver first 10.50 + in_sig_bt[i++] = T_OBJECT; 10.51 + first_arg_to_pass = 1; 10.52 + } 10.53 + 10.54 + // We need to convert the java args to where a native (non-jni) function 10.55 + // would expect them. To figure out where they go we convert the java 10.56 + // signature to a C signature. 10.57 + 10.58 + SignatureStream ss(method->signature()); 10.59 + for ( ; !ss.at_return_type(); ss.next()) { 10.60 + BasicType bt = ss.type(); 10.61 + in_sig_bt[i++] = bt; // Collect remaining bits of signature 10.62 + out_sig_bt[total_c_args++] = bt; 10.63 + if( bt == T_OBJECT) { 10.64 + symbolOop s = ss.as_symbol_or_null(); 10.65 + if (s == vmSymbols::java_lang_String()) { 10.66 + total_strings++; 10.67 + out_sig_bt[total_c_args-1] = T_ADDRESS; 10.68 + } else if (s == vmSymbols::java_lang_Boolean() || 10.69 + s == vmSymbols::java_lang_Character() || 10.70 + s == vmSymbols::java_lang_Byte() || 10.71 + s == vmSymbols::java_lang_Short() || 10.72 + s == vmSymbols::java_lang_Integer() || 10.73 + s == vmSymbols::java_lang_Float()) { 10.74 + out_sig_bt[total_c_args-1] = T_INT; 10.75 + } else if (s == vmSymbols::java_lang_Long() || 10.76 + s == vmSymbols::java_lang_Double()) { 10.77 + out_sig_bt[total_c_args-1] = T_LONG; 10.78 + out_sig_bt[total_c_args++] = T_VOID; 10.79 + } 10.80 + } else if ( bt == T_LONG || bt == T_DOUBLE ) { 10.81 + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots 10.82 + out_sig_bt[total_c_args++] = T_VOID; 10.83 + } 10.84 + } 10.85 + 10.86 + assert(i==total_args_passed, "validly parsed signature"); 10.87 + 10.88 + // Now get the compiled-Java layout as input arguments 10.89 + int comp_args_on_stack; 10.90 + comp_args_on_stack = SharedRuntime::java_calling_convention( 10.91 + in_sig_bt, in_regs, total_args_passed, false); 10.92 + 10.93 + // Now figure out where the args must be stored and how much stack space 10.94 + // they require (neglecting out_preserve_stack_slots). 10.95 + 10.96 + int out_arg_slots; 10.97 + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); 10.98 + 10.99 + // Calculate the total number of stack slots we will need. 10.100 + 10.101 + // First count the abi requirement plus all of the outgoing args 10.102 + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; 10.103 + 10.104 + // Now space for the string(s) we must convert 10.105 + 10.106 + int* string_locs = NEW_RESOURCE_ARRAY(int, total_strings + 1); 10.107 + for (i = 0; i < total_strings ; i++) { 10.108 + string_locs[i] = stack_slots; 10.109 + stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size; 10.110 + } 10.111 + 10.112 + // + 2 for return address (which we own) and saved rbp, 10.113 + 10.114 + stack_slots += 2; 10.115 + 10.116 + // Ok The space we have allocated will look like: 10.117 + // 10.118 + // 10.119 + // FP-> | | 10.120 + // |---------------------| 10.121 + // | string[n] | 10.122 + // |---------------------| <- string_locs[n] 10.123 + // | string[n-1] | 10.124 + // |---------------------| <- string_locs[n-1] 10.125 + // | ... | 10.126 + // | ... | 10.127 + // |---------------------| <- string_locs[1] 10.128 + // | string[0] | 10.129 + // |---------------------| <- string_locs[0] 10.130 + // | outbound memory | 10.131 + // | based arguments | 10.132 + // | | 10.133 + // |---------------------| 10.134 + // | | 10.135 + // SP-> | out_preserved_slots | 10.136 + // 10.137 + // 10.138 + 10.139 + // Now compute actual number of stack words we need rounding to make 10.140 + // stack properly aligned. 10.141 + stack_slots = round_to(stack_slots, 2 * VMRegImpl::slots_per_word); 10.142 + 10.143 + int stack_size = stack_slots * VMRegImpl::stack_slot_size; 10.144 + 10.145 + intptr_t start = (intptr_t)__ pc(); 10.146 + 10.147 + // First thing make an ic check to see if we should even be here 10.148 + 10.149 + // We are free to use all registers as temps without saving them and 10.150 + // restoring them except rbp. rbp, is the only callee save register 10.151 + // as far as the interpreter and the compiler(s) are concerned. 10.152 + 10.153 + const Register ic_reg = rax; 10.154 + const Register receiver = rcx; 10.155 + Label hit; 10.156 + Label exception_pending; 10.157 + 10.158 + 10.159 + __ verify_oop(receiver); 10.160 + __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); 10.161 + __ jcc(Assembler::equal, hit); 10.162 + 10.163 + __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); 10.164 + 10.165 + // verified entry must be aligned for code patching. 10.166 + // and the first 5 bytes must be in the same cache line 10.167 + // if we align at 8 then we will be sure 5 bytes are in the same line 10.168 + __ align(8); 10.169 + 10.170 + __ bind(hit); 10.171 + 10.172 + int vep_offset = ((intptr_t)__ pc()) - start; 10.173 + 10.174 + 10.175 + // The instruction at the verified entry point must be 5 bytes or longer 10.176 + // because it can be patched on the fly by make_non_entrant. The stack bang 10.177 + // instruction fits that requirement. 10.178 + 10.179 + // Generate stack overflow check 10.180 + 10.181 + 10.182 + if (UseStackBanging) { 10.183 + if (stack_size <= StackShadowPages*os::vm_page_size()) { 10.184 + __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); 10.185 + } else { 10.186 + __ movl(rax, stack_size); 10.187 + __ bang_stack_size(rax, rbx); 10.188 + } 10.189 + } else { 10.190 + // need a 5 byte instruction to allow MT safe patching to non-entrant 10.191 + __ fat_nop(); 10.192 + } 10.193 + 10.194 + assert(((int)__ pc() - start - vep_offset) >= 5, 10.195 + "valid size for make_non_entrant"); 10.196 + 10.197 + // Generate a new frame for the wrapper. 10.198 + __ enter(); 10.199 + 10.200 + // -2 because return address is already present and so is saved rbp, 10.201 + if (stack_size - 2*wordSize != 0) { 10.202 + __ subl(rsp, stack_size - 2*wordSize); 10.203 + } 10.204 + 10.205 + // Frame is now completed as far a size and linkage. 10.206 + 10.207 + int frame_complete = ((intptr_t)__ pc()) - start; 10.208 + 10.209 + // First thing we do store all the args as if we are doing the call. 10.210 + // Since the C calling convention is stack based that ensures that 10.211 + // all the Java register args are stored before we need to convert any 10.212 + // string we might have. 10.213 + 10.214 + int sid = 0; 10.215 + int c_arg, j_arg; 10.216 + int string_reg = 0; 10.217 + 10.218 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 10.219 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 10.220 + 10.221 + VMRegPair src = in_regs[j_arg]; 10.222 + VMRegPair dst = out_regs[c_arg]; 10.223 + assert(dst.first()->is_stack() || in_sig_bt[j_arg] == T_VOID, 10.224 + "stack based abi assumed"); 10.225 + 10.226 + switch (in_sig_bt[j_arg]) { 10.227 + 10.228 + case T_ARRAY: 10.229 + case T_OBJECT: 10.230 + if (out_sig_bt[c_arg] == T_ADDRESS) { 10.231 + // Any register based arg for a java string after the first 10.232 + // will be destroyed by the call to get_utf so we store 10.233 + // the original value in the location the utf string address 10.234 + // will eventually be stored. 10.235 + if (src.first()->is_reg()) { 10.236 + if (string_reg++ != 0) { 10.237 + simple_move32(masm, src, dst); 10.238 + } 10.239 + } 10.240 + } else if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { 10.241 + // need to unbox a one-word value 10.242 + Register in_reg = rax; 10.243 + if ( src.first()->is_reg() ) { 10.244 + in_reg = src.first()->as_Register(); 10.245 + } else { 10.246 + simple_move32(masm, src, in_reg->as_VMReg()); 10.247 + } 10.248 + Label skipUnbox; 10.249 + __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD); 10.250 + if ( out_sig_bt[c_arg] == T_LONG ) { 10.251 + __ movl(Address(rsp, reg2offset_out(dst.second())), NULL_WORD); 10.252 + } 10.253 + __ testl(in_reg, in_reg); 10.254 + __ jcc(Assembler::zero, skipUnbox); 10.255 + assert(dst.first()->is_stack() && 10.256 + (!dst.second()->is_valid() || dst.second()->is_stack()), 10.257 + "value(s) must go into stack slots"); 10.258 + if ( out_sig_bt[c_arg] == T_LONG ) { 10.259 + __ movl(rbx, Address(in_reg, 10.260 + box_offset + VMRegImpl::stack_slot_size)); 10.261 + __ movl(Address(rsp, reg2offset_out(dst.second())), rbx); 10.262 + } 10.263 + __ movl(in_reg, Address(in_reg, box_offset)); 10.264 + __ movl(Address(rsp, reg2offset_out(dst.first())), in_reg); 10.265 + __ bind(skipUnbox); 10.266 + } else { 10.267 + // Convert the arg to NULL 10.268 + __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD); 10.269 + } 10.270 + if (out_sig_bt[c_arg] == T_LONG) { 10.271 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 10.272 + ++c_arg; // Move over the T_VOID To keep the loop indices in sync 10.273 + } 10.274 + break; 10.275 + 10.276 + case T_VOID: 10.277 + break; 10.278 + 10.279 + case T_FLOAT: 10.280 + float_move(masm, src, dst); 10.281 + break; 10.282 + 10.283 + case T_DOUBLE: 10.284 + assert( j_arg + 1 < total_args_passed && 10.285 + in_sig_bt[j_arg + 1] == T_VOID, "bad arg list"); 10.286 + double_move(masm, src, dst); 10.287 + break; 10.288 + 10.289 + case T_LONG : 10.290 + long_move(masm, src, dst); 10.291 + break; 10.292 + 10.293 + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); 10.294 + 10.295 + default: 10.296 + simple_move32(masm, src, dst); 10.297 + } 10.298 + } 10.299 + 10.300 + // Now we must convert any string we have to utf8 10.301 + // 10.302 + 10.303 + for (sid = 0, j_arg = first_arg_to_pass, c_arg = 0 ; 10.304 + sid < total_strings ; j_arg++, c_arg++ ) { 10.305 + 10.306 + if (out_sig_bt[c_arg] == T_ADDRESS) { 10.307 + 10.308 + Address utf8_addr = Address( 10.309 + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); 10.310 + __ leal(rax, utf8_addr); 10.311 + 10.312 + // The first string we find might still be in the original java arg 10.313 + // register 10.314 + VMReg orig_loc = in_regs[j_arg].first(); 10.315 + Register string_oop; 10.316 + 10.317 + // This is where the argument will eventually reside 10.318 + Address dest = Address(rsp, reg2offset_out(out_regs[c_arg].first())); 10.319 + 10.320 + if (sid == 1 && orig_loc->is_reg()) { 10.321 + string_oop = orig_loc->as_Register(); 10.322 + assert(string_oop != rax, "smashed arg"); 10.323 + } else { 10.324 + 10.325 + if (orig_loc->is_reg()) { 10.326 + // Get the copy of the jls object 10.327 + __ movl(rcx, dest); 10.328 + } else { 10.329 + // arg is still in the original location 10.330 + __ movl(rcx, Address(rbp, reg2offset_in(orig_loc))); 10.331 + } 10.332 + string_oop = rcx; 10.333 + 10.334 + } 10.335 + Label nullString; 10.336 + __ movl(dest, NULL_WORD); 10.337 + __ testl(string_oop, string_oop); 10.338 + __ jcc(Assembler::zero, nullString); 10.339 + 10.340 + // Now we can store the address of the utf string as the argument 10.341 + __ movl(dest, rax); 10.342 + 10.343 + // And do the conversion 10.344 + __ call_VM_leaf(CAST_FROM_FN_PTR( 10.345 + address, SharedRuntime::get_utf), string_oop, rax); 10.346 + __ bind(nullString); 10.347 + } 10.348 + 10.349 + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { 10.350 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 10.351 + ++c_arg; // Move over the T_VOID To keep the loop indices in sync 10.352 + } 10.353 + } 10.354 + 10.355 + 10.356 + // Ok now we are done. Need to place the nop that dtrace wants in order to 10.357 + // patch in the trap 10.358 + 10.359 + int patch_offset = ((intptr_t)__ pc()) - start; 10.360 + 10.361 + __ nop(); 10.362 + 10.363 + 10.364 + // Return 10.365 + 10.366 + __ leave(); 10.367 + __ ret(0); 10.368 + 10.369 + __ flush(); 10.370 + 10.371 + nmethod *nm = nmethod::new_dtrace_nmethod( 10.372 + method, masm->code(), vep_offset, patch_offset, frame_complete, 10.373 + stack_slots / VMRegImpl::slots_per_word); 10.374 + return nm; 10.375 + 10.376 +} 10.377 + 10.378 +#endif // HAVE_DTRACE_H 10.379 + 10.380 // this function returns the adjust size (in number of words) to a c2i adapter 10.381 // activation for use during deoptimization 10.382 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) {
11.1 --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Wed Apr 16 17:36:29 2008 -0400 11.2 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Apr 17 22:18:15 2008 -0400 11.3 @@ -1886,6 +1886,627 @@ 11.4 11.5 } 11.6 11.7 +#ifdef HAVE_DTRACE_H 11.8 +// --------------------------------------------------------------------------- 11.9 +// Generate a dtrace nmethod for a given signature. The method takes arguments 11.10 +// in the Java compiled code convention, marshals them to the native 11.11 +// abi and then leaves nops at the position you would expect to call a native 11.12 +// function. When the probe is enabled the nops are replaced with a trap 11.13 +// instruction that dtrace inserts and the trace will cause a notification 11.14 +// to dtrace. 11.15 +// 11.16 +// The probes are only able to take primitive types and java/lang/String as 11.17 +// arguments. No other java types are allowed. Strings are converted to utf8 11.18 +// strings so that from dtrace point of view java strings are converted to C 11.19 +// strings. There is an arbitrary fixed limit on the total space that a method 11.20 +// can use for converting the strings. (256 chars per string in the signature). 11.21 +// So any java string larger then this is truncated. 11.22 + 11.23 +static int fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 }; 11.24 +static bool offsets_initialized = false; 11.25 + 11.26 + 11.27 +nmethod *SharedRuntime::generate_dtrace_nmethod(MacroAssembler *masm, 11.28 + methodHandle method) { 11.29 + 11.30 + 11.31 + // generate_dtrace_nmethod is guarded by a mutex so we are sure to 11.32 + // be single threaded in this method. 11.33 + assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be"); 11.34 + 11.35 + if (!offsets_initialized) { 11.36 + fp_offset[c_rarg0->as_VMReg()->value()] = -1 * wordSize; 11.37 + fp_offset[c_rarg1->as_VMReg()->value()] = -2 * wordSize; 11.38 + fp_offset[c_rarg2->as_VMReg()->value()] = -3 * wordSize; 11.39 + fp_offset[c_rarg3->as_VMReg()->value()] = -4 * wordSize; 11.40 + fp_offset[c_rarg4->as_VMReg()->value()] = -5 * wordSize; 11.41 + fp_offset[c_rarg5->as_VMReg()->value()] = -6 * wordSize; 11.42 + 11.43 + fp_offset[c_farg0->as_VMReg()->value()] = -7 * wordSize; 11.44 + fp_offset[c_farg1->as_VMReg()->value()] = -8 * wordSize; 11.45 + fp_offset[c_farg2->as_VMReg()->value()] = -9 * wordSize; 11.46 + fp_offset[c_farg3->as_VMReg()->value()] = -10 * wordSize; 11.47 + fp_offset[c_farg4->as_VMReg()->value()] = -11 * wordSize; 11.48 + fp_offset[c_farg5->as_VMReg()->value()] = -12 * wordSize; 11.49 + fp_offset[c_farg6->as_VMReg()->value()] = -13 * wordSize; 11.50 + fp_offset[c_farg7->as_VMReg()->value()] = -14 * wordSize; 11.51 + 11.52 + offsets_initialized = true; 11.53 + } 11.54 + // Fill in the signature array, for the calling-convention call. 11.55 + int total_args_passed = method->size_of_parameters(); 11.56 + 11.57 + BasicType* in_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); 11.58 + VMRegPair *in_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); 11.59 + 11.60 + // The signature we are going to use for the trap that dtrace will see 11.61 + // java/lang/String is converted. We drop "this" and any other object 11.62 + // is converted to NULL. (A one-slot java/lang/Long object reference 11.63 + // is converted to a two-slot long, which is why we double the allocation). 11.64 + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2); 11.65 + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2); 11.66 + 11.67 + int i=0; 11.68 + int total_strings = 0; 11.69 + int first_arg_to_pass = 0; 11.70 + int total_c_args = 0; 11.71 + int box_offset = java_lang_boxing_object::value_offset_in_bytes(); 11.72 + 11.73 + // Skip the receiver as dtrace doesn't want to see it 11.74 + if( !method->is_static() ) { 11.75 + in_sig_bt[i++] = T_OBJECT; 11.76 + first_arg_to_pass = 1; 11.77 + } 11.78 + 11.79 + // We need to convert the java args to where a native (non-jni) function 11.80 + // would expect them. To figure out where they go we convert the java 11.81 + // signature to a C signature. 11.82 + 11.83 + SignatureStream ss(method->signature()); 11.84 + for ( ; !ss.at_return_type(); ss.next()) { 11.85 + BasicType bt = ss.type(); 11.86 + in_sig_bt[i++] = bt; // Collect remaining bits of signature 11.87 + out_sig_bt[total_c_args++] = bt; 11.88 + if( bt == T_OBJECT) { 11.89 + symbolOop s = ss.as_symbol_or_null(); 11.90 + if (s == vmSymbols::java_lang_String()) { 11.91 + total_strings++; 11.92 + out_sig_bt[total_c_args-1] = T_ADDRESS; 11.93 + } else if (s == vmSymbols::java_lang_Boolean() || 11.94 + s == vmSymbols::java_lang_Character() || 11.95 + s == vmSymbols::java_lang_Byte() || 11.96 + s == vmSymbols::java_lang_Short() || 11.97 + s == vmSymbols::java_lang_Integer() || 11.98 + s == vmSymbols::java_lang_Float()) { 11.99 + out_sig_bt[total_c_args-1] = T_INT; 11.100 + } else if (s == vmSymbols::java_lang_Long() || 11.101 + s == vmSymbols::java_lang_Double()) { 11.102 + out_sig_bt[total_c_args-1] = T_LONG; 11.103 + out_sig_bt[total_c_args++] = T_VOID; 11.104 + } 11.105 + } else if ( bt == T_LONG || bt == T_DOUBLE ) { 11.106 + in_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots 11.107 + // We convert double to long 11.108 + out_sig_bt[total_c_args-1] = T_LONG; 11.109 + out_sig_bt[total_c_args++] = T_VOID; 11.110 + } else if ( bt == T_FLOAT) { 11.111 + // We convert float to int 11.112 + out_sig_bt[total_c_args-1] = T_INT; 11.113 + } 11.114 + } 11.115 + 11.116 + assert(i==total_args_passed, "validly parsed signature"); 11.117 + 11.118 + // Now get the compiled-Java layout as input arguments 11.119 + int comp_args_on_stack; 11.120 + comp_args_on_stack = SharedRuntime::java_calling_convention( 11.121 + in_sig_bt, in_regs, total_args_passed, false); 11.122 + 11.123 + // Now figure out where the args must be stored and how much stack space 11.124 + // they require (neglecting out_preserve_stack_slots but space for storing 11.125 + // the 1st six register arguments). It's weird see int_stk_helper. 11.126 + 11.127 + int out_arg_slots; 11.128 + out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args); 11.129 + 11.130 + // Calculate the total number of stack slots we will need. 11.131 + 11.132 + // First count the abi requirement plus all of the outgoing args 11.133 + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; 11.134 + 11.135 + // Now space for the string(s) we must convert 11.136 + int* string_locs = NEW_RESOURCE_ARRAY(int, total_strings + 1); 11.137 + for (i = 0; i < total_strings ; i++) { 11.138 + string_locs[i] = stack_slots; 11.139 + stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size; 11.140 + } 11.141 + 11.142 + // Plus the temps we might need to juggle register args 11.143 + // regs take two slots each 11.144 + stack_slots += (Argument::n_int_register_parameters_c + 11.145 + Argument::n_float_register_parameters_c) * 2; 11.146 + 11.147 + 11.148 + // + 4 for return address (which we own) and saved rbp, 11.149 + 11.150 + stack_slots += 4; 11.151 + 11.152 + // Ok The space we have allocated will look like: 11.153 + // 11.154 + // 11.155 + // FP-> | | 11.156 + // |---------------------| 11.157 + // | string[n] | 11.158 + // |---------------------| <- string_locs[n] 11.159 + // | string[n-1] | 11.160 + // |---------------------| <- string_locs[n-1] 11.161 + // | ... | 11.162 + // | ... | 11.163 + // |---------------------| <- string_locs[1] 11.164 + // | string[0] | 11.165 + // |---------------------| <- string_locs[0] 11.166 + // | outbound memory | 11.167 + // | based arguments | 11.168 + // | | 11.169 + // |---------------------| 11.170 + // | | 11.171 + // SP-> | out_preserved_slots | 11.172 + // 11.173 + // 11.174 + 11.175 + // Now compute actual number of stack words we need rounding to make 11.176 + // stack properly aligned. 11.177 + stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word); 11.178 + 11.179 + int stack_size = stack_slots * VMRegImpl::stack_slot_size; 11.180 + 11.181 + intptr_t start = (intptr_t)__ pc(); 11.182 + 11.183 + // First thing make an ic check to see if we should even be here 11.184 + 11.185 + // We are free to use all registers as temps without saving them and 11.186 + // restoring them except rbp. rbp, is the only callee save register 11.187 + // as far as the interpreter and the compiler(s) are concerned. 11.188 + 11.189 + const Register ic_reg = rax; 11.190 + const Register receiver = rcx; 11.191 + Label hit; 11.192 + Label exception_pending; 11.193 + 11.194 + 11.195 + __ verify_oop(receiver); 11.196 + __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes())); 11.197 + __ jcc(Assembler::equal, hit); 11.198 + 11.199 + __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); 11.200 + 11.201 + // verified entry must be aligned for code patching. 11.202 + // and the first 5 bytes must be in the same cache line 11.203 + // if we align at 8 then we will be sure 5 bytes are in the same line 11.204 + __ align(8); 11.205 + 11.206 + __ bind(hit); 11.207 + 11.208 + int vep_offset = ((intptr_t)__ pc()) - start; 11.209 + 11.210 + 11.211 + // The instruction at the verified entry point must be 5 bytes or longer 11.212 + // because it can be patched on the fly by make_non_entrant. The stack bang 11.213 + // instruction fits that requirement. 11.214 + 11.215 + // Generate stack overflow check 11.216 + 11.217 + if (UseStackBanging) { 11.218 + if (stack_size <= StackShadowPages*os::vm_page_size()) { 11.219 + __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); 11.220 + } else { 11.221 + __ movl(rax, stack_size); 11.222 + __ bang_stack_size(rax, rbx); 11.223 + } 11.224 + } else { 11.225 + // need a 5 byte instruction to allow MT safe patching to non-entrant 11.226 + __ fat_nop(); 11.227 + } 11.228 + 11.229 + assert(((uintptr_t)__ pc() - start - vep_offset) >= 5, 11.230 + "valid size for make_non_entrant"); 11.231 + 11.232 + // Generate a new frame for the wrapper. 11.233 + __ enter(); 11.234 + 11.235 + // -4 because return address is already present and so is saved rbp, 11.236 + if (stack_size - 2*wordSize != 0) { 11.237 + __ subq(rsp, stack_size - 2*wordSize); 11.238 + } 11.239 + 11.240 + // Frame is now completed as far a size and linkage. 11.241 + 11.242 + int frame_complete = ((intptr_t)__ pc()) - start; 11.243 + 11.244 + int c_arg, j_arg; 11.245 + 11.246 + // State of input register args 11.247 + 11.248 + bool live[ConcreteRegisterImpl::number_of_registers]; 11.249 + 11.250 + live[j_rarg0->as_VMReg()->value()] = false; 11.251 + live[j_rarg1->as_VMReg()->value()] = false; 11.252 + live[j_rarg2->as_VMReg()->value()] = false; 11.253 + live[j_rarg3->as_VMReg()->value()] = false; 11.254 + live[j_rarg4->as_VMReg()->value()] = false; 11.255 + live[j_rarg5->as_VMReg()->value()] = false; 11.256 + 11.257 + live[j_farg0->as_VMReg()->value()] = false; 11.258 + live[j_farg1->as_VMReg()->value()] = false; 11.259 + live[j_farg2->as_VMReg()->value()] = false; 11.260 + live[j_farg3->as_VMReg()->value()] = false; 11.261 + live[j_farg4->as_VMReg()->value()] = false; 11.262 + live[j_farg5->as_VMReg()->value()] = false; 11.263 + live[j_farg6->as_VMReg()->value()] = false; 11.264 + live[j_farg7->as_VMReg()->value()] = false; 11.265 + 11.266 + 11.267 + bool rax_is_zero = false; 11.268 + 11.269 + // All args (except strings) destined for the stack are moved first 11.270 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 11.271 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 11.272 + VMRegPair src = in_regs[j_arg]; 11.273 + VMRegPair dst = out_regs[c_arg]; 11.274 + 11.275 + // Get the real reg value or a dummy (rsp) 11.276 + 11.277 + int src_reg = src.first()->is_reg() ? 11.278 + src.first()->value() : 11.279 + rsp->as_VMReg()->value(); 11.280 + 11.281 + bool useless = in_sig_bt[j_arg] == T_ARRAY || 11.282 + (in_sig_bt[j_arg] == T_OBJECT && 11.283 + out_sig_bt[c_arg] != T_INT && 11.284 + out_sig_bt[c_arg] != T_ADDRESS && 11.285 + out_sig_bt[c_arg] != T_LONG); 11.286 + 11.287 + live[src_reg] = !useless; 11.288 + 11.289 + if (dst.first()->is_stack()) { 11.290 + 11.291 + // Even though a string arg in a register is still live after this loop 11.292 + // after the string conversion loop (next) it will be dead so we take 11.293 + // advantage of that now for simpler code to manage live. 11.294 + 11.295 + live[src_reg] = false; 11.296 + switch (in_sig_bt[j_arg]) { 11.297 + 11.298 + case T_ARRAY: 11.299 + case T_OBJECT: 11.300 + { 11.301 + Address stack_dst(rsp, reg2offset_out(dst.first())); 11.302 + 11.303 + if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { 11.304 + // need to unbox a one-word value 11.305 + Register in_reg = rax; 11.306 + if ( src.first()->is_reg() ) { 11.307 + in_reg = src.first()->as_Register(); 11.308 + } else { 11.309 + __ movq(rax, Address(rbp, reg2offset_in(src.first()))); 11.310 + rax_is_zero = false; 11.311 + } 11.312 + Label skipUnbox; 11.313 + __ movptr(Address(rsp, reg2offset_out(dst.first())), 11.314 + (int32_t)NULL_WORD); 11.315 + __ testq(in_reg, in_reg); 11.316 + __ jcc(Assembler::zero, skipUnbox); 11.317 + 11.318 + Address src1(in_reg, box_offset); 11.319 + if ( out_sig_bt[c_arg] == T_LONG ) { 11.320 + __ movq(in_reg, src1); 11.321 + __ movq(stack_dst, in_reg); 11.322 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 11.323 + ++c_arg; // skip over T_VOID to keep the loop indices in sync 11.324 + } else { 11.325 + __ movl(in_reg, src1); 11.326 + __ movl(stack_dst, in_reg); 11.327 + } 11.328 + 11.329 + __ bind(skipUnbox); 11.330 + } else if (out_sig_bt[c_arg] != T_ADDRESS) { 11.331 + // Convert the arg to NULL 11.332 + if (!rax_is_zero) { 11.333 + __ xorq(rax, rax); 11.334 + rax_is_zero = true; 11.335 + } 11.336 + __ movq(stack_dst, rax); 11.337 + } 11.338 + } 11.339 + break; 11.340 + 11.341 + case T_VOID: 11.342 + break; 11.343 + 11.344 + case T_FLOAT: 11.345 + // This does the right thing since we know it is destined for the 11.346 + // stack 11.347 + float_move(masm, src, dst); 11.348 + break; 11.349 + 11.350 + case T_DOUBLE: 11.351 + // This does the right thing since we know it is destined for the 11.352 + // stack 11.353 + double_move(masm, src, dst); 11.354 + break; 11.355 + 11.356 + case T_LONG : 11.357 + long_move(masm, src, dst); 11.358 + break; 11.359 + 11.360 + case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); 11.361 + 11.362 + default: 11.363 + move32_64(masm, src, dst); 11.364 + } 11.365 + } 11.366 + 11.367 + } 11.368 + 11.369 + // If we have any strings we must store any register based arg to the stack 11.370 + // This includes any still live xmm registers too. 11.371 + 11.372 + int sid = 0; 11.373 + 11.374 + if (total_strings > 0 ) { 11.375 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 11.376 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 11.377 + VMRegPair src = in_regs[j_arg]; 11.378 + VMRegPair dst = out_regs[c_arg]; 11.379 + 11.380 + if (src.first()->is_reg()) { 11.381 + Address src_tmp(rbp, fp_offset[src.first()->value()]); 11.382 + 11.383 + // string oops were left untouched by the previous loop even if the 11.384 + // eventual (converted) arg is destined for the stack so park them 11.385 + // away now (except for first) 11.386 + 11.387 + if (out_sig_bt[c_arg] == T_ADDRESS) { 11.388 + Address utf8_addr = Address( 11.389 + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); 11.390 + if (sid != 1) { 11.391 + // The first string arg won't be killed until after the utf8 11.392 + // conversion 11.393 + __ movq(utf8_addr, src.first()->as_Register()); 11.394 + } 11.395 + } else if (dst.first()->is_reg()) { 11.396 + if (in_sig_bt[j_arg] == T_FLOAT || in_sig_bt[j_arg] == T_DOUBLE) { 11.397 + 11.398 + // Convert the xmm register to an int and store it in the reserved 11.399 + // location for the eventual c register arg 11.400 + XMMRegister f = src.first()->as_XMMRegister(); 11.401 + if (in_sig_bt[j_arg] == T_FLOAT) { 11.402 + __ movflt(src_tmp, f); 11.403 + } else { 11.404 + __ movdbl(src_tmp, f); 11.405 + } 11.406 + } else { 11.407 + // If the arg is an oop type we don't support don't bother to store 11.408 + // it remember string was handled above. 11.409 + bool useless = in_sig_bt[j_arg] == T_ARRAY || 11.410 + (in_sig_bt[j_arg] == T_OBJECT && 11.411 + out_sig_bt[c_arg] != T_INT && 11.412 + out_sig_bt[c_arg] != T_LONG); 11.413 + 11.414 + if (!useless) { 11.415 + __ movq(src_tmp, src.first()->as_Register()); 11.416 + } 11.417 + } 11.418 + } 11.419 + } 11.420 + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { 11.421 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 11.422 + ++c_arg; // skip over T_VOID to keep the loop indices in sync 11.423 + } 11.424 + } 11.425 + 11.426 + // Now that the volatile registers are safe, convert all the strings 11.427 + sid = 0; 11.428 + 11.429 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 11.430 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 11.431 + if (out_sig_bt[c_arg] == T_ADDRESS) { 11.432 + // It's a string 11.433 + Address utf8_addr = Address( 11.434 + rsp, string_locs[sid++] * VMRegImpl::stack_slot_size); 11.435 + // The first string we find might still be in the original java arg 11.436 + // register 11.437 + 11.438 + VMReg src = in_regs[j_arg].first(); 11.439 + 11.440 + // We will need to eventually save the final argument to the trap 11.441 + // in the von-volatile location dedicated to src. This is the offset 11.442 + // from fp we will use. 11.443 + int src_off = src->is_reg() ? 11.444 + fp_offset[src->value()] : reg2offset_in(src); 11.445 + 11.446 + // This is where the argument will eventually reside 11.447 + VMRegPair dst = out_regs[c_arg]; 11.448 + 11.449 + if (src->is_reg()) { 11.450 + if (sid == 1) { 11.451 + __ movq(c_rarg0, src->as_Register()); 11.452 + } else { 11.453 + __ movq(c_rarg0, utf8_addr); 11.454 + } 11.455 + } else { 11.456 + // arg is still in the original location 11.457 + __ movq(c_rarg0, Address(rbp, reg2offset_in(src))); 11.458 + } 11.459 + Label done, convert; 11.460 + 11.461 + // see if the oop is NULL 11.462 + __ testq(c_rarg0, c_rarg0); 11.463 + __ jcc(Assembler::notEqual, convert); 11.464 + 11.465 + if (dst.first()->is_reg()) { 11.466 + // Save the ptr to utf string in the origina src loc or the tmp 11.467 + // dedicated to it 11.468 + __ movq(Address(rbp, src_off), c_rarg0); 11.469 + } else { 11.470 + __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg0); 11.471 + } 11.472 + __ jmp(done); 11.473 + 11.474 + __ bind(convert); 11.475 + 11.476 + __ lea(c_rarg1, utf8_addr); 11.477 + if (dst.first()->is_reg()) { 11.478 + __ movq(Address(rbp, src_off), c_rarg1); 11.479 + } else { 11.480 + __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg1); 11.481 + } 11.482 + // And do the conversion 11.483 + __ call(RuntimeAddress( 11.484 + CAST_FROM_FN_PTR(address, SharedRuntime::get_utf))); 11.485 + 11.486 + __ bind(done); 11.487 + } 11.488 + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { 11.489 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 11.490 + ++c_arg; // skip over T_VOID to keep the loop indices in sync 11.491 + } 11.492 + } 11.493 + // The get_utf call killed all the c_arg registers 11.494 + live[c_rarg0->as_VMReg()->value()] = false; 11.495 + live[c_rarg1->as_VMReg()->value()] = false; 11.496 + live[c_rarg2->as_VMReg()->value()] = false; 11.497 + live[c_rarg3->as_VMReg()->value()] = false; 11.498 + live[c_rarg4->as_VMReg()->value()] = false; 11.499 + live[c_rarg5->as_VMReg()->value()] = false; 11.500 + 11.501 + live[c_farg0->as_VMReg()->value()] = false; 11.502 + live[c_farg1->as_VMReg()->value()] = false; 11.503 + live[c_farg2->as_VMReg()->value()] = false; 11.504 + live[c_farg3->as_VMReg()->value()] = false; 11.505 + live[c_farg4->as_VMReg()->value()] = false; 11.506 + live[c_farg5->as_VMReg()->value()] = false; 11.507 + live[c_farg6->as_VMReg()->value()] = false; 11.508 + live[c_farg7->as_VMReg()->value()] = false; 11.509 + } 11.510 + 11.511 + // Now we can finally move the register args to their desired locations 11.512 + 11.513 + rax_is_zero = false; 11.514 + 11.515 + for (j_arg = first_arg_to_pass, c_arg = 0 ; 11.516 + j_arg < total_args_passed ; j_arg++, c_arg++ ) { 11.517 + 11.518 + VMRegPair src = in_regs[j_arg]; 11.519 + VMRegPair dst = out_regs[c_arg]; 11.520 + 11.521 + // Only need to look for args destined for the interger registers (since we 11.522 + // convert float/double args to look like int/long outbound) 11.523 + if (dst.first()->is_reg()) { 11.524 + Register r = dst.first()->as_Register(); 11.525 + 11.526 + // Check if the java arg is unsupported and thereofre useless 11.527 + bool useless = in_sig_bt[j_arg] == T_ARRAY || 11.528 + (in_sig_bt[j_arg] == T_OBJECT && 11.529 + out_sig_bt[c_arg] != T_INT && 11.530 + out_sig_bt[c_arg] != T_ADDRESS && 11.531 + out_sig_bt[c_arg] != T_LONG); 11.532 + 11.533 + 11.534 + // If we're going to kill an existing arg save it first 11.535 + if (live[dst.first()->value()]) { 11.536 + // you can't kill yourself 11.537 + if (src.first() != dst.first()) { 11.538 + __ movq(Address(rbp, fp_offset[dst.first()->value()]), r); 11.539 + } 11.540 + } 11.541 + if (src.first()->is_reg()) { 11.542 + if (live[src.first()->value()] ) { 11.543 + if (in_sig_bt[j_arg] == T_FLOAT) { 11.544 + __ movdl(r, src.first()->as_XMMRegister()); 11.545 + } else if (in_sig_bt[j_arg] == T_DOUBLE) { 11.546 + __ movdq(r, src.first()->as_XMMRegister()); 11.547 + } else if (r != src.first()->as_Register()) { 11.548 + if (!useless) { 11.549 + __ movq(r, src.first()->as_Register()); 11.550 + } 11.551 + } 11.552 + } else { 11.553 + // If the arg is an oop type we don't support don't bother to store 11.554 + // it 11.555 + if (!useless) { 11.556 + if (in_sig_bt[j_arg] == T_DOUBLE || 11.557 + in_sig_bt[j_arg] == T_LONG || 11.558 + in_sig_bt[j_arg] == T_OBJECT ) { 11.559 + __ movq(r, Address(rbp, fp_offset[src.first()->value()])); 11.560 + } else { 11.561 + __ movl(r, Address(rbp, fp_offset[src.first()->value()])); 11.562 + } 11.563 + } 11.564 + } 11.565 + live[src.first()->value()] = false; 11.566 + } else if (!useless) { 11.567 + // full sized move even for int should be ok 11.568 + __ movq(r, Address(rbp, reg2offset_in(src.first()))); 11.569 + } 11.570 + 11.571 + // At this point r has the original java arg in the final location 11.572 + // (assuming it wasn't useless). If the java arg was an oop 11.573 + // we have a bit more to do 11.574 + 11.575 + if (in_sig_bt[j_arg] == T_ARRAY || in_sig_bt[j_arg] == T_OBJECT ) { 11.576 + if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) { 11.577 + // need to unbox a one-word value 11.578 + Label skip; 11.579 + __ testq(r, r); 11.580 + __ jcc(Assembler::equal, skip); 11.581 + Address src1(r, box_offset); 11.582 + if ( out_sig_bt[c_arg] == T_LONG ) { 11.583 + __ movq(r, src1); 11.584 + } else { 11.585 + __ movl(r, src1); 11.586 + } 11.587 + __ bind(skip); 11.588 + 11.589 + } else if (out_sig_bt[c_arg] != T_ADDRESS) { 11.590 + // Convert the arg to NULL 11.591 + __ xorq(r, r); 11.592 + } 11.593 + } 11.594 + 11.595 + // dst can longer be holding an input value 11.596 + live[dst.first()->value()] = false; 11.597 + } 11.598 + if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) { 11.599 + assert(out_sig_bt[c_arg+1] == T_VOID, "must be"); 11.600 + ++c_arg; // skip over T_VOID to keep the loop indices in sync 11.601 + } 11.602 + } 11.603 + 11.604 + 11.605 + // Ok now we are done. Need to place the nop that dtrace wants in order to 11.606 + // patch in the trap 11.607 + int patch_offset = ((intptr_t)__ pc()) - start; 11.608 + 11.609 + __ nop(); 11.610 + 11.611 + 11.612 + // Return 11.613 + 11.614 + __ leave(); 11.615 + __ ret(0); 11.616 + 11.617 + __ flush(); 11.618 + 11.619 + nmethod *nm = nmethod::new_dtrace_nmethod( 11.620 + method, masm->code(), vep_offset, patch_offset, frame_complete, 11.621 + stack_slots / VMRegImpl::slots_per_word); 11.622 + return nm; 11.623 + 11.624 +} 11.625 + 11.626 +#endif // HAVE_DTRACE_H 11.627 + 11.628 // this function returns the adjust size (in number of words) to a c2i adapter 11.629 // activation for use during deoptimization 11.630 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) {
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/src/os/linux/vm/dtraceJSDT_linux.cpp Thu Apr 17 22:18:15 2008 -0400 12.3 @@ -0,0 +1,39 @@ 12.4 +/* 12.5 + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. 12.11 + * 12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 + * version 2 for more details (a copy is included in the LICENSE file that 12.16 + * accompanied this code). 12.17 + * 12.18 + * You should have received a copy of the GNU General Public License version 12.19 + * 2 along with this work; if not, write to the Free Software Foundation, 12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 + * 12.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 12.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 12.24 + * have any questions. 12.25 + * 12.26 + */ 12.27 + 12.28 +#include "incls/_precompiled.incl" 12.29 +#include "incls/_dtraceJSDT_linux.cpp.incl" 12.30 + 12.31 +int DTraceJSDT::pd_activate( 12.32 + void* baseAddress, jstring module, 12.33 + jint providers_count, JVM_DTraceProvider* providers) { 12.34 + return -1; 12.35 +} 12.36 + 12.37 +void DTraceJSDT::pd_dispose(int handle) { 12.38 +} 12.39 + 12.40 +jboolean DTraceJSDT::pd_is_supported() { 12.41 + return false; 12.42 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/src/os/solaris/vm/dtraceJSDT_solaris.cpp Thu Apr 17 22:18:15 2008 -0400 13.3 @@ -0,0 +1,685 @@ 13.4 +/* 13.5 + * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. 13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.7 + * 13.8 + * This code is free software; you can redistribute it and/or modify it 13.9 + * under the terms of the GNU General Public License version 2 only, as 13.10 + * published by the Free Software Foundation. 13.11 + * 13.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 13.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.15 + * version 2 for more details (a copy is included in the LICENSE file that 13.16 + * accompanied this code). 13.17 + * 13.18 + * You should have received a copy of the GNU General Public License version 13.19 + * 2 along with this work; if not, write to the Free Software Foundation, 13.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.21 + * 13.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 13.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 13.24 + * have any questions. 13.25 + * 13.26 + */ 13.27 + 13.28 +#include "incls/_precompiled.incl" 13.29 +#include "incls/_dtraceJSDT_solaris.cpp.incl" 13.30 + 13.31 +#ifdef HAVE_DTRACE_H 13.32 + 13.33 +#include <sys/types.h> 13.34 +#include <sys/stat.h> 13.35 +#include <fcntl.h> 13.36 +#include <unistd.h> 13.37 +#include <dtrace.h> 13.38 + 13.39 +static const char* devname = "/dev/dtrace/helper"; 13.40 +static const char* olddevname = "/devices/pseudo/dtrace@0:helper"; 13.41 + 13.42 +static const char* string_sig = "uintptr_t"; 13.43 +static const char* int_sig = "long"; 13.44 +static const char* long_sig = "long long"; 13.45 + 13.46 +static void printDOFHelper(dof_helper_t* helper); 13.47 + 13.48 +static int dofhelper_open() { 13.49 + int fd; 13.50 + if ((fd = open64(devname, O_RDWR)) < 0) { 13.51 + // Optimize next calls 13.52 + devname = olddevname; 13.53 + if ((fd = open64(devname, O_RDWR)) < 0) { 13.54 + return -1; 13.55 + } 13.56 + } 13.57 + return fd; 13.58 +} 13.59 + 13.60 +static jint dof_register(jstring module, uint8_t* dof, void* modaddr) { 13.61 + int probe; 13.62 + dof_helper_t dh; 13.63 + int fd; 13.64 + 13.65 + memset(&dh, 0, sizeof(dh)); 13.66 + 13.67 + char* module_name = java_lang_String::as_utf8_string( 13.68 + JNIHandles::resolve_non_null(module)); 13.69 + jio_snprintf(dh.dofhp_mod, sizeof(dh.dofhp_mod), "%s", module_name); 13.70 + dh.dofhp_dof = (uint64_t)dof; 13.71 + dh.dofhp_addr = (uint64_t)modaddr; 13.72 + 13.73 + fd = dofhelper_open(); 13.74 + if (fd < 0) 13.75 + return -1; 13.76 + probe = ioctl(fd, DTRACEHIOC_ADDDOF, &dh); 13.77 + close(fd); 13.78 + if (PrintDTraceDOF) { 13.79 + printDOFHelper(&dh); 13.80 + tty->print_cr("DOF helper id = %d", probe); 13.81 + } 13.82 + return probe; 13.83 +} 13.84 + 13.85 +int DTraceJSDT::pd_activate( 13.86 + void* moduleBaseAddress, jstring module, 13.87 + jint providers_count, JVM_DTraceProvider* providers) { 13.88 + 13.89 + // We need sections: 13.90 + // (1) STRTAB 13.91 + // ( 13.92 + // (2) PROVIDER 13.93 + // (3) PROBES 13.94 + // (4) PROBOFFS 13.95 + // (5) PROBARGS 13.96 + // ) * Number of Providers 13.97 + 13.98 + // Type of sections we create 13.99 + enum { 13.100 + STRTAB = 0, 13.101 + PROVIDERS = 1, 13.102 + PROBES = 2, 13.103 + PROBE_OFFSETS = 3, 13.104 + ARG_OFFSETS = 4, 13.105 + NUM_SECTIONS = 5 13.106 + }; 13.107 + 13.108 + static int alignment_for[NUM_SECTIONS] = { 1, 4, 8, 4, 1 }; 13.109 + 13.110 + ResourceMark rm; 13.111 + 13.112 + uint32_t num_sections = 1 + 4 * providers_count; 13.113 + uint32_t offset = sizeof(dof_hdr_t) + (num_sections * sizeof(dof_sec_t)); 13.114 + uint32_t* secoffs = NEW_RESOURCE_ARRAY(uint32_t, num_sections); 13.115 + uint32_t* secsize = NEW_RESOURCE_ARRAY(uint32_t, num_sections); 13.116 + 13.117 + // Store offsets of all strings here in such order: 13.118 + // zero-string (always 0) 13.119 + // provider1-name 13.120 + // probe1-function 13.121 + // probe1-name 13.122 + // arg-1 13.123 + // arg-2 13.124 + // ... 13.125 + // probe2-function 13.126 + // probe2-name 13.127 + // arg-1 13.128 + // arg-2 13.129 + // provider2-name 13.130 + // ... 13.131 + 13.132 + uint32_t strcount = 0; 13.133 + // Count the number of strings we'll need 13.134 + for(int prvc = 0; prvc < providers_count; ++prvc) { 13.135 + JVM_DTraceProvider* provider = &providers[prvc]; 13.136 + // Provider name 13.137 + ++strcount; 13.138 + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.139 + JVM_DTraceProbe* p = &(provider->probes[prbc]); 13.140 + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); 13.141 + // function + name + one per argument 13.142 + strcount += 2 + ArgumentCount(sig).size(); 13.143 + } 13.144 + } 13.145 + 13.146 + // Create place for string offsets 13.147 + uint32_t* stroffs = NEW_RESOURCE_ARRAY(uint32_t, strcount + 1); 13.148 + uint32_t string_index = 0; 13.149 + uint32_t curstr = 0; 13.150 + 13.151 + // First we need an empty string: "" 13.152 + stroffs[curstr++] = string_index; 13.153 + string_index += strlen("") + 1; 13.154 + 13.155 + for(int prvc = 0; prvc < providers_count; ++prvc) { 13.156 + JVM_DTraceProvider* provider = &providers[prvc]; 13.157 + char* provider_name = java_lang_String::as_utf8_string( 13.158 + JNIHandles::resolve_non_null(provider->name)); 13.159 + stroffs[curstr++] = string_index; 13.160 + string_index += strlen(provider_name) + 1; 13.161 + 13.162 + // All probes 13.163 + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.164 + JVM_DTraceProbe* p = &(provider->probes[prbc]); 13.165 + 13.166 + char* function = java_lang_String::as_utf8_string( 13.167 + JNIHandles::resolve_non_null(p->function)); 13.168 + stroffs[curstr++] = string_index; 13.169 + string_index += strlen(function) + 1; 13.170 + 13.171 + char* name = java_lang_String::as_utf8_string( 13.172 + JNIHandles::resolve_non_null(p->name)); 13.173 + stroffs[curstr++] = string_index; 13.174 + string_index += strlen(name) + 1; 13.175 + 13.176 + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); 13.177 + SignatureStream ss(sig); 13.178 + for ( ; !ss.at_return_type(); ss.next()) { 13.179 + BasicType bt = ss.type(); 13.180 + const char* t = NULL; 13.181 + if (bt == T_OBJECT && 13.182 + ss.as_symbol_or_null() == vmSymbols::java_lang_String()) { 13.183 + t = string_sig; 13.184 + } else if (bt == T_LONG) { 13.185 + t = long_sig; 13.186 + } else { 13.187 + t = int_sig; 13.188 + } 13.189 + stroffs[curstr++] = string_index; 13.190 + string_index += strlen(t) + 1; 13.191 + } 13.192 + } 13.193 + } 13.194 + secoffs[STRTAB] = offset; 13.195 + secsize[STRTAB] = string_index; 13.196 + offset += string_index; 13.197 + 13.198 + // Calculate the size of the rest 13.199 + for(int prvc = 0; prvc < providers_count; ++prvc) { 13.200 + JVM_DTraceProvider* provider = &providers[prvc]; 13.201 + size_t provider_sec = PROVIDERS + prvc * 4; 13.202 + size_t probe_sec = PROBES + prvc * 4; 13.203 + size_t probeoffs_sec = PROBE_OFFSETS + prvc * 4; 13.204 + size_t argoffs_sec = ARG_OFFSETS + prvc * 4; 13.205 + 13.206 + // Allocate space for the provider data struction 13.207 + secoffs[provider_sec] = align_size_up(offset, alignment_for[PROVIDERS]); 13.208 + secsize[provider_sec] = sizeof(dof_provider_t); 13.209 + offset = secoffs[provider_sec] + secsize[provider_sec]; 13.210 + 13.211 + // Allocate space for all the probes 13.212 + secoffs[probe_sec] = align_size_up(offset, alignment_for[PROBES]); 13.213 + secsize[probe_sec] = sizeof(dof_probe_t) * provider->probe_count; 13.214 + offset = secoffs[probe_sec] + secsize[probe_sec]; 13.215 + 13.216 + // Allocate space for the probe offsets 13.217 + secoffs[probeoffs_sec] = align_size_up(offset, alignment_for[PROBE_OFFSETS]); 13.218 + secsize[probeoffs_sec] = sizeof(uint32_t) * provider->probe_count; 13.219 + offset = secoffs[probeoffs_sec] + secsize[probeoffs_sec]; 13.220 + 13.221 + // We need number of arguments argoffs 13.222 + uint32_t argscount = 0; 13.223 + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.224 + JVM_DTraceProbe* p = &(provider->probes[prbc]); 13.225 + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); 13.226 + argscount += ArgumentCount(sig).size(); 13.227 + } 13.228 + secoffs[argoffs_sec] = align_size_up(offset, alignment_for[ARG_OFFSETS]); 13.229 + secsize[argoffs_sec] = sizeof(uint8_t) * argscount; 13.230 + offset = secoffs[argoffs_sec] + secsize[argoffs_sec]; 13.231 + } 13.232 + 13.233 + uint32_t size = offset; 13.234 + 13.235 + uint8_t* dof = NEW_RESOURCE_ARRAY(uint8_t, size); 13.236 + if (!dof) { 13.237 + return -1; 13.238 + } 13.239 + memset((void*)dof, 0, size); 13.240 + 13.241 + // Fill memory with proper values 13.242 + dof_hdr_t* hdr = (dof_hdr_t*)dof; 13.243 + hdr->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; 13.244 + hdr->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; 13.245 + hdr->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; 13.246 + hdr->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; 13.247 + hdr->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; // No variants 13.248 + hdr->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; // No variants 13.249 + hdr->dofh_ident[DOF_ID_VERSION] = DOF_VERSION_1; // No variants 13.250 + hdr->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION_2; // No variants 13.251 + // all other fields of ident to zero 13.252 + 13.253 + hdr->dofh_flags = 0; 13.254 + hdr->dofh_hdrsize = sizeof(dof_hdr_t); 13.255 + hdr->dofh_secsize = sizeof(dof_sec_t); 13.256 + hdr->dofh_secnum = num_sections; 13.257 + hdr->dofh_secoff = sizeof(dof_hdr_t); 13.258 + hdr->dofh_loadsz = size; 13.259 + hdr->dofh_filesz = size; 13.260 + 13.261 + // First section: STRTAB 13.262 + dof_sec_t* sec = (dof_sec_t*)(dof + sizeof(dof_hdr_t)); 13.263 + sec->dofs_type = DOF_SECT_STRTAB; 13.264 + sec->dofs_align = alignment_for[STRTAB]; 13.265 + sec->dofs_flags = DOF_SECF_LOAD; 13.266 + sec->dofs_entsize = 0; 13.267 + sec->dofs_offset = secoffs[STRTAB]; 13.268 + sec->dofs_size = secsize[STRTAB]; 13.269 + // Make data for this section 13.270 + char* str = (char*)(dof + sec->dofs_offset); 13.271 + 13.272 + *str = 0; str += 1; // "" 13.273 + 13.274 + // Run through all strings again 13.275 + for(int prvc = 0; prvc < providers_count; ++prvc) { 13.276 + JVM_DTraceProvider* provider = &providers[prvc]; 13.277 + char* provider_name = java_lang_String::as_utf8_string( 13.278 + JNIHandles::resolve_non_null(provider->name)); 13.279 + strcpy(str, provider_name); 13.280 + str += strlen(provider_name) + 1; 13.281 + 13.282 + // All probes 13.283 + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.284 + JVM_DTraceProbe* p = &(provider->probes[prbc]); 13.285 + 13.286 + char* function = java_lang_String::as_utf8_string( 13.287 + JNIHandles::resolve_non_null(p->function)); 13.288 + strcpy(str, function); 13.289 + str += strlen(str) + 1; 13.290 + 13.291 + char* name = java_lang_String::as_utf8_string( 13.292 + JNIHandles::resolve_non_null(p->name)); 13.293 + strcpy(str, name); 13.294 + str += strlen(name) + 1; 13.295 + 13.296 + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); 13.297 + SignatureStream ss(sig); 13.298 + for ( ; !ss.at_return_type(); ss.next()) { 13.299 + BasicType bt = ss.type(); 13.300 + const char* t; 13.301 + if (bt == T_OBJECT && 13.302 + ss.as_symbol_or_null() == vmSymbols::java_lang_String()) { 13.303 + t = string_sig; 13.304 + } else if (bt == T_LONG) { 13.305 + t = long_sig; 13.306 + } else { 13.307 + t = int_sig; 13.308 + } 13.309 + strcpy(str, t); 13.310 + str += strlen(t) + 1; 13.311 + } 13.312 + } 13.313 + } 13.314 + 13.315 + curstr = 1; 13.316 + for(int prvc = 0; prvc < providers_count; ++prvc) { 13.317 + JVM_DTraceProvider* provider = &providers[prvc]; 13.318 + size_t provider_sec = PROVIDERS + prvc * 4; 13.319 + size_t probe_sec = PROBES + prvc * 4; 13.320 + size_t probeoffs_sec = PROBE_OFFSETS + prvc * 4; 13.321 + size_t argoffs_sec = ARG_OFFSETS + prvc * 4; 13.322 + 13.323 + // PROVIDER /////////////////////////////////////////////////////////////// 13.324 + // Section header 13.325 + sec = (dof_sec_t*) 13.326 + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * provider_sec); 13.327 + sec->dofs_type = DOF_SECT_PROVIDER; 13.328 + sec->dofs_align = alignment_for[PROVIDERS]; 13.329 + sec->dofs_flags = DOF_SECF_LOAD; 13.330 + sec->dofs_entsize = 0; 13.331 + sec->dofs_offset = secoffs[provider_sec]; 13.332 + sec->dofs_size = secsize[provider_sec]; 13.333 + // Make provider decriiption 13.334 + dof_provider_t* prv = (dof_provider_t*)(dof + sec->dofs_offset); 13.335 + prv->dofpv_strtab = STRTAB; 13.336 + prv->dofpv_probes = probe_sec; 13.337 + prv->dofpv_prargs = argoffs_sec; 13.338 + prv->dofpv_proffs = probeoffs_sec; 13.339 + prv->dofpv_name = stroffs[curstr++]; // Index in string table 13.340 + prv->dofpv_provattr = DOF_ATTR( 13.341 + provider->providerAttributes.nameStability, 13.342 + provider->providerAttributes.dataStability, 13.343 + provider->providerAttributes.dependencyClass); 13.344 + prv->dofpv_modattr = DOF_ATTR( 13.345 + provider->moduleAttributes.nameStability, 13.346 + provider->moduleAttributes.dataStability, 13.347 + provider->moduleAttributes.dependencyClass); 13.348 + prv->dofpv_funcattr = DOF_ATTR( 13.349 + provider->functionAttributes.nameStability, 13.350 + provider->functionAttributes.dataStability, 13.351 + provider->functionAttributes.dependencyClass); 13.352 + prv->dofpv_nameattr = DOF_ATTR( 13.353 + provider->nameAttributes.nameStability, 13.354 + provider->nameAttributes.dataStability, 13.355 + provider->nameAttributes.dependencyClass); 13.356 + prv->dofpv_argsattr = DOF_ATTR( 13.357 + provider->argsAttributes.nameStability, 13.358 + provider->argsAttributes.dataStability, 13.359 + provider->argsAttributes.dependencyClass); 13.360 + 13.361 + // PROBES ///////////////////////////////////////////////////////////////// 13.362 + // Section header 13.363 + sec = (dof_sec_t*) 13.364 + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * probe_sec); 13.365 + sec->dofs_type = DOF_SECT_PROBES; 13.366 + sec->dofs_align = alignment_for[PROBES]; 13.367 + sec->dofs_flags = DOF_SECF_LOAD; 13.368 + sec->dofs_entsize = sizeof(dof_probe_t); 13.369 + sec->dofs_offset = secoffs[probe_sec]; 13.370 + sec->dofs_size = secsize[probe_sec]; 13.371 + // Make probes descriptions 13.372 + uint32_t argsoffs = 0; 13.373 + for(int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.374 + JVM_DTraceProbe* probe = &(provider->probes[prbc]); 13.375 + methodOop m = JNIHandles::resolve_jmethod_id(probe->method); 13.376 + int arg_count = ArgumentCount(m->signature()).size(); 13.377 + assert(m->code() != NULL, "must have an nmethod"); 13.378 + 13.379 + dof_probe_t* prb = 13.380 + (dof_probe_t*)(dof + sec->dofs_offset + prbc * sizeof(dof_probe_t)); 13.381 + 13.382 + prb->dofpr_addr = (uint64_t)m->code()->entry_point(); 13.383 + prb->dofpr_func = stroffs[curstr++]; // Index in string table 13.384 + prb->dofpr_name = stroffs[curstr++]; // Index in string table 13.385 + prb->dofpr_nargv = stroffs[curstr ]; // Index in string table 13.386 + // We spent siglen strings here 13.387 + curstr += arg_count; 13.388 + prb->dofpr_xargv = prb->dofpr_nargv; // Same bunch of strings 13.389 + prb->dofpr_argidx = argsoffs; 13.390 + prb->dofpr_offidx = prbc; 13.391 + prb->dofpr_nargc = arg_count; 13.392 + prb->dofpr_xargc = arg_count; 13.393 + prb->dofpr_noffs = 1; // Number of offsets 13.394 + // Next bunch of offsets 13.395 + argsoffs += arg_count; 13.396 + } 13.397 + 13.398 + // PROFFS ///////////////////////////////////////////////////////////////// 13.399 + // Section header 13.400 + sec = (dof_sec_t*) 13.401 + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * probeoffs_sec); 13.402 + sec->dofs_type = DOF_SECT_PROFFS; 13.403 + sec->dofs_align = alignment_for[PROBE_OFFSETS]; 13.404 + sec->dofs_flags = DOF_SECF_LOAD; 13.405 + sec->dofs_entsize = sizeof(uint32_t); 13.406 + sec->dofs_offset = secoffs[probeoffs_sec]; 13.407 + sec->dofs_size = secsize[probeoffs_sec]; 13.408 + // Make offsets 13.409 + for (int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.410 + uint32_t* pof = 13.411 + (uint32_t*)(dof + sec->dofs_offset + sizeof(uint32_t) * prbc); 13.412 + JVM_DTraceProbe* probe = &(provider->probes[prbc]); 13.413 + methodOop m = JNIHandles::resolve_jmethod_id(probe->method); 13.414 + *pof = m->code()->trap_offset(); 13.415 + } 13.416 + 13.417 + // PRARGS ///////////////////////////////////////////////////////////////// 13.418 + // Section header 13.419 + sec = (dof_sec_t*) 13.420 + (dof + sizeof(dof_hdr_t) + sizeof(dof_sec_t) * argoffs_sec); 13.421 + sec->dofs_type = DOF_SECT_PRARGS; 13.422 + sec->dofs_align = alignment_for[ARG_OFFSETS]; 13.423 + sec->dofs_flags = DOF_SECF_LOAD; 13.424 + sec->dofs_entsize = sizeof(uint8_t); 13.425 + sec->dofs_offset = secoffs[argoffs_sec]; 13.426 + sec->dofs_size = secsize[argoffs_sec]; 13.427 + // Make arguments 13.428 + uint8_t* par = (uint8_t*)(dof + sec->dofs_offset); 13.429 + for (int prbc = 0; prbc < provider->probe_count; ++prbc) { 13.430 + JVM_DTraceProbe* p = &(provider->probes[prbc]); 13.431 + symbolOop sig = JNIHandles::resolve_jmethod_id(p->method)->signature(); 13.432 + uint8_t count = (uint8_t)ArgumentCount(sig).size(); 13.433 + for (uint8_t i = 0; i < count; ++i) { 13.434 + *par++ = i; 13.435 + } 13.436 + } 13.437 + } 13.438 + 13.439 + // Register module 13.440 + return dof_register(module, dof, moduleBaseAddress); 13.441 +} 13.442 + 13.443 + 13.444 +void DTraceJSDT::pd_dispose(int handle) { 13.445 + int fd; 13.446 + if (handle == -1) { 13.447 + return; 13.448 + } 13.449 + fd = dofhelper_open(); 13.450 + if (fd < 0) 13.451 + return; 13.452 + ioctl(fd, DTRACEHIOC_REMOVE, handle); 13.453 + close(fd); 13.454 +} 13.455 + 13.456 +jboolean DTraceJSDT::pd_is_supported() { 13.457 + int fd = dofhelper_open(); 13.458 + if (fd < 0) { 13.459 + return false; 13.460 + } 13.461 + close(fd); 13.462 + return true; 13.463 +} 13.464 + 13.465 +static const char* dofSecTypeFor(uint32_t type) { 13.466 + switch (type) { 13.467 + case 0: return "DOF_SECT_NONE"; 13.468 + case 1: return "DOF_SECT_COMMENTS"; 13.469 + case 2: return "DOF_SECT_SOURCE"; 13.470 + case 3: return "DOF_SECT_ECBDESC"; 13.471 + case 4: return "DOF_SECT_PROBEDESC"; 13.472 + case 5: return "DOF_SECT_ACTDESC"; 13.473 + case 6: return "DOF_SECT_DIFOHDR"; 13.474 + case 7: return "DOF_SECT_DIF"; 13.475 + case 8: return "DOF_SECT_STRTAB"; 13.476 + case 9: return "DOF_SECT_VARTAB"; 13.477 + case 10: return "DOF_SECT_RELTAB"; 13.478 + case 11: return "DOF_SECT_TYPETAB"; 13.479 + case 12: return "DOF_SECT_URELHDR"; 13.480 + case 13: return "DOF_SECT_KRELHDR"; 13.481 + case 14: return "DOF_SECT_OPTDESC"; 13.482 + case 15: return "DOF_SECT_PROVIDER"; 13.483 + case 16: return "DOF_SECT_PROBES"; 13.484 + case 17: return "DOF_SECT_PRARGS"; 13.485 + case 18: return "DOF_SECT_PROFFS"; 13.486 + case 19: return "DOF_SECT_INTTAB"; 13.487 + case 20: return "DOF_SECT_UTSNAME"; 13.488 + case 21: return "DOF_SECT_XLTAB"; 13.489 + case 22: return "DOF_SECT_XLMEMBERS"; 13.490 + case 23: return "DOF_SECT_XLIMPORT"; 13.491 + case 24: return "DOF_SECT_XLEXPORT"; 13.492 + case 25: return "DOF_SECT_PREXPORT"; 13.493 + case 26: return "DOF_SECT_PRENOFFS"; 13.494 + default: return "<unknown>"; 13.495 + } 13.496 +} 13.497 + 13.498 +static void printDOFStringTabSec(void* dof, dof_sec_t* sec) { 13.499 + size_t tab = sec->dofs_offset; 13.500 + size_t limit = sec->dofs_size; 13.501 + tty->print_cr("// String Table:"); 13.502 + for (size_t idx = 0; idx < limit; /*empty*/) { 13.503 + char* str = ((char*)dof) + tab + idx; 13.504 + tty->print_cr("// [0x%x + 0x%x] '%s'", tab, idx, str); 13.505 + idx += strlen(str) + 1; 13.506 + } 13.507 +} 13.508 + 13.509 +static void printDOFProviderSec(void* dof, dof_sec_t* sec) { 13.510 + dof_provider_t* prov = (dof_provider_t*)((char*)dof + sec->dofs_offset); 13.511 + tty->print_cr("// dof_provider_t {"); 13.512 + tty->print_cr("// dofpv_strtab = %d", prov->dofpv_strtab); 13.513 + tty->print_cr("// dofpv_probes = %d", prov->dofpv_probes); 13.514 + tty->print_cr("// dofpv_prargs = %d", prov->dofpv_prargs); 13.515 + tty->print_cr("// dofpv_proffs = %d", prov->dofpv_proffs); 13.516 + tty->print_cr("// dofpv_name = 0x%x", prov->dofpv_name); 13.517 + tty->print_cr("// dofpv_provattr = 0x%08x", prov->dofpv_provattr); 13.518 + tty->print_cr("// dofpv_modattr = 0x%08x", prov->dofpv_modattr); 13.519 + tty->print_cr("// dofpv_funcattr = 0x%08x", prov->dofpv_funcattr); 13.520 + tty->print_cr("// dofpv_nameattr = 0x%08x", prov->dofpv_nameattr); 13.521 + tty->print_cr("// dofpv_argsattr = 0x%08x", prov->dofpv_argsattr); 13.522 + tty->print_cr("// }"); 13.523 +} 13.524 + 13.525 +static void printDOFProbesSec(void* dof, dof_sec_t* sec) { 13.526 + size_t idx = sec->dofs_offset; 13.527 + size_t limit = idx + sec->dofs_size; 13.528 + for (size_t idx = sec->dofs_offset; idx < limit; idx += sec->dofs_entsize) { 13.529 + dof_probe_t* prb = (dof_probe_t*)((char*)dof + idx); 13.530 + tty->print_cr("// dof_probe_t {"); 13.531 + tty->print_cr("// dofpr_addr = 0x%016llx", prb->dofpr_addr); 13.532 + tty->print_cr("// dofpr_func = 0x%x", prb->dofpr_func); 13.533 + tty->print_cr("// dofpr_name = 0x%x", prb->dofpr_name); 13.534 + tty->print_cr("// dofpr_nargv = 0x%x", prb->dofpr_nargv); 13.535 + tty->print_cr("// dofpr_xargv = 0x%x", prb->dofpr_xargv); 13.536 + tty->print_cr("// dofpr_argidx = 0x%x", prb->dofpr_argidx); 13.537 + tty->print_cr("// dofpr_offidx = 0x%x", prb->dofpr_offidx); 13.538 + tty->print_cr("// dofpr_nargc = %d", prb->dofpr_nargc); 13.539 + tty->print_cr("// dofpr_xargc = %d", prb->dofpr_xargc); 13.540 + tty->print_cr("// dofpr_noffs = %d", prb->dofpr_noffs); 13.541 + tty->print_cr("// }"); 13.542 + } 13.543 +} 13.544 + 13.545 +static void printDOFOffsetsSec(void* dof, dof_sec_t* sec) { 13.546 + size_t tab = sec->dofs_offset; 13.547 + size_t limit = sec->dofs_size; 13.548 + tty->print_cr("// Offsets:"); 13.549 + for (size_t idx = 0; idx < limit; idx += sec->dofs_entsize) { 13.550 + uint32_t* off = (uint32_t*)((char*)dof + tab + idx); 13.551 + tty->print_cr("// [0x%x + 0x%x]: %d", tab, idx, *off); 13.552 + } 13.553 +} 13.554 + 13.555 +static void printDOFArgsSec(void* dof, dof_sec_t* sec) { 13.556 + size_t tab = sec->dofs_offset; 13.557 + size_t limit = sec->dofs_size; 13.558 + tty->print_cr("// Arguments:"); 13.559 + for (size_t idx = 0; idx < limit; idx += sec->dofs_entsize) { 13.560 + uint8_t* arg = (uint8_t*)((char*)dof + tab + idx); 13.561 + tty->print_cr("// [0x%x + 0x%x]: %d", tab, idx, *arg); 13.562 + } 13.563 +} 13.564 + 13.565 +static void printDOFSection(void* dof, dof_sec_t* sec) { 13.566 + tty->print_cr("// dof_sec_t {"); 13.567 + tty->print_cr("// dofs_type = 0x%x /* %s */", 13.568 + sec->dofs_type, dofSecTypeFor(sec->dofs_type)); 13.569 + tty->print_cr("// dofs_align = %d", sec->dofs_align); 13.570 + tty->print_cr("// dofs_flags = 0x%x", sec->dofs_flags); 13.571 + tty->print_cr("// dofs_entsize = %d", sec->dofs_entsize); 13.572 + tty->print_cr("// dofs_offset = 0x%llx", sec->dofs_offset); 13.573 + tty->print_cr("// dofs_size = %lld", sec->dofs_size); 13.574 + tty->print_cr("// }"); 13.575 + switch (sec->dofs_type) { 13.576 + case DOF_SECT_STRTAB: printDOFStringTabSec(dof, sec); break; 13.577 + case DOF_SECT_PROVIDER: printDOFProviderSec(dof, sec); break; 13.578 + case DOF_SECT_PROBES: printDOFProbesSec(dof, sec); break; 13.579 + case DOF_SECT_PROFFS: printDOFOffsetsSec(dof, sec); break; 13.580 + case DOF_SECT_PRARGS: printDOFArgsSec(dof, sec); break; 13.581 + default: tty->print_cr("// <section type not recognized>"); 13.582 + } 13.583 +} 13.584 + 13.585 +static void printDOFHeader(dof_hdr_t* hdr) { 13.586 + tty->print_cr("// dof_hdr_t {"); 13.587 + tty->print_cr("// dofh_ident[DOF_ID_MAG0] = 0x%x", 13.588 + hdr->dofh_ident[DOF_ID_MAG0]); 13.589 + tty->print_cr("// dofh_ident[DOF_ID_MAG1] = 0x%x", 13.590 + hdr->dofh_ident[DOF_ID_MAG1]); 13.591 + tty->print_cr("// dofh_ident[DOF_ID_MAG2] = 0x%x", 13.592 + hdr->dofh_ident[DOF_ID_MAG2]); 13.593 + tty->print_cr("// dofh_ident[DOF_ID_MAG3] = 0x%x", 13.594 + hdr->dofh_ident[DOF_ID_MAG3]); 13.595 + tty->print_cr("// dofh_ident[DOF_ID_MODEL] = 0x%x", 13.596 + hdr->dofh_ident[DOF_ID_MODEL]); 13.597 + tty->print_cr("// dofh_ident[DOF_ID_ENCODING] = 0x%x", 13.598 + hdr->dofh_ident[DOF_ID_ENCODING]); 13.599 + tty->print_cr("// dofh_ident[DOF_ID_VERSION] = 0x%x", 13.600 + hdr->dofh_ident[DOF_ID_VERSION]); 13.601 + tty->print_cr("// dofh_ident[DOF_ID_DIFVERS] = 0x%x", 13.602 + hdr->dofh_ident[DOF_ID_DIFVERS]); 13.603 + tty->print_cr("// dofh_flags = 0x%x", hdr->dofh_flags); 13.604 + tty->print_cr("// dofh_hdrsize = %d", hdr->dofh_hdrsize); 13.605 + tty->print_cr("// dofh_secsize = %d", hdr->dofh_secsize); 13.606 + tty->print_cr("// dofh_secnum = %d", hdr->dofh_secnum); 13.607 + tty->print_cr("// dofh_secoff = %lld", hdr->dofh_secoff); 13.608 + tty->print_cr("// dofh_loadsz = %lld", hdr->dofh_loadsz); 13.609 + tty->print_cr("// dofh_filesz = %lld", hdr->dofh_filesz); 13.610 + tty->print_cr("// }"); 13.611 +} 13.612 + 13.613 +static void printDOF(void* dof) { 13.614 + dof_hdr_t* hdr = (dof_hdr_t*)dof; 13.615 + printDOFHeader(hdr); 13.616 + for (int i = 0; i < hdr->dofh_secnum; ++i) { 13.617 + dof_sec_t* sec = 13.618 + (dof_sec_t*)((char*)dof + sizeof(dof_hdr_t) + i * sizeof(dof_sec_t)); 13.619 + tty->print_cr("// [Section #%d]", i); 13.620 + printDOFSection(dof, sec); 13.621 + } 13.622 +} 13.623 + 13.624 +/** 13.625 + * This prints out hex data in a 'windbg' or 'xxd' form, where each line is: 13.626 + * <hex-address>: 8 * <hex-halfword> <ascii translation> 13.627 + * example: 13.628 + * 0000000: 7f44 4f46 0102 0102 0000 0000 0000 0000 .DOF............ 13.629 + * 0000010: 0000 0000 0000 0040 0000 0020 0000 0005 .......@... .... 13.630 + * 0000020: 0000 0000 0000 0040 0000 0000 0000 015d .......@.......] 13.631 + * ... 13.632 + */ 13.633 +static void printDOFRawData(void* dof) { 13.634 + size_t size = ((dof_hdr_t*)dof)->dofh_loadsz; 13.635 + size_t limit = (size + 16) / 16 * 16; 13.636 + for (size_t i = 0; i < limit; ++i) { 13.637 + if (i % 16 == 0) { 13.638 + tty->print("%07x:", i); 13.639 + } 13.640 + if (i % 2 == 0) { 13.641 + tty->print(" "); 13.642 + } 13.643 + if (i < size) { 13.644 + tty->print("%02x", ((unsigned char*)dof)[i]); 13.645 + } else { 13.646 + tty->print(" "); 13.647 + } 13.648 + if ((i + 1) % 16 == 0) { 13.649 + tty->print(" "); 13.650 + for (size_t j = 0; j < 16; ++j) { 13.651 + size_t idx = i + j - 15; 13.652 + char c = ((char*)dof)[idx]; 13.653 + if (idx < size) { 13.654 + tty->print("%c", c >= 32 && c <= 126 ? c : '.'); 13.655 + } 13.656 + } 13.657 + tty->print_cr(""); 13.658 + } 13.659 + } 13.660 + tty->print_cr(""); 13.661 +} 13.662 + 13.663 +static void printDOFHelper(dof_helper_t* helper) { 13.664 + tty->print_cr("// dof_helper_t {"); 13.665 + tty->print_cr("// dofhp_mod = \"%s\"", helper->dofhp_mod); 13.666 + tty->print_cr("// dofhp_addr = 0x%016llx", helper->dofhp_addr); 13.667 + tty->print_cr("// dofhp_dof = 0x%016llx", helper->dofhp_dof); 13.668 + printDOF((void*)helper->dofhp_dof); 13.669 + tty->print_cr("// }"); 13.670 + printDOFRawData((void*)helper->dofhp_dof); 13.671 +} 13.672 + 13.673 +#else // ndef HAVE_DTRACE_H 13.674 + 13.675 +// Get here if we're not building on at least Solaris 10 13.676 +int DTraceJSDT::pd_activate( 13.677 + void* baseAddress, jstring module, 13.678 + jint provider_count, JVM_DTraceProvider* providers) { 13.679 + return -1; 13.680 +} 13.681 + 13.682 +void DTraceJSDT::pd_dispose(int handle) { 13.683 +} 13.684 + 13.685 +jboolean DTraceJSDT::pd_is_supported() { 13.686 + return false; 13.687 +} 13.688 +#endif
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/os/windows/vm/dtraceJSDT_windows.cpp Thu Apr 17 22:18:15 2008 -0400 14.3 @@ -0,0 +1,39 @@ 14.4 +/* 14.5 + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 14.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 14.24 + * have any questions. 14.25 + * 14.26 + */ 14.27 + 14.28 +#include "incls/_precompiled.incl" 14.29 +#include "incls/_dtraceJSDT_windows.cpp.incl" 14.30 + 14.31 +int DTraceJSDT::pd_activate( 14.32 + void* baseAddress, jstring module, 14.33 + jint providers_count, JVM_DTraceProvider* providers) { 14.34 + return -1; 14.35 +} 14.36 + 14.37 +void DTraceJSDT::pd_dispose(int handle) { 14.38 +} 14.39 + 14.40 +jboolean DTraceJSDT::pd_is_supported() { 14.41 + return false; 14.42 +}
15.1 --- a/src/share/vm/asm/codeBuffer.hpp Wed Apr 16 17:36:29 2008 -0400 15.2 +++ b/src/share/vm/asm/codeBuffer.hpp Thu Apr 17 22:18:15 2008 -0400 15.3 @@ -36,6 +36,7 @@ 15.4 Verified_Entry, 15.5 Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete 15.6 OSR_Entry, 15.7 + Dtrace_trap = OSR_Entry, // dtrace probes can never have an OSR entry so reuse it 15.8 Exceptions, // Offset where exception handler lives 15.9 Deopt, // Offset where deopt handler lives 15.10 max_Entries };
16.1 --- a/src/share/vm/code/nmethod.cpp Wed Apr 16 17:36:29 2008 -0400 16.2 +++ b/src/share/vm/code/nmethod.cpp Thu Apr 17 22:18:15 2008 -0400 16.3 @@ -27,7 +27,6 @@ 16.4 16.5 #ifdef DTRACE_ENABLED 16.6 16.7 - 16.8 // Only bother with this argument setup if dtrace is available 16.9 16.10 HS_DTRACE_PROBE_DECL8(hotspot, compiled__method__load, 16.11 @@ -438,7 +437,6 @@ 16.12 { 16.13 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); 16.14 int native_nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); 16.15 - const int dummy = -1; // Flag to force proper "operator new" 16.16 CodeOffsets offsets; 16.17 offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); 16.18 offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); 16.19 @@ -461,6 +459,41 @@ 16.20 return nm; 16.21 } 16.22 16.23 +#ifdef HAVE_DTRACE_H 16.24 +nmethod* nmethod::new_dtrace_nmethod(methodHandle method, 16.25 + CodeBuffer *code_buffer, 16.26 + int vep_offset, 16.27 + int trap_offset, 16.28 + int frame_complete, 16.29 + int frame_size) { 16.30 + // create nmethod 16.31 + nmethod* nm = NULL; 16.32 + { 16.33 + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); 16.34 + int nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); 16.35 + CodeOffsets offsets; 16.36 + offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); 16.37 + offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset); 16.38 + offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); 16.39 + 16.40 + nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size); 16.41 + 16.42 + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); 16.43 + if (PrintAssembly && nm != NULL) 16.44 + Disassembler::decode(nm); 16.45 + } 16.46 + // verify nmethod 16.47 + debug_only(if (nm) nm->verify();) // might block 16.48 + 16.49 + if (nm != NULL) { 16.50 + nm->log_new_nmethod(); 16.51 + } 16.52 + 16.53 + return nm; 16.54 +} 16.55 + 16.56 +#endif // def HAVE_DTRACE_H 16.57 + 16.58 nmethod* nmethod::new_nmethod(methodHandle method, 16.59 int compile_id, 16.60 int entry_bci, 16.61 @@ -558,6 +591,9 @@ 16.62 _exception_offset = 0; 16.63 _deoptimize_offset = 0; 16.64 _orig_pc_offset = 0; 16.65 +#ifdef HAVE_DTRACE_H 16.66 + _trap_offset = 0; 16.67 +#endif // def HAVE_DTRACE_H 16.68 _stub_offset = data_offset(); 16.69 _consts_offset = data_offset(); 16.70 _scopes_data_offset = data_offset(); 16.71 @@ -615,6 +651,90 @@ 16.72 Events::log("Create nmethod " INTPTR_FORMAT, this); 16.73 } 16.74 16.75 +// For dtrace wrappers 16.76 +#ifdef HAVE_DTRACE_H 16.77 +nmethod::nmethod( 16.78 + methodOop method, 16.79 + int nmethod_size, 16.80 + CodeOffsets* offsets, 16.81 + CodeBuffer* code_buffer, 16.82 + int frame_size) 16.83 + : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod), 16.84 + nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL), 16.85 + _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), 16.86 + _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) 16.87 +{ 16.88 + { 16.89 + debug_only(No_Safepoint_Verifier nsv;) 16.90 + assert_locked_or_safepoint(CodeCache_lock); 16.91 + 16.92 + NOT_PRODUCT(_has_debug_info = false; ) 16.93 + _method = method; 16.94 + _entry_bci = InvocationEntryBci; 16.95 + _link = NULL; 16.96 + _compiler = NULL; 16.97 + // We have no exception handler or deopt handler make the 16.98 + // values something that will never match a pc like the nmethod vtable entry 16.99 + _exception_offset = 0; 16.100 + _deoptimize_offset = 0; 16.101 + _trap_offset = offsets->value(CodeOffsets::Dtrace_trap); 16.102 + _orig_pc_offset = 0; 16.103 + _stub_offset = data_offset(); 16.104 + _consts_offset = data_offset(); 16.105 + _scopes_data_offset = data_offset(); 16.106 + _scopes_pcs_offset = _scopes_data_offset; 16.107 + _dependencies_offset = _scopes_pcs_offset; 16.108 + _handler_table_offset = _dependencies_offset; 16.109 + _nul_chk_table_offset = _handler_table_offset; 16.110 + _nmethod_end_offset = _nul_chk_table_offset; 16.111 + _compile_id = 0; // default 16.112 + _comp_level = CompLevel_none; 16.113 + _entry_point = instructions_begin(); 16.114 + _verified_entry_point = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry); 16.115 + _osr_entry_point = NULL; 16.116 + _exception_cache = NULL; 16.117 + _pc_desc_cache.reset_to(NULL); 16.118 + 16.119 + flags.clear(); 16.120 + flags.state = alive; 16.121 + _markedForDeoptimization = 0; 16.122 + 16.123 + _lock_count = 0; 16.124 + _stack_traversal_mark = 0; 16.125 + 16.126 + code_buffer->copy_oops_to(this); 16.127 + debug_only(check_store();) 16.128 + CodeCache::commit(this); 16.129 + VTune::create_nmethod(this); 16.130 + } 16.131 + 16.132 + if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) { 16.133 + ttyLocker ttyl; // keep the following output all in one block 16.134 + // This output goes directly to the tty, not the compiler log. 16.135 + // To enable tools to match it up with the compilation activity, 16.136 + // be sure to tag this tty output with the compile ID. 16.137 + if (xtty != NULL) { 16.138 + xtty->begin_head("print_dtrace_nmethod"); 16.139 + xtty->method(_method); 16.140 + xtty->stamp(); 16.141 + xtty->end_head(" address='" INTPTR_FORMAT "'", (intptr_t) this); 16.142 + } 16.143 + // print the header part first 16.144 + print(); 16.145 + // then print the requested information 16.146 + if (PrintNMethods) { 16.147 + print_code(); 16.148 + } 16.149 + if (PrintRelocations) { 16.150 + print_relocations(); 16.151 + } 16.152 + if (xtty != NULL) { 16.153 + xtty->tail("print_dtrace_nmethod"); 16.154 + } 16.155 + } 16.156 + Events::log("Create nmethod " INTPTR_FORMAT, this); 16.157 +} 16.158 +#endif // def HAVE_DTRACE_H 16.159 16.160 void* nmethod::operator new(size_t size, int nmethod_size) { 16.161 // Always leave some room in the CodeCache for I2C/C2I adapters 16.162 @@ -658,6 +778,9 @@ 16.163 _link = NULL; 16.164 _compiler = compiler; 16.165 _orig_pc_offset = orig_pc_offset; 16.166 +#ifdef HAVE_DTRACE_H 16.167 + _trap_offset = 0; 16.168 +#endif // def HAVE_DTRACE_H 16.169 _stub_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start()); 16.170 16.171 // Exception handler and deopt handler are in the stub section 16.172 @@ -1885,7 +2008,6 @@ 16.173 } else if (is_compiled_by_c2()) { 16.174 tty->print("(c2) "); 16.175 } else { 16.176 - assert(is_native_method(), "Who else?"); 16.177 tty->print("(nm) "); 16.178 } 16.179
17.1 --- a/src/share/vm/code/nmethod.hpp Wed Apr 16 17:36:29 2008 -0400 17.2 +++ b/src/share/vm/code/nmethod.hpp Thu Apr 17 22:18:15 2008 -0400 17.3 @@ -140,6 +140,9 @@ 17.4 int _exception_offset; 17.5 // All deoptee's will resume execution at this location described by this offset 17.6 int _deoptimize_offset; 17.7 +#ifdef HAVE_DTRACE_H 17.8 + int _trap_offset; 17.9 +#endif // def HAVE_DTRACE_H 17.10 int _stub_offset; 17.11 int _consts_offset; 17.12 int _scopes_data_offset; 17.13 @@ -211,6 +214,15 @@ 17.14 ByteSize basic_lock_sp_offset, /* synchronized natives only */ 17.15 OopMapSet* oop_maps); 17.16 17.17 +#ifdef HAVE_DTRACE_H 17.18 + // For native wrappers 17.19 + nmethod(methodOop method, 17.20 + int nmethod_size, 17.21 + CodeOffsets* offsets, 17.22 + CodeBuffer *code_buffer, 17.23 + int frame_size); 17.24 +#endif // def HAVE_DTRACE_H 17.25 + 17.26 // Creation support 17.27 nmethod(methodOop method, 17.28 int nmethod_size, 17.29 @@ -272,6 +284,22 @@ 17.30 ByteSize basic_lock_sp_offset, 17.31 OopMapSet* oop_maps); 17.32 17.33 +#ifdef HAVE_DTRACE_H 17.34 + // The method we generate for a dtrace probe has to look 17.35 + // like an nmethod as far as the rest of the system is concerned 17.36 + // which is somewhat unfortunate. 17.37 + static nmethod* new_dtrace_nmethod(methodHandle method, 17.38 + CodeBuffer *code_buffer, 17.39 + int vep_offset, 17.40 + int trap_offset, 17.41 + int frame_complete, 17.42 + int frame_size); 17.43 + 17.44 + int trap_offset() const { return _trap_offset; } 17.45 + address trap_address() const { return code_begin() + _trap_offset; } 17.46 + 17.47 +#endif // def HAVE_DTRACE_H 17.48 + 17.49 // accessors 17.50 methodOop method() const { return _method; } 17.51 AbstractCompiler* compiler() const { return _compiler; }
18.1 --- a/src/share/vm/includeDB_core Wed Apr 16 17:36:29 2008 -0400 18.2 +++ b/src/share/vm/includeDB_core Thu Apr 17 22:18:15 2008 -0400 18.3 @@ -1497,6 +1497,30 @@ 18.4 dtraceAttacher.cpp vmThread.hpp 18.5 dtraceAttacher.cpp vm_operations.hpp 18.6 18.7 +dtraceJSDT.cpp allocation.hpp 18.8 +dtraceJSDT.cpp codeBlob.hpp 18.9 +dtraceJSDT.cpp dtraceJSDT.hpp 18.10 +dtraceJSDT.cpp exceptions.hpp 18.11 +dtraceJSDT.cpp globalDefinitions.hpp 18.12 +dtraceJSDT.cpp javaClasses.hpp 18.13 +dtraceJSDT.cpp jniHandles.hpp 18.14 +dtraceJSDT.cpp jvm.h 18.15 +dtraceJSDT.cpp os.hpp 18.16 +dtraceJSDT.cpp utf8.hpp 18.17 + 18.18 +dtraceJSDT.hpp nativeInst_<arch>.hpp 18.19 +dtraceJSDT.hpp nmethod.hpp 18.20 + 18.21 +dtraceJSDT_<os_family>.cpp allocation.hpp 18.22 +dtraceJSDT_<os_family>.cpp codeBlob.hpp 18.23 +dtraceJSDT_<os_family>.cpp dtraceJSDT.hpp 18.24 +dtraceJSDT_<os_family>.cpp globalDefinitions.hpp 18.25 +dtraceJSDT_<os_family>.cpp javaClasses.hpp 18.26 +dtraceJSDT_<os_family>.cpp jniHandles.hpp 18.27 +dtraceJSDT_<os_family>.cpp jvm.h 18.28 +dtraceJSDT_<os_family>.cpp os.hpp 18.29 +dtraceJSDT_<os_family>.cpp signature.hpp 18.30 + 18.31 // dump is jck optional, put cpp deps in includeDB_features 18.32 18.33 events.cpp allocation.inline.hpp 18.34 @@ -2400,6 +2424,7 @@ 18.35 jvm.cpp collectedHeap.inline.hpp 18.36 jvm.cpp copy.hpp 18.37 jvm.cpp defaultStream.hpp 18.38 +jvm.cpp dtraceJSDT.hpp 18.39 jvm.cpp events.hpp 18.40 jvm.cpp handles.inline.hpp 18.41 jvm.cpp histogram.hpp
19.1 --- a/src/share/vm/oops/methodOop.cpp Wed Apr 16 17:36:29 2008 -0400 19.2 +++ b/src/share/vm/oops/methodOop.cpp Thu Apr 17 22:18:15 2008 -0400 19.3 @@ -672,9 +672,6 @@ 19.4 } 19.5 19.6 address methodOopDesc::make_adapters(methodHandle mh, TRAPS) { 19.7 - // If running -Xint we need no adapters. 19.8 - if (Arguments::mode() == Arguments::_int) return NULL; 19.9 - 19.10 // Adapters for compiled code are made eagerly here. They are fairly 19.11 // small (generally < 100 bytes) and quick to make (and cached and shared) 19.12 // so making them eagerly shouldn't be too expensive.
20.1 --- a/src/share/vm/prims/jvm.cpp Wed Apr 16 17:36:29 2008 -0400 20.2 +++ b/src/share/vm/prims/jvm.cpp Thu Apr 17 22:18:15 2008 -0400 20.3 @@ -4168,6 +4168,36 @@ 20.4 return res == oldVal; 20.5 JVM_END 20.6 20.7 +// DTrace /////////////////////////////////////////////////////////////////// 20.8 + 20.9 +JVM_ENTRY(jint, JVM_DTraceGetVersion(JNIEnv* env)) 20.10 + JVMWrapper("JVM_DTraceGetVersion"); 20.11 + return (jint)JVM_TRACING_DTRACE_VERSION; 20.12 +JVM_END 20.13 + 20.14 +JVM_ENTRY(jlong,JVM_DTraceActivate( 20.15 + JNIEnv* env, jint version, jstring module_name, jint providers_count, 20.16 + JVM_DTraceProvider* providers)) 20.17 + JVMWrapper("JVM_DTraceActivate"); 20.18 + return DTraceJSDT::activate( 20.19 + version, module_name, providers_count, providers, CHECK_0); 20.20 +JVM_END 20.21 + 20.22 +JVM_ENTRY(jboolean,JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method)) 20.23 + JVMWrapper("JVM_DTraceIsProbeEnabled"); 20.24 + return DTraceJSDT::is_probe_enabled(method); 20.25 +JVM_END 20.26 + 20.27 +JVM_ENTRY(void,JVM_DTraceDispose(JNIEnv* env, jlong handle)) 20.28 + JVMWrapper("JVM_DTraceDispose"); 20.29 + DTraceJSDT::dispose(handle); 20.30 +JVM_END 20.31 + 20.32 +JVM_ENTRY(jboolean,JVM_DTraceIsSupported(JNIEnv* env)) 20.33 + JVMWrapper("JVM_DTraceIsSupported"); 20.34 + return DTraceJSDT::is_supported(); 20.35 +JVM_END 20.36 + 20.37 // Returns an array of all live Thread objects (VM internal JavaThreads, 20.38 // jvmti agent threads, and JNI attaching threads are skipped) 20.39 // See CR 6404306 regarding JNI attaching threads 20.40 @@ -4496,3 +4526,4 @@ 20.41 #endif // KERNEL 20.42 } 20.43 JVM_END 20.44 +
21.1 --- a/src/share/vm/prims/jvm.h Wed Apr 16 17:36:29 2008 -0400 21.2 +++ b/src/share/vm/prims/jvm.h Thu Apr 17 22:18:15 2008 -0400 21.3 @@ -606,6 +606,83 @@ 21.4 JNIEXPORT jboolean JNICALL 21.5 JVM_CX8Field(JNIEnv *env, jobject obj, jfieldID fldID, jlong oldVal, jlong newVal); 21.6 21.7 +/* 21.8 + * com.sun.dtrace.jsdt support 21.9 + */ 21.10 + 21.11 +#define JVM_TRACING_DTRACE_VERSION 1 21.12 + 21.13 +/* 21.14 + * Structure to pass one probe description to JVM. 21.15 + * 21.16 + * The VM will overwrite the definition of the referenced method with 21.17 + * code that will fire the probe. 21.18 + */ 21.19 +typedef struct { 21.20 + jmethodID method; 21.21 + jstring function; 21.22 + jstring name; 21.23 + void* reserved[4]; // for future use 21.24 +} JVM_DTraceProbe; 21.25 + 21.26 +/** 21.27 + * Encapsulates the stability ratings for a DTrace provider field 21.28 + */ 21.29 +typedef struct { 21.30 + jint nameStability; 21.31 + jint dataStability; 21.32 + jint dependencyClass; 21.33 +} JVM_DTraceInterfaceAttributes; 21.34 + 21.35 +/* 21.36 + * Structure to pass one provider description to JVM 21.37 + */ 21.38 +typedef struct { 21.39 + jstring name; 21.40 + JVM_DTraceProbe* probes; 21.41 + jint probe_count; 21.42 + JVM_DTraceInterfaceAttributes providerAttributes; 21.43 + JVM_DTraceInterfaceAttributes moduleAttributes; 21.44 + JVM_DTraceInterfaceAttributes functionAttributes; 21.45 + JVM_DTraceInterfaceAttributes nameAttributes; 21.46 + JVM_DTraceInterfaceAttributes argsAttributes; 21.47 + void* reserved[4]; // for future use 21.48 +} JVM_DTraceProvider; 21.49 + 21.50 +/* 21.51 + * Get the version number the JVM was built with 21.52 + */ 21.53 +JNIEXPORT jint JNICALL 21.54 +JVM_DTraceGetVersion(JNIEnv* env); 21.55 + 21.56 +/* 21.57 + * Register new probe with given signature, return global handle 21.58 + * 21.59 + * The version passed in is the version that the library code was 21.60 + * built with. 21.61 + */ 21.62 +JNIEXPORT jlong JNICALL 21.63 +JVM_DTraceActivate(JNIEnv* env, jint version, jstring module_name, 21.64 + jint providers_count, JVM_DTraceProvider* providers); 21.65 + 21.66 +/* 21.67 + * Check JSDT probe 21.68 + */ 21.69 +JNIEXPORT jboolean JNICALL 21.70 +JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method); 21.71 + 21.72 +/* 21.73 + * Destroy custom DOF 21.74 + */ 21.75 +JNIEXPORT void JNICALL 21.76 +JVM_DTraceDispose(JNIEnv* env, jlong handle); 21.77 + 21.78 +/* 21.79 + * Check to see if DTrace is supported by OS 21.80 + */ 21.81 +JNIEXPORT jboolean JNICALL 21.82 +JVM_DTraceIsSupported(JNIEnv* env); 21.83 + 21.84 /************************************************************************* 21.85 PART 2: Support for the Verifier and Class File Format Checker 21.86 ************************************************************************/
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/src/share/vm/runtime/dtraceJSDT.cpp Thu Apr 17 22:18:15 2008 -0400 22.3 @@ -0,0 +1,117 @@ 22.4 +/* 22.5 + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 22.7 + * 22.8 + * This code is free software; you can redistribute it and/or modify it 22.9 + * under the terms of the GNU General Public License version 2 only, as 22.10 + * published by the Free Software Foundation. 22.11 + * 22.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 22.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 22.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 22.15 + * version 2 for more details (a copy is included in the LICENSE file that 22.16 + * accompanied this code). 22.17 + * 22.18 + * You should have received a copy of the GNU General Public License version 22.19 + * 2 along with this work; if not, write to the Free Software Foundation, 22.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22.21 + * 22.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 22.24 + * have any questions. 22.25 + * 22.26 + */ 22.27 + 22.28 +#include "incls/_precompiled.incl" 22.29 +#include "incls/_dtraceJSDT.cpp.incl" 22.30 + 22.31 +#ifdef HAVE_DTRACE_H 22.32 + 22.33 +jlong DTraceJSDT::activate( 22.34 + jint version, jstring module_name, jint providers_count, 22.35 + JVM_DTraceProvider* providers, TRAPS) { 22.36 + 22.37 + size_t count = 0; 22.38 + RegisteredProbes* probes = NULL; 22.39 + 22.40 + if (!is_supported()) { 22.41 + return 0; 22.42 + } 22.43 + 22.44 + assert(module_name != NULL, "valid module name"); 22.45 + assert(providers != NULL, "valid provider array"); 22.46 + 22.47 + for (int i = 0; i < providers_count; ++i) { 22.48 + count += providers[i].probe_count; 22.49 + } 22.50 + probes = new RegisteredProbes(count); 22.51 + count = 0; 22.52 + 22.53 + for (int i = 0; i < providers_count; ++i) { 22.54 + assert(providers[i].name != NULL, "valid provider name"); 22.55 + assert(providers[i].probe_count == 0 || providers[i].probes != NULL, 22.56 + "valid probe count"); 22.57 + for (int j = 0; j < providers[i].probe_count; ++j) { 22.58 + JVM_DTraceProbe* probe = &(providers[i].probes[j]); 22.59 + assert(probe != NULL, "valid probe"); 22.60 + assert(probe->method != NULL, "valid method"); 22.61 + assert(probe->name != NULL, "valid probe name"); 22.62 + assert(probe->function != NULL, "valid probe function spec"); 22.63 + methodHandle h_method = 22.64 + methodHandle(THREAD, JNIHandles::resolve_jmethod_id(probe->method)); 22.65 + nmethod* nm = AdapterHandlerLibrary::create_dtrace_nmethod(h_method); 22.66 + h_method()->set_not_compilable(CompLevel_highest_tier); 22.67 + h_method()->set_code(h_method, nm); 22.68 + probes->nmethod_at_put(count++, nm); 22.69 + } 22.70 + } 22.71 + 22.72 + int handle = pd_activate((void*)probes, 22.73 + module_name, providers_count, providers); 22.74 + if (handle <= 0) { 22.75 + delete probes; 22.76 + THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), 22.77 + "Unable to register DTrace probes (internal error)."); 22.78 + } 22.79 + probes->set_helper_handle(handle); 22.80 + return RegisteredProbes::toOpaqueProbes(probes); 22.81 +} 22.82 + 22.83 +jboolean DTraceJSDT::is_probe_enabled(jmethodID method) { 22.84 + methodOop m = JNIHandles::resolve_jmethod_id(method); 22.85 + return nativeInstruction_at(m->code()->trap_address())->is_dtrace_trap(); 22.86 +} 22.87 + 22.88 +void DTraceJSDT::dispose(OpaqueProbes probes) { 22.89 + RegisteredProbes* p = RegisteredProbes::toRegisteredProbes(probes); 22.90 + if (probes != -1 && p != NULL) { 22.91 + pd_dispose(p->helper_handle()); 22.92 + delete p; 22.93 + } 22.94 +} 22.95 + 22.96 +jboolean DTraceJSDT::is_supported() { 22.97 + return pd_is_supported(); 22.98 +} 22.99 + 22.100 +#else // HAVE_DTRACE_H 22.101 + 22.102 +jlong DTraceJSDT::activate( 22.103 + jint version, jstring module_name, jint providers_count, 22.104 + JVM_DTraceProvider* providers, TRAPS) { 22.105 + return 0; 22.106 +} 22.107 + 22.108 +jboolean DTraceJSDT::is_probe_enabled(jmethodID method) { 22.109 + return false; 22.110 +} 22.111 + 22.112 +void DTraceJSDT::dispose(OpaqueProbes probes) { 22.113 + return; 22.114 +} 22.115 + 22.116 +jboolean DTraceJSDT::is_supported() { 22.117 + return false; 22.118 +} 22.119 + 22.120 +#endif // ndef HAVE_DTRACE_H
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/src/share/vm/runtime/dtraceJSDT.hpp Thu Apr 17 22:18:15 2008 -0400 23.3 @@ -0,0 +1,89 @@ 23.4 +/* 23.5 + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. 23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 23.7 + * 23.8 + * This code is free software; you can redistribute it and/or modify it 23.9 + * under the terms of the GNU General Public License version 2 only, as 23.10 + * published by the Free Software Foundation. 23.11 + * 23.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 23.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 23.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23.15 + * version 2 for more details (a copy is included in the LICENSE file that 23.16 + * accompanied this code). 23.17 + * 23.18 + * You should have received a copy of the GNU General Public License version 23.19 + * 2 along with this work; if not, write to the Free Software Foundation, 23.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 23.21 + * 23.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 23.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 23.24 + * have any questions. 23.25 + * 23.26 + */ 23.27 + 23.28 +class RegisteredProbes; 23.29 +typedef jlong OpaqueProbes; 23.30 + 23.31 +class DTraceJSDT : AllStatic { 23.32 + private: 23.33 + 23.34 + static int pd_activate(void* moduleBaseAddress, jstring module, 23.35 + jint providers_count, JVM_DTraceProvider* providers); 23.36 + static void pd_dispose(int handle); 23.37 + static jboolean pd_is_supported(); 23.38 + 23.39 + public: 23.40 + 23.41 + static OpaqueProbes activate( 23.42 + jint version, jstring module_name, jint providers_count, 23.43 + JVM_DTraceProvider* providers, TRAPS); 23.44 + static jboolean is_probe_enabled(jmethodID method); 23.45 + static void dispose(OpaqueProbes handle); 23.46 + static jboolean is_supported(); 23.47 +}; 23.48 + 23.49 +class RegisteredProbes : public CHeapObj { 23.50 + private: 23.51 + nmethod** _nmethods; // all the probe methods 23.52 + size_t _count; // number of probe methods 23.53 + int _helper_handle; // DTrace-assigned identifier 23.54 + 23.55 + public: 23.56 + RegisteredProbes(size_t count) { 23.57 + _count = count; 23.58 + _nmethods = NEW_C_HEAP_ARRAY(nmethod*, count); 23.59 + } 23.60 + 23.61 + ~RegisteredProbes() { 23.62 + for (size_t i = 0; i < _count; ++i) { 23.63 + // Let the sweeper reclaim it 23.64 + _nmethods[i]->make_not_entrant(); 23.65 + _nmethods[i]->method()->clear_code(); 23.66 + } 23.67 + FREE_C_HEAP_ARRAY(nmethod*, _nmethods); 23.68 + _nmethods = NULL; 23.69 + _count = 0; 23.70 + } 23.71 + 23.72 + static RegisteredProbes* toRegisteredProbes(OpaqueProbes p) { 23.73 + return (RegisteredProbes*)(intptr_t)p; 23.74 + } 23.75 + 23.76 + static OpaqueProbes toOpaqueProbes(RegisteredProbes* p) { 23.77 + return (OpaqueProbes)(intptr_t)p; 23.78 + } 23.79 + 23.80 + void set_helper_handle(int handle) { _helper_handle = handle; } 23.81 + int helper_handle() const { return _helper_handle; } 23.82 + 23.83 + nmethod* nmethod_at(size_t i) { 23.84 + assert(i >= 0 && i < _count, "bad nmethod index"); 23.85 + return _nmethods[i]; 23.86 + } 23.87 + 23.88 + void nmethod_at_put(size_t i, nmethod* nm) { 23.89 + assert(i >= 0 && i < _count, "bad nmethod index"); 23.90 + _nmethods[i] = nm; 23.91 + } 23.92 +};
24.1 --- a/src/share/vm/runtime/globals.hpp Wed Apr 16 17:36:29 2008 -0400 24.2 +++ b/src/share/vm/runtime/globals.hpp Thu Apr 17 22:18:15 2008 -0400 24.3 @@ -3188,6 +3188,9 @@ 24.4 product(bool, RelaxAccessControlCheck, false, \ 24.5 "Relax the access control checks in the verifier") \ 24.6 \ 24.7 + diagnostic(bool, PrintDTraceDOF, false, \ 24.8 + "Print the DTrace DOF passed to the system for JSDT probes") \ 24.9 + \ 24.10 product(bool, UseVMInterruptibleIO, true, \ 24.11 "(Unstable, Solaris-specific) Thread interrupt before or with " \ 24.12 "EINTR for I/O operations results in OS_INTRPT")
25.1 --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Apr 16 17:36:29 2008 -0400 25.2 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 17 22:18:15 2008 -0400 25.3 @@ -1748,11 +1748,6 @@ 25.4 // _fingerprints array (it is not safe for concurrent readers and a single 25.5 // writer: this can be fixed if it becomes a problem). 25.6 25.7 - // Shouldn't be here if running -Xint 25.8 - if (Arguments::mode() == Arguments::_int) { 25.9 - ShouldNotReachHere(); 25.10 - } 25.11 - 25.12 // Get the address of the ic_miss handlers before we grab the 25.13 // AdapterHandlerLibrary_lock. This fixes bug 6236259 which 25.14 // was caused by the initialization of the stubs happening 25.15 @@ -1997,6 +1992,64 @@ 25.16 return nm; 25.17 } 25.18 25.19 +#ifdef HAVE_DTRACE_H 25.20 +// Create a dtrace nmethod for this method. The wrapper converts the 25.21 +// java compiled calling convention to the native convention, makes a dummy call 25.22 +// (actually nops for the size of the call instruction, which become a trap if 25.23 +// probe is enabled). The returns to the caller. Since this all looks like a 25.24 +// leaf no thread transition is needed. 25.25 + 25.26 +nmethod *AdapterHandlerLibrary::create_dtrace_nmethod(methodHandle method) { 25.27 + ResourceMark rm; 25.28 + nmethod* nm = NULL; 25.29 + 25.30 + if (PrintCompilation) { 25.31 + ttyLocker ttyl; 25.32 + tty->print("--- n%s "); 25.33 + method->print_short_name(tty); 25.34 + if (method->is_static()) { 25.35 + tty->print(" (static)"); 25.36 + } 25.37 + tty->cr(); 25.38 + } 25.39 + 25.40 + { 25.41 + // perform the work while holding the lock, but perform any printing 25.42 + // outside the lock 25.43 + MutexLocker mu(AdapterHandlerLibrary_lock); 25.44 + // See if somebody beat us to it 25.45 + nm = method->code(); 25.46 + if (nm) { 25.47 + return nm; 25.48 + } 25.49 + 25.50 + // Improve alignment slightly 25.51 + u_char* buf = (u_char*) 25.52 + (((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1)); 25.53 + CodeBuffer buffer(buf, AdapterHandlerLibrary_size); 25.54 + // Need a few relocation entries 25.55 + double locs_buf[20]; 25.56 + buffer.insts()->initialize_shared_locs( 25.57 + (relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo)); 25.58 + MacroAssembler _masm(&buffer); 25.59 + 25.60 + // Generate the compiled-to-native wrapper code 25.61 + nm = SharedRuntime::generate_dtrace_nmethod(&_masm, method); 25.62 + } 25.63 + return nm; 25.64 +} 25.65 + 25.66 +// the dtrace method needs to convert java lang string to utf8 string. 25.67 +void SharedRuntime::get_utf(oopDesc* src, address dst) { 25.68 + typeArrayOop jlsValue = java_lang_String::value(src); 25.69 + int jlsOffset = java_lang_String::offset(src); 25.70 + int jlsLen = java_lang_String::length(src); 25.71 + jchar* jlsPos = (jlsLen == 0) ? NULL : 25.72 + jlsValue->char_at_addr(jlsOffset); 25.73 + (void) UNICODE::as_utf8(jlsPos, jlsLen, (char *)dst, max_dtrace_string_size); 25.74 +} 25.75 +#endif // ndef HAVE_DTRACE_H 25.76 + 25.77 // ------------------------------------------------------------------------- 25.78 // Java-Java calling convention 25.79 // (what you use when Java calls Java)
26.1 --- a/src/share/vm/runtime/sharedRuntime.hpp Wed Apr 16 17:36:29 2008 -0400 26.2 +++ b/src/share/vm/runtime/sharedRuntime.hpp Thu Apr 17 22:18:15 2008 -0400 26.3 @@ -59,6 +59,10 @@ 26.4 26.5 #endif // !PRODUCT 26.6 public: 26.7 + 26.8 + // max bytes for each dtrace string parameter 26.9 + enum { max_dtrace_string_size = 256 }; 26.10 + 26.11 // The following arithmetic routines are used on platforms that do 26.12 // not have machine instructions to implement their functionality. 26.13 // Do not remove these. 26.14 @@ -258,9 +262,6 @@ 26.15 26.16 public: 26.17 26.18 - 26.19 - static void create_native_wrapper (JavaThread* thread, methodOop method); 26.20 - 26.21 // Read the array of BasicTypes from a Java signature, and compute where 26.22 // compiled Java code would like to put the results. Values in reg_lo and 26.23 // reg_hi refer to 4-byte quantities. Values less than SharedInfo::stack0 are 26.24 @@ -354,6 +355,19 @@ 26.25 VMRegPair *regs, 26.26 BasicType ret_type ); 26.27 26.28 +#ifdef HAVE_DTRACE_H 26.29 + // Generate a dtrace wrapper for a given method. The method takes arguments 26.30 + // in the Java compiled code convention, marshals them to the native 26.31 + // convention (handlizes oops, etc), transitions to native, makes the call, 26.32 + // returns to java state (possibly blocking), unhandlizes any result and 26.33 + // returns. 26.34 + static nmethod *generate_dtrace_nmethod(MacroAssembler* masm, 26.35 + methodHandle method); 26.36 + 26.37 + // dtrace support to convert a Java string to utf8 26.38 + static void get_utf(oopDesc* src, address dst); 26.39 +#endif // def HAVE_DTRACE_H 26.40 + 26.41 // A compiled caller has just called the interpreter, but compiled code 26.42 // exists. Patch the caller so he no longer calls into the interpreter. 26.43 static void fixup_callers_callsite(methodOopDesc* moop, address ret_pc); 26.44 @@ -492,42 +506,55 @@ 26.45 address _c2i_unverified_entry; 26.46 26.47 public: 26.48 + 26.49 + // The name we give all buffer blobs 26.50 + static const char* name; 26.51 + 26.52 AdapterHandlerEntry(address i2c_entry, address c2i_entry, address c2i_unverified_entry): 26.53 _i2c_entry(i2c_entry), 26.54 _c2i_entry(c2i_entry), 26.55 _c2i_unverified_entry(c2i_unverified_entry) { 26.56 } 26.57 - // The name we give all buffer blobs 26.58 - static const char* name; 26.59 26.60 address get_i2c_entry() { return _i2c_entry; } 26.61 address get_c2i_entry() { return _c2i_entry; } 26.62 address get_c2i_unverified_entry() { return _c2i_unverified_entry; } 26.63 + 26.64 void relocate(address new_base); 26.65 #ifndef PRODUCT 26.66 void print(); 26.67 #endif /* PRODUCT */ 26.68 }; 26.69 26.70 - 26.71 class AdapterHandlerLibrary: public AllStatic { 26.72 private: 26.73 + static u_char _buffer[]; // the temporary code buffer 26.74 + static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection 26.75 + static GrowableArray<AdapterHandlerEntry*> * _handlers; // the corresponding handlers 26.76 enum { 26.77 AbstractMethodHandler = 1 // special handler for abstract methods 26.78 }; 26.79 - static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection 26.80 - static GrowableArray<AdapterHandlerEntry*> * _handlers; // the corresponding handlers 26.81 - static u_char _buffer[]; // the temporary code buffer 26.82 static void initialize(); 26.83 - static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); } 26.84 static int get_create_adapter_index(methodHandle method); 26.85 - static address get_i2c_entry( int index ) { return get_entry(index)->get_i2c_entry(); } 26.86 - static address get_c2i_entry( int index ) { return get_entry(index)->get_c2i_entry(); } 26.87 - static address get_c2i_unverified_entry( int index ) { return get_entry(index)->get_c2i_unverified_entry(); } 26.88 + static address get_i2c_entry( int index ) { 26.89 + return get_entry(index)->get_i2c_entry(); 26.90 + } 26.91 + static address get_c2i_entry( int index ) { 26.92 + return get_entry(index)->get_c2i_entry(); 26.93 + } 26.94 + static address get_c2i_unverified_entry( int index ) { 26.95 + return get_entry(index)->get_c2i_unverified_entry(); 26.96 + } 26.97 26.98 public: 26.99 + static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); } 26.100 static nmethod* create_native_wrapper(methodHandle method); 26.101 - static AdapterHandlerEntry* get_adapter(methodHandle method) { return get_entry(get_create_adapter_index(method)); } 26.102 + static AdapterHandlerEntry* get_adapter(methodHandle method) { 26.103 + return get_entry(get_create_adapter_index(method)); 26.104 + } 26.105 +#ifdef HAVE_DTRACE_H 26.106 + static nmethod* create_dtrace_nmethod (methodHandle method); 26.107 +#endif // HAVE_DTRACE_H 26.108 26.109 #ifndef PRODUCT 26.110 static void print_handler(CodeBlob* b);