#ifndef CodeOrigin_h
#define CodeOrigin_h
#include "CodeBlockHash.h"
#include "CodeSpecializationKind.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>
namespace JSC {
struct InlineCallFrame;
class ExecState;
class ScriptExecutable;
class JSFunction;
struct CodeOrigin {
static const unsigned invalidBytecodeIndex = UINT_MAX;
unsigned bytecodeIndex;
InlineCallFrame* inlineCallFrame;
CodeOrigin()
: bytecodeIndex(invalidBytecodeIndex)
, inlineCallFrame(0)
{
}
CodeOrigin(WTF::HashTableDeletedValueType)
: bytecodeIndex(invalidBytecodeIndex)
, inlineCallFrame(deletedMarker())
{
}
explicit CodeOrigin(unsigned bytecodeIndex, InlineCallFrame* inlineCallFrame = 0)
: bytecodeIndex(bytecodeIndex)
, inlineCallFrame(inlineCallFrame)
{
ASSERT(bytecodeIndex < invalidBytecodeIndex);
}
bool isSet() const { return bytecodeIndex != invalidBytecodeIndex; }
bool operator!() const { return !isSet(); }
bool isHashTableDeletedValue() const
{
return bytecodeIndex == invalidBytecodeIndex && !!inlineCallFrame;
}
unsigned inlineDepth() const;
ScriptExecutable* codeOriginOwner() 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); }
bool isApproximatelyEqualTo(const CodeOrigin& other) const;
unsigned approximateHash() const;
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 {
enum Kind {
Call,
Construct,
CallVarargs,
ConstructVarargs,
GetterCall,
SetterCall
};
static Kind kindFor(CodeSpecializationKind kind)
{
switch (kind) {
case CodeForCall:
return Call;
case CodeForConstruct:
return Construct;
}
RELEASE_ASSERT_NOT_REACHED();
return Call;
}
static Kind varargsKindFor(CodeSpecializationKind kind)
{
switch (kind) {
case CodeForCall:
return CallVarargs;
case CodeForConstruct:
return ConstructVarargs;
}
RELEASE_ASSERT_NOT_REACHED();
return Call;
}
static CodeSpecializationKind specializationKindFor(Kind kind)
{
switch (kind) {
case Call:
case CallVarargs:
case GetterCall:
case SetterCall:
return CodeForCall;
case Construct:
case ConstructVarargs:
return CodeForConstruct;
}
RELEASE_ASSERT_NOT_REACHED();
return CodeForCall;
}
static bool isVarargs(Kind kind)
{
switch (kind) {
case CallVarargs:
case ConstructVarargs:
return true;
default:
return false;
}
}
bool isVarargs() const
{
return isVarargs(static_cast<Kind>(kind));
}
Vector<ValueRecovery> arguments; WriteBarrier<ScriptExecutable> executable;
ValueRecovery calleeRecovery;
CodeOrigin caller;
signed stackOffset : 28;
unsigned kind : 3; bool isClosureCall : 1; VirtualRegister argumentCountRegister;
InlineCallFrame()
: stackOffset(0)
, kind(Call)
, isClosureCall(false)
{
}
CodeSpecializationKind specializationKind() const { return specializationKindFor(static_cast<Kind>(kind)); }
JSFunction* calleeConstant() const;
void visitAggregate(SlotVisitor&);
JSFunction* calleeForCallFrame(ExecState*) const;
CString inferredName() const;
CodeBlockHash hash() const;
CString hashAsStringIfPossible() const;
CodeBlock* baselineCodeBlock() const;
void setStackOffset(signed offset)
{
stackOffset = offset;
RELEASE_ASSERT(static_cast<signed>(stackOffset) == offset);
}
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);
};
inline int CodeOrigin::stackOffset() const
{
if (!inlineCallFrame)
return 0;
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 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 WTF {
void printInternal(PrintStream&, JSC::InlineCallFrame::Kind);
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;
};
}
#endif // CodeOrigin_h