6537506: Provide a mechanism for specifying Java-level USDT-like dtrace probes
authorkamg
Thu, 17 Apr 2008 22:18:15 -0400
changeset 363 99d43e8a76ad
parent 362 00cf4bffd828
child 368 61dbce75b71d
6537506: Provide a mechanism for specifying Java-level USDT-like dtrace probes Summary: Initial checkin of JSDT code Reviewed-by: acorn, sbohne
hotspot/make/linux/makefiles/mapfile-vers-debug
hotspot/make/linux/makefiles/mapfile-vers-product
hotspot/make/solaris/makefiles/dtrace.make
hotspot/make/solaris/makefiles/mapfile-vers
hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp
hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
hotspot/src/cpu/x86/vm/nativeInst_x86.cpp
hotspot/src/cpu/x86/vm/nativeInst_x86.hpp
hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
hotspot/src/os/linux/vm/dtraceJSDT_linux.cpp
hotspot/src/os/solaris/vm/dtraceJSDT_solaris.cpp
hotspot/src/os/windows/vm/dtraceJSDT_windows.cpp
hotspot/src/share/vm/asm/codeBuffer.hpp
hotspot/src/share/vm/code/nmethod.cpp
hotspot/src/share/vm/code/nmethod.hpp
hotspot/src/share/vm/includeDB_core
hotspot/src/share/vm/oops/methodOop.cpp
hotspot/src/share/vm/prims/jvm.cpp
hotspot/src/share/vm/prims/jvm.h
hotspot/src/share/vm/runtime/dtraceJSDT.cpp
hotspot/src/share/vm/runtime/dtraceJSDT.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/sharedRuntime.cpp
hotspot/src/share/vm/runtime/sharedRuntime.hpp
--- a/hotspot/make/linux/makefiles/mapfile-vers-debug	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/make/linux/makefiles/mapfile-vers-debug	Thu Apr 17 22:18:15 2008 -0400
@@ -1,3 +1,5 @@
+#
+# @(#)mapfile-vers-debug	1.18 07/10/25 16:47:35
 #
 
 #
@@ -75,6 +77,11 @@
                 JVM_DesiredAssertionStatus;
                 JVM_DisableCompiler;
                 JVM_DoPrivileged;
+                JVM_DTraceGetVersion;
+                JVM_DTraceActivate;
+                JVM_DTraceIsProbeEnabled;
+                JVM_DTraceIsSupported;
+                JVM_DTraceDispose;
                 JVM_DumpAllStacks;
                 JVM_DumpThreads;
                 JVM_EnableCompiler;
--- a/hotspot/make/linux/makefiles/mapfile-vers-product	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/make/linux/makefiles/mapfile-vers-product	Thu Apr 17 22:18:15 2008 -0400
@@ -1,3 +1,5 @@
+#
+# @(#)mapfile-vers-product	1.19 08/02/12 10:56:37
 #
 
 #
@@ -75,6 +77,11 @@
                 JVM_DesiredAssertionStatus;
                 JVM_DisableCompiler;
                 JVM_DoPrivileged;
+                JVM_DTraceGetVersion;
+                JVM_DTraceActivate;
+                JVM_DTraceIsProbeEnabled;
+                JVM_DTraceIsSupported;
+                JVM_DTraceDispose;
                 JVM_DumpAllStacks;
                 JVM_DumpThreads;
                 JVM_EnableCompiler;
--- a/hotspot/make/solaris/makefiles/dtrace.make	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/make/solaris/makefiles/dtrace.make	Thu Apr 17 22:18:15 2008 -0400
@@ -193,10 +193,16 @@
 
 .PHONY: dtraceCheck
 
+SYSTEM_DTRACE_H = /usr/include/dtrace.h
 SYSTEM_DTRACE_PROG = /usr/sbin/dtrace
 PATCH_DTRACE_PROG = /opt/SUNWdtrd/sbin/dtrace
 systemDtraceFound := $(wildcard ${SYSTEM_DTRACE_PROG})
 patchDtraceFound := $(wildcard ${PATCH_DTRACE_PROG})
+systemDtraceHdrFound := $(wildcard $(SYSTEM_DTRACE_H))
+
+ifneq ("$(systemDtraceHdrFound)", "") 
+CFLAGS += -DHAVE_DTRACE_H
+endif
 
 ifneq ("$(patchDtraceFound)", "")
 DTRACE_PROG=$(PATCH_DTRACE_PROG)
--- a/hotspot/make/solaris/makefiles/mapfile-vers	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/make/solaris/makefiles/mapfile-vers	Thu Apr 17 22:18:15 2008 -0400
@@ -1,3 +1,5 @@
+#
+# @(#)mapfile-vers	1.32 07/10/25 16:47:36
 #
 
 #
@@ -75,6 +77,11 @@
 		JVM_DesiredAssertionStatus;
 		JVM_DisableCompiler;
 		JVM_DoPrivileged;
+		JVM_DTraceGetVersion;
+		JVM_DTraceActivate;
+		JVM_DTraceIsProbeEnabled;
+		JVM_DTraceIsSupported;
+		JVM_DTraceDispose;
 		JVM_DumpAllStacks;
 		JVM_DumpThreads;
 		JVM_EnableCompiler;
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -26,6 +26,10 @@
 # include "incls/_nativeInst_sparc.cpp.incl"
 
 
+bool NativeInstruction::is_dtrace_trap() {
+  return !is_nop();
+}
+
 void NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) {
   ResourceMark rm;
   CodeBuffer buf(instaddr, 10 * BytesPerInstWord );
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -43,6 +43,7 @@
     nop_instruction_size        =    4
   };
 
+  bool is_dtrace_trap();
   bool is_nop()                        { return long_at(0) == nop_instruction(); }
   bool is_call()                       { return is_op(long_at(0), Assembler::call_op); }
   bool is_sethi()                      { return (is_op2(long_at(0), Assembler::sethi_op2)
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -1637,7 +1637,7 @@
     }
   } else if (dst.is_single_phys_reg()) {
     if (src.is_adjacent_aligned_on_stack(2)) {
-      __ ldd(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
+      __ ld_long(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register());
     } else {
       // dst is a single reg.
       // Remember lo is low address not msb for stack slots
@@ -2501,6 +2501,551 @@
 
 }
 
+#ifdef HAVE_DTRACE_H
+// ---------------------------------------------------------------------------
+// Generate a dtrace nmethod for a given signature.  The method takes arguments
+// in the Java compiled code convention, marshals them to the native
+// abi and then leaves nops at the position you would expect to call a native
+// function. When the probe is enabled the nops are replaced with a trap
+// instruction that dtrace inserts and the trace will cause a notification
+// to dtrace.
+//
+// The probes are only able to take primitive types and java/lang/String as
+// arguments.  No other java types are allowed. Strings are converted to utf8
+// strings so that from dtrace point of view java strings are converted to C
+// strings. There is an arbitrary fixed limit on the total space that a method
+// can use for converting the strings. (256 chars per string in the signature).
+// So any java string larger then this is truncated.
+
+static int  fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 };
+static bool offsets_initialized = false;
+
+static VMRegPair reg64_to_VMRegPair(Register r) {
+  VMRegPair ret;
+  if (wordSize == 8) {
+    ret.set2(r->as_VMReg());
+  } else {
+    ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg());
+  }
+  return ret;
+}
+
+
+nmethod *SharedRuntime::generate_dtrace_nmethod(
+    MacroAssembler *masm, methodHandle method) {
+
+
+  // generate_dtrace_nmethod is guarded by a mutex so we are sure to
+  // be single threaded in this method.
+  assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be");
+
+  // Fill in the signature array, for the calling-convention call.
+  int total_args_passed = method->size_of_parameters();
+
+  BasicType* in_sig_bt  = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
+  VMRegPair  *in_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
+
+  // The signature we are going to use for the trap that dtrace will see
+  // java/lang/String is converted. We drop "this" and any other object
+  // is converted to NULL.  (A one-slot java/lang/Long object reference
+  // is converted to a two-slot long, which is why we double the allocation).
+  BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2);
+  VMRegPair* out_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2);
+
+  int i=0;
+  int total_strings = 0;
+  int first_arg_to_pass = 0;
+  int total_c_args = 0;
+  int box_offset = java_lang_boxing_object::value_offset_in_bytes();
+
+  // Skip the receiver as dtrace doesn't want to see it
+  if( !method->is_static() ) {
+    in_sig_bt[i++] = T_OBJECT;
+    first_arg_to_pass = 1;
+  }
+
+  SignatureStream ss(method->signature());
+  for ( ; !ss.at_return_type(); ss.next()) {
+    BasicType bt = ss.type();
+    in_sig_bt[i++] = bt;  // Collect remaining bits of signature
+    out_sig_bt[total_c_args++] = bt;
+    if( bt == T_OBJECT) {
+      symbolOop s = ss.as_symbol_or_null();
+      if (s == vmSymbols::java_lang_String()) {
+        total_strings++;
+        out_sig_bt[total_c_args-1] = T_ADDRESS;
+      } else if (s == vmSymbols::java_lang_Boolean() ||
+                 s == vmSymbols::java_lang_Byte()) {
+        out_sig_bt[total_c_args-1] = T_BYTE;
+      } else if (s == vmSymbols::java_lang_Character() ||
+                 s == vmSymbols::java_lang_Short()) {
+        out_sig_bt[total_c_args-1] = T_SHORT;
+      } else if (s == vmSymbols::java_lang_Integer() ||
+                 s == vmSymbols::java_lang_Float()) {
+        out_sig_bt[total_c_args-1] = T_INT;
+      } else if (s == vmSymbols::java_lang_Long() ||
+                 s == vmSymbols::java_lang_Double()) {
+        out_sig_bt[total_c_args-1] = T_LONG;
+        out_sig_bt[total_c_args++] = T_VOID;
+      }
+    } else if ( bt == T_LONG || bt == T_DOUBLE ) {
+      in_sig_bt[i++] = T_VOID;   // Longs & doubles take 2 Java slots
+      // We convert double to long
+      out_sig_bt[total_c_args-1] = T_LONG;
+      out_sig_bt[total_c_args++] = T_VOID;
+    } else if ( bt == T_FLOAT) {
+      // We convert float to int
+      out_sig_bt[total_c_args-1] = T_INT;
+    }
+  }
+
+  assert(i==total_args_passed, "validly parsed signature");
+
+  // Now get the compiled-Java layout as input arguments
+  int comp_args_on_stack;
+  comp_args_on_stack = SharedRuntime::java_calling_convention(
+      in_sig_bt, in_regs, total_args_passed, false);
+
+  // We have received a description of where all the java arg are located
+  // on entry to the wrapper. We need to convert these args to where
+  // the a  native (non-jni) function would expect them. To figure out
+  // where they go we convert the java signature to a C signature and remove
+  // T_VOID for any long/double we might have received.
+
+
+  // Now figure out where the args must be stored and how much stack space
+  // they require (neglecting out_preserve_stack_slots but space for storing
+  // the 1st six register arguments). It's weird see int_stk_helper.
+  //
+  int out_arg_slots;
+  out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args);
+
+  // Calculate the total number of stack slots we will need.
+
+  // First count the abi requirement plus all of the outgoing args
+  int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots;
+
+  // Plus a temp for possible converion of float/double/long register args
+
+  int conversion_temp = stack_slots;
+  stack_slots += 2;
+
+
+  // Now space for the string(s) we must convert
+
+  int string_locs = stack_slots;
+  stack_slots += total_strings *
+                   (max_dtrace_string_size / VMRegImpl::stack_slot_size);
+
+  // Ok The space we have allocated will look like:
+  //
+  //
+  // FP-> |                     |
+  //      |---------------------|
+  //      | string[n]           |
+  //      |---------------------| <- string_locs[n]
+  //      | string[n-1]         |
+  //      |---------------------| <- string_locs[n-1]
+  //      | ...                 |
+  //      | ...                 |
+  //      |---------------------| <- string_locs[1]
+  //      | string[0]           |
+  //      |---------------------| <- string_locs[0]
+  //      | temp                |
+  //      |---------------------| <- conversion_temp
+  //      | outbound memory     |
+  //      | based arguments     |
+  //      |                     |
+  //      |---------------------|
+  //      |                     |
+  // SP-> | out_preserved_slots |
+  //
+  //
+
+  // Now compute actual number of stack words we need rounding to make
+  // stack properly aligned.
+  stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word);
+
+  int stack_size = stack_slots * VMRegImpl::stack_slot_size;
+
+  intptr_t start = (intptr_t)__ pc();
+
+  // First thing make an ic check to see if we should even be here
+
+  {
+    Label L;
+    const Register temp_reg = G3_scratch;
+    Address ic_miss(temp_reg, SharedRuntime::get_ic_miss_stub());
+    __ verify_oop(O0);
+    __ ld_ptr(O0, oopDesc::klass_offset_in_bytes(), temp_reg);
+    __ cmp(temp_reg, G5_inline_cache_reg);
+    __ brx(Assembler::equal, true, Assembler::pt, L);
+    __ delayed()->nop();
+
+    __ jump_to(ic_miss, 0);
+    __ delayed()->nop();
+    __ align(CodeEntryAlignment);
+    __ bind(L);
+  }
+
+  int vep_offset = ((intptr_t)__ pc()) - start;
+
+
+  // The instruction at the verified entry point must be 5 bytes or longer
+  // because it can be patched on the fly by make_non_entrant. The stack bang
+  // instruction fits that requirement.
+
+  // Generate stack overflow check before creating frame
+  __ generate_stack_overflow_check(stack_size);
+
+  assert(((intptr_t)__ pc() - start - vep_offset) >= 5,
+         "valid size for make_non_entrant");
+
+  // Generate a new frame for the wrapper.
+  __ save(SP, -stack_size, SP);
+
+  // Frame is now completed as far a size and linkage.
+
+  int frame_complete = ((intptr_t)__ pc()) - start;
+
+#ifdef ASSERT
+  bool reg_destroyed[RegisterImpl::number_of_registers];
+  bool freg_destroyed[FloatRegisterImpl::number_of_registers];
+  for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) {
+    reg_destroyed[r] = false;
+  }
+  for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) {
+    freg_destroyed[f] = false;
+  }
+
+#endif /* ASSERT */
+
+  VMRegPair zero;
+  zero.set2(G0->as_VMReg());
+
+  int c_arg, j_arg;
+
+  Register conversion_off = noreg;
+
+  for (j_arg = first_arg_to_pass, c_arg = 0 ;
+       j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+
+    VMRegPair src = in_regs[j_arg];
+    VMRegPair dst = out_regs[c_arg];
+
+#ifdef ASSERT
+    if (src.first()->is_Register()) {
+      assert(!reg_destroyed[src.first()->as_Register()->encoding()], "ack!");
+    } else if (src.first()->is_FloatRegister()) {
+      assert(!freg_destroyed[src.first()->as_FloatRegister()->encoding(
+                                               FloatRegisterImpl::S)], "ack!");
+    }
+    if (dst.first()->is_Register()) {
+      reg_destroyed[dst.first()->as_Register()->encoding()] = true;
+    } else if (dst.first()->is_FloatRegister()) {
+      freg_destroyed[dst.first()->as_FloatRegister()->encoding(
+                                                 FloatRegisterImpl::S)] = true;
+    }
+#endif /* ASSERT */
+
+    switch (in_sig_bt[j_arg]) {
+      case T_ARRAY:
+      case T_OBJECT:
+        {
+          if (out_sig_bt[c_arg] == T_BYTE  || out_sig_bt[c_arg] == T_SHORT ||
+              out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) {
+            // need to unbox a one-slot value
+            Register in_reg = L0;
+            Register tmp = L2;
+            if ( src.first()->is_reg() ) {
+              in_reg = src.first()->as_Register();
+            } else {
+              assert(Assembler::is_simm13(reg2offset(src.first()) + STACK_BIAS),
+                     "must be");
+              __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, in_reg);
+            }
+            // If the final destination is an acceptable register
+            if ( dst.first()->is_reg() ) {
+              if ( dst.is_single_phys_reg() || out_sig_bt[c_arg] != T_LONG ) {
+                tmp = dst.first()->as_Register();
+              }
+            }
+
+            Label skipUnbox;
+            if ( wordSize == 4 && out_sig_bt[c_arg] == T_LONG ) {
+              __ mov(G0, tmp->successor());
+            }
+            __ br_null(in_reg, true, Assembler::pn, skipUnbox);
+            __ delayed()->mov(G0, tmp);
+
+            switch (out_sig_bt[c_arg]) {
+                case T_BYTE:
+                  __ ldub(in_reg, box_offset, tmp); break;
+                case T_SHORT:
+                  __ lduh(in_reg, box_offset, tmp); break;
+                case T_INT:
+                  __ ld(in_reg, box_offset, tmp); break;
+                case T_LONG:
+                  __ ld_long(in_reg, box_offset, tmp); break;
+                default: ShouldNotReachHere();
+            }
+
+            __ bind(skipUnbox);
+            // If tmp wasn't final destination copy to final destination
+            if (tmp == L2) {
+              VMRegPair tmp_as_VM = reg64_to_VMRegPair(L2);
+              if (out_sig_bt[c_arg] == T_LONG) {
+                long_move(masm, tmp_as_VM, dst);
+              } else {
+                move32_64(masm, tmp_as_VM, out_regs[c_arg]);
+              }
+            }
+            if (out_sig_bt[c_arg] == T_LONG) {
+              assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+              ++c_arg; // move over the T_VOID to keep the loop indices in sync
+            }
+          } else if (out_sig_bt[c_arg] == T_ADDRESS) {
+            Register s =
+                src.first()->is_reg() ? src.first()->as_Register() : L2;
+            Register d =
+                dst.first()->is_reg() ? dst.first()->as_Register() : L2;
+
+            // We store the oop now so that the conversion pass can reach
+            // while in the inner frame. This will be the only store if
+            // the oop is NULL.
+            if (s != L2) {
+              // src is register
+              if (d != L2) {
+                // dst is register
+                __ mov(s, d);
+              } else {
+                assert(Assembler::is_simm13(reg2offset(dst.first()) +
+                          STACK_BIAS), "must be");
+                __ st_ptr(s, SP, reg2offset(dst.first()) + STACK_BIAS);
+              }
+            } else {
+                // src not a register
+                assert(Assembler::is_simm13(reg2offset(src.first()) +
+                           STACK_BIAS), "must be");
+                __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, d);
+                if (d == L2) {
+                  assert(Assembler::is_simm13(reg2offset(dst.first()) +
+                             STACK_BIAS), "must be");
+                  __ st_ptr(d, SP, reg2offset(dst.first()) + STACK_BIAS);
+                }
+            }
+          } else if (out_sig_bt[c_arg] != T_VOID) {
+            // Convert the arg to NULL
+            if (dst.first()->is_reg()) {
+              __ mov(G0, dst.first()->as_Register());
+            } else {
+              assert(Assembler::is_simm13(reg2offset(dst.first()) +
+                         STACK_BIAS), "must be");
+              __ st_ptr(G0, SP, reg2offset(dst.first()) + STACK_BIAS);
+            }
+          }
+        }
+        break;
+      case T_VOID:
+        break;
+
+      case T_FLOAT:
+        if (src.first()->is_stack()) {
+          // Stack to stack/reg is simple
+          move32_64(masm, src, dst);
+        } else {
+          if (dst.first()->is_reg()) {
+            // freg -> reg
+            int off =
+              STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size;
+            Register d = dst.first()->as_Register();
+            if (Assembler::is_simm13(off)) {
+              __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(),
+                     SP, off);
+              __ ld(SP, off, d);
+            } else {
+              if (conversion_off == noreg) {
+                __ set(off, L6);
+                conversion_off = L6;
+              }
+              __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(),
+                     SP, conversion_off);
+              __ ld(SP, conversion_off , d);
+            }
+          } else {
+            // freg -> mem
+            int off = STACK_BIAS + reg2offset(dst.first());
+            if (Assembler::is_simm13(off)) {
+              __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(),
+                     SP, off);
+            } else {
+              if (conversion_off == noreg) {
+                __ set(off, L6);
+                conversion_off = L6;
+              }
+              __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(),
+                     SP, conversion_off);
+            }
+          }
+        }
+        break;
+
+      case T_DOUBLE:
+        assert( j_arg + 1 < total_args_passed &&
+                in_sig_bt[j_arg + 1] == T_VOID &&
+                out_sig_bt[c_arg+1] == T_VOID, "bad arg list");
+        if (src.first()->is_stack()) {
+          // Stack to stack/reg is simple
+          long_move(masm, src, dst);
+        } else {
+          Register d = dst.first()->is_reg() ? dst.first()->as_Register() : L2;
+
+          // Destination could be an odd reg on 32bit in which case
+          // we can't load direct to the destination.
+
+          if (!d->is_even() && wordSize == 4) {
+            d = L2;
+          }
+          int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size;
+          if (Assembler::is_simm13(off)) {
+            __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(),
+                   SP, off);
+            __ ld_long(SP, off, d);
+          } else {
+            if (conversion_off == noreg) {
+              __ set(off, L6);
+              conversion_off = L6;
+            }
+            __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(),
+                   SP, conversion_off);
+            __ ld_long(SP, conversion_off, d);
+          }
+          if (d == L2) {
+            long_move(masm, reg64_to_VMRegPair(L2), dst);
+          }
+        }
+        break;
+
+      case T_LONG :
+        // 32bit can't do a split move of something like g1 -> O0, O1
+        // so use a memory temp
+        if (src.is_single_phys_reg() && wordSize == 4) {
+          Register tmp = L2;
+          if (dst.first()->is_reg() &&
+              (wordSize == 8 || dst.first()->as_Register()->is_even())) {
+            tmp = dst.first()->as_Register();
+          }
+
+          int off = STACK_BIAS + conversion_temp * VMRegImpl::stack_slot_size;
+          if (Assembler::is_simm13(off)) {
+            __ stx(src.first()->as_Register(), SP, off);
+            __ ld_long(SP, off, tmp);
+          } else {
+            if (conversion_off == noreg) {
+              __ set(off, L6);
+              conversion_off = L6;
+            }
+            __ stx(src.first()->as_Register(), SP, conversion_off);
+            __ ld_long(SP, conversion_off, tmp);
+          }
+
+          if (tmp == L2) {
+            long_move(masm, reg64_to_VMRegPair(L2), dst);
+          }
+        } else {
+          long_move(masm, src, dst);
+        }
+        break;
+
+      case T_ADDRESS: assert(false, "found T_ADDRESS in java args");
+
+      default:
+        move32_64(masm, src, dst);
+    }
+  }
+
+
+  // If we have any strings we must store any register based arg to the stack
+  // This includes any still live xmm registers too.
+
+  if (total_strings > 0 ) {
+
+    // protect all the arg registers
+    __ save_frame(0);
+    __ mov(G2_thread, L7_thread_cache);
+    const Register L2_string_off = L2;
+
+    // Get first string offset
+    __ set(string_locs * VMRegImpl::stack_slot_size, L2_string_off);
+
+    for (c_arg = 0 ; c_arg < total_c_args ; c_arg++ ) {
+      if (out_sig_bt[c_arg] == T_ADDRESS) {
+
+        VMRegPair dst = out_regs[c_arg];
+        const Register d = dst.first()->is_reg() ?
+            dst.first()->as_Register()->after_save() : noreg;
+
+        // It's a string the oop and it was already copied to the out arg
+        // position
+        if (d != noreg) {
+          __ mov(d, O0);
+        } else {
+          assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS),
+                 "must be");
+          __ ld_ptr(FP,  reg2offset(dst.first()) + STACK_BIAS, O0);
+        }
+        Label skip;
+
+        __ br_null(O0, false, Assembler::pn, skip);
+        __ delayed()->add(FP, L2_string_off, O1);
+
+        if (d != noreg) {
+          __ mov(O1, d);
+        } else {
+          assert(Assembler::is_simm13(reg2offset(dst.first()) + STACK_BIAS),
+                 "must be");
+          __ st_ptr(O1, FP,  reg2offset(dst.first()) + STACK_BIAS);
+        }
+
+        __ call(CAST_FROM_FN_PTR(address, SharedRuntime::get_utf),
+                relocInfo::runtime_call_type);
+        __ delayed()->add(L2_string_off, max_dtrace_string_size, L2_string_off);
+
+        __ bind(skip);
+
+      }
+
+    }
+    __ mov(L7_thread_cache, G2_thread);
+    __ restore();
+
+  }
+
+
+  // Ok now we are done. Need to place the nop that dtrace wants in order to
+  // patch in the trap
+
+  int patch_offset = ((intptr_t)__ pc()) - start;
+
+  __ nop();
+
+
+  // Return
+
+  __ ret();
+  __ delayed()->restore();
+
+  __ flush();
+
+  nmethod *nm = nmethod::new_dtrace_nmethod(
+      method, masm->code(), vep_offset, patch_offset, frame_complete,
+      stack_slots / VMRegImpl::slots_per_word);
+  return nm;
+
+}
+
+#endif // HAVE_DTRACE_H
+
 // this function returns the adjust size (in number of words) to a c2i adapter
 // activation for use during deoptimization
 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) {
--- a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -472,3 +472,7 @@
   else
     return addr_at(0) + length + sbyte_at(offset);
 }
+
+bool NativeInstruction::is_dtrace_trap() {
+  return (*(int32_t*)this & 0xff) == 0xcc;
+}
--- a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -50,6 +50,7 @@
   };
 
   bool is_nop()                        { return ubyte_at(0) == nop_instruction_code; }
+  bool is_dtrace_trap();
   inline bool is_call();
   inline bool is_illegal();
   inline bool is_return();
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -1880,6 +1880,379 @@
 
 }
 
+#ifdef HAVE_DTRACE_H
+// ---------------------------------------------------------------------------
+// Generate a dtrace nmethod for a given signature.  The method takes arguments
+// in the Java compiled code convention, marshals them to the native
+// abi and then leaves nops at the position you would expect to call a native
+// function. When the probe is enabled the nops are replaced with a trap
+// instruction that dtrace inserts and the trace will cause a notification
+// to dtrace.
+//
+// The probes are only able to take primitive types and java/lang/String as
+// arguments.  No other java types are allowed. Strings are converted to utf8
+// strings so that from dtrace point of view java strings are converted to C
+// strings. There is an arbitrary fixed limit on the total space that a method
+// can use for converting the strings. (256 chars per string in the signature).
+// So any java string larger then this is truncated.
+
+nmethod *SharedRuntime::generate_dtrace_nmethod(
+    MacroAssembler *masm, methodHandle method) {
+
+  // generate_dtrace_nmethod is guarded by a mutex so we are sure to
+  // be single threaded in this method.
+  assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be");
+
+  // Fill in the signature array, for the calling-convention call.
+  int total_args_passed = method->size_of_parameters();
+
+  BasicType* in_sig_bt  = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
+  VMRegPair  *in_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
+
+  // The signature we are going to use for the trap that dtrace will see
+  // java/lang/String is converted. We drop "this" and any other object
+  // is converted to NULL.  (A one-slot java/lang/Long object reference
+  // is converted to a two-slot long, which is why we double the allocation).
+  BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2);
+  VMRegPair* out_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2);
+
+  int i=0;
+  int total_strings = 0;
+  int first_arg_to_pass = 0;
+  int total_c_args = 0;
+  int box_offset = java_lang_boxing_object::value_offset_in_bytes();
+
+  if( !method->is_static() ) {  // Pass in receiver first
+    in_sig_bt[i++] = T_OBJECT;
+    first_arg_to_pass = 1;
+  }
+
+  // We need to convert the java args to where a native (non-jni) function
+  // would expect them. To figure out where they go we convert the java
+  // signature to a C signature.
+
+  SignatureStream ss(method->signature());
+  for ( ; !ss.at_return_type(); ss.next()) {
+    BasicType bt = ss.type();
+    in_sig_bt[i++] = bt;  // Collect remaining bits of signature
+    out_sig_bt[total_c_args++] = bt;
+    if( bt == T_OBJECT) {
+      symbolOop s = ss.as_symbol_or_null();
+      if (s == vmSymbols::java_lang_String()) {
+        total_strings++;
+        out_sig_bt[total_c_args-1] = T_ADDRESS;
+      } else if (s == vmSymbols::java_lang_Boolean() ||
+                 s == vmSymbols::java_lang_Character() ||
+                 s == vmSymbols::java_lang_Byte() ||
+                 s == vmSymbols::java_lang_Short() ||
+                 s == vmSymbols::java_lang_Integer() ||
+                 s == vmSymbols::java_lang_Float()) {
+        out_sig_bt[total_c_args-1] = T_INT;
+      } else if (s == vmSymbols::java_lang_Long() ||
+                 s == vmSymbols::java_lang_Double()) {
+        out_sig_bt[total_c_args-1] = T_LONG;
+        out_sig_bt[total_c_args++] = T_VOID;
+      }
+    } else if ( bt == T_LONG || bt == T_DOUBLE ) {
+      in_sig_bt[i++] = T_VOID;   // Longs & doubles take 2 Java slots
+      out_sig_bt[total_c_args++] = T_VOID;
+    }
+  }
+
+  assert(i==total_args_passed, "validly parsed signature");
+
+  // Now get the compiled-Java layout as input arguments
+  int comp_args_on_stack;
+  comp_args_on_stack = SharedRuntime::java_calling_convention(
+      in_sig_bt, in_regs, total_args_passed, false);
+
+  // Now figure out where the args must be stored and how much stack space
+  // they require (neglecting out_preserve_stack_slots).
+
+  int out_arg_slots;
+  out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args);
+
+  // Calculate the total number of stack slots we will need.
+
+  // First count the abi requirement plus all of the outgoing args
+  int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots;
+
+  // Now space for the string(s) we must convert
+
+  int* string_locs   = NEW_RESOURCE_ARRAY(int, total_strings + 1);
+  for (i = 0; i < total_strings ; i++) {
+    string_locs[i] = stack_slots;
+    stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size;
+  }
+
+  // + 2 for return address (which we own) and saved rbp,
+
+  stack_slots += 2;
+
+  // Ok The space we have allocated will look like:
+  //
+  //
+  // FP-> |                     |
+  //      |---------------------|
+  //      | string[n]           |
+  //      |---------------------| <- string_locs[n]
+  //      | string[n-1]         |
+  //      |---------------------| <- string_locs[n-1]
+  //      | ...                 |
+  //      | ...                 |
+  //      |---------------------| <- string_locs[1]
+  //      | string[0]           |
+  //      |---------------------| <- string_locs[0]
+  //      | outbound memory     |
+  //      | based arguments     |
+  //      |                     |
+  //      |---------------------|
+  //      |                     |
+  // SP-> | out_preserved_slots |
+  //
+  //
+
+  // Now compute actual number of stack words we need rounding to make
+  // stack properly aligned.
+  stack_slots = round_to(stack_slots, 2 * VMRegImpl::slots_per_word);
+
+  int stack_size = stack_slots * VMRegImpl::stack_slot_size;
+
+  intptr_t start = (intptr_t)__ pc();
+
+  // First thing make an ic check to see if we should even be here
+
+  // We are free to use all registers as temps without saving them and
+  // restoring them except rbp. rbp, is the only callee save register
+  // as far as the interpreter and the compiler(s) are concerned.
+
+  const Register ic_reg = rax;
+  const Register receiver = rcx;
+  Label hit;
+  Label exception_pending;
+
+
+  __ verify_oop(receiver);
+  __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes()));
+  __ jcc(Assembler::equal, hit);
+
+  __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
+
+  // verified entry must be aligned for code patching.
+  // and the first 5 bytes must be in the same cache line
+  // if we align at 8 then we will be sure 5 bytes are in the same line
+  __ align(8);
+
+  __ bind(hit);
+
+  int vep_offset = ((intptr_t)__ pc()) - start;
+
+
+  // The instruction at the verified entry point must be 5 bytes or longer
+  // because it can be patched on the fly by make_non_entrant. The stack bang
+  // instruction fits that requirement.
+
+  // Generate stack overflow check
+
+
+  if (UseStackBanging) {
+    if (stack_size <= StackShadowPages*os::vm_page_size()) {
+      __ bang_stack_with_offset(StackShadowPages*os::vm_page_size());
+    } else {
+      __ movl(rax, stack_size);
+      __ bang_stack_size(rax, rbx);
+    }
+  } else {
+    // need a 5 byte instruction to allow MT safe patching to non-entrant
+    __ fat_nop();
+  }
+
+  assert(((int)__ pc() - start - vep_offset) >= 5,
+         "valid size for make_non_entrant");
+
+  // Generate a new frame for the wrapper.
+  __ enter();
+
+  // -2 because return address is already present and so is saved rbp,
+  if (stack_size - 2*wordSize != 0) {
+    __ subl(rsp, stack_size - 2*wordSize);
+  }
+
+  // Frame is now completed as far a size and linkage.
+
+  int frame_complete = ((intptr_t)__ pc()) - start;
+
+  // First thing we do store all the args as if we are doing the call.
+  // Since the C calling convention is stack based that ensures that
+  // all the Java register args are stored before we need to convert any
+  // string we might have.
+
+  int sid = 0;
+  int c_arg, j_arg;
+  int string_reg = 0;
+
+  for (j_arg = first_arg_to_pass, c_arg = 0 ;
+       j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+
+    VMRegPair src = in_regs[j_arg];
+    VMRegPair dst = out_regs[c_arg];
+    assert(dst.first()->is_stack() || in_sig_bt[j_arg] == T_VOID,
+           "stack based abi assumed");
+
+    switch (in_sig_bt[j_arg]) {
+
+      case T_ARRAY:
+      case T_OBJECT:
+        if (out_sig_bt[c_arg] == T_ADDRESS) {
+          // Any register based arg for a java string after the first
+          // will be destroyed by the call to get_utf so we store
+          // the original value in the location the utf string address
+          // will eventually be stored.
+          if (src.first()->is_reg()) {
+            if (string_reg++ != 0) {
+              simple_move32(masm, src, dst);
+            }
+          }
+        } else if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) {
+          // need to unbox a one-word value
+          Register in_reg = rax;
+          if ( src.first()->is_reg() ) {
+            in_reg = src.first()->as_Register();
+          } else {
+            simple_move32(masm, src, in_reg->as_VMReg());
+          }
+          Label skipUnbox;
+          __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD);
+          if ( out_sig_bt[c_arg] == T_LONG ) {
+            __ movl(Address(rsp, reg2offset_out(dst.second())), NULL_WORD);
+          }
+          __ testl(in_reg, in_reg);
+          __ jcc(Assembler::zero, skipUnbox);
+          assert(dst.first()->is_stack() &&
+                 (!dst.second()->is_valid() || dst.second()->is_stack()),
+                 "value(s) must go into stack slots");
+          if ( out_sig_bt[c_arg] == T_LONG ) {
+            __ movl(rbx, Address(in_reg,
+                                 box_offset + VMRegImpl::stack_slot_size));
+            __ movl(Address(rsp, reg2offset_out(dst.second())), rbx);
+          }
+          __ movl(in_reg,  Address(in_reg, box_offset));
+          __ movl(Address(rsp, reg2offset_out(dst.first())), in_reg);
+          __ bind(skipUnbox);
+        } else {
+          // Convert the arg to NULL
+          __ movl(Address(rsp, reg2offset_out(dst.first())), NULL_WORD);
+        }
+        if (out_sig_bt[c_arg] == T_LONG) {
+          assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+          ++c_arg; // Move over the T_VOID To keep the loop indices in sync
+        }
+        break;
+
+      case T_VOID:
+        break;
+
+      case T_FLOAT:
+        float_move(masm, src, dst);
+        break;
+
+      case T_DOUBLE:
+        assert( j_arg + 1 < total_args_passed &&
+                in_sig_bt[j_arg + 1] == T_VOID, "bad arg list");
+        double_move(masm, src, dst);
+        break;
+
+      case T_LONG :
+        long_move(masm, src, dst);
+        break;
+
+      case T_ADDRESS: assert(false, "found T_ADDRESS in java args");
+
+      default:
+        simple_move32(masm, src, dst);
+    }
+  }
+
+  // Now we must convert any string we have to utf8
+  //
+
+  for (sid = 0, j_arg = first_arg_to_pass, c_arg = 0 ;
+       sid < total_strings ; j_arg++, c_arg++ ) {
+
+    if (out_sig_bt[c_arg] == T_ADDRESS) {
+
+      Address utf8_addr = Address(
+          rsp, string_locs[sid++] * VMRegImpl::stack_slot_size);
+      __ leal(rax, utf8_addr);
+
+      // The first string we find might still be in the original java arg
+      // register
+      VMReg orig_loc = in_regs[j_arg].first();
+      Register string_oop;
+
+      // This is where the argument will eventually reside
+      Address dest = Address(rsp, reg2offset_out(out_regs[c_arg].first()));
+
+      if (sid == 1 && orig_loc->is_reg()) {
+        string_oop = orig_loc->as_Register();
+        assert(string_oop != rax, "smashed arg");
+      } else {
+
+        if (orig_loc->is_reg()) {
+          // Get the copy of the jls object
+          __ movl(rcx, dest);
+        } else {
+          // arg is still in the original location
+          __ movl(rcx, Address(rbp, reg2offset_in(orig_loc)));
+        }
+        string_oop = rcx;
+
+      }
+      Label nullString;
+      __ movl(dest, NULL_WORD);
+      __ testl(string_oop, string_oop);
+      __ jcc(Assembler::zero, nullString);
+
+      // Now we can store the address of the utf string as the argument
+      __ movl(dest, rax);
+
+      // And do the conversion
+      __ call_VM_leaf(CAST_FROM_FN_PTR(
+             address, SharedRuntime::get_utf), string_oop, rax);
+      __ bind(nullString);
+    }
+
+    if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) {
+      assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+      ++c_arg; // Move over the T_VOID To keep the loop indices in sync
+    }
+  }
+
+
+  // Ok now we are done. Need to place the nop that dtrace wants in order to
+  // patch in the trap
+
+  int patch_offset = ((intptr_t)__ pc()) - start;
+
+  __ nop();
+
+
+  // Return
+
+  __ leave();
+  __ ret(0);
+
+  __ flush();
+
+  nmethod *nm = nmethod::new_dtrace_nmethod(
+      method, masm->code(), vep_offset, patch_offset, frame_complete,
+      stack_slots / VMRegImpl::slots_per_word);
+  return nm;
+
+}
+
+#endif // HAVE_DTRACE_H
+
 // this function returns the adjust size (in number of words) to a c2i adapter
 // activation for use during deoptimization
 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) {
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -1886,6 +1886,627 @@
 
 }
 
+#ifdef HAVE_DTRACE_H
+// ---------------------------------------------------------------------------
+// Generate a dtrace nmethod for a given signature.  The method takes arguments
+// in the Java compiled code convention, marshals them to the native
+// abi and then leaves nops at the position you would expect to call a native
+// function. When the probe is enabled the nops are replaced with a trap
+// instruction that dtrace inserts and the trace will cause a notification
+// to dtrace.
+//
+// The probes are only able to take primitive types and java/lang/String as
+// arguments.  No other java types are allowed. Strings are converted to utf8
+// strings so that from dtrace point of view java strings are converted to C
+// strings. There is an arbitrary fixed limit on the total space that a method
+// can use for converting the strings. (256 chars per string in the signature).
+// So any java string larger then this is truncated.
+
+static int  fp_offset[ConcreteRegisterImpl::number_of_registers] = { 0 };
+static bool offsets_initialized = false;
+
+
+nmethod *SharedRuntime::generate_dtrace_nmethod(MacroAssembler *masm,
+                                                methodHandle method) {
+
+
+  // generate_dtrace_nmethod is guarded by a mutex so we are sure to
+  // be single threaded in this method.
+  assert(AdapterHandlerLibrary_lock->owned_by_self(), "must be");
+
+  if (!offsets_initialized) {
+    fp_offset[c_rarg0->as_VMReg()->value()] = -1 * wordSize;
+    fp_offset[c_rarg1->as_VMReg()->value()] = -2 * wordSize;
+    fp_offset[c_rarg2->as_VMReg()->value()] = -3 * wordSize;
+    fp_offset[c_rarg3->as_VMReg()->value()] = -4 * wordSize;
+    fp_offset[c_rarg4->as_VMReg()->value()] = -5 * wordSize;
+    fp_offset[c_rarg5->as_VMReg()->value()] = -6 * wordSize;
+
+    fp_offset[c_farg0->as_VMReg()->value()] = -7 * wordSize;
+    fp_offset[c_farg1->as_VMReg()->value()] = -8 * wordSize;
+    fp_offset[c_farg2->as_VMReg()->value()] = -9 * wordSize;
+    fp_offset[c_farg3->as_VMReg()->value()] = -10 * wordSize;
+    fp_offset[c_farg4->as_VMReg()->value()] = -11 * wordSize;
+    fp_offset[c_farg5->as_VMReg()->value()] = -12 * wordSize;
+    fp_offset[c_farg6->as_VMReg()->value()] = -13 * wordSize;
+    fp_offset[c_farg7->as_VMReg()->value()] = -14 * wordSize;
+
+    offsets_initialized = true;
+  }
+  // Fill in the signature array, for the calling-convention call.
+  int total_args_passed = method->size_of_parameters();
+
+  BasicType* in_sig_bt  = NEW_RESOURCE_ARRAY(BasicType, total_args_passed);
+  VMRegPair  *in_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
+
+  // The signature we are going to use for the trap that dtrace will see
+  // java/lang/String is converted. We drop "this" and any other object
+  // is converted to NULL.  (A one-slot java/lang/Long object reference
+  // is converted to a two-slot long, which is why we double the allocation).
+  BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed * 2);
+  VMRegPair* out_regs   = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed * 2);
+
+  int i=0;
+  int total_strings = 0;
+  int first_arg_to_pass = 0;
+  int total_c_args = 0;
+  int box_offset = java_lang_boxing_object::value_offset_in_bytes();
+
+  // Skip the receiver as dtrace doesn't want to see it
+  if( !method->is_static() ) {
+    in_sig_bt[i++] = T_OBJECT;
+    first_arg_to_pass = 1;
+  }
+
+  // We need to convert the java args to where a native (non-jni) function
+  // would expect them. To figure out where they go we convert the java
+  // signature to a C signature.
+
+  SignatureStream ss(method->signature());
+  for ( ; !ss.at_return_type(); ss.next()) {
+    BasicType bt = ss.type();
+    in_sig_bt[i++] = bt;  // Collect remaining bits of signature
+    out_sig_bt[total_c_args++] = bt;
+    if( bt == T_OBJECT) {
+      symbolOop s = ss.as_symbol_or_null();
+      if (s == vmSymbols::java_lang_String()) {
+        total_strings++;
+        out_sig_bt[total_c_args-1] = T_ADDRESS;
+      } else if (s == vmSymbols::java_lang_Boolean() ||
+                 s == vmSymbols::java_lang_Character() ||
+                 s == vmSymbols::java_lang_Byte() ||
+                 s == vmSymbols::java_lang_Short() ||
+                 s == vmSymbols::java_lang_Integer() ||
+                 s == vmSymbols::java_lang_Float()) {
+        out_sig_bt[total_c_args-1] = T_INT;
+      } else if (s == vmSymbols::java_lang_Long() ||
+                 s == vmSymbols::java_lang_Double()) {
+        out_sig_bt[total_c_args-1] = T_LONG;
+        out_sig_bt[total_c_args++] = T_VOID;
+      }
+    } else if ( bt == T_LONG || bt == T_DOUBLE ) {
+      in_sig_bt[i++] = T_VOID;   // Longs & doubles take 2 Java slots
+      // We convert double to long
+      out_sig_bt[total_c_args-1] = T_LONG;
+      out_sig_bt[total_c_args++] = T_VOID;
+    } else if ( bt == T_FLOAT) {
+      // We convert float to int
+      out_sig_bt[total_c_args-1] = T_INT;
+    }
+  }
+
+  assert(i==total_args_passed, "validly parsed signature");
+
+  // Now get the compiled-Java layout as input arguments
+  int comp_args_on_stack;
+  comp_args_on_stack = SharedRuntime::java_calling_convention(
+      in_sig_bt, in_regs, total_args_passed, false);
+
+  // Now figure out where the args must be stored and how much stack space
+  // they require (neglecting out_preserve_stack_slots but space for storing
+  // the 1st six register arguments). It's weird see int_stk_helper.
+
+  int out_arg_slots;
+  out_arg_slots = c_calling_convention(out_sig_bt, out_regs, total_c_args);
+
+  // Calculate the total number of stack slots we will need.
+
+  // First count the abi requirement plus all of the outgoing args
+  int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots;
+
+  // Now space for the string(s) we must convert
+  int* string_locs   = NEW_RESOURCE_ARRAY(int, total_strings + 1);
+  for (i = 0; i < total_strings ; i++) {
+    string_locs[i] = stack_slots;
+    stack_slots += max_dtrace_string_size / VMRegImpl::stack_slot_size;
+  }
+
+  // Plus the temps we might need to juggle register args
+  // regs take two slots each
+  stack_slots += (Argument::n_int_register_parameters_c +
+                  Argument::n_float_register_parameters_c) * 2;
+
+
+  // + 4 for return address (which we own) and saved rbp,
+
+  stack_slots += 4;
+
+  // Ok The space we have allocated will look like:
+  //
+  //
+  // FP-> |                     |
+  //      |---------------------|
+  //      | string[n]           |
+  //      |---------------------| <- string_locs[n]
+  //      | string[n-1]         |
+  //      |---------------------| <- string_locs[n-1]
+  //      | ...                 |
+  //      | ...                 |
+  //      |---------------------| <- string_locs[1]
+  //      | string[0]           |
+  //      |---------------------| <- string_locs[0]
+  //      | outbound memory     |
+  //      | based arguments     |
+  //      |                     |
+  //      |---------------------|
+  //      |                     |
+  // SP-> | out_preserved_slots |
+  //
+  //
+
+  // Now compute actual number of stack words we need rounding to make
+  // stack properly aligned.
+  stack_slots = round_to(stack_slots, 4 * VMRegImpl::slots_per_word);
+
+  int stack_size = stack_slots * VMRegImpl::stack_slot_size;
+
+  intptr_t start = (intptr_t)__ pc();
+
+  // First thing make an ic check to see if we should even be here
+
+  // We are free to use all registers as temps without saving them and
+  // restoring them except rbp. rbp, is the only callee save register
+  // as far as the interpreter and the compiler(s) are concerned.
+
+  const Register ic_reg = rax;
+  const Register receiver = rcx;
+  Label hit;
+  Label exception_pending;
+
+
+  __ verify_oop(receiver);
+  __ cmpl(ic_reg, Address(receiver, oopDesc::klass_offset_in_bytes()));
+  __ jcc(Assembler::equal, hit);
+
+  __ jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
+
+  // verified entry must be aligned for code patching.
+  // and the first 5 bytes must be in the same cache line
+  // if we align at 8 then we will be sure 5 bytes are in the same line
+  __ align(8);
+
+  __ bind(hit);
+
+  int vep_offset = ((intptr_t)__ pc()) - start;
+
+
+  // The instruction at the verified entry point must be 5 bytes or longer
+  // because it can be patched on the fly by make_non_entrant. The stack bang
+  // instruction fits that requirement.
+
+  // Generate stack overflow check
+
+  if (UseStackBanging) {
+    if (stack_size <= StackShadowPages*os::vm_page_size()) {
+      __ bang_stack_with_offset(StackShadowPages*os::vm_page_size());
+    } else {
+      __ movl(rax, stack_size);
+      __ bang_stack_size(rax, rbx);
+    }
+  } else {
+    // need a 5 byte instruction to allow MT safe patching to non-entrant
+    __ fat_nop();
+  }
+
+  assert(((uintptr_t)__ pc() - start - vep_offset) >= 5,
+         "valid size for make_non_entrant");
+
+  // Generate a new frame for the wrapper.
+  __ enter();
+
+  // -4 because return address is already present and so is saved rbp,
+  if (stack_size - 2*wordSize != 0) {
+    __ subq(rsp, stack_size - 2*wordSize);
+  }
+
+  // Frame is now completed as far a size and linkage.
+
+  int frame_complete = ((intptr_t)__ pc()) - start;
+
+  int c_arg, j_arg;
+
+  // State of input register args
+
+  bool  live[ConcreteRegisterImpl::number_of_registers];
+
+  live[j_rarg0->as_VMReg()->value()] = false;
+  live[j_rarg1->as_VMReg()->value()] = false;
+  live[j_rarg2->as_VMReg()->value()] = false;
+  live[j_rarg3->as_VMReg()->value()] = false;
+  live[j_rarg4->as_VMReg()->value()] = false;
+  live[j_rarg5->as_VMReg()->value()] = false;
+
+  live[j_farg0->as_VMReg()->value()] = false;
+  live[j_farg1->as_VMReg()->value()] = false;
+  live[j_farg2->as_VMReg()->value()] = false;
+  live[j_farg3->as_VMReg()->value()] = false;
+  live[j_farg4->as_VMReg()->value()] = false;
+  live[j_farg5->as_VMReg()->value()] = false;
+  live[j_farg6->as_VMReg()->value()] = false;
+  live[j_farg7->as_VMReg()->value()] = false;
+
+
+  bool rax_is_zero = false;
+
+  // All args (except strings) destined for the stack are moved first
+  for (j_arg = first_arg_to_pass, c_arg = 0 ;
+       j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+    VMRegPair src = in_regs[j_arg];
+    VMRegPair dst = out_regs[c_arg];
+
+    // Get the real reg value or a dummy (rsp)
+
+    int src_reg = src.first()->is_reg() ?
+                  src.first()->value() :
+                  rsp->as_VMReg()->value();
+
+    bool useless =  in_sig_bt[j_arg] == T_ARRAY ||
+                    (in_sig_bt[j_arg] == T_OBJECT &&
+                     out_sig_bt[c_arg] != T_INT &&
+                     out_sig_bt[c_arg] != T_ADDRESS &&
+                     out_sig_bt[c_arg] != T_LONG);
+
+    live[src_reg] = !useless;
+
+    if (dst.first()->is_stack()) {
+
+      // Even though a string arg in a register is still live after this loop
+      // after the string conversion loop (next) it will be dead so we take
+      // advantage of that now for simpler code to manage live.
+
+      live[src_reg] = false;
+      switch (in_sig_bt[j_arg]) {
+
+        case T_ARRAY:
+        case T_OBJECT:
+          {
+            Address stack_dst(rsp, reg2offset_out(dst.first()));
+
+            if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) {
+              // need to unbox a one-word value
+              Register in_reg = rax;
+              if ( src.first()->is_reg() ) {
+                in_reg = src.first()->as_Register();
+              } else {
+                __ movq(rax, Address(rbp, reg2offset_in(src.first())));
+                rax_is_zero = false;
+              }
+              Label skipUnbox;
+              __ movptr(Address(rsp, reg2offset_out(dst.first())),
+                        (int32_t)NULL_WORD);
+              __ testq(in_reg, in_reg);
+              __ jcc(Assembler::zero, skipUnbox);
+
+              Address src1(in_reg, box_offset);
+              if ( out_sig_bt[c_arg] == T_LONG ) {
+                __ movq(in_reg,  src1);
+                __ movq(stack_dst, in_reg);
+                assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+                ++c_arg; // skip over T_VOID to keep the loop indices in sync
+              } else {
+                __ movl(in_reg,  src1);
+                __ movl(stack_dst, in_reg);
+              }
+
+              __ bind(skipUnbox);
+            } else if (out_sig_bt[c_arg] != T_ADDRESS) {
+              // Convert the arg to NULL
+              if (!rax_is_zero) {
+                __ xorq(rax, rax);
+                rax_is_zero = true;
+              }
+              __ movq(stack_dst, rax);
+            }
+          }
+          break;
+
+        case T_VOID:
+          break;
+
+        case T_FLOAT:
+          // This does the right thing since we know it is destined for the
+          // stack
+          float_move(masm, src, dst);
+          break;
+
+        case T_DOUBLE:
+          // This does the right thing since we know it is destined for the
+          // stack
+          double_move(masm, src, dst);
+          break;
+
+        case T_LONG :
+          long_move(masm, src, dst);
+          break;
+
+        case T_ADDRESS: assert(false, "found T_ADDRESS in java args");
+
+        default:
+          move32_64(masm, src, dst);
+      }
+    }
+
+  }
+
+  // If we have any strings we must store any register based arg to the stack
+  // This includes any still live xmm registers too.
+
+  int sid = 0;
+
+  if (total_strings > 0 ) {
+    for (j_arg = first_arg_to_pass, c_arg = 0 ;
+         j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+      VMRegPair src = in_regs[j_arg];
+      VMRegPair dst = out_regs[c_arg];
+
+      if (src.first()->is_reg()) {
+        Address src_tmp(rbp, fp_offset[src.first()->value()]);
+
+        // string oops were left untouched by the previous loop even if the
+        // eventual (converted) arg is destined for the stack so park them
+        // away now (except for first)
+
+        if (out_sig_bt[c_arg] == T_ADDRESS) {
+          Address utf8_addr = Address(
+              rsp, string_locs[sid++] * VMRegImpl::stack_slot_size);
+          if (sid != 1) {
+            // The first string arg won't be killed until after the utf8
+            // conversion
+            __ movq(utf8_addr, src.first()->as_Register());
+          }
+        } else if (dst.first()->is_reg()) {
+          if (in_sig_bt[j_arg] == T_FLOAT || in_sig_bt[j_arg] == T_DOUBLE) {
+
+            // Convert the xmm register to an int and store it in the reserved
+            // location for the eventual c register arg
+            XMMRegister f = src.first()->as_XMMRegister();
+            if (in_sig_bt[j_arg] == T_FLOAT) {
+              __ movflt(src_tmp, f);
+            } else {
+              __ movdbl(src_tmp, f);
+            }
+          } else {
+            // If the arg is an oop type we don't support don't bother to store
+            // it remember string was handled above.
+            bool useless =  in_sig_bt[j_arg] == T_ARRAY ||
+                            (in_sig_bt[j_arg] == T_OBJECT &&
+                             out_sig_bt[c_arg] != T_INT &&
+                             out_sig_bt[c_arg] != T_LONG);
+
+            if (!useless) {
+              __ movq(src_tmp, src.first()->as_Register());
+            }
+          }
+        }
+      }
+      if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) {
+        assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+        ++c_arg; // skip over T_VOID to keep the loop indices in sync
+      }
+    }
+
+    // Now that the volatile registers are safe, convert all the strings
+    sid = 0;
+
+    for (j_arg = first_arg_to_pass, c_arg = 0 ;
+         j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+      if (out_sig_bt[c_arg] == T_ADDRESS) {
+        // It's a string
+        Address utf8_addr = Address(
+            rsp, string_locs[sid++] * VMRegImpl::stack_slot_size);
+        // The first string we find might still be in the original java arg
+        // register
+
+        VMReg src = in_regs[j_arg].first();
+
+        // We will need to eventually save the final argument to the trap
+        // in the von-volatile location dedicated to src. This is the offset
+        // from fp we will use.
+        int src_off = src->is_reg() ?
+            fp_offset[src->value()] : reg2offset_in(src);
+
+        // This is where the argument will eventually reside
+        VMRegPair dst = out_regs[c_arg];
+
+        if (src->is_reg()) {
+          if (sid == 1) {
+            __ movq(c_rarg0, src->as_Register());
+          } else {
+            __ movq(c_rarg0, utf8_addr);
+          }
+        } else {
+          // arg is still in the original location
+          __ movq(c_rarg0, Address(rbp, reg2offset_in(src)));
+        }
+        Label done, convert;
+
+        // see if the oop is NULL
+        __ testq(c_rarg0, c_rarg0);
+        __ jcc(Assembler::notEqual, convert);
+
+        if (dst.first()->is_reg()) {
+          // Save the ptr to utf string in the origina src loc or the tmp
+          // dedicated to it
+          __ movq(Address(rbp, src_off), c_rarg0);
+        } else {
+          __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg0);
+        }
+        __ jmp(done);
+
+        __ bind(convert);
+
+        __ lea(c_rarg1, utf8_addr);
+        if (dst.first()->is_reg()) {
+          __ movq(Address(rbp, src_off), c_rarg1);
+        } else {
+          __ movq(Address(rsp, reg2offset_out(dst.first())), c_rarg1);
+        }
+        // And do the conversion
+        __ call(RuntimeAddress(
+                CAST_FROM_FN_PTR(address, SharedRuntime::get_utf)));
+
+        __ bind(done);
+      }
+      if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) {
+        assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+        ++c_arg; // skip over T_VOID to keep the loop indices in sync
+      }
+    }
+    // The get_utf call killed all the c_arg registers
+    live[c_rarg0->as_VMReg()->value()] = false;
+    live[c_rarg1->as_VMReg()->value()] = false;
+    live[c_rarg2->as_VMReg()->value()] = false;
+    live[c_rarg3->as_VMReg()->value()] = false;
+    live[c_rarg4->as_VMReg()->value()] = false;
+    live[c_rarg5->as_VMReg()->value()] = false;
+
+    live[c_farg0->as_VMReg()->value()] = false;
+    live[c_farg1->as_VMReg()->value()] = false;
+    live[c_farg2->as_VMReg()->value()] = false;
+    live[c_farg3->as_VMReg()->value()] = false;
+    live[c_farg4->as_VMReg()->value()] = false;
+    live[c_farg5->as_VMReg()->value()] = false;
+    live[c_farg6->as_VMReg()->value()] = false;
+    live[c_farg7->as_VMReg()->value()] = false;
+  }
+
+  // Now we can finally move the register args to their desired locations
+
+  rax_is_zero = false;
+
+  for (j_arg = first_arg_to_pass, c_arg = 0 ;
+       j_arg < total_args_passed ; j_arg++, c_arg++ ) {
+
+    VMRegPair src = in_regs[j_arg];
+    VMRegPair dst = out_regs[c_arg];
+
+    // Only need to look for args destined for the interger registers (since we
+    // convert float/double args to look like int/long outbound)
+    if (dst.first()->is_reg()) {
+      Register r =  dst.first()->as_Register();
+
+      // Check if the java arg is unsupported and thereofre useless
+      bool useless =  in_sig_bt[j_arg] == T_ARRAY ||
+                      (in_sig_bt[j_arg] == T_OBJECT &&
+                       out_sig_bt[c_arg] != T_INT &&
+                       out_sig_bt[c_arg] != T_ADDRESS &&
+                       out_sig_bt[c_arg] != T_LONG);
+
+
+      // If we're going to kill an existing arg save it first
+      if (live[dst.first()->value()]) {
+        // you can't kill yourself
+        if (src.first() != dst.first()) {
+          __ movq(Address(rbp, fp_offset[dst.first()->value()]), r);
+        }
+      }
+      if (src.first()->is_reg()) {
+        if (live[src.first()->value()] ) {
+          if (in_sig_bt[j_arg] == T_FLOAT) {
+            __ movdl(r, src.first()->as_XMMRegister());
+          } else if (in_sig_bt[j_arg] == T_DOUBLE) {
+            __ movdq(r, src.first()->as_XMMRegister());
+          } else if (r != src.first()->as_Register()) {
+            if (!useless) {
+              __ movq(r, src.first()->as_Register());
+            }
+          }
+        } else {
+          // If the arg is an oop type we don't support don't bother to store
+          // it
+          if (!useless) {
+            if (in_sig_bt[j_arg] == T_DOUBLE ||
+                in_sig_bt[j_arg] == T_LONG  ||
+                in_sig_bt[j_arg] == T_OBJECT ) {
+              __ movq(r, Address(rbp, fp_offset[src.first()->value()]));
+            } else {
+              __ movl(r, Address(rbp, fp_offset[src.first()->value()]));
+            }
+          }
+        }
+        live[src.first()->value()] = false;
+      } else if (!useless) {
+        // full sized move even for int should be ok
+        __ movq(r, Address(rbp, reg2offset_in(src.first())));
+      }
+
+      // At this point r has the original java arg in the final location
+      // (assuming it wasn't useless). If the java arg was an oop
+      // we have a bit more to do
+
+      if (in_sig_bt[j_arg] == T_ARRAY || in_sig_bt[j_arg] == T_OBJECT ) {
+        if (out_sig_bt[c_arg] == T_INT || out_sig_bt[c_arg] == T_LONG) {
+          // need to unbox a one-word value
+          Label skip;
+          __ testq(r, r);
+          __ jcc(Assembler::equal, skip);
+          Address src1(r, box_offset);
+          if ( out_sig_bt[c_arg] == T_LONG ) {
+            __ movq(r, src1);
+          } else {
+            __ movl(r, src1);
+          }
+          __ bind(skip);
+
+        } else if (out_sig_bt[c_arg] != T_ADDRESS) {
+          // Convert the arg to NULL
+          __ xorq(r, r);
+        }
+      }
+
+      // dst can longer be holding an input value
+      live[dst.first()->value()] = false;
+    }
+    if (in_sig_bt[j_arg] == T_OBJECT && out_sig_bt[c_arg] == T_LONG) {
+      assert(out_sig_bt[c_arg+1] == T_VOID, "must be");
+      ++c_arg; // skip over T_VOID to keep the loop indices in sync
+    }
+  }
+
+
+  // Ok now we are done. Need to place the nop that dtrace wants in order to
+  // patch in the trap
+  int patch_offset = ((intptr_t)__ pc()) - start;
+
+  __ nop();
+
+
+  // Return
+
+  __ leave();
+  __ ret(0);
+
+  __ flush();
+
+  nmethod *nm = nmethod::new_dtrace_nmethod(
+      method, masm->code(), vep_offset, patch_offset, frame_complete,
+      stack_slots / VMRegImpl::slots_per_word);
+  return nm;
+
+}
+
+#endif // HAVE_DTRACE_H
+
 // this function returns the adjust size (in number of words) to a c2i adapter
 // activation for use during deoptimization
 int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals ) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/linux/vm/dtraceJSDT_linux.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/solaris/vm/dtraceJSDT_solaris.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/windows/vm/dtraceJSDT_windows.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -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;
+}
--- a/hotspot/src/share/vm/asm/codeBuffer.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/asm/codeBuffer.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -36,6 +36,7 @@
                  Verified_Entry,
                  Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete
                  OSR_Entry,
+                 Dtrace_trap = OSR_Entry,  // dtrace probes can never have an OSR entry so reuse it
                  Exceptions,     // Offset where exception handler lives
                  Deopt,          // Offset where deopt handler lives
                  max_Entries };
--- a/hotspot/src/share/vm/code/nmethod.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -27,7 +27,6 @@
 
 #ifdef DTRACE_ENABLED
 
-
 // Only bother with this argument setup if dtrace is available
 
 HS_DTRACE_PROBE_DECL8(hotspot, compiled__method__load,
@@ -438,7 +437,6 @@
   {
     MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     int native_nmethod_size = allocation_size(code_buffer, sizeof(nmethod));
-    const int dummy = -1;               // Flag to force proper "operator new"
     CodeOffsets offsets;
     offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
     offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
@@ -461,6 +459,41 @@
   return nm;
 }
 
+#ifdef HAVE_DTRACE_H
+nmethod* nmethod::new_dtrace_nmethod(methodHandle method,
+                                     CodeBuffer *code_buffer,
+                                     int vep_offset,
+                                     int trap_offset,
+                                     int frame_complete,
+                                     int frame_size) {
+  // create nmethod
+  nmethod* nm = NULL;
+  {
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    int nmethod_size = allocation_size(code_buffer, sizeof(nmethod));
+    CodeOffsets offsets;
+    offsets.set_value(CodeOffsets::Verified_Entry, vep_offset);
+    offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset);
+    offsets.set_value(CodeOffsets::Frame_Complete, frame_complete);
+
+    nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size);
+
+    NOT_PRODUCT(if (nm != NULL)  nmethod_stats.note_nmethod(nm));
+    if (PrintAssembly && nm != NULL)
+      Disassembler::decode(nm);
+  }
+  // verify nmethod
+  debug_only(if (nm) nm->verify();) // might block
+
+  if (nm != NULL) {
+    nm->log_new_nmethod();
+  }
+
+  return nm;
+}
+
+#endif // def HAVE_DTRACE_H
+
 nmethod* nmethod::new_nmethod(methodHandle method,
   int compile_id,
   int entry_bci,
@@ -558,6 +591,9 @@
     _exception_offset        = 0;
     _deoptimize_offset       = 0;
     _orig_pc_offset          = 0;
+#ifdef HAVE_DTRACE_H
+    _trap_offset             = 0;
+#endif // def HAVE_DTRACE_H
     _stub_offset             = data_offset();
     _consts_offset           = data_offset();
     _scopes_data_offset      = data_offset();
@@ -615,6 +651,90 @@
   Events::log("Create nmethod " INTPTR_FORMAT, this);
 }
 
+// For dtrace wrappers
+#ifdef HAVE_DTRACE_H
+nmethod::nmethod(
+  methodOop method,
+  int nmethod_size,
+  CodeOffsets* offsets,
+  CodeBuffer* code_buffer,
+  int frame_size)
+  : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod),
+             nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL),
+  _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)),
+  _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1))
+{
+  {
+    debug_only(No_Safepoint_Verifier nsv;)
+    assert_locked_or_safepoint(CodeCache_lock);
+
+    NOT_PRODUCT(_has_debug_info = false; )
+    _method                  = method;
+    _entry_bci               = InvocationEntryBci;
+    _link                    = NULL;
+    _compiler                = NULL;
+    // We have no exception handler or deopt handler make the
+    // values something that will never match a pc like the nmethod vtable entry
+    _exception_offset        = 0;
+    _deoptimize_offset       = 0;
+    _trap_offset             = offsets->value(CodeOffsets::Dtrace_trap);
+    _orig_pc_offset          = 0;
+    _stub_offset             = data_offset();
+    _consts_offset           = data_offset();
+    _scopes_data_offset      = data_offset();
+    _scopes_pcs_offset       = _scopes_data_offset;
+    _dependencies_offset     = _scopes_pcs_offset;
+    _handler_table_offset    = _dependencies_offset;
+    _nul_chk_table_offset    = _handler_table_offset;
+    _nmethod_end_offset      = _nul_chk_table_offset;
+    _compile_id              = 0;  // default
+    _comp_level              = CompLevel_none;
+    _entry_point             = instructions_begin();
+    _verified_entry_point    = instructions_begin() + offsets->value(CodeOffsets::Verified_Entry);
+    _osr_entry_point         = NULL;
+    _exception_cache         = NULL;
+    _pc_desc_cache.reset_to(NULL);
+
+    flags.clear();
+    flags.state              = alive;
+    _markedForDeoptimization = 0;
+
+    _lock_count = 0;
+    _stack_traversal_mark    = 0;
+
+    code_buffer->copy_oops_to(this);
+    debug_only(check_store();)
+    CodeCache::commit(this);
+    VTune::create_nmethod(this);
+  }
+
+  if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) {
+    ttyLocker ttyl;  // keep the following output all in one block
+    // This output goes directly to the tty, not the compiler log.
+    // To enable tools to match it up with the compilation activity,
+    // be sure to tag this tty output with the compile ID.
+    if (xtty != NULL) {
+      xtty->begin_head("print_dtrace_nmethod");
+      xtty->method(_method);
+      xtty->stamp();
+      xtty->end_head(" address='" INTPTR_FORMAT "'", (intptr_t) this);
+    }
+    // print the header part first
+    print();
+    // then print the requested information
+    if (PrintNMethods) {
+      print_code();
+    }
+    if (PrintRelocations) {
+      print_relocations();
+    }
+    if (xtty != NULL) {
+      xtty->tail("print_dtrace_nmethod");
+    }
+  }
+  Events::log("Create nmethod " INTPTR_FORMAT, this);
+}
+#endif // def HAVE_DTRACE_H
 
 void* nmethod::operator new(size_t size, int nmethod_size) {
   // Always leave some room in the CodeCache for I2C/C2I adapters
@@ -658,6 +778,9 @@
     _link                    = NULL;
     _compiler                = compiler;
     _orig_pc_offset          = orig_pc_offset;
+#ifdef HAVE_DTRACE_H
+    _trap_offset             = 0;
+#endif // def HAVE_DTRACE_H
     _stub_offset             = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start());
 
     // Exception handler and deopt handler are in the stub section
@@ -1885,7 +2008,6 @@
   } else if (is_compiled_by_c2()) {
     tty->print("(c2) ");
   } else {
-    assert(is_native_method(), "Who else?");
     tty->print("(nm) ");
   }
 
--- a/hotspot/src/share/vm/code/nmethod.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/code/nmethod.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -140,6 +140,9 @@
   int _exception_offset;
   // All deoptee's will resume execution at this location described by this offset
   int _deoptimize_offset;
+#ifdef HAVE_DTRACE_H
+  int _trap_offset;
+#endif // def HAVE_DTRACE_H
   int _stub_offset;
   int _consts_offset;
   int _scopes_data_offset;
@@ -211,6 +214,15 @@
           ByteSize basic_lock_sp_offset,       /* synchronized natives only */
           OopMapSet* oop_maps);
 
+#ifdef HAVE_DTRACE_H
+  // For native wrappers
+  nmethod(methodOop method,
+          int nmethod_size,
+          CodeOffsets* offsets,
+          CodeBuffer *code_buffer,
+          int frame_size);
+#endif // def HAVE_DTRACE_H
+
   // Creation support
   nmethod(methodOop method,
           int nmethod_size,
@@ -272,6 +284,22 @@
                                      ByteSize basic_lock_sp_offset,
                                      OopMapSet* oop_maps);
 
+#ifdef HAVE_DTRACE_H
+  // The method we generate for a dtrace probe has to look
+  // like an nmethod as far as the rest of the system is concerned
+  // which is somewhat unfortunate.
+  static nmethod* new_dtrace_nmethod(methodHandle method,
+                                     CodeBuffer *code_buffer,
+                                     int vep_offset,
+                                     int trap_offset,
+                                     int frame_complete,
+                                     int frame_size);
+
+  int trap_offset() const      { return _trap_offset; }
+  address trap_address() const { return code_begin() + _trap_offset; }
+
+#endif // def HAVE_DTRACE_H
+
   // accessors
   methodOop method() const                        { return _method; }
   AbstractCompiler* compiler() const              { return _compiler; }
--- a/hotspot/src/share/vm/includeDB_core	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/includeDB_core	Thu Apr 17 22:18:15 2008 -0400
@@ -1497,6 +1497,30 @@
 dtraceAttacher.cpp                      vmThread.hpp
 dtraceAttacher.cpp                      vm_operations.hpp
 
+dtraceJSDT.cpp                          allocation.hpp
+dtraceJSDT.cpp                          codeBlob.hpp
+dtraceJSDT.cpp                          dtraceJSDT.hpp
+dtraceJSDT.cpp                          exceptions.hpp
+dtraceJSDT.cpp                          globalDefinitions.hpp
+dtraceJSDT.cpp                          javaClasses.hpp
+dtraceJSDT.cpp                          jniHandles.hpp
+dtraceJSDT.cpp                          jvm.h
+dtraceJSDT.cpp                          os.hpp
+dtraceJSDT.cpp                          utf8.hpp
+
+dtraceJSDT.hpp                          nativeInst_<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
 
 events.cpp                              allocation.inline.hpp
@@ -2400,6 +2424,7 @@
 jvm.cpp                                 collectedHeap.inline.hpp
 jvm.cpp                                 copy.hpp
 jvm.cpp                                 defaultStream.hpp
+jvm.cpp                                 dtraceJSDT.hpp
 jvm.cpp                                 events.hpp
 jvm.cpp                                 handles.inline.hpp
 jvm.cpp                                 histogram.hpp
--- a/hotspot/src/share/vm/oops/methodOop.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/oops/methodOop.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -672,9 +672,6 @@
 }
 
 address methodOopDesc::make_adapters(methodHandle mh, TRAPS) {
-  // If running -Xint we need no adapters.
-  if (Arguments::mode() == Arguments::_int) return NULL;
-
   // Adapters for compiled code are made eagerly here.  They are fairly
   // small (generally < 100 bytes) and quick to make (and cached and shared)
   // so making them eagerly shouldn't be too expensive.
--- a/hotspot/src/share/vm/prims/jvm.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -4168,6 +4168,36 @@
   return res == oldVal;
 JVM_END
 
+// DTrace ///////////////////////////////////////////////////////////////////
+
+JVM_ENTRY(jint, JVM_DTraceGetVersion(JNIEnv* env))
+  JVMWrapper("JVM_DTraceGetVersion");
+  return (jint)JVM_TRACING_DTRACE_VERSION;
+JVM_END
+
+JVM_ENTRY(jlong,JVM_DTraceActivate(
+    JNIEnv* env, jint version, jstring module_name, jint providers_count,
+    JVM_DTraceProvider* providers))
+  JVMWrapper("JVM_DTraceActivate");
+  return DTraceJSDT::activate(
+    version, module_name, providers_count, providers, CHECK_0);
+JVM_END
+
+JVM_ENTRY(jboolean,JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method))
+  JVMWrapper("JVM_DTraceIsProbeEnabled");
+  return DTraceJSDT::is_probe_enabled(method);
+JVM_END
+
+JVM_ENTRY(void,JVM_DTraceDispose(JNIEnv* env, jlong handle))
+  JVMWrapper("JVM_DTraceDispose");
+  DTraceJSDT::dispose(handle);
+JVM_END
+
+JVM_ENTRY(jboolean,JVM_DTraceIsSupported(JNIEnv* env))
+  JVMWrapper("JVM_DTraceIsSupported");
+  return DTraceJSDT::is_supported();
+JVM_END
+
 // Returns an array of all live Thread objects (VM internal JavaThreads,
 // jvmti agent threads, and JNI attaching threads  are skipped)
 // See CR 6404306 regarding JNI attaching threads
@@ -4496,3 +4526,4 @@
 #endif // KERNEL
 }
 JVM_END
+
--- a/hotspot/src/share/vm/prims/jvm.h	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/prims/jvm.h	Thu Apr 17 22:18:15 2008 -0400
@@ -606,6 +606,83 @@
 JNIEXPORT jboolean JNICALL
 JVM_CX8Field(JNIEnv *env, jobject obj, jfieldID fldID, jlong oldVal, jlong newVal);
 
+/*
+ * com.sun.dtrace.jsdt support
+ */
+
+#define JVM_TRACING_DTRACE_VERSION 1
+
+/*
+ * Structure to pass one probe description to JVM.
+ *
+ * The VM will overwrite the definition of the referenced method with
+ * code that will fire the probe.
+ */
+typedef struct {
+    jmethodID method;
+    jstring   function;
+    jstring   name;
+    void*     reserved[4];     // for future use
+} JVM_DTraceProbe;
+
+/**
+ * Encapsulates the stability ratings for a DTrace provider field
+ */
+typedef struct {
+    jint nameStability;
+    jint dataStability;
+    jint dependencyClass;
+} JVM_DTraceInterfaceAttributes;
+
+/*
+ * Structure to pass one provider description to JVM
+ */
+typedef struct {
+    jstring                       name;
+    JVM_DTraceProbe*              probes;
+    jint                          probe_count;
+    JVM_DTraceInterfaceAttributes providerAttributes;
+    JVM_DTraceInterfaceAttributes moduleAttributes;
+    JVM_DTraceInterfaceAttributes functionAttributes;
+    JVM_DTraceInterfaceAttributes nameAttributes;
+    JVM_DTraceInterfaceAttributes argsAttributes;
+    void*                         reserved[4]; // for future use
+} JVM_DTraceProvider;
+
+/*
+ * Get the version number the JVM was built with
+ */
+JNIEXPORT jint JNICALL
+JVM_DTraceGetVersion(JNIEnv* env);
+
+/*
+ * Register new probe with given signature, return global handle
+ *
+ * The version passed in is the version that the library code was
+ * built with.
+ */
+JNIEXPORT jlong JNICALL
+JVM_DTraceActivate(JNIEnv* env, jint version, jstring module_name,
+  jint providers_count, JVM_DTraceProvider* providers);
+
+/*
+ * Check JSDT probe
+ */
+JNIEXPORT jboolean JNICALL
+JVM_DTraceIsProbeEnabled(JNIEnv* env, jmethodID method);
+
+/*
+ * Destroy custom DOF
+ */
+JNIEXPORT void JNICALL
+JVM_DTraceDispose(JNIEnv* env, jlong handle);
+
+/*
+ * Check to see if DTrace is supported by OS
+ */
+JNIEXPORT jboolean JNICALL
+JVM_DTraceIsSupported(JNIEnv* env);
+
 /*************************************************************************
  PART 2: Support for the Verifier and Class File Format Checker
  ************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/dtraceJSDT.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/dtraceJSDT.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -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;
+  }
+};
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -3188,6 +3188,9 @@
   product(bool, RelaxAccessControlCheck, false,                             \
           "Relax the access control checks in the verifier")                \
                                                                             \
+  diagnostic(bool, PrintDTraceDOF, false,                                   \
+             "Print the DTrace DOF passed to the system for JSDT probes")   \
+                                                                            \
   product(bool, UseVMInterruptibleIO, true,                                 \
           "(Unstable, Solaris-specific) Thread interrupt before or with "   \
           "EINTR for I/O operations results in OS_INTRPT")
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Thu Apr 17 22:18:15 2008 -0400
@@ -1748,11 +1748,6 @@
   // _fingerprints array (it is not safe for concurrent readers and a single
   // writer: this can be fixed if it becomes a problem).
 
-  // Shouldn't be here if running -Xint
-  if (Arguments::mode() == Arguments::_int) {
-    ShouldNotReachHere();
-  }
-
   // Get the address of the ic_miss handlers before we grab the
   // AdapterHandlerLibrary_lock. This fixes bug 6236259 which
   // was caused by the initialization of the stubs happening
@@ -1997,6 +1992,64 @@
   return nm;
 }
 
+#ifdef HAVE_DTRACE_H
+// Create a dtrace nmethod for this method.  The wrapper converts the
+// java compiled calling convention to the native convention, makes a dummy call
+// (actually nops for the size of the call instruction, which become a trap if
+// probe is enabled). The returns to the caller. Since this all looks like a
+// leaf no thread transition is needed.
+
+nmethod *AdapterHandlerLibrary::create_dtrace_nmethod(methodHandle method) {
+  ResourceMark rm;
+  nmethod* nm = NULL;
+
+  if (PrintCompilation) {
+    ttyLocker ttyl;
+    tty->print("---   n%s  ");
+    method->print_short_name(tty);
+    if (method->is_static()) {
+      tty->print(" (static)");
+    }
+    tty->cr();
+  }
+
+  {
+    // perform the work while holding the lock, but perform any printing
+    // outside the lock
+    MutexLocker mu(AdapterHandlerLibrary_lock);
+    // See if somebody beat us to it
+    nm = method->code();
+    if (nm) {
+      return nm;
+    }
+
+    // Improve alignment slightly
+    u_char* buf = (u_char*)
+        (((intptr_t)_buffer + CodeEntryAlignment-1) & ~(CodeEntryAlignment-1));
+    CodeBuffer buffer(buf, AdapterHandlerLibrary_size);
+    // Need a few relocation entries
+    double locs_buf[20];
+    buffer.insts()->initialize_shared_locs(
+        (relocInfo*)locs_buf, sizeof(locs_buf) / sizeof(relocInfo));
+    MacroAssembler _masm(&buffer);
+
+    // Generate the compiled-to-native wrapper code
+    nm = SharedRuntime::generate_dtrace_nmethod(&_masm, method);
+  }
+  return nm;
+}
+
+// the dtrace method needs to convert java lang string to utf8 string.
+void SharedRuntime::get_utf(oopDesc* src, address dst) {
+  typeArrayOop jlsValue  = java_lang_String::value(src);
+  int          jlsOffset = java_lang_String::offset(src);
+  int          jlsLen    = java_lang_String::length(src);
+  jchar*       jlsPos    = (jlsLen == 0) ? NULL :
+                                           jlsValue->char_at_addr(jlsOffset);
+  (void) UNICODE::as_utf8(jlsPos, jlsLen, (char *)dst, max_dtrace_string_size);
+}
+#endif // ndef HAVE_DTRACE_H
+
 // -------------------------------------------------------------------------
 // Java-Java calling convention
 // (what you use when Java calls Java)
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Wed Apr 16 17:36:29 2008 -0400
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Thu Apr 17 22:18:15 2008 -0400
@@ -59,6 +59,10 @@
 
 #endif // !PRODUCT
  public:
+
+  // max bytes for each dtrace string parameter
+  enum { max_dtrace_string_size = 256 };
+
   // The following arithmetic routines are used on platforms that do
   // not have machine instructions to implement their functionality.
   // Do not remove these.
@@ -258,9 +262,6 @@
 
  public:
 
-
-  static void create_native_wrapper (JavaThread* thread, methodOop method);
-
   // Read the array of BasicTypes from a Java signature, and compute where
   // compiled Java code would like to put the results.  Values in reg_lo and
   // reg_hi refer to 4-byte quantities.  Values less than SharedInfo::stack0 are
@@ -354,6 +355,19 @@
                                           VMRegPair *regs,
                                           BasicType ret_type );
 
+#ifdef HAVE_DTRACE_H
+  // Generate a dtrace wrapper for a given method.  The method takes arguments
+  // in the Java compiled code convention, marshals them to the native
+  // convention (handlizes oops, etc), transitions to native, makes the call,
+  // returns to java state (possibly blocking), unhandlizes any result and
+  // returns.
+  static nmethod *generate_dtrace_nmethod(MacroAssembler* masm,
+                                          methodHandle method);
+
+  // dtrace support to convert a Java string to utf8
+  static void get_utf(oopDesc* src, address dst);
+#endif // def HAVE_DTRACE_H
+
   // A compiled caller has just called the interpreter, but compiled code
   // exists.  Patch the caller so he no longer calls into the interpreter.
   static void fixup_callers_callsite(methodOopDesc* moop, address ret_pc);
@@ -492,42 +506,55 @@
   address _c2i_unverified_entry;
 
  public:
+
+  // The name we give all buffer blobs
+  static const char* name;
+
   AdapterHandlerEntry(address i2c_entry, address c2i_entry, address c2i_unverified_entry):
     _i2c_entry(i2c_entry),
     _c2i_entry(c2i_entry),
     _c2i_unverified_entry(c2i_unverified_entry) {
   }
-  // The name we give all buffer blobs
-  static const char* name;
 
   address get_i2c_entry()            { return _i2c_entry; }
   address get_c2i_entry()            { return _c2i_entry; }
   address get_c2i_unverified_entry() { return _c2i_unverified_entry; }
+
   void relocate(address new_base);
 #ifndef PRODUCT
   void print();
 #endif /* PRODUCT */
 };
 
-
 class AdapterHandlerLibrary: public AllStatic {
  private:
+  static u_char                   _buffer[];  // the temporary code buffer
+  static GrowableArray<uint64_t>* _fingerprints; // the fingerprint collection
+  static GrowableArray<AdapterHandlerEntry*> * _handlers; // the corresponding handlers
   enum {
     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 AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); }
   static int get_create_adapter_index(methodHandle method);
-  static address get_i2c_entry( int index ) { return get_entry(index)->get_i2c_entry(); }
-  static address get_c2i_entry( int index ) { return get_entry(index)->get_c2i_entry(); }
-  static address get_c2i_unverified_entry( int index ) { return get_entry(index)->get_c2i_unverified_entry(); }
+  static address get_i2c_entry( int index ) {
+    return get_entry(index)->get_i2c_entry();
+  }
+  static address get_c2i_entry( int index ) {
+    return get_entry(index)->get_c2i_entry();
+  }
+  static address get_c2i_unverified_entry( int index ) {
+    return get_entry(index)->get_c2i_unverified_entry();
+  }
 
  public:
+  static AdapterHandlerEntry* get_entry( int index ) { return _handlers->at(index); }
   static nmethod* create_native_wrapper(methodHandle method);
-  static AdapterHandlerEntry* get_adapter(methodHandle method)  { return get_entry(get_create_adapter_index(method)); }
+  static AdapterHandlerEntry* get_adapter(methodHandle method)  {
+    return get_entry(get_create_adapter_index(method));
+  }
+#ifdef HAVE_DTRACE_H
+  static nmethod* create_dtrace_nmethod (methodHandle method);
+#endif // HAVE_DTRACE_H
 
 #ifndef PRODUCT
   static void print_handler(CodeBlob* b);