2008-10-25 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 Oct 2008 19:59:47 +0000 (19:59 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 25 Oct 2008 19:59:47 +0000 (19:59 +0000)
        Reviewed by Sam Weinig, with Gavin Barraclough's help.

        Fixed Sampling Tool:
            - Made CodeBlock sampling work with CTI
            - Improved accuracy by unifying most sampling data into a single
              32bit word, which can be written / read atomically.
            - Split out three different #ifdefs for modularity: OPCODE_SAMPLING;
              CODEBLOCK_SAMPLING; OPCODE_STATS.
            - Improved reporting clarity
            - Refactored for code clarity

        * JavaScriptCore.exp: Exported another symbol.

        * VM/CTI.cpp:
        (JSC::CTI::emitCTICall):
        (JSC::CTI::compileOpCall):
        (JSC::CTI::emitSlowScriptCheck):
        (JSC::CTI::compileBinaryArithOpSlowCase):
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        (JSC::CTI::privateCompile):
        * VM/CTI.h: Updated CTI codegen to use the unified SamplingTool interface
        for encoding samples. (This required passing the current vPC to a lot
        more functions, since the unified interface samples the current vPC.)
        Added hooks for writing the current CodeBlock* on function entry and
        after a function call, for the sake of the CodeBlock sampler. Removed
        obsolete hook for clearing the current sample inside op_end. Also removed
        the custom enum used to differentiate flavors of op_call, since the
        OpcodeID enum works just as well. (This was important in an earlier
        version of the patch, but now it's just cleanup.)

        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::lineNumberForVPC):
        * VM/CodeBlock.h: Upated for refactored #ifdefs. Changed lineNumberForVPC
        to be robust against vPCs not recorded for exception handling, since
        the Sampler may ask for an arbitrary vPC.

        * VM/Machine.cpp:
        (JSC::Machine::execute):
        (JSC::Machine::privateExecute):
        (JSC::Machine::cti_op_call_NotJSFunction):
        (JSC::Machine::cti_op_construct_NotJSConstruct):
        * VM/Machine.h:
        (JSC::Machine::setSampler):
        (JSC::Machine::sampler):
        (JSC::Machine::jitCodeBuffer): Upated for refactored #ifdefs. Changed
        Machine to use SamplingTool helper objects to record movement in and
        out of host code. This makes samples a bit more precise.

        * VM/Opcode.cpp:
        (JSC::OpcodeStats::~OpcodeStats):
        * VM/Opcode.h: Upated for refactored #ifdefs. Added a little more padding,
        to accomodate our more verbose opcode names.

        * VM/SamplingTool.cpp:
        (JSC::ScopeSampleRecord::sample): Only count a sample toward our total
        if we actually record it. This solves cases where a CodeBlock will
        claim to have been sampled many times, with reported samples that don't
        match.

        (JSC::SamplingTool::run): Read the current sample into a Sample helper
        object, to ensure that the data doesn't change while we're analyzing it,
        and to help decode the data. Only access the CodeBlock sampling hash
        table if CodeBlock sampling has been enabled, so non-CodeBlock sampling
        runs can operate with even less overhead.

        (JSC::SamplingTool::dump): I reorganized this code a lot to print the
        most important info at the top, print as a table, annotate and document
        the stuff I didn't understand when I started, etc.

        * VM/SamplingTool.h: New helper classes, described above.

        * kjs/Parser.h:
        * kjs/Shell.cpp:
        (runWithScripts):
        * kjs/nodes.cpp:
        (JSC::ScopeNode::ScopeNode): Updated for new sampling APIs.

        * wtf/Platform.h: Moved sampling #defines here, since our custom is to
        put ENABLE #defines into Platform.h. Made explicit the fact that
        CODEBLOCK_SAMPLING depends on OPCODE_SAMPLING.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@37891 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeBlock.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.cpp
JavaScriptCore/VM/Opcode.h
JavaScriptCore/VM/SamplingTool.cpp
JavaScriptCore/VM/SamplingTool.h
JavaScriptCore/kjs/Parser.h
JavaScriptCore/kjs/Shell.cpp
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/wtf/Platform.h

index 0407f81..2ecdef5 100644 (file)
@@ -1,3 +1,87 @@
+2008-10-25  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Sam Weinig, with Gavin Barraclough's help.
+        
+        Fixed Sampling Tool:
+            - Made CodeBlock sampling work with CTI
+            - Improved accuracy by unifying most sampling data into a single
+              32bit word, which can be written / read atomically.
+            - Split out three different #ifdefs for modularity: OPCODE_SAMPLING;
+              CODEBLOCK_SAMPLING; OPCODE_STATS.
+            - Improved reporting clarity
+            - Refactored for code clarity
+
+        * JavaScriptCore.exp: Exported another symbol.
+
+        * VM/CTI.cpp:
+        (JSC::CTI::emitCTICall):
+        (JSC::CTI::compileOpCall):
+        (JSC::CTI::emitSlowScriptCheck):
+        (JSC::CTI::compileBinaryArithOpSlowCase):
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        (JSC::CTI::privateCompile):
+        * VM/CTI.h: Updated CTI codegen to use the unified SamplingTool interface
+        for encoding samples. (This required passing the current vPC to a lot
+        more functions, since the unified interface samples the current vPC.)
+        Added hooks for writing the current CodeBlock* on function entry and
+        after a function call, for the sake of the CodeBlock sampler. Removed
+        obsolete hook for clearing the current sample inside op_end. Also removed
+        the custom enum used to differentiate flavors of op_call, since the
+        OpcodeID enum works just as well. (This was important in an earlier
+        version of the patch, but now it's just cleanup.)
+
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::lineNumberForVPC):
+        * VM/CodeBlock.h: Upated for refactored #ifdefs. Changed lineNumberForVPC
+        to be robust against vPCs not recorded for exception handling, since
+        the Sampler may ask for an arbitrary vPC.
+
+        * VM/Machine.cpp:
+        (JSC::Machine::execute):
+        (JSC::Machine::privateExecute):
+        (JSC::Machine::cti_op_call_NotJSFunction):
+        (JSC::Machine::cti_op_construct_NotJSConstruct):
+        * VM/Machine.h:
+        (JSC::Machine::setSampler):
+        (JSC::Machine::sampler):
+        (JSC::Machine::jitCodeBuffer): Upated for refactored #ifdefs. Changed
+        Machine to use SamplingTool helper objects to record movement in and
+        out of host code. This makes samples a bit more precise.
+        
+        * VM/Opcode.cpp:
+        (JSC::OpcodeStats::~OpcodeStats):
+        * VM/Opcode.h: Upated for refactored #ifdefs. Added a little more padding,
+        to accomodate our more verbose opcode names.
+
+        * VM/SamplingTool.cpp:
+        (JSC::ScopeSampleRecord::sample): Only count a sample toward our total
+        if we actually record it. This solves cases where a CodeBlock will
+        claim to have been sampled many times, with reported samples that don't
+        match.
+
+        (JSC::SamplingTool::run): Read the current sample into a Sample helper
+        object, to ensure that the data doesn't change while we're analyzing it,
+        and to help decode the data. Only access the CodeBlock sampling hash
+        table if CodeBlock sampling has been enabled, so non-CodeBlock sampling
+        runs can operate with even less overhead.
+
+        (JSC::SamplingTool::dump): I reorganized this code a lot to print the
+        most important info at the top, print as a table, annotate and document
+        the stuff I didn't understand when I started, etc.
+
+        * VM/SamplingTool.h: New helper classes, described above.
+
+        * kjs/Parser.h:
+        * kjs/Shell.cpp:
+        (runWithScripts):
+        * kjs/nodes.cpp:
+        (JSC::ScopeNode::ScopeNode): Updated for new sampling APIs.
+
+        * wtf/Platform.h: Moved sampling #defines here, since our custom is to
+        put ENABLE #defines into Platform.h. Made explicit the fact that
+        CODEBLOCK_SAMPLING depends on OPCODE_SAMPLING.
+
 2008-10-25  Jan Michael Alonzo  <jmalonzo@webkit.org>
 
         JSC Build fix, not reviewed.
index f2b3f38..8f42609 100644 (file)
@@ -124,6 +124,7 @@ __ZN3JSC12JSGlobalData10ClientDataD2Ev
 __ZN3JSC12JSGlobalData12createLeakedEv
 __ZN3JSC12JSGlobalData6createEv
 __ZN3JSC12JSGlobalDataD1Ev
+__ZN3JSC12SamplingTool13notifyOfScopeEPNS_9ScopeNodeE
 __ZN3JSC12SamplingTool4dumpEPNS_9ExecStateE
 __ZN3JSC12SamplingTool4stopEv
 __ZN3JSC12SamplingTool5startEj
index dcc9a45..f21013f 100644 (file)
@@ -34,6 +34,7 @@
 #include "Machine.h"
 #include "wrec/WREC.h"
 #include "ResultType.h"
+#include "SamplingTool.h"
 
 #ifndef NDEBUG
 #include <stdio.h>
@@ -262,10 +263,6 @@ ALWAYS_INLINE void CTI::emitInitRegister(unsigned dst)
     // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
 }
 
-#if ENABLE(SAMPLING_TOOL)
-unsigned inCalledCode = 0;
-#endif
-
 void ctiSetReturnAddress(void** where, void* what)
 {
     *where = what;
@@ -329,113 +326,127 @@ ALWAYS_INLINE  X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, voi
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_j helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_j helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_o helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_o helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_p helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_p helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_b helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_b helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_v helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_v helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_s helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_s helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
 }
 
-ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(unsigned opcodeIndex, CTIHelper_2 helper)
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCTICall(Instruction* vPC, unsigned opcodeIndex, CTIHelper_2 helper)
 {
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(1, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, true), m_machine->sampler()->sampleSlot());
+#else
+    UNUSED_PARAM(vPC);
 #endif
     m_jit.emitRestoreArgumentReference();
     emitPutCTIParam(X86::edi, CTI_ARGS_callFrame);
     X86Assembler::JmpSrc call = m_jit.emitCall();
     m_calls.append(CallRecord(call, helper, opcodeIndex));
-#if ENABLE(SAMPLING_TOOL)
-    m_jit.movl_i32m(0, &inCalledCode);
+#if ENABLE(OPCODE_SAMPLING)
+    m_jit.movl_i32m(m_machine->sampler()->encodeSample(vPC, false), m_machine->sampler()->sampleSlot());
 #endif
 
     return call;
@@ -526,7 +537,7 @@ CTI::CTI(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock)
     case name: { \
         emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
         emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx); \
-        emitCTICall(i, Machine::cti_##name); \
+        emitCTICall(instruction + i, i, Machine::cti_##name); \
         emitPutResult(instruction[i + 1].u.operand); \
         i += 4; \
         break; \
@@ -535,16 +546,12 @@ CTI::CTI(Machine* machine, CallFrame* callFrame, CodeBlock* codeBlock)
 #define CTI_COMPILE_UNARY_OP(name) \
     case name: { \
         emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
-        emitCTICall(i, Machine::cti_##name); \
+        emitCTICall(instruction + i, i, Machine::cti_##name); \
         emitPutResult(instruction[i + 1].u.operand); \
         i += 3; \
         break; \
     }
 
-#if ENABLE(SAMPLING_TOOL)
-OpcodeID currentOpcodeID = static_cast<OpcodeID>(-1);
-#endif
-
 static void unreachable()
 {
     ASSERT_NOT_REACHED();
@@ -581,7 +588,7 @@ void CTI::compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, boo
         emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
 }
 
-void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkInfoIndex, CompileOpCallType type)
+void CTI::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex)
 {
     int dst = instruction[1].u.operand;
     int callee = instruction[2].u.operand;
@@ -590,7 +597,7 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkI
     int registerOffset = instruction[6].u.operand;
 
     // Setup this value as the first argument (does not apply to constructors)
-    if (type != OpConstruct) {
+    if (opcodeID != op_construct) {
         int thisVal = instruction[3].u.operand;
         if (thisVal == missingThisObjectMarker()) {
             // FIXME: should this be loaded dynamically off m_callFrame?
@@ -603,11 +610,11 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkI
 
     // Handle eval
     X86Assembler::JmpSrc wasEval;
-    if (type == OpCallEval) {
+    if (opcodeID == op_call_eval) {
         emitGetArg(callee, X86::ecx);
         compileOpCallSetupArgs(instruction, false, true);
 
-        emitCTICall(i, Machine::cti_op_call_eval);
+        emitCTICall(instruction, i, Machine::cti_op_call_eval);
         m_jit.cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::eax);
         wasEval = m_jit.emitUnlinkedJne();
     }
@@ -624,10 +631,10 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkI
     // The following is the fast case, only used whan a callee can be linked.
 
     // In the case of OpConstruct, call oout to a cti_ function to create the new object.
-    if (type == OpConstruct) {
+    if (opcodeID == op_construct) {
         emitPutArg(X86::ecx, 0);
         emitGetPutArg(instruction[3].u.operand, 4, X86::eax);
-        emitCTICall(i, Machine::cti_op_construct_JSConstructFast);
+        emitCTICall(instruction, i, Machine::cti_op_construct_JSConstructFast);
         emitPutResult(instruction[4].u.operand);
         emitGetArg(callee, X86::ecx);
     }
@@ -645,11 +652,15 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkI
     // Call to the callee
     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(i, unreachable);
     
-    if (type == OpCallEval)
+    if (opcodeID == op_call_eval)
         m_jit.link(wasEval, m_jit.label());
 
     // Put the return value in dst. In the interpreter, op_ret does this.
     emitPutResult(dst);
+
+#if ENABLE(CODEBLOCK_SAMPLING)
+        m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
+#endif
 }
 
 void CTI::compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type)
@@ -708,11 +719,11 @@ void CTI::compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStric
     emitPutResult(dst);
 }
 
-void CTI::emitSlowScriptCheck(unsigned opcodeIndex)
+void CTI::emitSlowScriptCheck(Instruction* vPC, unsigned opcodeIndex)
 {
     m_jit.subl_i8r(1, X86::esi);
     X86Assembler::JmpSrc skipTimeout = m_jit.emitUnlinkedJne();
-    emitCTICall(opcodeIndex, Machine::cti_timeout_check);
+    emitCTICall(vPC, opcodeIndex, Machine::cti_timeout_check);
 
     emitGetCTIParam(CTI_ARGS_globalData, X86::ecx);
     m_jit.movl_mr(OBJECT_OFFSET(JSGlobalData, machine), X86::ecx, X86::ecx);
@@ -905,7 +916,7 @@ void CTI::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, u
     }
 }
 
-void CTI::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
+void CTI::compileBinaryArithOpSlowCase(Instruction* vPC, OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
 {
     X86Assembler::JmpDst here = m_jit.label();
     m_jit.link(iter->from, here);
@@ -939,12 +950,12 @@ void CTI::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>:
     emitGetPutArg(src1, 0, X86::ecx);
     emitGetPutArg(src2, 4, X86::ecx);
     if (opcodeID == op_add)
-        emitCTICall(i, Machine::cti_op_add);
+        emitCTICall(vPC, i, Machine::cti_op_add);
     else if (opcodeID == op_sub)
-        emitCTICall(i, Machine::cti_op_sub);
+        emitCTICall(vPC, i, Machine::cti_op_sub);
     else {
         ASSERT(opcodeID == op_mul);
-        emitCTICall(i, Machine::cti_op_mul);
+        emitCTICall(vPC, i, Machine::cti_op_mul);
     }
     emitPutResult(dst);
 }
@@ -958,14 +969,15 @@ void CTI::privateCompileMainPass()
     unsigned callLinkInfoIndex = 0;
 
     for (unsigned i = 0; i < instructionCount; ) {
-        m_labels[i] = m_jit.label();
+        ASSERT_WITH_MESSAGE(m_machine->isOpcode(instruction[i].u.opcode), "privateCompileMainPass gone bad @ %d", i);
 
-#if ENABLE(SAMPLING_TOOL)
-        m_jit.movl_i32m(m_machine->getOpcodeID(instruction[i].u.opcode), &currentOpcodeID);
+#if ENABLE(OPCODE_SAMPLING)
+        m_jit.movl_i32m(m_machine->sampler()->encodeSample(instruction + i), m_machine->sampler()->sampleSlot());
 #endif
 
-        ASSERT_WITH_MESSAGE(m_machine->isOpcode(instruction[i].u.opcode), "privateCompileMainPass gone bad @ %d", i);
-        switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
+        m_labels[i] = m_jit.label();
+        OpcodeID opcodeID = m_machine->getOpcodeID(instruction[i].u.opcode);
+        switch (opcodeID) {
         case op_mov: {
             unsigned src = instruction[i + 2].u.operand;
             if (isConstant(src))
@@ -1000,7 +1012,7 @@ void CTI::privateCompileMainPass()
                 else {
                     emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
                     emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
-                    emitCTICall(i, Machine::cti_op_add);
+                    emitCTICall(instruction + i, i, Machine::cti_op_add);
                     emitPutResult(instruction[i + 1].u.operand);
                 }
             }
@@ -1010,11 +1022,8 @@ void CTI::privateCompileMainPass()
         }
         case op_end: {
             if (m_codeBlock->needsFullScopeChain)
-                emitCTICall(i, Machine::cti_op_end);
+                emitCTICall(instruction + i, i, Machine::cti_op_end);
             emitGetArg(instruction[i + 1].u.operand, X86::eax);
-#if ENABLE(SAMPLING_TOOL)
-            m_jit.movl_i32m(-1, &currentOpcodeID);
-#endif
             m_jit.pushl_m(RegisterFile::ReturnPC * static_cast<int>(sizeof(Register)), X86::edi);
             m_jit.ret();
             i += 2;
@@ -1037,7 +1046,7 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_loop: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 1].u.operand;
             m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 1 + target));
@@ -1045,7 +1054,7 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_loop_if_less: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 3].u.operand;
             JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
@@ -1066,7 +1075,7 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_loop_if_lesseq: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 3].u.operand;
             JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
@@ -1087,7 +1096,7 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_new_object: {
-            emitCTICall(i, Machine::cti_op_new_object);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_object);
             emitPutResult(instruction[i + 1].u.operand);
             i += 2;
             break;
@@ -1213,7 +1222,7 @@ void CTI::privateCompileMainPass()
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
-            emitCTICall(i, Machine::cti_op_del_by_id);
+            emitCTICall(instruction + i, i, Machine::cti_op_del_by_id);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -1252,13 +1261,13 @@ void CTI::privateCompileMainPass()
         case op_new_func: {
             FuncDeclNode* func = (m_codeBlock->functions[instruction[i + 2].u.operand]).get();
             emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
-            emitCTICall(i, Machine::cti_op_new_func);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_func);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
         }
         case op_call: {
-            compileOpCall(instruction + i, i, callLinkInfoIndex++);
+            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
             i += 7;
             break;
         }
@@ -1306,19 +1315,19 @@ void CTI::privateCompileMainPass()
         }
         case op_tear_off_activation: {
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
-            emitCTICall(i, Machine::cti_op_tear_off_activation);
+            emitCTICall(instruction + i, i, Machine::cti_op_tear_off_activation);
             i += 2;
             break;
         }
         case op_tear_off_arguments: {
-            emitCTICall(i, Machine::cti_op_tear_off_arguments);
+            emitCTICall(instruction + i, i, Machine::cti_op_tear_off_arguments);
             i += 1;
             break;
         }
         case op_ret: {
             // We could JIT generate the deref, only calling out to C when the refcount hits zero.
             if (m_codeBlock->needsFullScopeChain)
-                emitCTICall(i, Machine::cti_op_ret_scopeChain);
+                emitCTICall(instruction + i, i, Machine::cti_op_ret_scopeChain);
 
             // Return the result in %eax.
             emitGetArg(instruction[i + 1].u.operand, X86::eax);
@@ -1340,7 +1349,7 @@ void CTI::privateCompileMainPass()
             m_jit.leal_mr(sizeof(Register) * instruction[i + 2].u.operand, X86::edi, X86::edx);
             emitPutArg(X86::edx, 0);
             emitPutArgConstant(instruction[i + 3].u.operand, 4);
-            emitCTICall(i, Machine::cti_op_new_array);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_array);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -1348,13 +1357,13 @@ void CTI::privateCompileMainPass()
         case op_resolve: {
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
-            emitCTICall(i, Machine::cti_op_resolve);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
         }
         case op_construct: {
-            compileOpCall(instruction + i, i, callLinkInfoIndex++, OpConstruct);
+            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
             i += 7;
             break;
         }
@@ -1399,7 +1408,7 @@ void CTI::privateCompileMainPass()
         case op_resolve_func: {
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
-            emitCTICall(i, Machine::cti_op_resolve_func);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve_func);
             emitPutResult(instruction[i + 1].u.operand);
             emitPutResult(instruction[i + 2].u.operand, X86::edx);
             i += 4;
@@ -1442,7 +1451,7 @@ void CTI::privateCompileMainPass()
         }
         CTI_COMPILE_BINARY_OP(op_lesseq)
         case op_loop_if_true: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 2].u.operand;
             emitGetArg(instruction[i + 1].u.operand, X86::eax);
@@ -1464,14 +1473,14 @@ void CTI::privateCompileMainPass()
         case op_resolve_base: {
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
-            emitCTICall(i, Machine::cti_op_resolve_base);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve_base);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
         }
         case op_negate: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
-            emitCTICall(i, Machine::cti_op_negate);
+            emitCTICall(instruction + i, i, Machine::cti_op_negate);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -1480,7 +1489,7 @@ void CTI::privateCompileMainPass()
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
             emitPutArgConstant(instruction[i + 3].u.operand + m_codeBlock->needsFullScopeChain, 4);
-            emitCTICall(i, Machine::cti_op_resolve_skip);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve_skip);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -1510,7 +1519,7 @@ void CTI::privateCompileMainPass()
             emitPutArgConstant(globalObject, 0);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
             emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 8);
-            emitCTICall(i, Machine::cti_op_resolve_global);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve_global);
             emitPutResult(instruction[i + 1].u.operand);
             m_jit.link(end, m_jit.label());
             i += 6;
@@ -1741,7 +1750,7 @@ void CTI::privateCompileMainPass()
         case op_resolve_with_base: {
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
-            emitCTICall(i, Machine::cti_op_resolve_with_base);
+            emitCTICall(instruction + i, i, Machine::cti_op_resolve_with_base);
             emitPutResult(instruction[i + 1].u.operand);
             emitPutResult(instruction[i + 2].u.operand, X86::edx);
             i += 4;
@@ -1750,7 +1759,7 @@ void CTI::privateCompileMainPass()
         case op_new_func_exp: {
             FuncExprNode* func = (m_codeBlock->functionExpressions[instruction[i + 2].u.operand]).get();
             emitPutArgConstant(reinterpret_cast<unsigned>(func), 0);
-            emitCTICall(i, Machine::cti_op_new_func_exp);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_func_exp);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -1830,7 +1839,7 @@ void CTI::privateCompileMainPass()
         case op_new_regexp: {
             RegExp* regExp = m_codeBlock->regexps[instruction[i + 2].u.operand].get();
             emitPutArgConstant(reinterpret_cast<unsigned>(regExp), 0);
-            emitCTICall(i, Machine::cti_op_new_regexp);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_regexp);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -1845,13 +1854,13 @@ void CTI::privateCompileMainPass()
             break;
         }
         case op_call_eval: {
-            compileOpCall(instruction + i, i, callLinkInfoIndex++, OpCallEval);
+            compileOpCall(opcodeID, instruction + i, i, callLinkInfoIndex++);
             i += 7;
             break;
         }
         case op_throw: {
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
-            emitCTICall(i, Machine::cti_op_throw);
+            emitCTICall(instruction + i, i, Machine::cti_op_throw);
             m_jit.addl_i8r(0x20, X86::esp);
             m_jit.popl_r(X86::ebx);
             m_jit.popl_r(X86::edi);
@@ -1862,7 +1871,7 @@ void CTI::privateCompileMainPass()
         }
         case op_get_pnames: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
-            emitCTICall(i, Machine::cti_op_get_pnames);
+            emitCTICall(instruction + i, i, Machine::cti_op_get_pnames);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -1870,7 +1879,7 @@ void CTI::privateCompileMainPass()
         case op_next_pname: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             unsigned target = instruction[i + 3].u.operand;
-            emitCTICall(i, Machine::cti_op_next_pname);
+            emitCTICall(instruction + i, i, Machine::cti_op_next_pname);
             m_jit.testl_rr(X86::eax, X86::eax);
             X86Assembler::JmpSrc endOfIter = m_jit.emitUnlinkedJe();
             emitPutResult(instruction[i + 1].u.operand);
@@ -1881,12 +1890,12 @@ void CTI::privateCompileMainPass()
         }
         case op_push_scope: {
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
-            emitCTICall(i, Machine::cti_op_push_scope);
+            emitCTICall(instruction + i, i, Machine::cti_op_push_scope);
             i += 2;
             break;
         }
         case op_pop_scope: {
-            emitCTICall(i, Machine::cti_op_pop_scope);
+            emitCTICall(instruction + i, i, Machine::cti_op_pop_scope);
             i += 1;
             break;
         }
@@ -1929,7 +1938,7 @@ void CTI::privateCompileMainPass()
         case op_in: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
-            emitCTICall(i, Machine::cti_op_in);
+            emitCTICall(instruction + i, i, Machine::cti_op_in);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -1938,7 +1947,7 @@ void CTI::privateCompileMainPass()
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 0);
             emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
-            emitCTICall(i, Machine::cti_op_push_new_scope);
+            emitCTICall(instruction + i, i, Machine::cti_op_push_new_scope);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -1952,7 +1961,7 @@ void CTI::privateCompileMainPass()
         case op_jmp_scopes: {
             unsigned count = instruction[i + 1].u.operand;
             emitPutArgConstant(count, 0);
-            emitCTICall(i, Machine::cti_op_jmp_scopes);
+            emitCTICall(instruction + i, i, Machine::cti_op_jmp_scopes);
             unsigned target = instruction[i + 2].u.operand;
             m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJmp(), i + 2 + target));
             i += 3;
@@ -1962,7 +1971,7 @@ void CTI::privateCompileMainPass()
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
             emitPutArgConstant(instruction[i + 2].u.operand, 4);
             emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
-            emitCTICall(i, Machine::cti_op_put_by_index);
+            emitCTICall(instruction + i, i, Machine::cti_op_put_by_index);
             i += 4;
             break;
         }
@@ -1978,7 +1987,7 @@ void CTI::privateCompileMainPass()
 
             emitGetPutArg(scrutinee, 0, X86::ecx);
             emitPutArgConstant(tableIndex, 4);
-            emitCTICall(i, Machine::cti_op_switch_imm);
+            emitCTICall(instruction + i, i, Machine::cti_op_switch_imm);
             m_jit.jmp_r(X86::eax);
             i += 4;
             break;
@@ -1995,7 +2004,7 @@ void CTI::privateCompileMainPass()
 
             emitGetPutArg(scrutinee, 0, X86::ecx);
             emitPutArgConstant(tableIndex, 4);
-            emitCTICall(i, Machine::cti_op_switch_char);
+            emitCTICall(instruction + i, i, Machine::cti_op_switch_char);
             m_jit.jmp_r(X86::eax);
             i += 4;
             break;
@@ -2011,7 +2020,7 @@ void CTI::privateCompileMainPass()
 
             emitGetPutArg(scrutinee, 0, X86::ecx);
             emitPutArgConstant(tableIndex, 4);
-            emitCTICall(i, Machine::cti_op_switch_string);
+            emitCTICall(instruction + i, i, Machine::cti_op_switch_string);
             m_jit.jmp_r(X86::eax);
             i += 4;
             break;
@@ -2019,7 +2028,7 @@ void CTI::privateCompileMainPass()
         case op_del_by_val: {
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
-            emitCTICall(i, Machine::cti_op_del_by_val);
+            emitCTICall(instruction + i, i, Machine::cti_op_del_by_val);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2029,7 +2038,7 @@ void CTI::privateCompileMainPass()
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
             emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
-            emitCTICall(i, Machine::cti_op_put_getter);
+            emitCTICall(instruction + i, i, Machine::cti_op_put_getter);
             i += 4;
             break;
         }
@@ -2038,7 +2047,7 @@ void CTI::privateCompileMainPass()
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 2].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
             emitGetPutArg(instruction[i + 3].u.operand, 8, X86::ecx);
-            emitCTICall(i, Machine::cti_op_put_setter);
+            emitCTICall(instruction + i, i, Machine::cti_op_put_setter);
             i += 4;
             break;
         }
@@ -2047,7 +2056,7 @@ void CTI::privateCompileMainPass()
             emitPutArgConstant(instruction[i + 2].u.operand, 0);
             emitPutArgConstant(asInteger(message), 4);
             emitPutArgConstant(m_codeBlock->lineNumberForVPC(&instruction[i]), 8);
-            emitCTICall(i, Machine::cti_op_new_error);
+            emitCTICall(instruction + i, i, Machine::cti_op_new_error);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2056,7 +2065,7 @@ void CTI::privateCompileMainPass()
             emitPutArgConstant(instruction[i + 1].u.operand, 0);
             emitPutArgConstant(instruction[i + 2].u.operand, 4);
             emitPutArgConstant(instruction[i + 3].u.operand, 8);
-            emitCTICall(i, Machine::cti_op_debug);
+            emitCTICall(instruction + i, i, Machine::cti_op_debug);
             i += 4;
             break;
         }
@@ -2139,14 +2148,14 @@ void CTI::privateCompileMainPass()
             for (size_t j = 0; j < count; ++j)
                 emitInitRegister(j);
 
-            emitCTICall(i, Machine::cti_op_push_activation);
+            emitCTICall(instruction + i, i, Machine::cti_op_push_activation);
             emitPutResult(instruction[i + 1].u.operand);
 
             i+= 2;
             break;
         }
         case op_create_arguments: {
-            emitCTICall(i, (m_codeBlock->numParameters == 1) ? Machine::cti_op_create_arguments_no_params : Machine::cti_op_create_arguments);
+            emitCTICall(instruction + i, i, (m_codeBlock->numParameters == 1) ? Machine::cti_op_create_arguments_no_params : Machine::cti_op_create_arguments);
             i += 1;
             break;
         }
@@ -2166,7 +2175,7 @@ void CTI::privateCompileMainPass()
             m_jit.cmpl_i32m(0, X86::eax);
             X86Assembler::JmpSrc noProfiler = m_jit.emitUnlinkedJe();
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::eax);
-            emitCTICall(i, Machine::cti_op_profile_will_call);
+            emitCTICall(instruction + i, i, Machine::cti_op_profile_will_call);
             m_jit.link(noProfiler, m_jit.label());
 
             i += 2;
@@ -2177,7 +2186,7 @@ void CTI::privateCompileMainPass()
             m_jit.cmpl_i32m(0, X86::eax);
             X86Assembler::JmpSrc noProfiler = m_jit.emitUnlinkedJe();
             emitGetPutArg(instruction[i + 1].u.operand, 0, X86::eax);
-            emitCTICall(i, Machine::cti_op_profile_did_call);
+            emitCTICall(instruction + i, i, Machine::cti_op_profile_did_call);
             m_jit.link(noProfiler, m_jit.label());
 
             i += 2;
@@ -2214,7 +2223,7 @@ void CTI::privateCompileLinkPass()
         m_jit.link(iter->from, m_jit.label()); \
         emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx); \
         emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx); \
-        emitCTICall(i, Machine::cti_##name); \
+        emitCTICall(instruction + i, i, Machine::cti_##name); \
         emitPutResult(instruction[i + 1].u.operand); \
         i += 4; \
         break; \
@@ -2233,7 +2242,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             m_jit.link((++iter)->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_convert_this);
+            emitCTICall(instruction + i, i, Machine::cti_op_convert_this);
             emitPutResult(instruction[i + 1].u.operand);
             i += 2;
             break;
@@ -2249,7 +2258,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(notImm, m_jit.label());
                 emitGetPutArg(src1, 0, X86::ecx);
                 emitPutArg(X86::edx, 4);
-                emitCTICall(i, Machine::cti_op_add);
+                emitCTICall(instruction + i, i, Machine::cti_op_add);
                 emitPutResult(dst);
             } else if (JSValue* value = getConstantImmediateNumericArg(src2)) {
                 X86Assembler::JmpSrc notImm = iter->from;
@@ -2258,12 +2267,12 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(notImm, m_jit.label());
                 emitPutArg(X86::eax, 0);
                 emitGetPutArg(src2, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_add);
+                emitCTICall(instruction + i, i, Machine::cti_op_add);
                 emitPutResult(dst);
             } else {
                 OperandTypes types = OperandTypes::fromInt(instruction[i + 4].u.operand);
                 if (types.first().mightBeNumber() && types.second().mightBeNumber())
-                    compileBinaryArithOpSlowCase(op_add, iter, dst, src1, src2, types, i);
+                    compileBinaryArithOpSlowCase(instruction, op_add, iter, dst, src1, src2, types, i);
                 else
                     ASSERT_NOT_REACHED();
             }
@@ -2282,7 +2291,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(notImm, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
-            emitCTICall(i, Machine::cti_op_get_by_val);
+            emitCTICall(instruction + i, i, Machine::cti_op_get_by_val);
             emitPutResult(instruction[i + 1].u.operand);
             m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 4]);
 
@@ -2303,7 +2312,7 @@ void CTI::privateCompileSlowCases()
             break;
         }
         case op_sub: {
-            compileBinaryArithOpSlowCase(op_sub, iter, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
+            compileBinaryArithOpSlowCase(instruction, op_sub, iter, instruction[i + 1].u.operand, instruction[i + 2].u.operand, instruction[i + 3].u.operand, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
             i += 5;
             break;
         }
@@ -2312,7 +2321,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link((++iter)->from, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::ecx, 4);
-            emitCTICall(i, Machine::cti_op_rshift);
+            emitCTICall(instruction + i, i, Machine::cti_op_rshift);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2327,13 +2336,13 @@ void CTI::privateCompileSlowCases()
             m_jit.link(notImm2, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::ecx, 4);
-            emitCTICall(i, Machine::cti_op_lshift);
+            emitCTICall(instruction + i, i, Machine::cti_op_lshift);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
         }
         case op_loop_if_less: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 3].u.operand;
             JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
@@ -2341,7 +2350,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(iter->from, m_jit.label());
                 emitPutArg(X86::edx, 0);
                 emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_loop_if_less);
+                emitCTICall(instruction + i, i, Machine::cti_op_loop_if_less);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
             } else {
@@ -2349,7 +2358,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link((++iter)->from, m_jit.label());
                 emitPutArg(X86::eax, 0);
                 emitPutArg(X86::edx, 4);
-                emitCTICall(i, Machine::cti_op_loop_if_less);
+                emitCTICall(instruction + i, i, Machine::cti_op_loop_if_less);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
             }
@@ -2364,7 +2373,7 @@ void CTI::privateCompileSlowCases()
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 8);
-            X86Assembler::JmpSrc call = emitCTICall(i, Machine::cti_op_put_by_id);
+            X86Assembler::JmpSrc call = emitCTICall(instruction + i, i, Machine::cti_op_put_by_id);
 
             // Track the location of the call; this will be used to recover repatch information.
             ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
@@ -2390,7 +2399,7 @@ void CTI::privateCompileSlowCases()
             emitPutArg(X86::eax, 0);
             Identifier* ident = &(m_codeBlock->identifiers[instruction[i + 3].u.operand]);
             emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
-            X86Assembler::JmpSrc call = emitCTICall(i, Machine::cti_op_get_by_id);
+            X86Assembler::JmpSrc call = emitCTICall(instruction + i, i, Machine::cti_op_get_by_id);
             ASSERT(X86Assembler::getDifferenceBetweenLabels(coldPathBegin, call) == repatchOffsetGetByIdSlowCaseCall);
             emitPutResult(instruction[i + 1].u.operand);
 
@@ -2403,7 +2412,7 @@ void CTI::privateCompileSlowCases()
             break;
         }
         case op_loop_if_lesseq: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             unsigned target = instruction[i + 3].u.operand;
             JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
@@ -2411,7 +2420,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(iter->from, m_jit.label());
                 emitPutArg(X86::edx, 0);
                 emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_loop_if_lesseq);
+                emitCTICall(instruction + i, i, Machine::cti_op_loop_if_lesseq);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
             } else {
@@ -2419,7 +2428,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link((++iter)->from, m_jit.label());
                 emitPutArg(X86::eax, 0);
                 emitPutArg(X86::edx, 4);
-                emitCTICall(i, Machine::cti_op_loop_if_lesseq);
+                emitCTICall(instruction + i, i, Machine::cti_op_loop_if_lesseq);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
             }
@@ -2433,7 +2442,7 @@ void CTI::privateCompileSlowCases()
             m_jit.subl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
             m_jit.link(notImm, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_pre_inc);
+            emitCTICall(instruction + i, i, Machine::cti_op_pre_inc);
             emitPutResult(srcDst);
             i += 2;
             break;
@@ -2449,7 +2458,7 @@ void CTI::privateCompileSlowCases()
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
             emitPutArg(X86::ecx, 8);
-            emitCTICall(i, Machine::cti_op_put_by_val);
+            emitCTICall(instruction + i, i, Machine::cti_op_put_by_val);
             m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 4]);
 
             // slow cases for immediate int accesses to arrays
@@ -2459,17 +2468,17 @@ void CTI::privateCompileSlowCases()
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
             emitPutArg(X86::ecx, 8);
-            emitCTICall(i, Machine::cti_op_put_by_val_array);
+            emitCTICall(instruction + i, i, Machine::cti_op_put_by_val_array);
 
             i += 4;
             break;
         }
         case op_loop_if_true: {
-            emitSlowScriptCheck(i);
+            emitSlowScriptCheck(instruction, i);
 
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_jtrue);
+            emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
             m_jit.testl_rr(X86::eax, X86::eax);
             unsigned target = instruction[i + 2].u.operand;
             m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
@@ -2483,7 +2492,7 @@ void CTI::privateCompileSlowCases()
             m_jit.addl_i8r(getDeTaggedConstantImmediate(JSImmediate::oneImmediate()), X86::eax);
             m_jit.link(notImm, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_pre_dec);
+            emitCTICall(instruction + i, i, Machine::cti_op_pre_dec);
             emitPutResult(srcDst);
             i += 2;
             break;
@@ -2495,7 +2504,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(iter->from, m_jit.label());
                 emitPutArg(X86::edx, 0);
                 emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_jless);
+                emitCTICall(instruction + i, i, Machine::cti_op_jless);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
             } else {
@@ -2503,7 +2512,7 @@ void CTI::privateCompileSlowCases()
                 m_jit.link((++iter)->from, m_jit.label());
                 emitPutArg(X86::eax, 0);
                 emitPutArg(X86::edx, 4);
-                emitCTICall(i, Machine::cti_op_jless);
+                emitCTICall(instruction + i, i, Machine::cti_op_jless);
                 m_jit.testl_rr(X86::eax, X86::eax);
                 m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 3 + target]);
             }
@@ -2514,7 +2523,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             m_jit.xorl_i8r(JSImmediate::FullTagTypeBool, X86::eax);
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_not);
+            emitCTICall(instruction + i, i, Machine::cti_op_not);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -2522,7 +2531,7 @@ void CTI::privateCompileSlowCases()
         case op_jfalse: {
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_jtrue);
+            emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
             m_jit.testl_rr(X86::eax, X86::eax);
             unsigned target = instruction[i + 2].u.operand;
             m_jit.link(m_jit.emitUnlinkedJe(), m_labels[i + 2 + target]); // inverted!
@@ -2534,7 +2543,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             m_jit.link((++iter)->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_post_inc);
+            emitCTICall(instruction + i, i, Machine::cti_op_post_inc);
             emitPutResult(instruction[i + 1].u.operand);
             emitPutResult(srcDst, X86::edx);
             i += 3;
@@ -2543,7 +2552,7 @@ void CTI::privateCompileSlowCases()
         case op_bitnot: {
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_bitnot);
+            emitCTICall(instruction + i, i, Machine::cti_op_bitnot);
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
             break;
@@ -2556,19 +2565,19 @@ void CTI::privateCompileSlowCases()
                 m_jit.link(iter->from, m_jit.label());
                 emitGetPutArg(src1, 0, X86::ecx);
                 emitPutArg(X86::eax, 4);
-                emitCTICall(i, Machine::cti_op_bitand);
+                emitCTICall(instruction + i, i, Machine::cti_op_bitand);
                 emitPutResult(dst);
             } else if (getConstantImmediateNumericArg(src2)) {
                 m_jit.link(iter->from, m_jit.label());
                 emitPutArg(X86::eax, 0);
                 emitGetPutArg(src2, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_bitand);
+                emitCTICall(instruction + i, i, Machine::cti_op_bitand);
                 emitPutResult(dst);
             } else {
                 m_jit.link(iter->from, m_jit.label());
                 emitGetPutArg(src1, 0, X86::ecx);
                 emitPutArg(X86::edx, 4);
-                emitCTICall(i, Machine::cti_op_bitand);
+                emitCTICall(instruction + i, i, Machine::cti_op_bitand);
                 emitPutResult(dst);
             }
             i += 5;
@@ -2577,7 +2586,7 @@ void CTI::privateCompileSlowCases()
         case op_jtrue: {
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_jtrue);
+            emitCTICall(instruction + i, i, Machine::cti_op_jtrue);
             m_jit.testl_rr(X86::eax, X86::eax);
             unsigned target = instruction[i + 2].u.operand;
             m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 2 + target]);
@@ -2589,7 +2598,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             m_jit.link((++iter)->from, m_jit.label());
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_post_dec);
+            emitCTICall(instruction + i, i, Machine::cti_op_post_dec);
             emitPutResult(instruction[i + 1].u.operand);
             emitPutResult(srcDst, X86::edx);
             i += 3;
@@ -2599,7 +2608,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
-            emitCTICall(i, Machine::cti_op_bitxor);
+            emitCTICall(instruction + i, i, Machine::cti_op_bitxor);
             emitPutResult(instruction[i + 1].u.operand);
             i += 5;
             break;
@@ -2608,7 +2617,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
-            emitCTICall(i, Machine::cti_op_bitor);
+            emitCTICall(instruction + i, i, Machine::cti_op_bitor);
             emitPutResult(instruction[i + 1].u.operand);
             i += 5;
             break;
@@ -2617,7 +2626,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
-            emitCTICall(i, Machine::cti_op_eq);
+            emitCTICall(instruction + i, i, Machine::cti_op_eq);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2626,7 +2635,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::edx, 4);
-            emitCTICall(i, Machine::cti_op_neq);
+            emitCTICall(instruction + i, i, Machine::cti_op_neq);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2638,7 +2647,7 @@ void CTI::privateCompileSlowCases()
             emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
             emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
             emitGetPutArg(instruction[i + 4].u.operand, 8, X86::ecx);
-            emitCTICall(i, Machine::cti_op_instanceof);
+            emitCTICall(instruction + i, i, Machine::cti_op_instanceof);
             emitPutResult(instruction[i + 1].u.operand);
             i += 5;
             break;
@@ -2653,7 +2662,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(notImm2, m_jit.label());
             emitPutArg(X86::eax, 0);
             emitPutArg(X86::ecx, 4);
-            emitCTICall(i, Machine::cti_op_mod);
+            emitCTICall(instruction + i, i, Machine::cti_op_mod);
             emitPutResult(instruction[i + 1].u.operand);
             i += 4;
             break;
@@ -2670,17 +2679,17 @@ void CTI::privateCompileSlowCases()
                 // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
                 emitGetPutArg(src1, 0, X86::ecx);
                 emitGetPutArg(src2, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_mul);
+                emitCTICall(instruction + i, i, Machine::cti_op_mul);
                 emitPutResult(dst);
             } else if (src2Value && ((value = JSImmediate::intValue(src2Value)) > 0)) {
                 m_jit.link(iter->from, m_jit.label());
                 // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
                 emitGetPutArg(src1, 0, X86::ecx);
                 emitGetPutArg(src2, 4, X86::ecx);
-                emitCTICall(i, Machine::cti_op_mul);
+                emitCTICall(instruction + i, i, Machine::cti_op_mul);
                 emitPutResult(dst);
             } else
-                compileBinaryArithOpSlowCase(op_mul, iter, dst, src1, src2, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
+                compileBinaryArithOpSlowCase(instruction, op_mul, iter, dst, src1, src2, OperandTypes::fromInt(instruction[i + 4].u.operand), i);
             i += 5;
             break;
         }
@@ -2705,7 +2714,7 @@ void CTI::privateCompileSlowCases()
             X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
 
             // This handles JSFunctions
-            emitCTICall(i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
+            emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
             // initialize the new call frame (pointed to by edx, after the last call), then set edi to point to it.
             compileOpCallInitializeCallFrame(callee, argCount);
             m_jit.movl_rr(X86::edx, X86::edi);
@@ -2714,7 +2723,7 @@ void CTI::privateCompileSlowCases()
             CallLinkInfo* info = &(m_codeBlock->callLinkInfos[callLinkInfoIndex]);
             emitPutArgConstant(reinterpret_cast<unsigned>(info), 4);
             m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
-                emitCTICall(i, Machine::cti_vm_lazyLinkCall);
+                emitCTICall(instruction + i, i, Machine::cti_vm_lazyLinkCall);
             emitNakedCall(i, X86::eax);
             X86Assembler::JmpSrc storeResultForFirstRun = m_jit.emitUnlinkedJmp();
 
@@ -2736,12 +2745,12 @@ void CTI::privateCompileSlowCases()
             m_jit.link(isNotObject, notJSFunctionlabel);
             m_jit.link(callLinkFailNotObject, notJSFunctionlabel);
             m_jit.link(callLinkFailNotJSFunction, notJSFunctionlabel);
-            emitCTICall(i, ((opcodeID == op_construct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
+            emitCTICall(instruction + i, i, ((opcodeID == op_construct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
             X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
 
             // Next, handle JSFunctions...
             m_jit.link(isJSFunction, m_jit.label());
-            emitCTICall(i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
+            emitCTICall(instruction + i, i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
             // initialize the new call frame (pointed to by edx, after the last call).
             compileOpCallInitializeCallFrame(callee, argCount);
             m_jit.movl_rr(X86::edx, X86::edi);
@@ -2755,7 +2764,7 @@ void CTI::privateCompileSlowCases()
             // Check the ctiCode has been generated (if not compile it now), and make the call.
             m_jit.testl_rr(X86::eax, X86::eax);
             X86Assembler::JmpSrc hasCode = m_jit.emitUnlinkedJne();
-            emitCTICall(i, Machine::cti_vm_compile);
+            emitCTICall(instruction + i, i, Machine::cti_vm_compile);
             m_jit.link(hasCode, m_jit.label());
 
             emitNakedCall(i, X86::eax);
@@ -2766,7 +2775,11 @@ void CTI::privateCompileSlowCases()
             m_jit.link(storeResultForFirstRun, storeResult);
             emitPutResult(dst);
 
+#if ENABLE(CODEBLOCK_SAMPLING)
+            m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
+#endif
             ++callLinkInfoIndex;
+
             i += 7;
             break;
         }
@@ -2775,7 +2788,7 @@ void CTI::privateCompileSlowCases()
             m_jit.link(iter->from, m_jit.label());
 
             emitPutArg(X86::eax, 0);
-            emitCTICall(i, Machine::cti_op_to_jsnumber);
+            emitCTICall(instruction + i, i, Machine::cti_op_to_jsnumber);
 
             emitPutResult(instruction[i + 1].u.operand);
             i += 3;
@@ -2796,6 +2809,13 @@ void CTI::privateCompileSlowCases()
 
 void CTI::privateCompile()
 {
+#if ENABLE(CODEBLOCK_SAMPLING)
+        m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_machine->sampler()->codeBlockSlot());
+#endif
+#if ENABLE(OPCODE_SAMPLING)
+        m_jit.movl_i32m(m_machine->sampler()->encodeSample(m_codeBlock->instructions.begin()), m_machine->sampler()->sampleSlot());
+#endif
+
     // Could use a popl_m, but would need to offset the following instruction if so.
     m_jit.popl_r(X86::ecx);
     emitPutToCallFrameHeader(X86::ecx, RegisterFile::ReturnPC);
@@ -2819,7 +2839,7 @@ void CTI::privateCompile()
 
     if (m_codeBlock->codeType == FunctionCode) {
         m_jit.link(slowRegisterFileCheck, m_jit.label());
-        emitCTICall(0, Machine::cti_register_file_check);
+        emitCTICall(m_codeBlock->instructions.begin(), 0, Machine::cti_register_file_check);
         X86Assembler::JmpSrc backToBody = m_jit.emitUnlinkedJmp();
         m_jit.link(backToBody, afterRegisterFileCheck);
     }
index ee6d596..66f34a0 100644 (file)
@@ -266,7 +266,7 @@ namespace JSC {
         static const int repatchOffsetGetByIdStructureID = 19;
         static const int repatchOffsetGetByIdBranchToSlowCase = 25;
         static const int repatchOffsetGetByIdPropertyMapOffset = 34;
-#if ENABLE(SAMPLING_TOOL)
+#if ENABLE(OPCODE_SAMPLING)
         static const int repatchOffsetGetByIdSlowCaseCall = 27 + 4 + ctiArgumentInitSize;
 #else
         static const int repatchOffsetGetByIdSlowCaseCall = 17 + 4 + ctiArgumentInitSize;
@@ -365,15 +365,14 @@ namespace JSC {
         void* privateCompileStringLengthTrampoline();
         void privateCompilePatchGetArrayLength(void* returnAddress);
 
-        enum CompileOpCallType { OpCallNormal, OpCallEval, OpConstruct };
-        void compileOpCall(Instruction* instruction, unsigned i, unsigned structureIDInstructionIndex, CompileOpCallType type = OpCallNormal);
+        void compileOpCall(OpcodeID, Instruction* instruction, unsigned i, unsigned callLinkInfoIndex);
         void compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount);
         void compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval);
         enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq };
         void compileOpStrictEq(Instruction* instruction, unsigned i, CompileOpStrictEqType type);
         void putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, X86Assembler::JmpSrc* wroteJSNumberCell,  X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2);
         void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
-        void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
+        void compileBinaryArithOpSlowCase(Instruction*, OpcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi, unsigned i);
 
         void emitGetArg(int src, X86Assembler::RegisterID dst);
         void emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch);
@@ -411,18 +410,18 @@ namespace JSC {
 
         X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, X86::RegisterID);
         X86Assembler::JmpSrc emitNakedCall(unsigned opcodeIndex, void(*function)());
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_j);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_o);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_p);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_v);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_s);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_b);
-        X86Assembler::JmpSrc emitCTICall(unsigned opcodeIndex, CTIHelper_2);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_j);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_o);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_p);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_v);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_s);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_b);
+        X86Assembler::JmpSrc emitCTICall(Instruction*, unsigned opcodeIndex, CTIHelper_2);
 
         void emitGetVariableObjectRegister(X86Assembler::RegisterID variableObject, int index, X86Assembler::RegisterID dst);
         void emitPutVariableObjectRegister(X86Assembler::RegisterID src, X86Assembler::RegisterID variableObject, int index);
         
-        void emitSlowScriptCheck(unsigned opcodeIndex);
+        void emitSlowScriptCheck(Instruction*, unsigned opcodeIndex);
 #ifndef NDEBUG
         void printOpcodeOperandTypes(unsigned src1, unsigned src2);
 #endif
index 603a2a8..3bd2468 100644 (file)
@@ -39,7 +39,7 @@
 
 namespace JSC {
 
-#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
+#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
 
 static UString escapeQuotes(const UString& str)
 {
@@ -946,7 +946,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
     }
 }
 
-#endif // !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
+#endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
 
 CodeBlock::~CodeBlock()
 {
@@ -1110,12 +1110,11 @@ void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
 
 int CodeBlock::lineNumberForVPC(const Instruction* vPC)
 {
-    ASSERT(lineInfo.size());    
     unsigned instructionOffset = vPC - instructions.begin();
     ASSERT(instructionOffset < instructions.size());
 
     if (!lineInfo.size())
-        return 1; // Empty function
+        return ownerNode->source().firstLine(); // Empty function
 
     int low = 0;
     int high = lineInfo.size();
@@ -1126,6 +1125,9 @@ int CodeBlock::lineNumberForVPC(const Instruction* vPC)
         else
             high = mid;
     }
+    
+    if (!low)
+        return ownerNode->source().firstLine();
     return lineInfo[low - 1].lineNumber;
 }
 
index ce93812..7e7146c 100644 (file)
@@ -289,7 +289,7 @@ namespace JSC {
             linkedCallerList.shrink(lastPos);
         }
 
-#if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
+#if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING
         void dump(ExecState*) const;
         void printStructureIDs(const Instruction*) const;
         void printStructureID(const char* name, const Instruction*, int operand) const;
@@ -361,7 +361,7 @@ namespace JSC {
         EvalCodeCache evalCodeCache;
 
     private:
-#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
+#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
         void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
 #endif
 
index be1941c..b15c45d 100644 (file)
@@ -923,17 +923,20 @@ JSValue* Machine::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeC
     if (*profiler)
         (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo());
 
-    m_reentryDepth++;
+    JSValue* result;
+    {
+        SamplingTool::CallRecord callRecord(m_sampler);
+
+        m_reentryDepth++;
 #if ENABLE(CTI)
-    if (!codeBlock->ctiCode)
-        CTI::compile(this, newCallFrame, codeBlock);
-    JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+        if (!codeBlock->ctiCode)
+            CTI::compile(this, newCallFrame, codeBlock);
+        result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
 #else
-    JSValue* result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+        result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
 #endif
-    m_reentryDepth--;
-
-    MACHINE_SAMPLING_privateExecuteReturned();
+        m_reentryDepth--;
+    }
 
     if (*profiler)
         (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo());
@@ -986,21 +989,24 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFra
     if (*profiler)
         (*profiler)->willExecute(newCallFrame, function);
 
-    m_reentryDepth++;
+    JSValue* result;
+    {
+        SamplingTool::CallRecord callRecord(m_sampler);
+
+        m_reentryDepth++;
 #if ENABLE(CTI)
-    if (!codeBlock->ctiCode)
-        CTI::compile(this, newCallFrame, codeBlock);
-    JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+        if (!codeBlock->ctiCode)
+            CTI::compile(this, newCallFrame, codeBlock);
+        result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
 #else
-    JSValue* result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+        result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
 #endif
-    m_reentryDepth--;
+        m_reentryDepth--;
+    }
 
     if (*profiler)
         (*profiler)->didExecute(newCallFrame, function);
 
-    MACHINE_SAMPLING_privateExecuteReturned();
-
     m_registerFile.shrink(oldEnd);
     return result;
 }
@@ -1075,17 +1081,20 @@ JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* th
     if (*profiler)
         (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo());
 
-    m_reentryDepth++;
+    JSValue* result;
+    {
+        SamplingTool::CallRecord callRecord(m_sampler);
+
+        m_reentryDepth++;
 #if ENABLE(CTI)
-    if (!codeBlock->ctiCode)
-        CTI::compile(this, newCallFrame, codeBlock);
-    JSValue* result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
+        if (!codeBlock->ctiCode)
+            CTI::compile(this, newCallFrame, codeBlock);
+        result = CTI::execute(codeBlock->ctiCode, &m_registerFile, newCallFrame, scopeChain->globalData, exception);
 #else
-    JSValue* result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
+        result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
 #endif
-    m_reentryDepth--;
-
-    MACHINE_SAMPLING_privateExecuteReturned();
+        m_reentryDepth--;
+    }
 
     if (*profiler)
         (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo());
@@ -1472,7 +1481,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         } \
     } while (0)
 
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
     OpcodeStats::resetLastInstruction();
 #endif
 
@@ -1482,18 +1491,26 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
             goto vm_throw; \
         tickCount = m_ticksUntilNextTimeoutCheck; \
     }
+    
+#if ENABLE(OPCODE_SAMPLING)
+    #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
+    #define CTI_SAMPLER ARG_globalData->machine->sampler()
+#else
+    #define SAMPLE(codeBlock, vPC)
+    #define CTI_SAMPLER
+#endif
 
 #if HAVE(COMPUTED_GOTO)
-    #define NEXT_OPCODE MACHINE_SAMPLING_sample(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
-#if DUMP_OPCODE_STATS
+    #define NEXT_OPCODE SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
+#if ENABLE(OPCODE_STATS)
     #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
 #else
     #define BEGIN_OPCODE(opcode) opcode:
 #endif
     NEXT_OPCODE;
 #else
-    #define NEXT_OPCODE MACHINE_SAMPLING_sample(callFrame->codeBlock(), vPC); goto interpreterLoopStart
-#if DUMP_OPCODE_STATS
+    #define NEXT_OPCODE SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
+#if ENABLE(OPCODE_STATS)
     #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
 #else
     #define BEGIN_OPCODE(opcode) case opcode:
@@ -2958,7 +2975,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
            Additionally this loop instruction may terminate JS execution is
            the JS timeout is reached.
          */
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
         OpcodeStats::resetLastInstruction();
 #endif
         int target = (++vPC)->u.operand;
@@ -2972,7 +2989,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
            Jumps unconditionally to offset target from the current
            instruction.
         */
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
         OpcodeStats::resetLastInstruction();
 #endif
         int target = (++vPC)->u.operand;
@@ -3353,7 +3370,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
             callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
             vPC = newCodeBlock->instructions.begin();
 
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
             OpcodeStats::resetLastInstruction();
 #endif
 
@@ -3368,9 +3385,11 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
             CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
             newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
 
-            MACHINE_SAMPLING_callingHostFunction();
-
-            JSValue* returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+            JSValue* returnValue;
+            {
+                SamplingTool::HostCallRecord callRecord(m_sampler);
+                returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
+            }
             VM_CHECK_EXCEPTION();
 
             callFrame[dst] = returnValue;
@@ -3598,7 +3617,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
             callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
             vPC = newCodeBlock->instructions.begin();
 
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
             OpcodeStats::resetLastInstruction();
 #endif
 
@@ -3612,10 +3631,11 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
             CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
             newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
 
-            MACHINE_SAMPLING_callingHostFunction();
-
-            JSValue* returnValue = constructData.native.function(newCallFrame, asObject(v), args);
-
+            JSValue* returnValue;
+            {
+                SamplingTool::HostCallRecord callRecord(m_sampler);
+                returnValue = constructData.native.function(newCallFrame, asObject(v), args);
+            }
             VM_CHECK_EXCEPTION();
             callFrame[dst] = returnValue;
 
@@ -4794,9 +4814,11 @@ JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
         Register* argv = ARG_callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
         ArgList argList(argv + 1, argCount - 1);
 
-        CTI_MACHINE_SAMPLING_callingHostFunction();
-
-        JSValue* returnValue = callData.native.function(callFrame, asObject(funcVal), argv[0].jsValue(callFrame), argList);
+        JSValue* returnValue;
+        {
+            SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
+            returnValue = callData.native.function(callFrame, asObject(funcVal), argv[0].jsValue(callFrame), argList);
+        }
         ARG_setCallFrame(previousCallFrame);
         VM_CHECK_EXCEPTION();
 
@@ -4999,9 +5021,11 @@ JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
     if (constructType == ConstructTypeHost) {
         ArgList argList(callFrame->registers() + firstArg + 1, argCount - 1);
 
-        CTI_MACHINE_SAMPLING_callingHostFunction();
-
-        JSValue* returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
+        JSValue* returnValue;
+        {
+            SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
+            returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
+        }
         VM_CHECK_EXCEPTION();
 
         return returnValue;
index 6568b85..c33ad06 100644 (file)
@@ -157,7 +157,8 @@ namespace JSC {
             m_timeoutCheckCount = 0;
         }
 
-        SamplingTool* m_sampler;
+        void setSampler(SamplingTool* sampler) { m_sampler = sampler; }
+        SamplingTool* sampler() { return m_sampler; }
 
 #if ENABLE(CTI)
 
@@ -318,11 +319,16 @@ namespace JSC {
         void* getCTIArrayLengthTrampoline(CallFrame*, CodeBlock*);
         void* getCTIStringLengthTrampoline(CallFrame*, CodeBlock*);
 
+        JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
+#endif
+
+        SamplingTool* m_sampler;
+
+#if ENABLE(CTI)
         void* m_ctiArrayLengthTrampoline;
         void* m_ctiStringLengthTrampoline;
 
         OwnPtr<JITCodeBuffer> m_jitCodeBuffer;
-        JITCodeBuffer* jitCodeBuffer() const { return m_jitCodeBuffer.get(); }
 #endif
 
         int m_reentryDepth;
index 3993c0b..cc70418 100644 (file)
@@ -34,7 +34,7 @@ using namespace std;
 
 namespace JSC {
 
-#if ENABLE(SAMPLING_TOOL) || DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_SAMPLING) || ENABLE(CODEBLOCK_SAMPLING) || ENABLE(OPCODE_STATS)
 
 const char* const opcodeNames[] = {
 #define OPCODE_NAME_ENTRY(opcode) #opcode,
@@ -44,7 +44,7 @@ const char* const opcodeNames[] = {
 
 #endif
 
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
 
 long long OpcodeStats::opcodeCounts[numOpcodeIDs];
 long long OpcodeStats::opcodePairCounts[numOpcodeIDs][numOpcodeIDs];
@@ -121,7 +121,7 @@ OpcodeStats::~OpcodeStats()
 
     for (int i = 0; i < numOpcodeIDs; ++i) {
         int index = sortedIndices[i];
-        printf("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 24), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0);    
+        printf("%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCounts[index], ((double) opcodeCounts[index]) / ((double) totalInstructions) * 100.0);    
     }
     
     printf("\n");
@@ -134,7 +134,7 @@ OpcodeStats::~OpcodeStats()
         if (!count)
             break;
         
-        printf("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 24), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 24), count, ((double) count) / ((double) totalInstructionPairs) * 100.0);
+        printf("%s%s %s:%s %lld %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), count, ((double) count) / ((double) totalInstructionPairs) * 100.0);
     }
     
     printf("\n");
@@ -146,7 +146,7 @@ OpcodeStats::~OpcodeStats()
         double opcodeProportion = ((double) opcodeCount) / ((double) totalInstructions);
         if (opcodeProportion < 0.0001)
             break;
-        printf("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 24), opcodeCount, opcodeProportion * 100.0);
+        printf("\n%s:%s %lld - %.2f%%\n", opcodeNames[index], padOpcodeName((OpcodeID)index, 28), opcodeCount, opcodeProportion * 100.0);
 
         for (int j = 0; j < numOpcodeIDs * numOpcodeIDs; ++j) {
             pair<int, int> indexPair = sortedPairIndices[j];
@@ -159,7 +159,7 @@ OpcodeStats::~OpcodeStats()
             if (indexPair.first != index && indexPair.second != index)
                 continue;
 
-            printf("    %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 24), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 24), pairCount, pairProportion * 100.0);
+            printf("    %s%s %s:%s %lld - %.2f%%\n", opcodeNames[indexPair.first], padOpcodeName((OpcodeID)indexPair.first, 28), opcodeNames[indexPair.second], padOpcodeName((OpcodeID)indexPair.second, 28), pairCount, pairProportion * 100.0);
         }
         
     }
index cc809bc..fb65cec 100644 (file)
@@ -37,8 +37,6 @@
 
 namespace JSC {
 
-#define DUMP_OPCODE_STATS 0
-
     #define FOR_EACH_OPCODE_ID(macro) \
         macro(op_enter) \
         macro(op_enter_with_activation) \
@@ -182,7 +180,7 @@ namespace JSC {
     typedef OpcodeID Opcode;
 #endif
 
-#if ENABLE(SAMPLING_TOOL) || DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_SAMPLING) || ENABLE(CODEBLOCK_SAMPLING) || ENABLE(OPCODE_STATS)
 
 #define PADDING_STRING "                                "
 #define PADDING_STRING_LENGTH static_cast<unsigned>(strlen(PADDING_STRING))
@@ -201,7 +199,7 @@ namespace JSC {
 
 #endif
 
-#if DUMP_OPCODE_STATS
+#if ENABLE(OPCODE_STATS)
 
     struct OpcodeStats {
         OpcodeStats();
index ca0c15c..47ae39b 100644 (file)
@@ -41,18 +41,19 @@ namespace JSC {
 
 void ScopeSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC)
 {
-    m_totalCount++;
-
     if (!m_vpcCounts) {
         m_size = codeBlock->instructions.size();
         m_vpcCounts = static_cast<int*>(calloc(m_size, sizeof(int)));
         m_codeBlock = codeBlock;
     }
 
-    unsigned codeOffset = static_cast<unsigned>(reinterpret_cast<ptrdiff_t>(vPC) - reinterpret_cast<ptrdiff_t>(codeBlock->instructions.begin())) / sizeof(Instruction*);
-    // This could occur if codeBlock & vPC are not consistent - e.g. sample mid op_call/op_ret.
-    if (codeOffset < m_size)
+    unsigned codeOffset = vPC - codeBlock->instructions.begin();
+    // Since we don't read and write codeBlock and vPC atomically, this check
+    // can fail if we sample mid op_call / op_ret.
+    if (codeOffset < m_size) {
         m_vpcCounts[codeOffset]++;
+        m_totalCount++;
+    }
 }
 
 #if PLATFORM(WIN_OS)
@@ -79,34 +80,32 @@ static inline unsigned hertz2us(unsigned hertz)
     return 1000000 / hertz;
 }
 
-#if ENABLE(SAMPLING_TOOL)
-unsigned totalOpcodeIDCount = 0;
-unsigned opcodeIDCountInCalledCode[numOpcodeIDs] = {0};
-unsigned opcodeIDCountInJITCode[numOpcodeIDs] = {0};
-#endif
-
 void SamplingTool::run()
 {
     while (m_running) {
         sleepForMicroseconds(hertz2us(m_hertz));
 
-        m_totalSamples++;
-#if ENABLE(SAMPLING_TOOL)
-        if (currentOpcodeID != static_cast<OpcodeID>(-1)) {
-            ++totalOpcodeIDCount;
-            if (inCalledCode)
-                opcodeIDCountInCalledCode[currentOpcodeID]++;
-            else
-                opcodeIDCountInJITCode[currentOpcodeID]++;
-        }
-#endif        
-        CodeBlock* codeBlock = m_recordedCodeBlock;
-        Instruction* vPC = m_recordedVPC;
+        Sample sample(m_sample, m_codeBlock);
+        ++m_sampleCount;
+
+        if (sample.isNull())
+            continue;
 
-        if (codeBlock && vPC) {
-            if (ScopeSampleRecord* record = m_scopeSampleMap->get(codeBlock->ownerNode))
-                record->sample(codeBlock, vPC);
+        if (!sample.inHostFunction()) {
+            unsigned opcodeID = m_machine->getOpcodeID(sample.vPC()[0].u.opcode);
+
+            ++m_opcodeSampleCount;
+            ++m_opcodeSamples[opcodeID];
+
+            if (sample.inCTIFunction())
+                m_opcodeSamplesInCTIFunctions[opcodeID]++;
         }
+
+#if ENABLE(CODEBLOCK_SAMPLING)
+        ScopeSampleRecord* record = m_scopeSampleMap->get(sample.codeBlock()->ownerNode);
+        ASSERT(record);
+        record->sample(sample.codeBlock(), sample.vPC());
+#endif
     }
 }
 
@@ -137,12 +136,12 @@ void SamplingTool::stop()
     waitForThreadCompletion(m_samplingThread, 0);
 }
 
-#if ENABLE(SAMPLING_TOOL)
+#if ENABLE(OPCODE_SAMPLING)
 
 struct OpcodeSampleInfo {
     OpcodeID opcode;
     long long count;
-    long long countInCalledCode;
+    long long countInCTIFunctions;
 };
 
 struct LineCountInfo {
@@ -177,40 +176,79 @@ static int compareScopeSampleRecords(const void* left, const void* right)
 void SamplingTool::dump(ExecState* exec)
 {
     // Tidies up SunSpider output by removing short scripts - such a small number of samples would likely not be useful anyhow.
-    if (m_totalSamples < 10)
+    if (m_sampleCount < 10)
         return;
     
-    // (1) Calculate 'totalCodeBlockSamples', build and sort 'codeBlockSamples' array.
+    // (1) Build and sort 'opcodeSampleInfo' array.
+
+    OpcodeSampleInfo opcodeSampleInfo[numOpcodeIDs];
+    for (int i = 0; i < numOpcodeIDs; ++i) {
+        opcodeSampleInfo[i].opcode = static_cast<OpcodeID>(i);
+        opcodeSampleInfo[i].count = m_opcodeSamples[i];
+        opcodeSampleInfo[i].countInCTIFunctions = m_opcodeSamplesInCTIFunctions[i];
+    }
+
+    qsort(opcodeSampleInfo, numOpcodeIDs, sizeof(OpcodeSampleInfo), compareOpcodeIndicesSampling);
+
+    // (2) Print Opcode sampling results.
+
+    printf("\nOpcode samples [*]\n");
+    printf("                             sample   %% of       %% of     |   cti     cti %%\n");
+    printf("opcode                       count     VM        total    |  count   of self\n");
+    printf("-------------------------------------------------------   |  ----------------\n");
+
+    for (int i = 0; i < numOpcodeIDs; ++i) {
+        long long count = opcodeSampleInfo[i].count;
+        if (!count)
+            continue;
+
+        OpcodeID opcode = opcodeSampleInfo[i].opcode;
+        
+        const char* opcodeName = opcodeNames[opcode];
+        const char* opcodePadding = padOpcodeName(opcode, 28);
+        double percentOfVM = (static_cast<double>(count) * 100) / m_opcodeSampleCount;
+        double percentOfTotal = (static_cast<double>(count) * 100) / m_sampleCount;
+        long long countInCTIFunctions = opcodeSampleInfo[i].countInCTIFunctions;
+        double percentInCTIFunctions = (static_cast<double>(countInCTIFunctions) * 100) / count;
+        fprintf(stdout, "%s:%s%-6lld %.3f%%\t%.3f%%\t  |   %-6lld %.3f%%\n", opcodeName, opcodePadding, count, percentOfVM, percentOfTotal, countInCTIFunctions, percentInCTIFunctions);
+    }
+    
+    printf("\n[*] Samples inside host code are not charged to any Opcode.\n\n");
+    printf("\tSamples inside VM:\t\t%lld / %lld (%.3f%%)\n", m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_opcodeSampleCount) * 100) / m_sampleCount);
+    printf("\tSamples inside host code:\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - m_opcodeSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - m_opcodeSampleCount) * 100) / m_sampleCount);
+    printf("\tsample count:\tsamples inside this opcode\n");
+    printf("\t%% of VM:\tsample count / all opcode samples\n");
+    printf("\t%% of total:\tsample count / all samples\n");
+    printf("\t--------------\n");
+    printf("\tcti count:\tsamples inside a CTI function called by this opcode\n");
+    printf("\tcti %% of self:\tcti count / sample count\n");
+    
+    // (3) Calculate 'codeBlockSampleCount', build and sort 'codeBlockSamples' array.
 
     int scopeCount = m_scopeSampleMap->size();
-    long long totalCodeBlockSamples = 0;
+    long long codeBlockSampleCount = 0;
     Vector<ScopeSampleRecord*> codeBlockSamples(scopeCount);
     ScopeSampleRecordMap::iterator iter = m_scopeSampleMap->begin();
     for (int i = 0; i < scopeCount; ++i, ++iter) {
         codeBlockSamples[i] = iter->second;
-        totalCodeBlockSamples += codeBlockSamples[i]->m_totalCount;
+        codeBlockSampleCount += codeBlockSamples[i]->m_totalCount;
     }
 
     qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScopeSampleRecord*), compareScopeSampleRecords);
 
-    // (2) Print data from 'codeBlockSamples' array, calculate 'totalOpcodeSamples', populate 'opcodeSampleCounts' array.
-
-    long long totalOpcodeSamples = 0;
-    long long opcodeSampleCounts[numOpcodeIDs] = { 0 };
+    // (4) Print data from 'codeBlockSamples' array.
 
-    printf("\nBlock sampling results\n\n"); 
-    printf("Total blocks sampled (total samples): %lld (%lld)\n\n", totalCodeBlockSamples, m_totalSamples);
+    printf("\nCodeBlock samples [*]\n\n"); 
 
     for (int i = 0; i < scopeCount; ++i) {
         ScopeSampleRecord* record = codeBlockSamples[i];
         CodeBlock* codeBlock = record->m_codeBlock;
 
-        double totalPercent = (record->m_totalCount * 100.0)/m_totalSamples;
-        double blockPercent = (record->m_totalCount * 100.0)/totalCodeBlockSamples;
+        double blockPercent = (record->m_totalCount * 100.0) / codeBlockSampleCount;
 
-        if ((blockPercent >= 1) && codeBlock) {
+        if (blockPercent >= 1) {
             Instruction* code = codeBlock->instructions.begin();
-            printf("#%d: %s:%d: sampled %d times - %.3f%% (%.3f%%)\n", i + 1, record->m_scope->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForVPC(code), record->m_totalCount, blockPercent, totalPercent);
+            printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_scope->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForVPC(code), record->m_totalCount, codeBlockSampleCount, blockPercent);
             if (i < 10) {
                 HashMap<unsigned,unsigned> lineCounts;
                 codeBlock->dump(exec);
@@ -239,42 +277,11 @@ void SamplingTool::dump(ExecState* exec)
                 printf("\n");
             }
         }
-        
-        if (record->m_vpcCounts && codeBlock) {
-            Instruction* instructions = codeBlock->instructions.begin();
-            for (unsigned op = 0; op < record->m_size; ++op) {
-                Opcode opcode = instructions[op].u.opcode;
-                if (exec->machine()->isOpcode(opcode)) {
-                    totalOpcodeSamples += record->m_vpcCounts[op];
-                    opcodeSampleCounts[exec->machine()->getOpcodeID(opcode)] += record->m_vpcCounts[op];
-                }
-            }
-        }
     }
-    printf("\n");
 
-    // (3) Build and sort 'opcodeSampleInfo' array.
-
-    OpcodeSampleInfo opcodeSampleInfo[numOpcodeIDs];
-    for (int i = 0; i < numOpcodeIDs; ++i) {
-        opcodeSampleInfo[i].opcode = static_cast<OpcodeID>(i);
-        opcodeSampleInfo[i].count = opcodeIDCountInJITCode[i] + opcodeIDCountInCalledCode[i];
-        opcodeSampleInfo[i].countInCalledCode = opcodeIDCountInCalledCode[i];
-    }
-
-    qsort(opcodeSampleInfo, numOpcodeIDs, sizeof(OpcodeSampleInfo), compareOpcodeIndicesSampling);
-
-    // (4) Print Opcode sampling results.
-
-    printf("\nOpcode sampling results\n\n"); 
-
-    for (int i = 0; i < numOpcodeIDs; ++i) {
-        OpcodeID opcode = opcodeSampleInfo[i].opcode;
-        long long count = opcodeSampleInfo[i].count;
-        long long countInCalledCode = opcodeSampleInfo[i].countInCalledCode;
-        fprintf(stdout, "%s:%s%6lld\t%6lld\t%.3f%%\t%.3f%%\t(%.3f%%)\n", opcodeNames[opcode], padOpcodeName(opcode, 20), count, countInCalledCode, (static_cast<double>(count) * 100) / totalOpcodeIDCount, (static_cast<double>(count) * 100) / m_totalSamples, (static_cast<double>(countInCalledCode) * 100) / m_totalSamples);    
-    }
-    printf("\n");
+    printf("\n[*] Samples inside host code are charged to the calling Opcode.\n");
+    printf("    Samples that fall on a call / return boundary are discarded.\n\n");
+    printf("\tSamples discarded:\t\t%lld / %lld (%.3f%%)\n\n", m_sampleCount - codeBlockSampleCount, m_sampleCount, (static_cast<double>(m_sampleCount - codeBlockSampleCount) * 100) / m_sampleCount);
 }
 
 #else
index b788654..1314c70 100644 (file)
 #include <wtf/HashMap.h>
 #include <wtf/Threading.h>
 
-#include <nodes.h>
-#include <Opcode.h>
+#include "nodes.h"
+#include "Opcode.h"
 
 namespace JSC {
 
+    class CodeBlock;
     class ExecState;
+    class Machine;
     class ScopeNode;
-    class CodeBlock;
     struct Instruction;
 
-#if ENABLE(SAMPLING_TOOL)
-    extern OpcodeID currentOpcodeID;
-    extern unsigned inCalledCode;
-#endif
-
     struct ScopeSampleRecord {
         RefPtr<ScopeNode> m_scope;
         CodeBlock* m_codeBlock;
@@ -70,20 +66,74 @@ namespace JSC {
                 free(m_vpcCounts);
         }
         
-        void sample(CodeBlock* codeBlock, Instruction* vPC);
+        void sample(CodeBlock*, Instruction*);
     };
 
     typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap;
 
     class SamplingTool {
     public:
-        SamplingTool()
-            : m_running(false)
-            , m_recordedCodeBlock(0)
-            , m_recordedVPC(0)
-            , m_totalSamples(0)
+        friend class CallRecord;
+        friend class HostCallRecord;
+        
+#if ENABLE(OPCODE_SAMPLING)
+        class CallRecord : Noncopyable {
+        public:
+            CallRecord(SamplingTool* samplingTool)
+                : m_samplingTool(samplingTool)
+                , m_savedSample(samplingTool->m_sample)
+                , m_savedCodeBlock(samplingTool->m_codeBlock)
+            {
+            }
+
+            ~CallRecord()
+            {
+                m_samplingTool->m_sample = m_savedSample;
+                m_samplingTool->m_codeBlock = m_savedCodeBlock;
+            }
+
+        private:
+            SamplingTool* m_samplingTool;
+            intptr_t m_savedSample;
+            CodeBlock* m_savedCodeBlock;
+        };
+        
+        class HostCallRecord : public CallRecord {
+        public:
+            HostCallRecord(SamplingTool* samplingTool)
+                : CallRecord(samplingTool)
+            {
+                samplingTool->m_sample |= 0x1;
+            }
+        };
+#else
+        class CallRecord : Noncopyable {
+        public:
+            CallRecord(SamplingTool*)
+            {
+            }
+        };
+
+        class HostCallRecord : public CallRecord {
+        public:
+            HostCallRecord(SamplingTool* samplingTool)
+                : CallRecord(samplingTool)
+            {
+            }
+        };
+#endif        
+
+        SamplingTool(Machine* machine)
+            : m_machine(machine)
+            , m_running(false)
+            , m_codeBlock(0)
+            , m_sample(0)
+            , m_sampleCount(0)
+            , m_opcodeSampleCount(0)
             , m_scopeSampleMap(new ScopeSampleRecordMap())
         {
+            memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples));
+            memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions));
         }
 
         ~SamplingTool()
@@ -97,63 +147,64 @@ namespace JSC {
 
         void notifyOfScope(ScopeNode* scope);
 
-        void sample(CodeBlock* recordedCodeBlock, Instruction* recordedVPC)
+        void sample(CodeBlock* codeBlock, Instruction* vPC)
         {
-            m_recordedCodeBlock = recordedCodeBlock;
-            m_recordedVPC = recordedVPC;
+            ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
+            m_codeBlock = codeBlock;
+            m_sample = reinterpret_cast<intptr_t>(vPC);
         }
 
-        void privateExecuteReturned()
-        {
-            m_recordedCodeBlock = 0;
-            m_recordedVPC = 0;
-#if ENABLE(SAMPLING_TOOL)
-            currentOpcodeID = static_cast<OpcodeID>(-1);
-#endif
-        }
-        
-        void callingHostFunction()
+        CodeBlock** codeBlockSlot() { return &m_codeBlock; }
+        intptr_t* sampleSlot() { return &m_sample; }
+
+        unsigned encodeSample(Instruction* vPC, bool inCTIFunction = false, bool inHostFunction = false)
         {
-            m_recordedCodeBlock = 0;
-            m_recordedVPC = 0;
-#if ENABLE(SAMPLING_TOOL)
-            currentOpcodeID = static_cast<OpcodeID>(-1);
-#endif
+            ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
+            return reinterpret_cast<intptr_t>(vPC) | (inCTIFunction << 1) | inHostFunction;
         }
 
     private:
+        class Sample {
+        public:
+            Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock)
+                : m_sample(sample)
+                , m_codeBlock(codeBlock)
+            {
+            }
+            
+            bool isNull() { return !m_sample || !m_codeBlock; }
+            CodeBlock* codeBlock() { return m_codeBlock; }
+            Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); }
+            bool inHostFunction() { return m_sample & 0x1; }
+            bool inCTIFunction() { return m_sample & 0x2; }
+
+        private:
+            intptr_t m_sample;
+            CodeBlock* m_codeBlock;
+        };
+        
         static void* threadStartFunc(void*);
         void run();
         
+        Machine* m_machine;
+        
         // Sampling thread state.
         bool m_running;
         unsigned m_hertz;
         ThreadIdentifier m_samplingThread;
 
         // State tracked by the main thread, used by the sampling thread.
-        CodeBlock* m_recordedCodeBlock;
-        Instruction* m_recordedVPC;
+        CodeBlock* m_codeBlock;
+        intptr_t m_sample;
 
         // Gathered sample data.
-        long long m_totalSamples;
+        long long m_sampleCount;
+        long long m_opcodeSampleCount;
+        unsigned m_opcodeSamples[numOpcodeIDs];
+        unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
         OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap;
     };
 
-// SCOPENODE_ / MACHINE_ macros for use from within member methods on ScopeNode / Machine respectively.
-#if ENABLE(SAMPLING_TOOL)
-#define SCOPENODE_SAMPLING_notifyOfScope(sampler) sampler->notifyOfScope(this)
-#define MACHINE_SAMPLING_sample(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
-#define MACHINE_SAMPLING_privateExecuteReturned() m_sampler->privateExecuteReturned()
-#define MACHINE_SAMPLING_callingHostFunction() m_sampler->callingHostFunction()
-#define CTI_MACHINE_SAMPLING_callingHostFunction() ARG_globalData->machine->m_sampler->callingHostFunction()
-#else
-#define SCOPENODE_SAMPLING_notifyOfScope(sampler)
-#define MACHINE_SAMPLING_sample(codeBlock, vPC)
-#define MACHINE_SAMPLING_privateExecuteReturned()
-#define MACHINE_SAMPLING_callingHostFunction()
-#define CTI_MACHINE_SAMPLING_callingHostFunction()
-#endif
-
 } // namespace JSC
 
 #endif // SamplingTool_h
index 5539f3d..a8435ad 100644 (file)
@@ -23,8 +23,8 @@
 #ifndef Parser_h
 #define Parser_h
 
-#include "debugger.h"
 #include "SourceProvider.h"
+#include "debugger.h"
 #include "nodes.h"
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
index b9488f5..afb5dc0 100644 (file)
@@ -322,10 +322,9 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fi
     if (dump)
         CodeGenerator::setDumpsGeneratedCode(true);
 
-#if ENABLE(SAMPLING_TOOL)
+#if ENABLE(OPCODE_SAMPLING)
     Machine* machine = globalObject->globalData()->machine;
-    machine->m_sampler = new SamplingTool();
-    machine->m_sampler->start();
+    machine->setSampler(new SamplingTool(machine));
 #endif
 
     bool success = true;
@@ -338,6 +337,9 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fi
         if (prettyPrint)
             prettyPrintScript(globalObject->globalExec(), fileName, script);
         else {
+#if ENABLE(OPCODE_SAMPLING)
+            machine->sampler()->start();
+#endif
             Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
             success = success && completion.complType() != Throw;
             if (dump) {
@@ -348,13 +350,16 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fi
             }
 
             globalObject->globalExec()->clearException();
+
+#if ENABLE(OPCODE_SAMPLING)
+            machine->sampler()->stop();
+#endif
         }
     }
 
-#if ENABLE(SAMPLING_TOOL)
-    machine->m_sampler->stop();
-    machine->m_sampler->dump(globalObject->globalExec());
-    delete machine->m_sampler;
+#if ENABLE(OPCODE_SAMPLING)
+    machine->sampler()->dump(globalObject->globalExec());
+    delete machine->sampler();
 #endif
     return success;
 }
index b28c39c..db8bd5f 100644 (file)
 #include "Parser.h"
 #include "PropertyNameArray.h"
 #include "RegExpObject.h"
+#include "SamplingTool.h"
 #include "debugger.h"
 #include "lexer.h"
 #include "operations.h"
-#include "SamplingTool.h"
 #include <math.h>
 #include <wtf/Assertions.h>
 #include <wtf/HashCountedSet.h>
@@ -1698,8 +1698,9 @@ ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceE
         m_varStack = *varStack;
     if (funcStack)
         m_functionStack = *funcStack;
-
-    SCOPENODE_SAMPLING_notifyOfScope(globalData->machine->m_sampler);
+#if ENABLE(OPCODE_SAMPLING)
+    globalData->machine->sampler()->notifyOfScope(this);
+#endif
 }
 
 // ------------------------------ ProgramNode -----------------------------
index 115019b..61dd736 100644 (file)
 #define ENABLE_NETSCAPE_PLUGIN_API 1
 #endif
 
-#if !defined(ENABLE_SAMPLING_TOOL)
-#define ENABLE_SAMPLING_TOOL 0
+#if !defined(ENABLE_OPCODE_STATS)
+#define ENABLE_OPCODE_STATS 0
+#endif
+
+#if !defined(ENABLE_CODEBLOCK_SAMPLING)
+#define ENABLE_CODEBLOCK_SAMPLING 0
+#endif
+
+#if ENABLE(CODEBLOCK_SAMPLING) && !defined(ENABLE_OPCODE_SAMPLING)
+#define ENABLE_OPCODE_SAMPLING 1
+#endif
+
+#if !defined(ENABLE_OPCODE_SAMPLING)
+#define ENABLE_OPCODE_SAMPLING 0
 #endif
 
 #if !defined(ENABLE_GEOLOCATION)