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