X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..fb8617cde5834786bd4e4afd579883e4acf5666e:/bytecode/CodeBlock.h diff --git a/bytecode/CodeBlock.h b/bytecode/CodeBlock.h index e5d78d3..eb874cc 100644 --- a/bytecode/CodeBlock.h +++ b/bytecode/CodeBlock.h @@ -32,11 +32,14 @@ #include "EvalCodeCache.h" #include "Instruction.h" +#include "JITCode.h" #include "JSGlobalObject.h" #include "JumpTable.h" #include "Nodes.h" +#include "PtrAndFlags.h" #include "RegExp.h" #include "UString.h" +#include #include #include @@ -44,8 +47,18 @@ #include "StructureStubInfo.h" #endif +// Register numbers used in bytecode operations have different meaning accoring to their ranges: +// 0x80000000-0xFFFFFFFF Negative indicies from the CallFrame pointer are entries in the call frame, see RegisterFile.h. +// 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. +// 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. +static const int FirstConstantRegisterIndex = 0x40000000; + namespace JSC { + enum HasSeenShouldRepatch { + hasSeenShouldRepatch + }; + class ExecState; enum CodeType { GlobalCode, EvalCode, FunctionCode }; @@ -58,38 +71,10 @@ namespace JSC { uint32_t target; uint32_t scopeDepth; #if ENABLE(JIT) - void* nativeCode; + CodeLocationLabel nativeCode; #endif }; -#if ENABLE(JIT) - // The code, and the associated pool from which it was allocated. - struct JITCodeRef { - void* code; -#ifndef NDEBUG - unsigned codeSize; -#endif - RefPtr executablePool; - - JITCodeRef() - : code(0) -#ifndef NDEBUG - , codeSize(0) -#endif - { - } - - JITCodeRef(void* code, PassRefPtr executablePool) - : code(code) -#ifndef NDEBUG - , codeSize(0) -#endif - , executablePool(executablePool) - { - } - }; -#endif - struct ExpressionRangeInfo { enum { MaxOffset = (1 << 7) - 1, @@ -117,24 +102,52 @@ namespace JSC { #if ENABLE(JIT) struct CallLinkInfo { CallLinkInfo() - : callReturnLocation(0) - , hotPathBegin(0) - , hotPathOther(0) - , coldPathOther(0) - , callee(0) + : callee(0) { } unsigned bytecodeIndex; - void* callReturnLocation; - void* hotPathBegin; - void* hotPathOther; - void* coldPathOther; + CodeLocationNearCall callReturnLocation; + CodeLocationDataLabelPtr hotPathBegin; + CodeLocationNearCall hotPathOther; + PtrAndFlags ownerCodeBlock; CodeBlock* callee; unsigned position; void setUnlinked() { callee = 0; } bool isLinked() { return callee; } + + bool seenOnce() + { + return ownerCodeBlock.isFlagSet(hasSeenShouldRepatch); + } + + void setSeen() + { + ownerCodeBlock.setFlag(hasSeenShouldRepatch); + } + }; + + struct MethodCallLinkInfo { + MethodCallLinkInfo() + : cachedStructure(0) + { + } + + bool seenOnce() + { + return cachedPrototypeStructure.isFlagSet(hasSeenShouldRepatch); + } + + void setSeen() + { + cachedPrototypeStructure.setFlag(hasSeenShouldRepatch); + } + + CodeLocationCall callReturnLocation; + CodeLocationDataLabelPtr structureLabel; + Structure* cachedStructure; + PtrAndFlags cachedPrototypeStructure; }; struct FunctionRegisterInfo { @@ -161,14 +174,18 @@ namespace JSC { unsigned bytecodeOffset; }; - struct PC { - PC(ptrdiff_t nativePCOffset, unsigned bytecodeIndex) - : nativePCOffset(nativePCOffset) + // This structure is used to map from a call return location + // (given as an offset in bytes into the JIT code) back to + // the bytecode index of the corresponding bytecode operation. + // This is then used to look up the corresponding handler. + struct CallReturnOffsetToBytecodeIndex { + CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex) + : callReturnOffset(callReturnOffset) , bytecodeIndex(bytecodeIndex) { } - ptrdiff_t nativePCOffset; + unsigned callReturnOffset; unsigned bytecodeIndex; }; @@ -176,17 +193,22 @@ namespace JSC { inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) { - return structureStubInfo->callReturnLocation; + return structureStubInfo->callReturnLocation.executableAddress(); } inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) { - return callLinkInfo->callReturnLocation; + return callLinkInfo->callReturnLocation.executableAddress(); + } + + inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) + { + return methodCallLinkInfo->callReturnLocation.executableAddress(); } - inline ptrdiff_t getNativePCOffset(PC* pc) + inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc) { - return pc->nativePCOffset; + return pc->callReturnOffset; } // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array, @@ -226,16 +248,27 @@ namespace JSC { } #endif - class CodeBlock { + struct ExceptionInfo : FastAllocBase { + Vector m_expressionInfo; + Vector m_lineInfo; + Vector m_getByIdExceptionInfo; + +#if ENABLE(JIT) + Vector m_callReturnIndexVector; +#endif + }; + + class CodeBlock : public FastAllocBase { friend class JIT; + protected: + CodeBlock(ScriptExecutable* ownerExecutable, CodeType, PassRefPtr, unsigned sourceOffset, SymbolTable* symbolTable); public: - CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr, unsigned sourceOffset); - ~CodeBlock(); + virtual ~CodeBlock(); - void mark(); + void markAggregate(MarkStack&); void refStructures(Instruction* vPC) const; void derefStructures(Instruction* vPC) const; -#if ENABLE(JIT) +#if ENABLE(JIT_OPTIMIZE_CALL) void unlinkCallers(); #endif @@ -258,19 +291,9 @@ namespace JSC { return false; } - ALWAYS_INLINE bool isConstantRegisterIndex(int index) - { - return index >= m_numVars && index < m_numVars + m_numConstants; - } - - ALWAYS_INLINE JSValuePtr getConstant(int index) - { - return m_constantRegisters[index - m_numVars].getJSValue(); - } - ALWAYS_INLINE bool isTemporaryRegisterIndex(int index) { - return index >= m_numVars + m_numConstants; + return index >= m_numVars; } HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); @@ -298,21 +321,25 @@ namespace JSC { m_linkedCallerList.shrink(lastPos); } - StructureStubInfo& getStubInfo(void* returnAddress) + StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) { - return *(binaryChop(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress)); + return *(binaryChop(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value())); } - CallLinkInfo& getCallLinkInfo(void* returnAddress) + CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) { - return *(binaryChop(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress)); + return *(binaryChop(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value())); } - unsigned getBytecodeIndex(CallFrame* callFrame, void* nativePC) + MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) + { + return *(binaryChop(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); + } + + unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) { reparseForExceptionInfoIfNecessary(callFrame); - ptrdiff_t nativePCOffset = reinterpret_cast(nativePC) - reinterpret_cast(m_jitCode.code); - return binaryChop(m_exceptionInfo->m_pcVector.begin(), m_exceptionInfo->m_pcVector.size(), nativePCOffset)->bytecodeIndex; + return binaryChop(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerExecutable()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; } bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); @@ -322,17 +349,19 @@ namespace JSC { bool isNumericCompareFunction() { return m_isNumericCompareFunction; } Vector& instructions() { return m_instructions; } + void discardBytecode() { m_instructions.clear(); } + #ifndef NDEBUG + unsigned instructionCount() { return m_instructionCount; } void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } #endif #if ENABLE(JIT) - void setJITCode(JITCodeRef& jitCode); - void* jitCode() { return m_jitCode.code; } - ExecutablePool* executablePool() { return m_jitCode.executablePool.get(); } + JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); } + ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); } #endif - ScopeNode* ownerNode() const { return m_ownerNode; } + ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; } void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } @@ -373,6 +402,9 @@ namespace JSC { void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); } CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } + void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(n); } + MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } + void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); } #endif @@ -384,6 +416,7 @@ namespace JSC { bool hasExceptionInfo() const { return m_exceptionInfo; } void clearExceptionInfo() { m_exceptionInfo.clear(); } + ExceptionInfo* extractExceptionInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); } void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } @@ -393,7 +426,7 @@ namespace JSC { LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } #if ENABLE(JIT) - Vector& pcVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_pcVector; } + Vector& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; } #endif // Constant Pool @@ -404,18 +437,15 @@ namespace JSC { size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); } - Register& constantRegister(int index) { return m_constantRegisters[index]; } - - unsigned addFunctionExpression(FuncExprNode* n) { unsigned size = m_functionExpressions.size(); m_functionExpressions.append(n); return size; } - FuncExprNode* functionExpression(int index) const { return m_functionExpressions[index].get(); } - - unsigned addFunction(FuncDeclNode* n) { createRareDataIfNecessary(); unsigned size = m_rareData->m_functions.size(); m_rareData->m_functions.append(n); return size; } - FuncDeclNode* function(int index) const { ASSERT(m_rareData); return m_rareData->m_functions[index].get(); } + Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } + ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } + ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } - bool hasFunctions() const { return m_functionExpressions.size() || (m_rareData && m_rareData->m_functions.size()); } - - unsigned addUnexpectedConstant(JSValuePtr v) { createRareDataIfNecessary(); unsigned size = m_rareData->m_unexpectedConstants.size(); m_rareData->m_unexpectedConstants.append(v); return size; } - JSValuePtr unexpectedConstant(int index) const { ASSERT(m_rareData); return m_rareData->m_unexpectedConstants[index]; } + unsigned addFunctionDecl(NonNullPassRefPtr n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(n); return size; } + FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } + int numberOfFunctionDecls() { return m_functionDecls.size(); } + unsigned addFunctionExpr(NonNullPassRefPtr n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(n); return size; } + FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; } RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } @@ -436,7 +466,8 @@ namespace JSC { StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } - SymbolTable& symbolTable() { return m_symbolTable; } + SymbolTable* symbolTable() { return m_symbolTable; } + SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast(m_symbolTable); } EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } @@ -445,17 +476,19 @@ namespace JSC { // FIXME: Make these remaining members private. int m_numCalleeRegisters; - // NOTE: numConstants holds the number of constant registers allocated - // by the code generator, not the number of constant registers used. - // (Duplicate constants are uniqued during code generation, and spare - // constant registers may be allocated.) - int m_numConstants; int m_numVars; int m_numParameters; private: #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) void dump(ExecState*, const Vector::const_iterator& begin, Vector::const_iterator&) const; + + CString registerName(ExecState*, int r) const; + void printUnaryOp(ExecState*, int location, Vector::const_iterator&, const char* op) const; + void printBinaryOp(ExecState*, int location, Vector::const_iterator&, const char* op) const; + void printConditionalJump(ExecState*, const Vector::const_iterator&, Vector::const_iterator&, int location, const char* op) const; + void printGetByIdOp(ExecState*, int location, Vector::const_iterator&, const char* op) const; + void printPutByIdOp(ExecState*, int location, Vector::const_iterator&, const char* op) const; #endif void reparseForExceptionInfoIfNecessary(CallFrame*); @@ -466,16 +499,13 @@ namespace JSC { m_rareData.set(new RareData); } - ScopeNode* m_ownerNode; + ScriptExecutable* m_ownerExecutable; JSGlobalData* m_globalData; Vector m_instructions; #ifndef NDEBUG unsigned m_instructionCount; #endif -#if ENABLE(JIT) - JITCodeRef m_jitCode; -#endif int m_thisRegister; @@ -496,6 +526,7 @@ namespace JSC { Vector m_structureStubInfos; Vector m_globalResolveInfos; Vector m_callLinkInfos; + Vector m_methodCallLinkInfos; Vector m_linkedCallerList; #endif @@ -504,27 +535,17 @@ namespace JSC { // Constant Pool Vector m_identifiers; Vector m_constantRegisters; - Vector > m_functionExpressions; - - SymbolTable m_symbolTable; + Vector > m_functionDecls; + Vector > m_functionExprs; - struct ExceptionInfo { - Vector m_expressionInfo; - Vector m_lineInfo; - Vector m_getByIdExceptionInfo; + SymbolTable* m_symbolTable; -#if ENABLE(JIT) - Vector m_pcVector; -#endif - }; OwnPtr m_exceptionInfo; - struct RareData { + struct RareData : FastAllocBase { Vector m_exceptionHandlers; // Rare Constants - Vector > m_functions; - Vector m_unexpectedConstants; Vector > m_regexps; // Jump Tables @@ -544,16 +565,16 @@ namespace JSC { // Program code is not marked by any function, so we make the global object // responsible for marking it. - class ProgramCodeBlock : public CodeBlock { + class GlobalCodeBlock : public CodeBlock { public: - ProgramCodeBlock(ScopeNode* ownerNode, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr sourceProvider) - : CodeBlock(ownerNode, codeType, sourceProvider, 0) + GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr sourceProvider, unsigned sourceOffset, JSGlobalObject* globalObject) + : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, &m_unsharedSymbolTable) , m_globalObject(globalObject) { m_globalObject->codeBlocks().add(this); } - ~ProgramCodeBlock() + ~GlobalCodeBlock() { if (m_globalObject) m_globalObject->codeBlocks().remove(this); @@ -563,22 +584,64 @@ namespace JSC { private: JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. + SymbolTable m_unsharedSymbolTable; }; - class EvalCodeBlock : public ProgramCodeBlock { + class ProgramCodeBlock : public GlobalCodeBlock { public: - EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr sourceProvider, int baseScopeDepth) - : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider) + ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr sourceProvider) + : GlobalCodeBlock(ownerExecutable, codeType, sourceProvider, 0, globalObject) + { + } + }; + + class EvalCodeBlock : public GlobalCodeBlock { + public: + EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr sourceProvider, int baseScopeDepth) + : GlobalCodeBlock(ownerExecutable, EvalCode, sourceProvider, 0, globalObject) , m_baseScopeDepth(baseScopeDepth) { } int baseScopeDepth() const { return m_baseScopeDepth; } + const Identifier& variable(unsigned index) { return m_variables[index]; } + unsigned numVariables() { return m_variables.size(); } + void adoptVariables(Vector& variables) + { + ASSERT(m_variables.isEmpty()); + m_variables.swap(variables); + } + private: int m_baseScopeDepth; + Vector m_variables; }; + class FunctionCodeBlock : public CodeBlock { + public: + // Rather than using the usual RefCounted::create idiom for SharedSymbolTable we just use new + // as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared + // symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref + // in the destructor. + FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr sourceProvider, unsigned sourceOffset) + : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable) + { + } + ~FunctionCodeBlock() + { + sharedSymbolTable()->deref(); + } + }; + + inline Register& ExecState::r(int index) + { + CodeBlock* codeBlock = this->codeBlock(); + if (codeBlock->isConstantRegisterIndex(index)) + return codeBlock->constantRegister(index); + return this[index]; + } + } // namespace JSC #endif // CodeBlock_h