1 /* 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #ifndef CodeBlock_h 31 #define CodeBlock_h 32 33 #include "EvalCodeCache.h" 34 #include "Instruction.h" 35 #include "JITCode.h" 36 #include "JSGlobalObject.h" 37 #include "JumpTable.h" 38 #include "Nodes.h" 39 #include "PtrAndFlags.h" 40 #include "RegExp.h" 41 #include "UString.h" 42 #include <wtf/FastAllocBase.h> 43 #include <wtf/RefPtr.h> 44 #include <wtf/Vector.h> 45 46 #if ENABLE(JIT) 47 #include "StructureStubInfo.h" 48 #endif 49 50 // Register numbers used in bytecode operations have different meaning accoring to their ranges: 51 // 0x80000000-0xFFFFFFFF Negative indicies from the CallFrame pointer are entries in the call frame, see RegisterFile.h. 52 // 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. 53 // 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. 54 static const int FirstConstantRegisterIndex = 0x40000000; 55 56 namespace JSC { 57 58 enum HasSeenShouldRepatch { 59 hasSeenShouldRepatch 60 }; 61 62 class ExecState; 63 64 enum CodeType { GlobalCode, EvalCode, FunctionCode }; 65 missingThisObjectMarker()66 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } 67 68 struct HandlerInfo { 69 uint32_t start; 70 uint32_t end; 71 uint32_t target; 72 uint32_t scopeDepth; 73 #if ENABLE(JIT) 74 CodeLocationLabel nativeCode; 75 #endif 76 }; 77 78 struct ExpressionRangeInfo { 79 enum { 80 MaxOffset = (1 << 7) - 1, 81 MaxDivot = (1 << 25) - 1 82 }; 83 uint32_t instructionOffset : 25; 84 uint32_t divotPoint : 25; 85 uint32_t startOffset : 7; 86 uint32_t endOffset : 7; 87 }; 88 89 struct LineInfo { 90 uint32_t instructionOffset; 91 int32_t lineNumber; 92 }; 93 94 // Both op_construct and op_instanceof require a use of op_get_by_id to get 95 // the prototype property from an object. The exception messages for exceptions 96 // thrown by these instances op_get_by_id need to reflect this. 97 struct GetByIdExceptionInfo { 98 unsigned bytecodeOffset : 31; 99 bool isOpConstruct : 1; 100 }; 101 102 #if ENABLE(JIT) 103 struct CallLinkInfo { CallLinkInfoCallLinkInfo104 CallLinkInfo() 105 : callee(0) 106 { 107 } 108 109 unsigned bytecodeIndex; 110 CodeLocationNearCall callReturnLocation; 111 CodeLocationDataLabelPtr hotPathBegin; 112 CodeLocationNearCall hotPathOther; 113 PtrAndFlags<CodeBlock, HasSeenShouldRepatch> ownerCodeBlock; 114 CodeBlock* callee; 115 unsigned position; 116 setUnlinkedCallLinkInfo117 void setUnlinked() { callee = 0; } isLinkedCallLinkInfo118 bool isLinked() { return callee; } 119 seenOnceCallLinkInfo120 bool seenOnce() 121 { 122 return ownerCodeBlock.isFlagSet(hasSeenShouldRepatch); 123 } 124 setSeenCallLinkInfo125 void setSeen() 126 { 127 ownerCodeBlock.setFlag(hasSeenShouldRepatch); 128 } 129 }; 130 131 struct MethodCallLinkInfo { MethodCallLinkInfoMethodCallLinkInfo132 MethodCallLinkInfo() 133 : cachedStructure(0) 134 { 135 } 136 seenOnceMethodCallLinkInfo137 bool seenOnce() 138 { 139 return cachedPrototypeStructure.isFlagSet(hasSeenShouldRepatch); 140 } 141 setSeenMethodCallLinkInfo142 void setSeen() 143 { 144 cachedPrototypeStructure.setFlag(hasSeenShouldRepatch); 145 } 146 147 CodeLocationCall callReturnLocation; 148 CodeLocationDataLabelPtr structureLabel; 149 Structure* cachedStructure; 150 PtrAndFlags<Structure, HasSeenShouldRepatch> cachedPrototypeStructure; 151 }; 152 153 struct FunctionRegisterInfo { FunctionRegisterInfoFunctionRegisterInfo154 FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex) 155 : bytecodeOffset(bytecodeOffset) 156 , functionRegisterIndex(functionRegisterIndex) 157 { 158 } 159 160 unsigned bytecodeOffset; 161 int functionRegisterIndex; 162 }; 163 164 struct GlobalResolveInfo { GlobalResolveInfoGlobalResolveInfo165 GlobalResolveInfo(unsigned bytecodeOffset) 166 : structure(0) 167 , offset(0) 168 , bytecodeOffset(bytecodeOffset) 169 { 170 } 171 172 Structure* structure; 173 unsigned offset; 174 unsigned bytecodeOffset; 175 }; 176 177 // This structure is used to map from a call return location 178 // (given as an offset in bytes into the JIT code) back to 179 // the bytecode index of the corresponding bytecode operation. 180 // This is then used to look up the corresponding handler. 181 struct CallReturnOffsetToBytecodeIndex { CallReturnOffsetToBytecodeIndexCallReturnOffsetToBytecodeIndex182 CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex) 183 : callReturnOffset(callReturnOffset) 184 , bytecodeIndex(bytecodeIndex) 185 { 186 } 187 188 unsigned callReturnOffset; 189 unsigned bytecodeIndex; 190 }; 191 192 // valueAtPosition helpers for the binaryChop algorithm below. 193 getStructureStubInfoReturnLocation(StructureStubInfo * structureStubInfo)194 inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) 195 { 196 return structureStubInfo->callReturnLocation.executableAddress(); 197 } 198 getCallLinkInfoReturnLocation(CallLinkInfo * callLinkInfo)199 inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) 200 { 201 return callLinkInfo->callReturnLocation.executableAddress(); 202 } 203 getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo * methodCallLinkInfo)204 inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) 205 { 206 return methodCallLinkInfo->callReturnLocation.executableAddress(); 207 } 208 getCallReturnOffset(CallReturnOffsetToBytecodeIndex * pc)209 inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc) 210 { 211 return pc->callReturnOffset; 212 } 213 214 // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array, 215 // compares result with key (KeyTypes should be comparable with '--', '<', '>'). 216 // Optimized for cases where the array contains the key, checked by assertions. 217 template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)> binaryChop(ArrayType * array,size_t size,KeyType key)218 inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key) 219 { 220 // The array must contain at least one element (pre-condition, array does conatin key). 221 // If the array only contains one element, no need to do the comparison. 222 while (size > 1) { 223 // Pick an element to check, half way through the array, and read the value. 224 int pos = (size - 1) >> 1; 225 KeyType val = valueAtPosition(&array[pos]); 226 227 // If the key matches, success! 228 if (val == key) 229 return &array[pos]; 230 // The item we are looking for is smaller than the item being check; reduce the value of 'size', 231 // chopping off the right hand half of the array. 232 else if (key < val) 233 size = pos; 234 // Discard all values in the left hand half of the array, up to and including the item at pos. 235 else { 236 size -= (pos + 1); 237 array += (pos + 1); 238 } 239 240 // 'size' should never reach zero. 241 ASSERT(size); 242 } 243 244 // If we reach this point we've chopped down to one element, no need to check it matches 245 ASSERT(size == 1); 246 ASSERT(key == valueAtPosition(&array[0])); 247 return &array[0]; 248 } 249 #endif 250 251 struct ExceptionInfo : FastAllocBase { 252 Vector<ExpressionRangeInfo> m_expressionInfo; 253 Vector<LineInfo> m_lineInfo; 254 Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; 255 256 #if ENABLE(JIT) 257 Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector; 258 #endif 259 }; 260 261 class CodeBlock : public FastAllocBase { 262 friend class JIT; 263 protected: 264 CodeBlock(ScriptExecutable* ownerExecutable, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable* symbolTable); 265 public: 266 virtual ~CodeBlock(); 267 268 void markAggregate(MarkStack&); 269 void refStructures(Instruction* vPC) const; 270 void derefStructures(Instruction* vPC) const; 271 #if ENABLE(JIT_OPTIMIZE_CALL) 272 void unlinkCallers(); 273 #endif 274 275 static void dumpStatistics(); 276 277 #if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING 278 void dump(ExecState*) const; 279 void printStructures(const Instruction*) const; 280 void printStructure(const char* name, const Instruction*, int operand) const; 281 #endif 282 isKnownNotImmediate(int index)283 inline bool isKnownNotImmediate(int index) 284 { 285 if (index == m_thisRegister) 286 return true; 287 288 if (isConstantRegisterIndex(index)) 289 return getConstant(index).isCell(); 290 291 return false; 292 } 293 isTemporaryRegisterIndex(int index)294 ALWAYS_INLINE bool isTemporaryRegisterIndex(int index) 295 { 296 return index >= m_numVars; 297 } 298 299 HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); 300 int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset); 301 int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); 302 bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&); 303 304 #if ENABLE(JIT) addCaller(CallLinkInfo * caller)305 void addCaller(CallLinkInfo* caller) 306 { 307 caller->callee = this; 308 caller->position = m_linkedCallerList.size(); 309 m_linkedCallerList.append(caller); 310 } 311 removeCaller(CallLinkInfo * caller)312 void removeCaller(CallLinkInfo* caller) 313 { 314 unsigned pos = caller->position; 315 unsigned lastPos = m_linkedCallerList.size() - 1; 316 317 if (pos != lastPos) { 318 m_linkedCallerList[pos] = m_linkedCallerList[lastPos]; 319 m_linkedCallerList[pos]->position = pos; 320 } 321 m_linkedCallerList.shrink(lastPos); 322 } 323 getStubInfo(ReturnAddressPtr returnAddress)324 StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) 325 { 326 return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value())); 327 } 328 getCallLinkInfo(ReturnAddressPtr returnAddress)329 CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) 330 { 331 return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value())); 332 } 333 getMethodCallLinkInfo(ReturnAddressPtr returnAddress)334 MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) 335 { 336 return *(binaryChop<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); 337 } 338 getBytecodeIndex(CallFrame * callFrame,ReturnAddressPtr returnAddress)339 unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) 340 { 341 reparseForExceptionInfoIfNecessary(callFrame); 342 return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerExecutable()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; 343 } 344 345 bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); 346 #endif 347 setIsNumericCompareFunction(bool isNumericCompareFunction)348 void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } isNumericCompareFunction()349 bool isNumericCompareFunction() { return m_isNumericCompareFunction; } 350 instructions()351 Vector<Instruction>& instructions() { return m_instructions; } discardBytecode()352 void discardBytecode() { m_instructions.clear(); } 353 354 #ifndef NDEBUG instructionCount()355 unsigned instructionCount() { return m_instructionCount; } setInstructionCount(unsigned instructionCount)356 void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } 357 #endif 358 359 #if ENABLE(JIT) getJITCode()360 JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); } executablePool()361 ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); } 362 #endif 363 ownerExecutable()364 ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; } 365 setGlobalData(JSGlobalData * globalData)366 void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } 367 setThisRegister(int thisRegister)368 void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } thisRegister()369 int thisRegister() const { return m_thisRegister; } 370 setNeedsFullScopeChain(bool needsFullScopeChain)371 void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } needsFullScopeChain()372 bool needsFullScopeChain() const { return m_needsFullScopeChain; } setUsesEval(bool usesEval)373 void setUsesEval(bool usesEval) { m_usesEval = usesEval; } usesEval()374 bool usesEval() const { return m_usesEval; } setUsesArguments(bool usesArguments)375 void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; } usesArguments()376 bool usesArguments() const { return m_usesArguments; } 377 codeType()378 CodeType codeType() const { return m_codeType; } 379 source()380 SourceProvider* source() const { return m_source.get(); } sourceOffset()381 unsigned sourceOffset() const { return m_sourceOffset; } 382 numberOfJumpTargets()383 size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } addJumpTarget(unsigned jumpTarget)384 void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } jumpTarget(int index)385 unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } lastJumpTarget()386 unsigned lastJumpTarget() const { return m_jumpTargets.last(); } 387 388 #if !ENABLE(JIT) addPropertyAccessInstruction(unsigned propertyAccessInstruction)389 void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); } addGlobalResolveInstruction(unsigned globalResolveInstruction)390 void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); } 391 bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); 392 #else numberOfStructureStubInfos()393 size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } addStructureStubInfo(const StructureStubInfo & stubInfo)394 void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); } structureStubInfo(int index)395 StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; } 396 addGlobalResolveInfo(unsigned globalResolveInstruction)397 void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); } globalResolveInfo(int index)398 GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } 399 bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); 400 numberOfCallLinkInfos()401 size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } addCallLinkInfo()402 void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); } callLinkInfo(int index)403 CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } 404 addMethodCallLinkInfos(unsigned n)405 void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(n); } methodCallLinkInfo(int index)406 MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } 407 addFunctionRegisterInfo(unsigned bytecodeOffset,int functionIndex)408 void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); } 409 #endif 410 411 // Exception handling support 412 numberOfExceptionHandlers()413 size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } addExceptionHandler(const HandlerInfo & hanler)414 void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } exceptionHandler(int index)415 HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } 416 hasExceptionInfo()417 bool hasExceptionInfo() const { return m_exceptionInfo; } clearExceptionInfo()418 void clearExceptionInfo() { m_exceptionInfo.clear(); } extractExceptionInfo()419 ExceptionInfo* extractExceptionInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); } 420 addExpressionInfo(const ExpressionRangeInfo & expressionInfo)421 void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } addGetByIdExceptionInfo(const GetByIdExceptionInfo & info)422 void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } 423 numberOfLineInfos()424 size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } addLineInfo(const LineInfo & lineInfo)425 void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); } lastLineInfo()426 LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } 427 428 #if ENABLE(JIT) callReturnIndexVector()429 Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; } 430 #endif 431 432 // Constant Pool 433 numberOfIdentifiers()434 size_t numberOfIdentifiers() const { return m_identifiers.size(); } addIdentifier(const Identifier & i)435 void addIdentifier(const Identifier& i) { return m_identifiers.append(i); } identifier(int index)436 Identifier& identifier(int index) { return m_identifiers[index]; } 437 numberOfConstantRegisters()438 size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } addConstantRegister(const Register & r)439 void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); } constantRegister(int index)440 Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } isConstantRegisterIndex(int index)441 ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } getConstant(int index)442 ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } 443 addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n)444 unsigned addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(n); return size; } functionDecl(int index)445 FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } numberOfFunctionDecls()446 int numberOfFunctionDecls() { return m_functionDecls.size(); } addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n)447 unsigned addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(n); return size; } functionExpr(int index)448 FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } 449 addRegExp(RegExp * r)450 unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; } regexp(int index)451 RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } 452 453 454 // Jump Tables 455 numberOfImmediateSwitchJumpTables()456 size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; } addImmediateSwitchJumpTable()457 SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); } immediateSwitchJumpTable(int tableIndex)458 SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; } 459 numberOfCharacterSwitchJumpTables()460 size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; } addCharacterSwitchJumpTable()461 SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); } characterSwitchJumpTable(int tableIndex)462 SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; } 463 numberOfStringSwitchJumpTables()464 size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; } addStringSwitchJumpTable()465 StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } stringSwitchJumpTable(int tableIndex)466 StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } 467 468 symbolTable()469 SymbolTable* symbolTable() { return m_symbolTable; } sharedSymbolTable()470 SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast<SharedSymbolTable*>(m_symbolTable); } 471 evalCodeCache()472 EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } 473 474 void shrinkToFit(); 475 476 // FIXME: Make these remaining members private. 477 478 int m_numCalleeRegisters; 479 int m_numVars; 480 int m_numParameters; 481 482 private: 483 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) 484 void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const; 485 486 CString registerName(ExecState*, int r) const; 487 void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; 488 void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; 489 void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const; 490 void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; 491 void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; 492 #endif 493 494 void reparseForExceptionInfoIfNecessary(CallFrame*); 495 createRareDataIfNecessary()496 void createRareDataIfNecessary() 497 { 498 if (!m_rareData) 499 m_rareData.set(new RareData); 500 } 501 502 ScriptExecutable* m_ownerExecutable; 503 JSGlobalData* m_globalData; 504 505 Vector<Instruction> m_instructions; 506 #ifndef NDEBUG 507 unsigned m_instructionCount; 508 #endif 509 510 int m_thisRegister; 511 512 bool m_needsFullScopeChain; 513 bool m_usesEval; 514 bool m_usesArguments; 515 bool m_isNumericCompareFunction; 516 517 CodeType m_codeType; 518 519 RefPtr<SourceProvider> m_source; 520 unsigned m_sourceOffset; 521 522 #if !ENABLE(JIT) 523 Vector<unsigned> m_propertyAccessInstructions; 524 Vector<unsigned> m_globalResolveInstructions; 525 #else 526 Vector<StructureStubInfo> m_structureStubInfos; 527 Vector<GlobalResolveInfo> m_globalResolveInfos; 528 Vector<CallLinkInfo> m_callLinkInfos; 529 Vector<MethodCallLinkInfo> m_methodCallLinkInfos; 530 Vector<CallLinkInfo*> m_linkedCallerList; 531 #endif 532 533 Vector<unsigned> m_jumpTargets; 534 535 // Constant Pool 536 Vector<Identifier> m_identifiers; 537 Vector<Register> m_constantRegisters; 538 Vector<RefPtr<FunctionExecutable> > m_functionDecls; 539 Vector<RefPtr<FunctionExecutable> > m_functionExprs; 540 541 SymbolTable* m_symbolTable; 542 543 OwnPtr<ExceptionInfo> m_exceptionInfo; 544 545 struct RareData : FastAllocBase { 546 Vector<HandlerInfo> m_exceptionHandlers; 547 548 // Rare Constants 549 Vector<RefPtr<RegExp> > m_regexps; 550 551 // Jump Tables 552 Vector<SimpleJumpTable> m_immediateSwitchJumpTables; 553 Vector<SimpleJumpTable> m_characterSwitchJumpTables; 554 Vector<StringJumpTable> m_stringSwitchJumpTables; 555 556 EvalCodeCache m_evalCodeCache; 557 558 #if ENABLE(JIT) 559 Vector<FunctionRegisterInfo> m_functionRegisterInfos; 560 #endif 561 }; 562 OwnPtr<RareData> m_rareData; 563 }; 564 565 // Program code is not marked by any function, so we make the global object 566 // responsible for marking it. 567 568 class GlobalCodeBlock : public CodeBlock { 569 public: GlobalCodeBlock(ScriptExecutable * ownerExecutable,CodeType codeType,PassRefPtr<SourceProvider> sourceProvider,unsigned sourceOffset,JSGlobalObject * globalObject)570 GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, JSGlobalObject* globalObject) 571 : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, &m_unsharedSymbolTable) 572 , m_globalObject(globalObject) 573 { 574 m_globalObject->codeBlocks().add(this); 575 } 576 ~GlobalCodeBlock()577 ~GlobalCodeBlock() 578 { 579 if (m_globalObject) 580 m_globalObject->codeBlocks().remove(this); 581 } 582 clearGlobalObject()583 void clearGlobalObject() { m_globalObject = 0; } 584 585 private: 586 JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. 587 SymbolTable m_unsharedSymbolTable; 588 }; 589 590 class ProgramCodeBlock : public GlobalCodeBlock { 591 public: ProgramCodeBlock(ProgramExecutable * ownerExecutable,CodeType codeType,JSGlobalObject * globalObject,PassRefPtr<SourceProvider> sourceProvider)592 ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider) 593 : GlobalCodeBlock(ownerExecutable, codeType, sourceProvider, 0, globalObject) 594 { 595 } 596 }; 597 598 class EvalCodeBlock : public GlobalCodeBlock { 599 public: EvalCodeBlock(EvalExecutable * ownerExecutable,JSGlobalObject * globalObject,PassRefPtr<SourceProvider> sourceProvider,int baseScopeDepth)600 EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth) 601 : GlobalCodeBlock(ownerExecutable, EvalCode, sourceProvider, 0, globalObject) 602 , m_baseScopeDepth(baseScopeDepth) 603 { 604 } 605 baseScopeDepth()606 int baseScopeDepth() const { return m_baseScopeDepth; } 607 variable(unsigned index)608 const Identifier& variable(unsigned index) { return m_variables[index]; } numVariables()609 unsigned numVariables() { return m_variables.size(); } adoptVariables(Vector<Identifier> & variables)610 void adoptVariables(Vector<Identifier>& variables) 611 { 612 ASSERT(m_variables.isEmpty()); 613 m_variables.swap(variables); 614 } 615 616 private: 617 int m_baseScopeDepth; 618 Vector<Identifier> m_variables; 619 }; 620 621 class FunctionCodeBlock : public CodeBlock { 622 public: 623 // Rather than using the usual RefCounted::create idiom for SharedSymbolTable we just use new 624 // as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared 625 // symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref 626 // in the destructor. FunctionCodeBlock(FunctionExecutable * ownerExecutable,CodeType codeType,PassRefPtr<SourceProvider> sourceProvider,unsigned sourceOffset)627 FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset) 628 : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable) 629 { 630 } ~FunctionCodeBlock()631 ~FunctionCodeBlock() 632 { 633 sharedSymbolTable()->deref(); 634 } 635 }; 636 r(int index)637 inline Register& ExecState::r(int index) 638 { 639 CodeBlock* codeBlock = this->codeBlock(); 640 if (codeBlock->isConstantRegisterIndex(index)) 641 return codeBlock->constantRegister(index); 642 return this[index]; 643 } 644 645 } // namespace JSC 646 647 #endif // CodeBlock_h 648