X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..1df5f87f1309a8daa30dabdee855f48ae40d14ab:/bytecode/CodeBlock.h diff --git a/bytecode/CodeBlock.h b/bytecode/CodeBlock.h index e5d78d3..7aa356e 100644 --- a/bytecode/CodeBlock.h +++ b/bytecode/CodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * * Redistribution and use in source and binary forms, with or without @@ -32,11 +32,15 @@ #include "EvalCodeCache.h" #include "Instruction.h" +#include "JITCode.h" +#include "JITWriteBarrier.h" #include "JSGlobalObject.h" #include "JumpTable.h" #include "Nodes.h" -#include "RegExp.h" +#include "RegExpObject.h" #include "UString.h" +#include +#include #include #include @@ -44,12 +48,24 @@ #include "StructureStubInfo.h" #endif +// Register numbers used in bytecode operations have different meaning according to their ranges: +// 0x80000000-0xFFFFFFFF Negative indices 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 }; + inline int unmodifiedArgumentsRegister(int argumentsRegister) { return argumentsRegister - 1; } + static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits::max(); } struct HandlerInfo { @@ -58,37 +74,9 @@ namespace JSC { uint32_t target; uint32_t scopeDepth; #if ENABLE(JIT) - void* 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) + CodeLocationLabel nativeCode; #endif - , executablePool(executablePool) - { - } }; -#endif struct ExpressionRangeInfo { enum { @@ -106,138 +94,134 @@ namespace JSC { int32_t lineNumber; }; - // Both op_construct and op_instanceof require a use of op_get_by_id to get - // the prototype property from an object. The exception messages for exceptions - // thrown by these instances op_get_by_id need to reflect this. - struct GetByIdExceptionInfo { - unsigned bytecodeOffset : 31; - bool isOpConstruct : 1; - }; - #if ENABLE(JIT) struct CallLinkInfo { CallLinkInfo() - : callReturnLocation(0) - , hotPathBegin(0) - , hotPathOther(0) - , coldPathOther(0) - , callee(0) + : hasSeenShouldRepatch(false) + , isCall(false) { } - - unsigned bytecodeIndex; - void* callReturnLocation; - void* hotPathBegin; - void* hotPathOther; - void* coldPathOther; - CodeBlock* callee; - unsigned position; - - void setUnlinked() { callee = 0; } + + CodeLocationNearCall callReturnLocation; + CodeLocationDataLabelPtr hotPathBegin; + CodeLocationNearCall hotPathOther; + JITWriteBarrier callee; + bool hasSeenShouldRepatch : 1; + bool isCall : 1; + bool isLinked() { return callee; } + void unlink() + { + hasSeenShouldRepatch = false; + callee.clear(); + } + + bool seenOnce() + { + return hasSeenShouldRepatch; + } + + void setSeen() + { + hasSeenShouldRepatch = true; + } }; - struct FunctionRegisterInfo { - FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex) - : bytecodeOffset(bytecodeOffset) - , functionRegisterIndex(functionRegisterIndex) + struct MethodCallLinkInfo { + MethodCallLinkInfo() { } - unsigned bytecodeOffset; - int functionRegisterIndex; + bool seenOnce() + { + ASSERT(!cachedStructure); + return cachedPrototypeStructure.isFlagged(); + } + + void setSeen() + { + ASSERT(!cachedStructure && !cachedPrototypeStructure); + // We use the values of cachedStructure & cachedPrototypeStructure to indicate the + // current state. + // - In the initial state, both are null. + // - Once this transition has been taken once, cachedStructure is + // null and cachedPrototypeStructure is set to a nun-null value. + // - Once the call is linked both structures are set to non-null values. + cachedPrototypeStructure.setFlagOnBarrier(); + } + + CodeLocationCall callReturnLocation; + JITWriteBarrier cachedStructure; + JITWriteBarrier cachedPrototypeStructure; + // We'd like this to actually be JSFunction, but InternalFunction and JSFunction + // don't have a common parent class and we allow specialisation on both + JITWriteBarrier cachedFunction; + JITWriteBarrier cachedPrototype; }; struct GlobalResolveInfo { GlobalResolveInfo(unsigned bytecodeOffset) - : structure(0) - , offset(0) + : offset(0) , bytecodeOffset(bytecodeOffset) { } - Structure* structure; + WriteBarrier structure; unsigned offset; unsigned bytecodeOffset; }; - struct PC { - PC(ptrdiff_t nativePCOffset, unsigned bytecodeIndex) - : nativePCOffset(nativePCOffset) - , bytecodeIndex(bytecodeIndex) + // 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 CallReturnOffsetToBytecodeOffset { + CallReturnOffsetToBytecodeOffset(unsigned callReturnOffset, unsigned bytecodeOffset) + : callReturnOffset(callReturnOffset) + , bytecodeOffset(bytecodeOffset) { } - ptrdiff_t nativePCOffset; - unsigned bytecodeIndex; + unsigned callReturnOffset; + unsigned bytecodeOffset; }; - // valueAtPosition helpers for the binaryChop algorithm below. + // valueAtPosition helpers for the binarySearch algorithm. 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 ptrdiff_t getNativePCOffset(PC* pc) + inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) { - return pc->nativePCOffset; + return methodCallLinkInfo->callReturnLocation.executableAddress(); } - // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array, - // compares result with key (KeyTypes should be comparable with '--', '<', '>'). - // Optimized for cases where the array contains the key, checked by assertions. - template - inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key) + inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeOffset* pc) { - // The array must contain at least one element (pre-condition, array does conatin key). - // If the array only contains one element, no need to do the comparison. - while (size > 1) { - // Pick an element to check, half way through the array, and read the value. - int pos = (size - 1) >> 1; - KeyType val = valueAtPosition(&array[pos]); - - // If the key matches, success! - if (val == key) - return &array[pos]; - // The item we are looking for is smaller than the item being check; reduce the value of 'size', - // chopping off the right hand half of the array. - else if (key < val) - size = pos; - // Discard all values in the left hand half of the array, up to and including the item at pos. - else { - size -= (pos + 1); - array += (pos + 1); - } - - // 'size' should never reach zero. - ASSERT(size); - } - - // If we reach this point we've chopped down to one element, no need to check it matches - ASSERT(size == 1); - ASSERT(key == valueAtPosition(&array[0])); - return &array[0]; + return pc->callReturnOffset; } #endif class CodeBlock { + WTF_MAKE_FAST_ALLOCATED; friend class JIT; + protected: + CodeBlock(ScriptExecutable* ownerExecutable, CodeType, JSGlobalObject*, PassRefPtr, unsigned sourceOffset, SymbolTable* symbolTable, bool isConstructor); + + WriteBarrier m_globalObject; + Heap* m_heap; + public: - CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr, unsigned sourceOffset); - ~CodeBlock(); + virtual ~CodeBlock(); - void mark(); - void refStructures(Instruction* vPC) const; - void derefStructures(Instruction* vPC) const; -#if ENABLE(JIT) - void unlinkCallers(); -#endif + void visitAggregate(SlotVisitor&); static void dumpStatistics(); @@ -247,9 +231,11 @@ namespace JSC { void printStructure(const char* name, const Instruction*, int operand) const; #endif + bool isStrictMode() const { return m_isStrictMode; } + inline bool isKnownNotImmediate(int index) { - if (index == m_thisRegister) + if (index == m_thisRegister && !m_isStrictMode) return true; if (isConstantRegisterIndex(index)) @@ -258,81 +244,69 @@ 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); - int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset); - int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); - bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&); + int lineNumberForBytecodeOffset(unsigned bytecodeOffset); + void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); #if ENABLE(JIT) - void addCaller(CallLinkInfo* caller) + + StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) { - caller->callee = this; - caller->position = m_linkedCallerList.size(); - m_linkedCallerList.append(caller); + return *(binarySearch(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value())); } - void removeCaller(CallLinkInfo* caller) + CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) { - unsigned pos = caller->position; - unsigned lastPos = m_linkedCallerList.size() - 1; - - if (pos != lastPos) { - m_linkedCallerList[pos] = m_linkedCallerList[lastPos]; - m_linkedCallerList[pos]->position = pos; - } - m_linkedCallerList.shrink(lastPos); + return *(binarySearch(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value())); } - StructureStubInfo& getStubInfo(void* returnAddress) + MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) { - return *(binaryChop(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress)); + return *(binarySearch(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); } - CallLinkInfo& getCallLinkInfo(void* returnAddress) + unsigned bytecodeOffset(ReturnAddressPtr returnAddress) { - return *(binaryChop(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress)); + if (!m_rareData) + return 1; + Vector& callIndices = m_rareData->m_callReturnIndexVector; + if (!callIndices.size()) + return 1; + return binarySearch(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset; } - unsigned getBytecodeIndex(CallFrame* callFrame, void* nativePC) + void unlinkCalls(); +#endif + +#if ENABLE(INTERPRETER) + unsigned bytecodeOffset(Instruction* 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 static_cast(returnAddress) - instructions().begin(); } - - bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); #endif void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } 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 m_isConstructor ? ownerExecutable()->generatedJITCodeForConstruct() : ownerExecutable()->generatedJITCodeForCall(); } + ExecutablePool* executablePool() { return getJITCode().getExecutablePool(); } #endif - ScopeNode* ownerNode() const { return m_ownerNode; } + ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); } void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } @@ -343,8 +317,28 @@ namespace JSC { bool needsFullScopeChain() const { return m_needsFullScopeChain; } void setUsesEval(bool usesEval) { m_usesEval = usesEval; } bool usesEval() const { return m_usesEval; } - void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; } - bool usesArguments() const { return m_usesArguments; } + + void setArgumentsRegister(int argumentsRegister) + { + ASSERT(argumentsRegister != -1); + m_argumentsRegister = argumentsRegister; + ASSERT(usesArguments()); + } + int argumentsRegister() + { + ASSERT(usesArguments()); + return m_argumentsRegister; + } + void setActivationRegister(int activationRegister) + { + m_activationRegister = activationRegister; + } + int activationRegister() + { + ASSERT(needsFullScopeChain()); + return m_activationRegister; + } + bool usesArguments() const { return m_argumentsRegister != -1; } CodeType codeType() const { return m_codeType; } @@ -356,16 +350,37 @@ namespace JSC { unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } unsigned lastJumpTarget() const { return m_jumpTargets.last(); } -#if !ENABLE(JIT) - void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); } - void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); } + void createActivation(CallFrame*); + + void clearEvalCache(); + +#if ENABLE(INTERPRETER) + void addPropertyAccessInstruction(unsigned propertyAccessInstruction) + { + if (!m_globalData->canUseJIT()) + m_propertyAccessInstructions.append(propertyAccessInstruction); + } + void addGlobalResolveInstruction(unsigned globalResolveInstruction) + { + if (!m_globalData->canUseJIT()) + m_globalResolveInstructions.append(globalResolveInstruction); + } bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); -#else +#endif +#if ENABLE(JIT) size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } - void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); } + void addStructureStubInfo(const StructureStubInfo& stubInfo) + { + if (m_globalData->canUseJIT()) + m_structureStubInfos.append(stubInfo); + } StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; } - void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); } + void addGlobalResolveInfo(unsigned globalResolveInstruction) + { + if (m_globalData->canUseJIT()) + m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); + } GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); @@ -373,8 +388,17 @@ namespace JSC { void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); } CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } - void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); } + void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); } + MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } #endif + unsigned globalResolveInfoCount() const + { +#if ENABLE(JIT) + if (m_globalData->canUseJIT()) + return m_globalResolveInfos.size(); +#endif + return 0; + } // Exception handling support @@ -382,18 +406,38 @@ namespace JSC { void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } - bool hasExceptionInfo() const { return m_exceptionInfo; } - void clearExceptionInfo() { m_exceptionInfo.clear(); } + void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) + { + createRareDataIfNecessary(); + m_rareData->m_expressionInfo.append(expressionInfo); + } - 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); } + void addLineInfo(unsigned bytecodeOffset, int lineNo) + { + createRareDataIfNecessary(); + Vector& lineInfo = m_rareData->m_lineInfo; + if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) { + LineInfo info = { bytecodeOffset, lineNo }; + lineInfo.append(info); + } + } - size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } - void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); } - LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } + bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); } + bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); } + // We only generate exception handling info if the user is debugging + // (and may want line number info), or if the function contains exception handler. + bool needsCallReturnIndices() + { + return m_rareData && + (m_rareData->m_expressionInfo.size() || m_rareData->m_lineInfo.size() || m_rareData->m_exceptionHandlers.size()); + } #if ENABLE(JIT) - Vector& pcVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_pcVector; } + Vector& callReturnIndexVector() + { + createRareDataIfNecessary(); + return m_rareData->m_callReturnIndexVector; + } #endif // Constant Pool @@ -403,23 +447,57 @@ namespace JSC { Identifier& identifier(int index) { return m_identifiers[index]; } 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(); } + void addConstant(JSValue v) + { + m_constantRegisters.append(WriteBarrier()); + m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v); + } + WriteBarrier& 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].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(); } + unsigned addFunctionDecl(FunctionExecutable* n) + { + unsigned size = m_functionDecls.size(); + m_functionDecls.append(WriteBarrier()); + m_functionDecls.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n); + return size; + } + FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } + int numberOfFunctionDecls() { return m_functionDecls.size(); } + unsigned addFunctionExpr(FunctionExecutable* n) + { + unsigned size = m_functionExprs.size(); + m_functionExprs.append(WriteBarrier()); + m_functionExprs.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n); + return size; + } + FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } - bool hasFunctions() const { return m_functionExpressions.size() || (m_rareData && m_rareData->m_functions.size()); } + unsigned addRegExp(RegExp* r) + { + createRareDataIfNecessary(); + unsigned size = m_rareData->m_regexps.size(); + m_rareData->m_regexps.append(WriteBarrier(*m_globalData, ownerExecutable(), r)); + return size; + } + RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } - 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 addConstantBuffer(unsigned length) + { + createRareDataIfNecessary(); + unsigned size = m_rareData->m_constantBuffers.size(); + m_rareData->m_constantBuffers.append(Vector(length)); + return size; + } - 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(); } + JSValue* constantBuffer(unsigned index) + { + ASSERT(m_rareData); + return m_rareData->m_constantBuffers[index].data(); + } + JSGlobalObject* globalObject() { return m_globalObject.get(); } // Jump Tables @@ -436,7 +514,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,88 +524,85 @@ 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_numCapturedVars; int m_numParameters; + bool m_isConstructor; private: #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) void dump(ExecState*, const Vector::const_iterator& begin, Vector::const_iterator&) const; -#endif - void reparseForExceptionInfoIfNecessary(CallFrame*); + 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 visitStructures(SlotVisitor&, Instruction* vPC) const; void createRareDataIfNecessary() { if (!m_rareData) - m_rareData.set(new RareData); + m_rareData = adoptPtr(new RareData); } - ScopeNode* m_ownerNode; + WriteBarrier m_ownerExecutable; JSGlobalData* m_globalData; Vector m_instructions; #ifndef NDEBUG unsigned m_instructionCount; #endif -#if ENABLE(JIT) - JITCodeRef m_jitCode; -#endif int m_thisRegister; + int m_argumentsRegister; + int m_activationRegister; bool m_needsFullScopeChain; bool m_usesEval; - bool m_usesArguments; bool m_isNumericCompareFunction; + bool m_isStrictMode; CodeType m_codeType; RefPtr m_source; unsigned m_sourceOffset; -#if !ENABLE(JIT) +#if ENABLE(INTERPRETER) Vector m_propertyAccessInstructions; Vector m_globalResolveInstructions; -#else +#endif +#if ENABLE(JIT) Vector m_structureStubInfos; Vector m_globalResolveInfos; Vector m_callLinkInfos; - Vector m_linkedCallerList; + Vector m_methodCallLinkInfos; #endif Vector m_jumpTargets; // Constant Pool Vector m_identifiers; - Vector m_constantRegisters; - Vector > m_functionExpressions; - - SymbolTable m_symbolTable; + COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier), Register_must_be_same_size_as_WriteBarrier_Unknown); + Vector > m_constantRegisters; + Vector > m_functionDecls; + Vector > m_functionExprs; - struct ExceptionInfo { - Vector m_expressionInfo; - Vector m_lineInfo; - Vector m_getByIdExceptionInfo; - -#if ENABLE(JIT) - Vector m_pcVector; -#endif - }; - OwnPtr m_exceptionInfo; + SymbolTable* m_symbolTable; struct RareData { + WTF_MAKE_FAST_ALLOCATED; + public: Vector m_exceptionHandlers; // Rare Constants - Vector > m_functions; - Vector m_unexpectedConstants; - Vector > m_regexps; + Vector > m_regexps; + // Buffers used for large array literals + Vector > m_constantBuffers; + // Jump Tables Vector m_immediateSwitchJumpTables; Vector m_characterSwitchJumpTables; @@ -534,51 +610,95 @@ namespace JSC { EvalCodeCache m_evalCodeCache; + // Expression info - present if debugging. + Vector m_expressionInfo; + // Line info - present if profiling or debugging. + Vector m_lineInfo; #if ENABLE(JIT) - Vector m_functionRegisterInfos; + Vector m_callReturnIndexVector; #endif }; +#if COMPILER(MSVC) + friend void WTF::deleteOwnedPtr(RareData*); +#endif OwnPtr m_rareData; }; // 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) - , m_globalObject(globalObject) + GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr sourceProvider, unsigned sourceOffset) + : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, &m_unsharedSymbolTable, false) { - m_globalObject->codeBlocks().add(this); } - ~ProgramCodeBlock() + private: + SymbolTable m_unsharedSymbolTable; + }; + + class ProgramCodeBlock : public GlobalCodeBlock { + public: + ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr sourceProvider) + : GlobalCodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, 0) { - if (m_globalObject) - m_globalObject->codeBlocks().remove(this); } - - void clearGlobalObject() { m_globalObject = 0; } - - private: - JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. }; - class EvalCodeBlock : public ProgramCodeBlock { + class EvalCodeBlock : public GlobalCodeBlock { public: - EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr sourceProvider, int baseScopeDepth) - : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider) + EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr sourceProvider, int baseScopeDepth) + : GlobalCodeBlock(ownerExecutable, EvalCode, globalObject, sourceProvider, 0) , 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, JSGlobalObject* globalObject, PassRefPtr sourceProvider, unsigned sourceOffset, bool isConstructor) + : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, SharedSymbolTable::create().leakRef(), isConstructor) + { + } + ~FunctionCodeBlock() + { + sharedSymbolTable()->deref(); + } + }; + + inline Register& ExecState::r(int index) + { + CodeBlock* codeBlock = this->codeBlock(); + if (codeBlock->isConstantRegisterIndex(index)) + return *reinterpret_cast(&codeBlock->constantRegister(index)); + return this[index]; + } + + inline Register& ExecState::uncheckedR(int index) + { + ASSERT(index < FirstConstantRegisterIndex); + return this[index]; + } + } // namespace JSC #endif // CodeBlock_h