X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..ef99ff287df9046eb88937225e0554eabb00e33c:/bytecode/CodeOrigin.h?ds=sidebyside diff --git a/bytecode/CodeOrigin.h b/bytecode/CodeOrigin.h index 5d9eaa0..cffd4eb 100644 --- a/bytecode/CodeOrigin.h +++ b/bytecode/CodeOrigin.h @@ -28,9 +28,11 @@ #include "CodeBlockHash.h" #include "CodeSpecializationKind.h" +#include "JSFunction.h" #include "ValueRecovery.h" #include "WriteBarrier.h" #include +#include #include #include #include @@ -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 inlineStack() const; void dump(PrintStream&) const; + void dumpInContext(PrintStream&, DumpContext*) const; + +private: + static InlineCallFrame* deletedMarker() + { + return bitwise_cast(static_cast(1)); + } }; struct InlineCallFrame { - Vector arguments; - WriteBarrier executable; - WriteBarrier callee; // This may be null, indicating that this is a closure call and that the JSFunction and JSScope are already on the stack. + Vector arguments; // Includes 'this'. + WriteBarrier 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(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::hash(bytecodeIndex) + + WTF::PtrHash::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 struct DefaultHash; +template<> struct DefaultHash { + typedef JSC::CodeOriginHash Hash; +}; + +template struct HashTraits; +template<> struct HashTraits : SimpleClassHashTraits { + static const bool emptyValueIsZero = false; +}; + +} // namespace WTF + #endif // CodeOrigin_h