| 1 | /* |
| 2 | * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. |
| 3 | * Copyright (C) 2008 Cameron Zwarich <[email protected]> |
| 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 | |
| 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 { |
| 104 | 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 | |
| 117 | void setUnlinked() { callee = 0; } |
| 118 | bool isLinked() { return callee; } |
| 119 | |
| 120 | bool seenOnce() |
| 121 | { |
| 122 | return ownerCodeBlock.isFlagSet(flagNumber: hasSeenShouldRepatch); |
| 123 | } |
| 124 | |
| 125 | void setSeen() |
| 126 | { |
| 127 | ownerCodeBlock.setFlag(hasSeenShouldRepatch); |
| 128 | } |
| 129 | }; |
| 130 | |
| 131 | struct MethodCallLinkInfo { |
| 132 | MethodCallLinkInfo() |
| 133 | : cachedStructure(0) |
| 134 | { |
| 135 | } |
| 136 | |
| 137 | bool seenOnce() |
| 138 | { |
| 139 | return cachedPrototypeStructure.isFlagSet(flagNumber: hasSeenShouldRepatch); |
| 140 | } |
| 141 | |
| 142 | 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 { |
| 154 | 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 { |
| 165 | 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 { |
| 182 | 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 | |
| 194 | inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) |
| 195 | { |
| 196 | return structureStubInfo->callReturnLocation.executableAddress(); |
| 197 | } |
| 198 | |
| 199 | inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) |
| 200 | { |
| 201 | return callLinkInfo->callReturnLocation.executableAddress(); |
| 202 | } |
| 203 | |
| 204 | inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) |
| 205 | { |
| 206 | return methodCallLinkInfo->callReturnLocation.executableAddress(); |
| 207 | } |
| 208 | |
| 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*)> |
| 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 | |
| 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 | |
| 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) |
| 305 | void addCaller(CallLinkInfo* caller) |
| 306 | { |
| 307 | caller->callee = this; |
| 308 | caller->position = m_linkedCallerList.size(); |
| 309 | m_linkedCallerList.append(val: caller); |
| 310 | } |
| 311 | |
| 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(size: lastPos); |
| 322 | } |
| 323 | |
| 324 | StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) |
| 325 | { |
| 326 | return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(array: m_structureStubInfos.begin(), size: m_structureStubInfos.size(), key: returnAddress.value())); |
| 327 | } |
| 328 | |
| 329 | CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) |
| 330 | { |
| 331 | return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(array: m_callLinkInfos.begin(), size: m_callLinkInfos.size(), key: returnAddress.value())); |
| 332 | } |
| 333 | |
| 334 | MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) |
| 335 | { |
| 336 | return *(binaryChop<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(array: m_methodCallLinkInfos.begin(), size: m_methodCallLinkInfos.size(), key: returnAddress.value())); |
| 337 | } |
| 338 | |
| 339 | unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) |
| 340 | { |
| 341 | reparseForExceptionInfoIfNecessary(callFrame); |
| 342 | return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(array: callReturnIndexVector().begin(), size: callReturnIndexVector().size(), key: ownerExecutable()->generatedJITCode().offsetOf(pointerIntoCode: returnAddress.value()))->bytecodeIndex; |
| 343 | } |
| 344 | |
| 345 | bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); |
| 346 | #endif |
| 347 | |
| 348 | void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } |
| 349 | bool isNumericCompareFunction() { return m_isNumericCompareFunction; } |
| 350 | |
| 351 | Vector<Instruction>& instructions() { return m_instructions; } |
| 352 | void discardBytecode() { m_instructions.clear(); } |
| 353 | |
| 354 | #ifndef NDEBUG |
| 355 | unsigned instructionCount() { return m_instructionCount; } |
| 356 | void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } |
| 357 | #endif |
| 358 | |
| 359 | #if ENABLE(JIT) |
| 360 | JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); } |
| 361 | ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); } |
| 362 | #endif |
| 363 | |
| 364 | ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; } |
| 365 | |
| 366 | void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } |
| 367 | |
| 368 | void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } |
| 369 | int thisRegister() const { return m_thisRegister; } |
| 370 | |
| 371 | void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } |
| 372 | bool needsFullScopeChain() const { return m_needsFullScopeChain; } |
| 373 | void setUsesEval(bool usesEval) { m_usesEval = usesEval; } |
| 374 | bool usesEval() const { return m_usesEval; } |
| 375 | void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; } |
| 376 | bool usesArguments() const { return m_usesArguments; } |
| 377 | |
| 378 | CodeType codeType() const { return m_codeType; } |
| 379 | |
| 380 | SourceProvider* source() const { return m_source.get(); } |
| 381 | unsigned sourceOffset() const { return m_sourceOffset; } |
| 382 | |
| 383 | size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } |
| 384 | void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(val: jumpTarget); } |
| 385 | unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } |
| 386 | unsigned lastJumpTarget() const { return m_jumpTargets.last(); } |
| 387 | |
| 388 | #if !ENABLE(JIT) |
| 389 | void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); } |
| 390 | void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); } |
| 391 | bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); |
| 392 | #else |
| 393 | size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } |
| 394 | void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(val: stubInfo); } |
| 395 | StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; } |
| 396 | |
| 397 | void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(val: GlobalResolveInfo(globalResolveInstruction)); } |
| 398 | GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } |
| 399 | bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); |
| 400 | |
| 401 | size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } |
| 402 | void addCallLinkInfo() { m_callLinkInfos.append(val: CallLinkInfo()); } |
| 403 | CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } |
| 404 | |
| 405 | void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(size: n); } |
| 406 | MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } |
| 407 | |
| 408 | void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(val: FunctionRegisterInfo(bytecodeOffset, functionIndex)); } |
| 409 | #endif |
| 410 | |
| 411 | // Exception handling support |
| 412 | |
| 413 | size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } |
| 414 | void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(val: hanler); } |
| 415 | HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } |
| 416 | |
| 417 | bool hasExceptionInfo() const { return m_exceptionInfo; } |
| 418 | void clearExceptionInfo() { m_exceptionInfo.clear(); } |
| 419 | ExceptionInfo* () { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); } |
| 420 | |
| 421 | void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(val: expressionInfo); } |
| 422 | void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(val: info); } |
| 423 | |
| 424 | size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } |
| 425 | void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(val: lineInfo); } |
| 426 | LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } |
| 427 | |
| 428 | #if ENABLE(JIT) |
| 429 | Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; } |
| 430 | #endif |
| 431 | |
| 432 | // Constant Pool |
| 433 | |
| 434 | size_t numberOfIdentifiers() const { return m_identifiers.size(); } |
| 435 | void addIdentifier(const Identifier& i) { return m_identifiers.append(val: i); } |
| 436 | Identifier& identifier(int index) { return m_identifiers[index]; } |
| 437 | |
| 438 | size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } |
| 439 | void addConstantRegister(const Register& r) { return m_constantRegisters.append(val: r); } |
| 440 | Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } |
| 441 | ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } |
| 442 | ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } |
| 443 | |
| 444 | unsigned addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(val: n); return size; } |
| 445 | FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } |
| 446 | int numberOfFunctionDecls() { return m_functionDecls.size(); } |
| 447 | unsigned addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(val: n); return size; } |
| 448 | FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } |
| 449 | |
| 450 | unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(val: r); return size; } |
| 451 | RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } |
| 452 | |
| 453 | |
| 454 | // Jump Tables |
| 455 | |
| 456 | size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; } |
| 457 | SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(val: SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); } |
| 458 | SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; } |
| 459 | |
| 460 | size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; } |
| 461 | SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(val: SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); } |
| 462 | SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; } |
| 463 | |
| 464 | size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; } |
| 465 | StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(val: StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } |
| 466 | StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } |
| 467 | |
| 468 | |
| 469 | SymbolTable* symbolTable() { return m_symbolTable; } |
| 470 | SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast<SharedSymbolTable*>(m_symbolTable); } |
| 471 | |
| 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 | |
| 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: |
| 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(value: this); |
| 575 | } |
| 576 | |
| 577 | ~GlobalCodeBlock() |
| 578 | { |
| 579 | if (m_globalObject) |
| 580 | m_globalObject->codeBlocks().remove(value: this); |
| 581 | } |
| 582 | |
| 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: |
| 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: |
| 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 | |
| 606 | int baseScopeDepth() const { return m_baseScopeDepth; } |
| 607 | |
| 608 | const Identifier& variable(unsigned index) { return m_variables[index]; } |
| 609 | unsigned numVariables() { return m_variables.size(); } |
| 610 | void adoptVariables(Vector<Identifier>& variables) |
| 611 | { |
| 612 | ASSERT(m_variables.isEmpty()); |
| 613 | m_variables.swap(other&: 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. |
| 627 | FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset) |
| 628 | : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable) |
| 629 | { |
| 630 | } |
| 631 | ~FunctionCodeBlock() |
| 632 | { |
| 633 | sharedSymbolTable()->deref(); |
| 634 | } |
| 635 | }; |
| 636 | |
| 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 | |