]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - bytecode/CodeOrigin.h
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / bytecode / CodeOrigin.h
index 5d9eaa041e4d4b8a3d92cd0e61d4d2e108df684d..cffd4eb9e55e8863e04dabc829d46357b4f6081b 100644 (file)
 
 #include "CodeBlockHash.h"
 #include "CodeSpecializationKind.h"
+#include "JSFunction.h"
 #include "ValueRecovery.h"
 #include "WriteBarrier.h"
 #include <wtf/BitVector.h>
+#include <wtf/HashMap.h>
 #include <wtf/PrintStream.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/Vector.h>
@@ -39,41 +41,45 @@ namespace JSC {
 
 struct InlineCallFrame;
 class ExecState;
-class ExecutableBase;
+class ScriptExecutable;
 class JSFunction;
 
 struct CodeOrigin {
-    static const unsigned maximumBytecodeIndex = (1u << 29) - 1;
+    static const unsigned invalidBytecodeIndex = UINT_MAX;
     
-    // Bytecode offset that you'd use to re-execute this instruction.
-    unsigned bytecodeIndex : 29;
-    // Bytecode offset corresponding to the opcode that gives the result (needed to handle
-    // op_call/op_call_put_result and op_method_check/op_get_by_id).
-    unsigned valueProfileOffset : 3;
+    // Bytecode offset that you'd use to re-execute this instruction, and the
+    // bytecode index of the bytecode instruction that produces some result that
+    // you're interested in (used for mapping Nodes whose values you're using
+    // to bytecode instructions that have the appropriate value profile).
+    unsigned bytecodeIndex;
     
     InlineCallFrame* inlineCallFrame;
     
     CodeOrigin()
-        : bytecodeIndex(maximumBytecodeIndex)
-        , valueProfileOffset(0)
+        : bytecodeIndex(invalidBytecodeIndex)
         , inlineCallFrame(0)
     {
     }
     
-    explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0, unsigned valueProfileOffset = 0)
+    CodeOrigin(WTF::HashTableDeletedValueType)
+        : bytecodeIndex(invalidBytecodeIndex)
+        , inlineCallFrame(deletedMarker())
+    {
+    }
+    
+    explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0)
         : bytecodeIndex(bytecodeIndex)
-        , valueProfileOffset(valueProfileOffset)
         , inlineCallFrame(inlineCallFrame)
     {
-        RELEASE_ASSERT(bytecodeIndex <= maximumBytecodeIndex);
-        RELEASE_ASSERT(valueProfileOffset < (1u << 3));
+        ASSERT(bytecodeIndex < invalidBytecodeIndex);
     }
     
-    bool isSet() const { return bytecodeIndex != maximumBytecodeIndex; }
+    bool isSet() const { return bytecodeIndex != invalidBytecodeIndex; }
+    bool operator!() const { return !isSet(); }
     
-    unsigned bytecodeIndexForValueProfile() const
+    bool isHashTableDeletedValue() const
     {
-        return bytecodeIndex + valueProfileOffset;
+        return bytecodeIndex == invalidBytecodeIndex && !!inlineCallFrame;
     }
     
     // The inline depth is the depth of the inline stack, so 1 = not inlined,
@@ -82,55 +88,90 @@ struct CodeOrigin {
     
     // If the code origin corresponds to inlined code, gives you the heap object that
     // would have owned the code if it had not been inlined. Otherwise returns 0.
-    ExecutableBase* codeOriginOwner() const;
+    ScriptExecutable* codeOriginOwner() const;
     
-    unsigned stackOffset() const;
+    int stackOffset() const;
     
     static unsigned inlineDepthForCallFrame(InlineCallFrame*);
     
+    unsigned hash() const;
     bool operator==(const CodeOrigin& other) const;
-    
     bool operator!=(const CodeOrigin& other) const { return !(*this == other); }
     
+    // This checks if the two code origins correspond to the same stack trace snippets,
+    // but ignore whether the InlineCallFrame's are identical.
+    bool isApproximatelyEqualTo(const CodeOrigin& other) const;
+    
+    unsigned approximateHash() const;
+    
     // Get the inline stack. This is slow, and is intended for debugging only.
     Vector<CodeOrigin> inlineStack() const;
     
     void dump(PrintStream&) const;
+    void dumpInContext(PrintStream&, DumpContext*) const;
+
+private:
+    static InlineCallFrame* deletedMarker()
+    {
+        return bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(1));
+    }
 };
 
 struct InlineCallFrame {
-    Vector<ValueRecovery> arguments;
-    WriteBarrier<ExecutableBase> executable;
-    WriteBarrier<JSFunction> callee; // This may be null, indicating that this is a closure call and that the JSFunction and JSScope are already on the stack.
+    Vector<ValueRecovery> arguments; // Includes 'this'.
+    WriteBarrier<ScriptExecutable> executable;
+    ValueRecovery calleeRecovery;
     CodeOrigin caller;
     BitVector capturedVars; // Indexed by the machine call frame's variable numbering.
-    unsigned stackOffset : 31;
+    signed stackOffset : 30;
     bool isCall : 1;
+    bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually.
+    VirtualRegister argumentsRegister; // This is only set if the code uses arguments. The unmodified arguments register follows the unmodifiedArgumentsRegister() convention (see CodeBlock.h).
+    
+    // There is really no good notion of a "default" set of values for
+    // InlineCallFrame's fields. This constructor is here just to reduce confusion if
+    // we forgot to initialize explicitly.
+    InlineCallFrame()
+        : stackOffset(0)
+        , isCall(false)
+        , isClosureCall(false)
+    {
+    }
     
     CodeSpecializationKind specializationKind() const { return specializationFromIsCall(isCall); }
-    
-    bool isClosureCall() const { return !callee; }
+
+    JSFunction* calleeConstant() const
+    {
+        if (calleeRecovery.isConstant())
+            return jsCast<JSFunction*>(calleeRecovery.constant());
+        return 0;
+    }
+
+    void visitAggregate(SlotVisitor& visitor)
+    {
+        visitor.append(&executable);
+    }
     
     // Get the callee given a machine call frame to which this InlineCallFrame belongs.
     JSFunction* calleeForCallFrame(ExecState*) const;
     
-    String inferredName() const;
+    CString inferredName() const;
     CodeBlockHash hash() const;
+    CString hashAsStringIfPossible() const;
     
     CodeBlock* baselineCodeBlock() const;
     
+    ptrdiff_t callerFrameOffset() const { return stackOffset * sizeof(Register) + CallFrame::callerFrameOffset(); }
+    ptrdiff_t returnPCOffset() const { return stackOffset * sizeof(Register) + CallFrame::returnPCOffset(); }
+
     void dumpBriefFunctionInformation(PrintStream&) const;
     void dump(PrintStream&) const;
+    void dumpInContext(PrintStream&, DumpContext*) const;
 
     MAKE_PRINT_METHOD(InlineCallFrame, dumpBriefFunctionInformation, briefFunctionInformation);
 };
 
-struct CodeOriginAtCallReturnOffset {
-    CodeOrigin codeOrigin;
-    unsigned callReturnOffset;
-};
-
-inline unsigned CodeOrigin::stackOffset() const
+inline int CodeOrigin::stackOffset() const
 {
     if (!inlineCallFrame)
         return 0;
@@ -138,25 +179,52 @@ inline unsigned CodeOrigin::stackOffset() const
     return inlineCallFrame->stackOffset;
 }
 
+inline unsigned CodeOrigin::hash() const
+{
+    return WTF::IntHash<unsigned>::hash(bytecodeIndex) +
+        WTF::PtrHash<InlineCallFrame*>::hash(inlineCallFrame);
+}
+
 inline bool CodeOrigin::operator==(const CodeOrigin& other) const
 {
     return bytecodeIndex == other.bytecodeIndex
         && inlineCallFrame == other.inlineCallFrame;
 }
     
-inline unsigned getCallReturnOffsetForCodeOrigin(CodeOriginAtCallReturnOffset* data)
-{
-    return data->callReturnOffset;
-}
-
-inline ExecutableBase* CodeOrigin::codeOriginOwner() const
+inline ScriptExecutable* CodeOrigin::codeOriginOwner() const
 {
     if (!inlineCallFrame)
         return 0;
     return inlineCallFrame->executable.get();
 }
 
+struct CodeOriginHash {
+    static unsigned hash(const CodeOrigin& key) { return key.hash(); }
+    static bool equal(const CodeOrigin& a, const CodeOrigin& b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct CodeOriginApproximateHash {
+    static unsigned hash(const CodeOrigin& key) { return key.approximateHash(); }
+    static bool equal(const CodeOrigin& a, const CodeOrigin& b) { return a.isApproximatelyEqualTo(b); }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
 } // namespace JSC
 
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::CodeOrigin> {
+    typedef JSC::CodeOriginHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::CodeOrigin> : SimpleClassHashTraits<JSC::CodeOrigin> {
+    static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
 #endif // CodeOrigin_h