Changeset 41126 in webkit for trunk/JavaScriptCore/runtime/TimeoutChecker.cpp
- Timestamp:
- Feb 22, 2009, 3:26:07 PM (16 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/runtime/TimeoutChecker.cpp
r41100 r41126 29 29 30 30 #include "config.h" 31 #include " Interpreter.h"31 #include "TimeoutChecker.h" 32 32 33 #include "Arguments.h"34 #include "BatchedTransitionOptimizer.h"35 #include "CodeBlock.h"36 #include "DebuggerCallFrame.h"37 #include "EvalCodeCache.h"38 #include "ExceptionHelpers.h"39 33 #include "CallFrame.h" 40 #include "GlobalEvalFunction.h" 41 #include "JSActivation.h" 42 #include "JSArray.h" 43 #include "JSByteArray.h" 44 #include "JSFunction.h" 45 #include "JSNotAnObject.h" 46 #include "JSPropertyNameIterator.h" 47 #include "JSStaticScopeObject.h" 48 #include "JSString.h" 49 #include "ObjectPrototype.h" 50 #include "Parser.h" 51 #include "Profiler.h" 52 #include "RegExpObject.h" 53 #include "RegExpPrototype.h" 54 #include "Register.h" 55 #include "Collector.h" 56 #include "Debugger.h" 57 #include "Operations.h" 58 #include "SamplingTool.h" 59 #include <stdio.h> 60 61 #if ENABLE(JIT) 62 #include "JIT.h" 63 #endif 64 65 #if ENABLE(ASSEMBLER) 66 #include "AssemblerBuffer.h" 67 #endif 34 #include "JSGlobalObject.h" 68 35 69 36 #if PLATFORM(DARWIN) … … 87 54 namespace JSC { 88 55 89 // Preferred number of milliseconds between each timeout check90 static const int preferredScriptCheckTimeInterval = 1000;56 // Number of ticks before the first timeout check is done. 57 static const int ticksUntilFirstCheck = 1024; 91 58 92 static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc) 93 { 94 #if ENABLE(JIT) 95 return codeBlock->getBytecodeIndex(callFrame, pc); 96 #else 97 UNUSED_PARAM(callFrame); 98 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin(); 99 #endif 100 } 101 102 // Returns the depth of the scope chain within a given call frame. 103 static int depth(CodeBlock* codeBlock, ScopeChain& sc) 104 { 105 if (!codeBlock->needsFullScopeChain()) 106 return 0; 107 return sc.localDepth(); 108 } 109 110 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue) 111 { 112 int dst = (vPC + 1)->u.operand; 113 int property = (vPC + 2)->u.operand; 114 115 ScopeChainNode* scopeChain = callFrame->scopeChain(); 116 ScopeChainIterator iter = scopeChain->begin(); 117 ScopeChainIterator end = scopeChain->end(); 118 ASSERT(iter != end); 119 120 CodeBlock* codeBlock = callFrame->codeBlock(); 121 Identifier& ident = codeBlock->identifier(property); 122 do { 123 JSObject* o = *iter; 124 PropertySlot slot(o); 125 if (o->getPropertySlot(callFrame, ident, slot)) { 126 JSValuePtr result = slot.getValue(callFrame, ident); 127 exceptionValue = callFrame->globalData().exception; 128 if (exceptionValue) 129 return false; 130 callFrame[dst] = JSValuePtr(result); 131 return true; 132 } 133 } while (++iter != end); 134 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 135 return false; 136 } 137 138 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue) 139 { 140 CodeBlock* codeBlock = callFrame->codeBlock(); 141 142 int dst = (vPC + 1)->u.operand; 143 int property = (vPC + 2)->u.operand; 144 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain(); 145 146 ScopeChainNode* scopeChain = callFrame->scopeChain(); 147 ScopeChainIterator iter = scopeChain->begin(); 148 ScopeChainIterator end = scopeChain->end(); 149 ASSERT(iter != end); 150 while (skip--) { 151 ++iter; 152 ASSERT(iter != end); 153 } 154 Identifier& ident = codeBlock->identifier(property); 155 do { 156 JSObject* o = *iter; 157 PropertySlot slot(o); 158 if (o->getPropertySlot(callFrame, ident, slot)) { 159 JSValuePtr result = slot.getValue(callFrame, ident); 160 exceptionValue = callFrame->globalData().exception; 161 if (exceptionValue) 162 return false; 163 callFrame[dst] = JSValuePtr(result); 164 return true; 165 } 166 } while (++iter != end); 167 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 168 return false; 169 } 170 171 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue) 172 { 173 int dst = (vPC + 1)->u.operand; 174 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell); 175 ASSERT(globalObject->isGlobalObject()); 176 int property = (vPC + 3)->u.operand; 177 Structure* structure = (vPC + 4)->u.structure; 178 int offset = (vPC + 5)->u.operand; 179 180 if (structure == globalObject->structure()) { 181 callFrame[dst] = JSValuePtr(globalObject->getDirectOffset(offset)); 182 return true; 183 } 184 185 CodeBlock* codeBlock = callFrame->codeBlock(); 186 Identifier& ident = codeBlock->identifier(property); 187 PropertySlot slot(globalObject); 188 if (globalObject->getPropertySlot(callFrame, ident, slot)) { 189 JSValuePtr result = slot.getValue(callFrame, ident); 190 if (slot.isCacheable() && !globalObject->structure()->isDictionary()) { 191 if (vPC[4].u.structure) 192 vPC[4].u.structure->deref(); 193 globalObject->structure()->ref(); 194 vPC[4] = globalObject->structure(); 195 vPC[5] = slot.cachedOffset(); 196 callFrame[dst] = JSValuePtr(result); 197 return true; 198 } 199 200 exceptionValue = callFrame->globalData().exception; 201 if (exceptionValue) 202 return false; 203 callFrame[dst] = JSValuePtr(result); 204 return true; 205 } 206 207 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 208 return false; 209 } 210 211 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC) 212 { 213 int dst = (vPC + 1)->u.operand; 214 int property = (vPC + 2)->u.operand; 215 callFrame[dst] = JSValuePtr(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain())); 216 } 217 218 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue) 219 { 220 int baseDst = (vPC + 1)->u.operand; 221 int propDst = (vPC + 2)->u.operand; 222 int property = (vPC + 3)->u.operand; 223 224 ScopeChainNode* scopeChain = callFrame->scopeChain(); 225 ScopeChainIterator iter = scopeChain->begin(); 226 ScopeChainIterator end = scopeChain->end(); 227 228 // FIXME: add scopeDepthIsZero optimization 229 230 ASSERT(iter != end); 231 232 CodeBlock* codeBlock = callFrame->codeBlock(); 233 Identifier& ident = codeBlock->identifier(property); 234 JSObject* base; 235 do { 236 base = *iter; 237 PropertySlot slot(base); 238 if (base->getPropertySlot(callFrame, ident, slot)) { 239 JSValuePtr result = slot.getValue(callFrame, ident); 240 exceptionValue = callFrame->globalData().exception; 241 if (exceptionValue) 242 return false; 243 callFrame[propDst] = JSValuePtr(result); 244 callFrame[baseDst] = JSValuePtr(base); 245 return true; 246 } 247 ++iter; 248 } while (iter != end); 249 250 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 251 return false; 252 } 253 254 NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValuePtr& exceptionValue) 255 { 256 int baseDst = (vPC + 1)->u.operand; 257 int funcDst = (vPC + 2)->u.operand; 258 int property = (vPC + 3)->u.operand; 259 260 ScopeChainNode* scopeChain = callFrame->scopeChain(); 261 ScopeChainIterator iter = scopeChain->begin(); 262 ScopeChainIterator end = scopeChain->end(); 263 264 // FIXME: add scopeDepthIsZero optimization 265 266 ASSERT(iter != end); 267 268 CodeBlock* codeBlock = callFrame->codeBlock(); 269 Identifier& ident = codeBlock->identifier(property); 270 JSObject* base; 271 do { 272 base = *iter; 273 PropertySlot slot(base); 274 if (base->getPropertySlot(callFrame, ident, slot)) { 275 // ECMA 11.2.3 says that if we hit an activation the this value should be null. 276 // However, section 10.2.3 says that in the case where the value provided 277 // by the caller is null, the global object should be used. It also says 278 // that the section does not apply to internal functions, but for simplicity 279 // of implementation we use the global object anyway here. This guarantees 280 // that in host objects you always get a valid object for this. 281 // We also handle wrapper substitution for the global object at the same time. 282 JSObject* thisObj = base->toThisObject(callFrame); 283 JSValuePtr result = slot.getValue(callFrame, ident); 284 exceptionValue = callFrame->globalData().exception; 285 if (exceptionValue) 286 return false; 287 288 callFrame[baseDst] = JSValuePtr(thisObj); 289 callFrame[funcDst] = JSValuePtr(result); 290 return true; 291 } 292 ++iter; 293 } while (iter != end); 294 295 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 296 return false; 297 } 298 299 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc) 300 { 301 Register* r = callFrame->registers(); 302 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters; 303 304 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments 305 if (UNLIKELY(!registerFile->grow(newEnd))) 306 return 0; 307 r += registerOffset; 308 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks 309 size_t omittedArgCount = newCodeBlock->m_numParameters - argc; 310 registerOffset += omittedArgCount; 311 newEnd += omittedArgCount; 312 if (!registerFile->grow(newEnd)) 313 return 0; 314 r += registerOffset; 315 316 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; 317 for (size_t i = 0; i < omittedArgCount; ++i) 318 argv[i] = jsUndefined(); 319 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind 320 size_t numParameters = newCodeBlock->m_numParameters; 321 registerOffset += numParameters; 322 newEnd += numParameters; 323 324 if (!registerFile->grow(newEnd)) 325 return 0; 326 r += registerOffset; 327 328 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc; 329 for (size_t i = 0; i < numParameters; ++i) 330 argv[i + argc] = argv[i]; 331 } 332 333 return CallFrame::create(r); 334 } 335 336 static NEVER_INLINE bool isNotObject(CallFrame* callFrame, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValuePtr value, JSValuePtr& exceptionData) 337 { 338 if (value.isObject()) 339 return false; 340 exceptionData = createInvalidParamError(callFrame, forInstanceOf ? "instanceof" : "in" , value, vPC - codeBlock->instructions().begin(), codeBlock); 341 return true; 342 } 343 344 NEVER_INLINE JSValuePtr Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValuePtr& exceptionValue) 345 { 346 if (argc < 2) 347 return jsUndefined(); 348 349 JSValuePtr program = argv[1].jsValue(callFrame); 350 351 if (!program.isString()) 352 return program; 353 354 UString programSource = asString(program)->value(); 355 356 ScopeChainNode* scopeChain = callFrame->scopeChain(); 357 CodeBlock* codeBlock = callFrame->codeBlock(); 358 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); 359 360 JSValuePtr result = jsUndefined(); 361 if (evalNode) 362 result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); 363 364 return result; 365 } 366 367 Interpreter::Interpreter() 368 : m_sampler(0) 369 #if ENABLE(JIT) 370 , m_ctiArrayLengthTrampoline(0) 371 , m_ctiStringLengthTrampoline(0) 372 , m_ctiVirtualCallPreLink(0) 373 , m_ctiVirtualCallLink(0) 374 , m_ctiVirtualCall(0) 375 #endif 376 , m_reentryDepth(0) 377 , m_timeoutTime(0) 378 , m_timeAtLastCheckTimeout(0) 379 , m_timeExecuting(0) 380 , m_timeoutCheckCount(0) 381 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold) 382 { 383 initTimeout(); 384 privateExecute(InitializeAndReturn, 0, 0, 0); 385 386 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. 387 void* storage = fastMalloc(sizeof(CollectorBlock)); 388 389 JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); 390 m_jsArrayVptr = jsArray->vptr(); 391 jsArray->~JSCell(); 392 393 JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); 394 m_jsByteArrayVptr = jsByteArray->vptr(); 395 jsByteArray->~JSCell(); 396 397 JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); 398 m_jsStringVptr = jsString->vptr(); 399 jsString->~JSCell(); 400 401 JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); 402 m_jsFunctionVptr = jsFunction->vptr(); 403 jsFunction->~JSCell(); 404 405 fastFree(storage); 406 } 407 408 void Interpreter::initialize(JSGlobalData* globalData) 409 { 410 #if ENABLE(JIT) 411 JIT::compileCTIMachineTrampolines(globalData); 412 #else 413 UNUSED_PARAM(globalData); 414 #endif 415 } 416 417 Interpreter::~Interpreter() 418 { 419 } 420 421 #ifndef NDEBUG 422 423 void Interpreter::dumpCallFrame(CallFrame* callFrame) 424 { 425 callFrame->codeBlock()->dump(callFrame); 426 dumpRegisters(callFrame); 427 } 428 429 void Interpreter::dumpRegisters(CallFrame* callFrame) 430 { 431 printf("Register frame: \n\n"); 432 printf("----------------------------------------------------\n"); 433 printf(" use | address | value \n"); 434 printf("----------------------------------------------------\n"); 435 436 CodeBlock* codeBlock = callFrame->codeBlock(); 437 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile(); 438 const Register* it; 439 const Register* end; 440 441 if (codeBlock->codeType() == GlobalCode) { 442 it = registerFile->lastGlobal(); 443 end = it + registerFile->numGlobals(); 444 while (it != end) { 445 printf("[global var] | %10p | %10p \n", it, (*it).v()); 446 ++it; 447 } 448 printf("----------------------------------------------------\n"); 449 } 450 451 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters; 452 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it; 453 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this" 454 if (it != end) { 455 do { 456 printf("[param] | %10p | %10p \n", it, (*it).v()); 457 ++it; 458 } while (it != end); 459 } 460 printf("----------------------------------------------------\n"); 461 462 printf("[CodeBlock] | %10p | %10p \n", it, (*it).v()); ++it; 463 printf("[ScopeChain] | %10p | %10p \n", it, (*it).v()); ++it; 464 printf("[CallerRegisters] | %10p | %10p \n", it, (*it).v()); ++it; 465 printf("[ReturnPC] | %10p | %10p \n", it, (*it).v()); ++it; 466 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it; 467 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it; 468 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it; 469 printf("[OptionalCalleeArguments] | %10p | %10p \n", it, (*it).v()); ++it; 470 printf("----------------------------------------------------\n"); 471 472 int registerCount = 0; 473 474 end = it + codeBlock->m_numVars; 475 if (it != end) { 476 do { 477 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); 478 ++it; 479 ++registerCount; 480 } while (it != end); 481 } 482 printf("----------------------------------------------------\n"); 483 484 end = it + codeBlock->m_numConstants; 485 if (it != end) { 486 do { 487 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); 488 ++it; 489 ++registerCount; 490 } while (it != end); 491 } 492 printf("----------------------------------------------------\n"); 493 494 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numConstants - codeBlock->m_numVars; 495 if (it != end) { 496 do { 497 printf("[r%2d] | %10p | %10p \n", registerCount, it, (*it).v()); 498 ++it; 499 ++registerCount; 500 } while (it != end); 501 } 502 printf("----------------------------------------------------\n"); 503 } 504 505 #endif 506 507 bool Interpreter::isOpcode(Opcode opcode) 508 { 509 #if HAVE(COMPUTED_GOTO) 510 return opcode != HashTraits<Opcode>::emptyValue() 511 && !HashTraits<Opcode>::isDeletedValue(opcode) 512 && m_opcodeIDTable.contains(opcode); 513 #else 514 return opcode >= 0 && opcode <= op_end; 515 #endif 516 } 517 518 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValuePtr exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock) 519 { 520 CodeBlock* oldCodeBlock = codeBlock; 521 ScopeChainNode* scopeChain = callFrame->scopeChain(); 522 523 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { 524 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); 525 if (callFrame->callee()) 526 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); 527 else 528 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); 529 } 530 531 if (Profiler* profiler = *Profiler::enabledProfilerReference()) { 532 if (callFrame->callee()) 533 profiler->didExecute(callFrame, callFrame->callee()); 534 else 535 profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo()); 536 } 537 538 // If this call frame created an activation or an 'arguments' object, tear it off. 539 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { 540 while (!scopeChain->object->isObject(&JSActivation::info)) 541 scopeChain = scopeChain->pop(); 542 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments()); 543 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) { 544 if (!arguments->isTornOff()) 545 arguments->copyRegisters(); 546 } 547 548 if (oldCodeBlock->needsFullScopeChain()) 549 scopeChain->deref(); 550 551 void* returnPC = callFrame->returnPC(); 552 callFrame = callFrame->callerFrame(); 553 if (callFrame->hasHostCallFrameFlag()) 554 return false; 555 556 codeBlock = callFrame->codeBlock(); 557 bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC); 558 return true; 559 } 560 561 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValuePtr& exceptionValue, unsigned bytecodeOffset, bool explicitThrow) 562 { 563 // Set up the exception object 564 565 CodeBlock* codeBlock = callFrame->codeBlock(); 566 if (exceptionValue.isObject()) { 567 JSObject* exception = asObject(exceptionValue); 568 if (exception->isNotAnObjectErrorStub()) { 569 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock); 570 exceptionValue = exception; 571 } else { 572 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) && 573 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) && 574 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) && 575 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) && 576 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) && 577 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) { 578 if (explicitThrow) { 579 int startOffset = 0; 580 int endOffset = 0; 581 int divotPoint = 0; 582 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset); 583 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete); 584 585 // We only hit this path for error messages and throw statements, which don't have a specific failure position 586 // So we just give the full range of the error/throw statement. 587 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete); 588 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete); 589 } else 590 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete); 591 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete); 592 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete); 593 } 594 595 if (exception->isWatchdogException()) { 596 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { 597 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. 598 } 599 return 0; 600 } 601 } 602 } 603 604 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { 605 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); 606 debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)); 607 } 608 609 // If we throw in the middle of a call instruction, we need to notify 610 // the profiler manually that the call instruction has returned, since 611 // we'll never reach the relevant op_profile_did_call. 612 if (Profiler* profiler = *Profiler::enabledProfilerReference()) { 613 #if !ENABLE(JIT) 614 if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode)) 615 profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 2].u.operand].jsValue(callFrame)); 616 else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) 617 profiler->didExecute(callFrame, callFrame[codeBlock->instructions()[bytecodeOffset + 10].u.operand].jsValue(callFrame)); 618 #else 619 int functionRegisterIndex; 620 if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex)) 621 profiler->didExecute(callFrame, callFrame[functionRegisterIndex].jsValue(callFrame)); 622 #endif 623 } 624 625 // Calculate an exception handler vPC, unwinding call frames as necessary. 626 627 HandlerInfo* handler = 0; 628 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { 629 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) 630 return 0; 631 } 632 633 // Now unwind the scope chain within the exception handler's call frame. 634 635 ScopeChainNode* scopeChain = callFrame->scopeChain(); 636 ScopeChain sc(scopeChain); 637 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth; 638 ASSERT(scopeDelta >= 0); 639 while (scopeDelta--) 640 scopeChain = scopeChain->pop(); 641 callFrame->setScopeChain(scopeChain); 642 643 return handler; 644 } 645 646 JSValuePtr Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValuePtr* exception) 647 { 648 ASSERT(!scopeChain->globalData->exception); 649 650 if (m_reentryDepth >= MaxReentryDepth) { 651 *exception = createStackOverflowError(callFrame); 652 return jsNull(); 653 } 654 655 CodeBlock* codeBlock = &programNode->bytecode(scopeChain); 656 657 Register* oldEnd = m_registerFile.end(); 658 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; 659 if (!m_registerFile.grow(newEnd)) { 660 *exception = createStackOverflowError(callFrame); 661 return jsNull(); 662 } 663 664 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject()); 665 666 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject(); 667 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject(); 668 globalObject->copyGlobalsTo(m_registerFile); 669 670 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize); 671 newCallFrame[codeBlock->thisRegister()] = JSValuePtr(thisObj); 672 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0); 673 674 if (codeBlock->needsFullScopeChain()) 675 scopeChain->ref(); 676 677 Profiler** profiler = Profiler::enabledProfilerReference(); 678 if (*profiler) 679 (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo()); 680 681 JSValuePtr result; 682 { 683 SamplingTool::CallRecord callRecord(m_sampler); 684 685 m_reentryDepth++; 686 #if ENABLE(JIT) 687 if (!codeBlock->jitCode()) 688 JIT::compile(scopeChain->globalData, codeBlock); 689 result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 690 #else 691 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 692 #endif 693 m_reentryDepth--; 694 } 695 696 if (*profiler) 697 (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo()); 698 699 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject) 700 lastGlobalObject->copyGlobalsTo(m_registerFile); 701 702 m_registerFile.shrink(oldEnd); 703 704 return result; 705 } 706 707 JSValuePtr Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValuePtr* exception) 708 { 709 ASSERT(!scopeChain->globalData->exception); 710 711 if (m_reentryDepth >= MaxReentryDepth) { 712 *exception = createStackOverflowError(callFrame); 713 return jsNull(); 714 } 715 716 Register* oldEnd = m_registerFile.end(); 717 int argc = 1 + args.size(); // implicit "this" parameter 718 719 if (!m_registerFile.grow(oldEnd + argc)) { 720 *exception = createStackOverflowError(callFrame); 721 return jsNull(); 722 } 723 724 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); 725 726 CallFrame* newCallFrame = CallFrame::create(oldEnd); 727 size_t dst = 0; 728 newCallFrame[0] = JSValuePtr(thisObj); 729 ArgList::const_iterator end = args.end(); 730 for (ArgList::const_iterator it = args.begin(); it != end; ++it) 731 newCallFrame[++dst] = *it; 732 733 CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain); 734 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); 735 if (UNLIKELY(!newCallFrame)) { 736 *exception = createStackOverflowError(callFrame); 737 m_registerFile.shrink(oldEnd); 738 return jsNull(); 739 } 740 // a 0 codeBlock indicates a built-in caller 741 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function); 742 743 Profiler** profiler = Profiler::enabledProfilerReference(); 744 if (*profiler) 745 (*profiler)->willExecute(callFrame, function); 746 747 JSValuePtr result; 748 { 749 SamplingTool::CallRecord callRecord(m_sampler); 750 751 m_reentryDepth++; 752 #if ENABLE(JIT) 753 if (!codeBlock->jitCode()) 754 JIT::compile(scopeChain->globalData, codeBlock); 755 result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 756 #else 757 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 758 #endif 759 m_reentryDepth--; 760 } 761 762 if (*profiler) 763 (*profiler)->didExecute(callFrame, function); 764 765 m_registerFile.shrink(oldEnd); 766 return result; 767 } 768 769 JSValuePtr Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValuePtr* exception) 770 { 771 return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->bytecode(scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception); 772 } 773 774 JSValuePtr Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValuePtr* exception) 775 { 776 ASSERT(!scopeChain->globalData->exception); 777 778 if (m_reentryDepth >= MaxReentryDepth) { 779 *exception = createStackOverflowError(callFrame); 780 return jsNull(); 781 } 782 783 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); 784 785 EvalCodeBlock* codeBlock = &evalNode->bytecode(scopeChain); 786 787 JSVariableObject* variableObject; 788 for (ScopeChainNode* node = scopeChain; ; node = node->next) { 789 ASSERT(node); 790 if (node->object->isVariableObject()) { 791 variableObject = static_cast<JSVariableObject*>(node->object); 792 break; 793 } 794 } 795 796 { // Scope for BatchedTransitionOptimizer 797 798 BatchedTransitionOptimizer optimizer(variableObject); 799 800 const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack(); 801 DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end(); 802 for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) { 803 const Identifier& ident = (*it).first; 804 if (!variableObject->hasProperty(callFrame, ident)) { 805 PutPropertySlot slot; 806 variableObject->put(callFrame, ident, jsUndefined(), slot); 807 } 808 } 809 810 const DeclarationStacks::FunctionStack& functionStack = codeBlock->ownerNode()->functionStack(); 811 DeclarationStacks::FunctionStack::const_iterator functionStackEnd = functionStack.end(); 812 for (DeclarationStacks::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) { 813 PutPropertySlot slot; 814 variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot); 815 } 816 817 } 818 819 Register* oldEnd = m_registerFile.end(); 820 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters; 821 if (!m_registerFile.grow(newEnd)) { 822 *exception = createStackOverflowError(callFrame); 823 return jsNull(); 824 } 825 826 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset); 827 828 // a 0 codeBlock indicates a built-in caller 829 newCallFrame[codeBlock->thisRegister()] = JSValuePtr(thisObj); 830 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0); 831 832 if (codeBlock->needsFullScopeChain()) 833 scopeChain->ref(); 834 835 Profiler** profiler = Profiler::enabledProfilerReference(); 836 if (*profiler) 837 (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo()); 838 839 JSValuePtr result; 840 { 841 SamplingTool::CallRecord callRecord(m_sampler); 842 843 m_reentryDepth++; 844 #if ENABLE(JIT) 845 if (!codeBlock->jitCode()) 846 JIT::compile(scopeChain->globalData, codeBlock); 847 result = codeBlock->jitCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 848 #else 849 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 850 #endif 851 m_reentryDepth--; 852 } 853 854 if (*profiler) 855 (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo()); 856 857 m_registerFile.shrink(oldEnd); 858 return result; 859 } 860 861 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine) 862 { 863 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger(); 864 if (!debugger) 865 return; 866 867 switch (debugHookID) { 868 case DidEnterCallFrame: 869 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); 870 return; 871 case WillLeaveCallFrame: 872 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); 873 return; 874 case WillExecuteStatement: 875 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); 876 return; 877 case WillExecuteProgram: 878 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); 879 return; 880 case DidExecuteProgram: 881 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); 882 return; 883 case DidReachBreakpoint: 884 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); 885 return; 886 } 887 } 888 889 void Interpreter::resetTimeoutCheck() 890 { 891 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold; 892 m_timeAtLastCheckTimeout = 0; 893 m_timeExecuting = 0; 894 } 59 // Number of milliseconds between each timeout check. 60 static const int intervalBetweenChecks = 1000; 895 61 896 62 // Returns the time the current thread has spent executing, in milliseconds. … … 936 102 } 937 103 938 bool Interpreter::checkTimeout(JSGlobalObject* globalObject) 104 TimeoutChecker::TimeoutChecker() 105 : m_timeoutInterval(0) 106 , m_startCount(0) 107 { 108 reset(); 109 } 110 111 void TimeoutChecker::reset() 112 { 113 m_ticksUntilNextCheck = ticksUntilFirstCheck; 114 m_timeAtLastCheck = 0; 115 m_timeExecuting = 0; 116 } 117 118 bool TimeoutChecker::didTimeOut(ExecState* exec) 939 119 { 940 120 unsigned currentTime = getCPUTime(); 941 121 942 if (!m_timeAtLastCheck Timeout) {122 if (!m_timeAtLastCheck) { 943 123 // Suspicious amount of looping in a script -- start timing it 944 m_timeAtLastCheck Timeout= currentTime;124 m_timeAtLastCheck = currentTime; 945 125 return false; 946 126 } 947 127 948 unsigned timeDiff = currentTime - m_timeAtLastCheck Timeout;128 unsigned timeDiff = currentTime - m_timeAtLastCheck; 949 129 950 130 if (timeDiff == 0) … … 952 132 953 133 m_timeExecuting += timeDiff; 954 m_timeAtLastCheck Timeout= currentTime;134 m_timeAtLastCheck = currentTime; 955 135 956 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in957 // preferredScriptCheckTimeInterval958 m_ticksUntilNext TimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);136 // Adjust the tick threshold so we get the next checkTimeout call in the 137 // interval specified in intervalBetweenChecks. 138 m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck); 959 139 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the 960 140 // preferred script check time interval. 961 if (m_ticksUntilNext TimeoutCheck == 0)962 m_ticksUntilNext TimeoutCheck = initialTickCountThreshold;141 if (m_ticksUntilNextCheck == 0) 142 m_ticksUntilNextCheck = ticksUntilFirstCheck; 963 143 964 if (m_timeout Time && m_timeExecuting > m_timeoutTime) {965 if ( globalObject->shouldInterruptScript())144 if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) { 145 if (exec->dynamicGlobalObject()->shouldInterruptScript()) 966 146 return true; 967 147 968 reset TimeoutCheck();148 reset(); 969 149 } 970 150 … … 972 152 } 973 153 974 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)975 {976 int dst = (++vPC)->u.operand;977 CodeBlock* codeBlock = callFrame->codeBlock();978 Identifier& property = codeBlock->identifier((++vPC)->u.operand);979 JSValuePtr value = callFrame[(++vPC)->u.operand].jsValue(callFrame);980 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);981 callFrame[dst] = JSValuePtr(scope);982 983 return callFrame->scopeChain()->push(scope);984 }985 986 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const PutPropertySlot& slot)987 {988 // Recursive invocation may already have specialized this instruction.989 if (vPC[0].u.opcode != getOpcode(op_put_by_id))990 return;991 992 if (!baseValue.isCell())993 return;994 995 // Uncacheable: give up.996 if (!slot.isCacheable()) {997 vPC[0] = getOpcode(op_put_by_id_generic);998 return;999 }1000 1001 JSCell* baseCell = asCell(baseValue);1002 Structure* structure = baseCell->structure();1003 1004 if (structure->isDictionary()) {1005 vPC[0] = getOpcode(op_put_by_id_generic);1006 return;1007 }1008 1009 // Cache miss: record Structure to compare against next time.1010 Structure* lastStructure = vPC[4].u.structure;1011 if (structure != lastStructure) {1012 // First miss: record Structure to compare against next time.1013 if (!lastStructure) {1014 vPC[4] = structure;1015 return;1016 }1017 1018 // Second miss: give up.1019 vPC[0] = getOpcode(op_put_by_id_generic);1020 return;1021 }1022 1023 // Cache hit: Specialize instruction and ref Structures.1024 1025 // If baseCell != slot.base(), then baseCell must be a proxy for another object.1026 if (baseCell != slot.base()) {1027 vPC[0] = getOpcode(op_put_by_id_generic);1028 return;1029 }1030 1031 // Structure transition, cache transition info1032 if (slot.type() == PutPropertySlot::NewProperty) {1033 vPC[0] = getOpcode(op_put_by_id_transition);1034 vPC[4] = structure->previousID();1035 vPC[5] = structure;1036 StructureChain* chain = structure->cachedPrototypeChain();1037 if (!chain) {1038 chain = cachePrototypeChain(callFrame, structure);1039 if (!chain) {1040 // This happens if someone has manually inserted null into the prototype chain1041 vPC[0] = getOpcode(op_put_by_id_generic);1042 return;1043 }1044 }1045 vPC[6] = chain;1046 vPC[7] = slot.cachedOffset();1047 codeBlock->refStructures(vPC);1048 return;1049 }1050 1051 vPC[0] = getOpcode(op_put_by_id_replace);1052 vPC[5] = slot.cachedOffset();1053 codeBlock->refStructures(vPC);1054 }1055 1056 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)1057 {1058 codeBlock->derefStructures(vPC);1059 vPC[0] = getOpcode(op_put_by_id);1060 vPC[4] = 0;1061 }1062 1063 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValuePtr baseValue, const Identifier& propertyName, const PropertySlot& slot)1064 {1065 // Recursive invocation may already have specialized this instruction.1066 if (vPC[0].u.opcode != getOpcode(op_get_by_id))1067 return;1068 1069 // FIXME: Cache property access for immediates.1070 if (!baseValue.isCell()) {1071 vPC[0] = getOpcode(op_get_by_id_generic);1072 return;1073 }1074 1075 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {1076 vPC[0] = getOpcode(op_get_array_length);1077 return;1078 }1079 1080 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {1081 vPC[0] = getOpcode(op_get_string_length);1082 return;1083 }1084 1085 // Uncacheable: give up.1086 if (!slot.isCacheable()) {1087 vPC[0] = getOpcode(op_get_by_id_generic);1088 return;1089 }1090 1091 Structure* structure = asCell(baseValue)->structure();1092 1093 if (structure->isDictionary()) {1094 vPC[0] = getOpcode(op_get_by_id_generic);1095 return;1096 }1097 1098 // Cache miss1099 Structure* lastStructure = vPC[4].u.structure;1100 if (structure != lastStructure) {1101 // First miss: record Structure to compare against next time.1102 if (!lastStructure) {1103 vPC[4] = structure;1104 return;1105 }1106 1107 // Second miss: give up.1108 vPC[0] = getOpcode(op_get_by_id_generic);1109 return;1110 }1111 1112 // Cache hit: Specialize instruction and ref Structures.1113 1114 if (slot.slotBase() == baseValue) {1115 vPC[0] = getOpcode(op_get_by_id_self);1116 vPC[5] = slot.cachedOffset();1117 1118 codeBlock->refStructures(vPC);1119 return;1120 }1121 1122 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {1123 ASSERT(slot.slotBase().isObject());1124 1125 JSObject* baseObject = asObject(slot.slotBase());1126 1127 // Since we're accessing a prototype in a loop, it's a good bet that it1128 // should not be treated as a dictionary.1129 if (baseObject->structure()->isDictionary()) {1130 RefPtr<Structure> transition = Structure::fromDictionaryTransition(baseObject->structure());1131 baseObject->setStructure(transition.release());1132 asCell(baseValue)->structure()->setCachedPrototypeChain(0);1133 }1134 1135 vPC[0] = getOpcode(op_get_by_id_proto);1136 vPC[5] = baseObject->structure();1137 vPC[6] = slot.cachedOffset();1138 1139 codeBlock->refStructures(vPC);1140 return;1141 }1142 1143 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);1144 if (!count) {1145 vPC[0] = getOpcode(op_get_by_id_generic);1146 return;1147 }1148 1149 StructureChain* chain = structure->cachedPrototypeChain();1150 if (!chain)1151 chain = cachePrototypeChain(callFrame, structure);1152 ASSERT(chain);1153 1154 vPC[0] = getOpcode(op_get_by_id_chain);1155 vPC[4] = structure;1156 vPC[5] = chain;1157 vPC[6] = count;1158 vPC[7] = slot.cachedOffset();1159 codeBlock->refStructures(vPC);1160 }1161 1162 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)1163 {1164 codeBlock->derefStructures(vPC);1165 vPC[0] = getOpcode(op_get_by_id);1166 vPC[4] = 0;1167 }1168 1169 JSValuePtr Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValuePtr* exception)1170 {1171 // One-time initialization of our address tables. We have to put this code1172 // here because our labels are only in scope inside this function.1173 if (flag == InitializeAndReturn) {1174 #if HAVE(COMPUTED_GOTO)1175 #define ADD_BYTECODE(id, length) m_opcodeTable[id] = &&id;1176 FOR_EACH_OPCODE_ID(ADD_BYTECODE);1177 #undef ADD_BYTECODE1178 1179 #define ADD_OPCODE_ID(id, length) m_opcodeIDTable.add(&&id, id);1180 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);1181 #undef ADD_OPCODE_ID1182 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);1183 #endif // HAVE(COMPUTED_GOTO)1184 return noValue();1185 }1186 1187 #if ENABLE(JIT)1188 // Currently with CTI enabled we never interpret functions1189 ASSERT_NOT_REACHED();1190 #endif1191 1192 JSGlobalData* globalData = &callFrame->globalData();1193 JSValuePtr exceptionValue = noValue();1194 HandlerInfo* handler = 0;1195 1196 Instruction* vPC = callFrame->codeBlock()->instructions().begin();1197 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();1198 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;1199 1200 #define CHECK_FOR_EXCEPTION() \1201 do { \1202 if (UNLIKELY(globalData->exception != noValue())) { \1203 exceptionValue = globalData->exception; \1204 goto vm_throw; \1205 } \1206 } while (0)1207 1208 #if ENABLE(OPCODE_STATS)1209 OpcodeStats::resetLastInstruction();1210 #endif1211 1212 #define CHECK_FOR_TIMEOUT() \1213 if (!--tickCount) { \1214 if (checkTimeout(callFrame->dynamicGlobalObject())) { \1215 exceptionValue = jsNull(); \1216 goto vm_throw; \1217 } \1218 tickCount = m_ticksUntilNextTimeoutCheck; \1219 }1220 1221 #if ENABLE(OPCODE_SAMPLING)1222 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)1223 #else1224 #define SAMPLE(codeBlock, vPC)1225 #endif1226 1227 #if HAVE(COMPUTED_GOTO)1228 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode1229 #if ENABLE(OPCODE_STATS)1230 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);1231 #else1232 #define DEFINE_OPCODE(opcode) opcode:1233 #endif1234 NEXT_INSTRUCTION();1235 #else1236 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart1237 #if ENABLE(OPCODE_STATS)1238 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);1239 #else1240 #define DEFINE_OPCODE(opcode) case opcode:1241 #endif1242 while (1) { // iterator loop begins1243 interpreterLoopStart:;1244 switch (vPC->u.opcode)1245 #endif1246 {1247 DEFINE_OPCODE(op_new_object) {1248 /* new_object dst(r)1249 1250 Constructs a new empty Object instance using the original1251 constructor, and puts the result in register dst.1252 */1253 int dst = (++vPC)->u.operand;1254 callFrame[dst] = JSValuePtr(constructEmptyObject(callFrame));1255 1256 ++vPC;1257 NEXT_INSTRUCTION();1258 }1259 DEFINE_OPCODE(op_new_array) {1260 /* new_array dst(r) firstArg(r) argCount(n)1261 1262 Constructs a new Array instance using the original1263 constructor, and puts the result in register dst.1264 The array will contain argCount elements with values1265 taken from registers starting at register firstArg.1266 */1267 int dst = (++vPC)->u.operand;1268 int firstArg = (++vPC)->u.operand;1269 int argCount = (++vPC)->u.operand;1270 ArgList args(callFrame->registers() + firstArg, argCount);1271 callFrame[dst] = JSValuePtr(constructArray(callFrame, args));1272 1273 ++vPC;1274 NEXT_INSTRUCTION();1275 }1276 DEFINE_OPCODE(op_new_regexp) {1277 /* new_regexp dst(r) regExp(re)1278 1279 Constructs a new RegExp instance using the original1280 constructor from regexp regExp, and puts the result in1281 register dst.1282 */1283 int dst = (++vPC)->u.operand;1284 int regExp = (++vPC)->u.operand;1285 callFrame[dst] = JSValuePtr(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject()->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));1286 1287 ++vPC;1288 NEXT_INSTRUCTION();1289 }1290 DEFINE_OPCODE(op_mov) {1291 /* mov dst(r) src(r)1292 1293 Copies register src to register dst.1294 */1295 int dst = (++vPC)->u.operand;1296 int src = (++vPC)->u.operand;1297 callFrame[dst] = callFrame[src];1298 1299 ++vPC;1300 NEXT_INSTRUCTION();1301 }1302 DEFINE_OPCODE(op_eq) {1303 /* eq dst(r) src1(r) src2(r)1304 1305 Checks whether register src1 and register src2 are equal,1306 as with the ECMAScript '==' operator, and puts the result1307 as a boolean in register dst.1308 */1309 int dst = (++vPC)->u.operand;1310 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1311 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1312 if (JSFastMath::canDoFastBitwiseOperations(src1, src2))1313 callFrame[dst] = JSFastMath::equal(src1, src2);1314 else {1315 JSValuePtr result = jsBoolean(JSValuePtr::equalSlowCase(callFrame, src1, src2));1316 CHECK_FOR_EXCEPTION();1317 callFrame[dst] = result;1318 }1319 1320 ++vPC;1321 NEXT_INSTRUCTION();1322 }1323 DEFINE_OPCODE(op_eq_null) {1324 /* eq_null dst(r) src(r)1325 1326 Checks whether register src is null, as with the ECMAScript '!='1327 operator, and puts the result as a boolean in register dst.1328 */1329 int dst = (++vPC)->u.operand;1330 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);1331 1332 if (src.isUndefinedOrNull()) {1333 callFrame[dst] = jsBoolean(true);1334 ++vPC;1335 NEXT_INSTRUCTION();1336 }1337 1338 callFrame[dst] = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());1339 ++vPC;1340 NEXT_INSTRUCTION();1341 }1342 DEFINE_OPCODE(op_neq) {1343 /* neq dst(r) src1(r) src2(r)1344 1345 Checks whether register src1 and register src2 are not1346 equal, as with the ECMAScript '!=' operator, and puts the1347 result as a boolean in register dst.1348 */1349 int dst = (++vPC)->u.operand;1350 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1351 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1352 if (JSFastMath::canDoFastBitwiseOperations(src1, src2))1353 callFrame[dst] = JSFastMath::notEqual(src1, src2);1354 else {1355 JSValuePtr result = jsBoolean(!JSValuePtr::equalSlowCase(callFrame, src1, src2));1356 CHECK_FOR_EXCEPTION();1357 callFrame[dst] = result;1358 }1359 1360 ++vPC;1361 NEXT_INSTRUCTION();1362 }1363 DEFINE_OPCODE(op_neq_null) {1364 /* neq_null dst(r) src(r)1365 1366 Checks whether register src is not null, as with the ECMAScript '!='1367 operator, and puts the result as a boolean in register dst.1368 */1369 int dst = (++vPC)->u.operand;1370 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);1371 1372 if (src.isUndefinedOrNull()) {1373 callFrame[dst] = jsBoolean(false);1374 ++vPC;1375 NEXT_INSTRUCTION();1376 }1377 1378 callFrame[dst] = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());1379 ++vPC;1380 NEXT_INSTRUCTION();1381 }1382 DEFINE_OPCODE(op_stricteq) {1383 /* stricteq dst(r) src1(r) src2(r)1384 1385 Checks whether register src1 and register src2 are strictly1386 equal, as with the ECMAScript '===' operator, and puts the1387 result as a boolean in register dst.1388 */1389 int dst = (++vPC)->u.operand;1390 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1391 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1392 callFrame[dst] = jsBoolean(JSValuePtr::strictEqual(src1, src2));1393 1394 ++vPC;1395 NEXT_INSTRUCTION();1396 }1397 DEFINE_OPCODE(op_nstricteq) {1398 /* nstricteq dst(r) src1(r) src2(r)1399 1400 Checks whether register src1 and register src2 are not1401 strictly equal, as with the ECMAScript '!==' operator, and1402 puts the result as a boolean in register dst.1403 */1404 int dst = (++vPC)->u.operand;1405 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1406 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1407 callFrame[dst] = jsBoolean(!JSValuePtr::strictEqual(src1, src2));1408 1409 ++vPC;1410 NEXT_INSTRUCTION();1411 }1412 DEFINE_OPCODE(op_less) {1413 /* less dst(r) src1(r) src2(r)1414 1415 Checks whether register src1 is less than register src2, as1416 with the ECMAScript '<' operator, and puts the result as1417 a boolean in register dst.1418 */1419 int dst = (++vPC)->u.operand;1420 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1421 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1422 JSValuePtr result = jsBoolean(jsLess(callFrame, src1, src2));1423 CHECK_FOR_EXCEPTION();1424 callFrame[dst] = result;1425 1426 ++vPC;1427 NEXT_INSTRUCTION();1428 }1429 DEFINE_OPCODE(op_lesseq) {1430 /* lesseq dst(r) src1(r) src2(r)1431 1432 Checks whether register src1 is less than or equal to1433 register src2, as with the ECMAScript '<=' operator, and1434 puts the result as a boolean in register dst.1435 */1436 int dst = (++vPC)->u.operand;1437 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1438 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1439 JSValuePtr result = jsBoolean(jsLessEq(callFrame, src1, src2));1440 CHECK_FOR_EXCEPTION();1441 callFrame[dst] = result;1442 1443 ++vPC;1444 NEXT_INSTRUCTION();1445 }1446 DEFINE_OPCODE(op_pre_inc) {1447 /* pre_inc srcDst(r)1448 1449 Converts register srcDst to number, adds one, and puts the result1450 back in register srcDst.1451 */1452 int srcDst = (++vPC)->u.operand;1453 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);1454 if (JSFastMath::canDoFastAdditiveOperations(v))1455 callFrame[srcDst] = JSValuePtr(JSFastMath::incImmediateNumber(v));1456 else {1457 JSValuePtr result = jsNumber(callFrame, v.toNumber(callFrame) + 1);1458 CHECK_FOR_EXCEPTION();1459 callFrame[srcDst] = result;1460 }1461 1462 ++vPC;1463 NEXT_INSTRUCTION();1464 }1465 DEFINE_OPCODE(op_pre_dec) {1466 /* pre_dec srcDst(r)1467 1468 Converts register srcDst to number, subtracts one, and puts the result1469 back in register srcDst.1470 */1471 int srcDst = (++vPC)->u.operand;1472 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);1473 if (JSFastMath::canDoFastAdditiveOperations(v))1474 callFrame[srcDst] = JSValuePtr(JSFastMath::decImmediateNumber(v));1475 else {1476 JSValuePtr result = jsNumber(callFrame, v.toNumber(callFrame) - 1);1477 CHECK_FOR_EXCEPTION();1478 callFrame[srcDst] = result;1479 }1480 1481 ++vPC;1482 NEXT_INSTRUCTION();1483 }1484 DEFINE_OPCODE(op_post_inc) {1485 /* post_inc dst(r) srcDst(r)1486 1487 Converts register srcDst to number. The number itself is1488 written to register dst, and the number plus one is written1489 back to register srcDst.1490 */1491 int dst = (++vPC)->u.operand;1492 int srcDst = (++vPC)->u.operand;1493 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);1494 if (JSFastMath::canDoFastAdditiveOperations(v)) {1495 callFrame[dst] = v;1496 callFrame[srcDst] = JSValuePtr(JSFastMath::incImmediateNumber(v));1497 } else {1498 JSValuePtr number = callFrame[srcDst].jsValue(callFrame).toJSNumber(callFrame);1499 CHECK_FOR_EXCEPTION();1500 callFrame[dst] = number;1501 callFrame[srcDst] = JSValuePtr(jsNumber(callFrame, number.uncheckedGetNumber() + 1));1502 }1503 1504 ++vPC;1505 NEXT_INSTRUCTION();1506 }1507 DEFINE_OPCODE(op_post_dec) {1508 /* post_dec dst(r) srcDst(r)1509 1510 Converts register srcDst to number. The number itself is1511 written to register dst, and the number minus one is written1512 back to register srcDst.1513 */1514 int dst = (++vPC)->u.operand;1515 int srcDst = (++vPC)->u.operand;1516 JSValuePtr v = callFrame[srcDst].jsValue(callFrame);1517 if (JSFastMath::canDoFastAdditiveOperations(v)) {1518 callFrame[dst] = v;1519 callFrame[srcDst] = JSValuePtr(JSFastMath::decImmediateNumber(v));1520 } else {1521 JSValuePtr number = callFrame[srcDst].jsValue(callFrame).toJSNumber(callFrame);1522 CHECK_FOR_EXCEPTION();1523 callFrame[dst] = number;1524 callFrame[srcDst] = JSValuePtr(jsNumber(callFrame, number.uncheckedGetNumber() - 1));1525 }1526 1527 ++vPC;1528 NEXT_INSTRUCTION();1529 }1530 DEFINE_OPCODE(op_to_jsnumber) {1531 /* to_jsnumber dst(r) src(r)1532 1533 Converts register src to number, and puts the result1534 in register dst.1535 */1536 int dst = (++vPC)->u.operand;1537 int src = (++vPC)->u.operand;1538 1539 JSValuePtr srcVal = callFrame[src].jsValue(callFrame);1540 1541 if (LIKELY(srcVal.isNumber()))1542 callFrame[dst] = callFrame[src];1543 else {1544 JSValuePtr result = srcVal.toJSNumber(callFrame);1545 CHECK_FOR_EXCEPTION();1546 callFrame[dst] = result;1547 }1548 1549 ++vPC;1550 NEXT_INSTRUCTION();1551 }1552 DEFINE_OPCODE(op_negate) {1553 /* negate dst(r) src(r)1554 1555 Converts register src to number, negates it, and puts the1556 result in register dst.1557 */1558 int dst = (++vPC)->u.operand;1559 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);1560 ++vPC;1561 double v;1562 if (src.getNumber(v))1563 callFrame[dst] = JSValuePtr(jsNumber(callFrame, -v));1564 else {1565 JSValuePtr result = jsNumber(callFrame, -src.toNumber(callFrame));1566 CHECK_FOR_EXCEPTION();1567 callFrame[dst] = result;1568 }1569 1570 NEXT_INSTRUCTION();1571 }1572 DEFINE_OPCODE(op_add) {1573 /* add dst(r) src1(r) src2(r)1574 1575 Adds register src1 and register src2, and puts the result1576 in register dst. (JS add may be string concatenation or1577 numeric add, depending on the types of the operands.)1578 */1579 int dst = (++vPC)->u.operand;1580 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1581 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1582 if (JSFastMath::canDoFastAdditiveOperations(src1, src2))1583 callFrame[dst] = JSValuePtr(JSFastMath::addImmediateNumbers(src1, src2));1584 else {1585 JSValuePtr result = jsAdd(callFrame, src1, src2);1586 CHECK_FOR_EXCEPTION();1587 callFrame[dst] = result;1588 }1589 vPC += 2;1590 NEXT_INSTRUCTION();1591 }1592 DEFINE_OPCODE(op_mul) {1593 /* mul dst(r) src1(r) src2(r)1594 1595 Multiplies register src1 and register src2 (converted to1596 numbers), and puts the product in register dst.1597 */1598 int dst = (++vPC)->u.operand;1599 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1600 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1601 double left;1602 double right;1603 if (JSValuePtr::areBothInt32Fast(src1, src2)) {1604 int32_t left = src1.getInt32Fast();1605 int32_t right = src2.getInt32Fast();1606 if ((left | right) >> 15 == 0)1607 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left * right));1608 else1609 callFrame[dst] = JSValuePtr(jsNumber(callFrame, static_cast<double>(left) * static_cast<double>(right)));1610 } else if (src1.getNumber(left) && src2.getNumber(right))1611 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left * right));1612 else {1613 JSValuePtr result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));1614 CHECK_FOR_EXCEPTION();1615 callFrame[dst] = result;1616 }1617 1618 vPC += 2;1619 NEXT_INSTRUCTION();1620 }1621 DEFINE_OPCODE(op_div) {1622 /* div dst(r) dividend(r) divisor(r)1623 1624 Divides register dividend (converted to number) by the1625 register divisor (converted to number), and puts the1626 quotient in register dst.1627 */1628 int dst = (++vPC)->u.operand;1629 JSValuePtr dividend = callFrame[(++vPC)->u.operand].jsValue(callFrame);1630 JSValuePtr divisor = callFrame[(++vPC)->u.operand].jsValue(callFrame);1631 double left;1632 double right;1633 if (dividend.getNumber(left) && divisor.getNumber(right))1634 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left / right));1635 else {1636 JSValuePtr result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));1637 CHECK_FOR_EXCEPTION();1638 callFrame[dst] = result;1639 }1640 ++vPC;1641 NEXT_INSTRUCTION();1642 }1643 DEFINE_OPCODE(op_mod) {1644 /* mod dst(r) dividend(r) divisor(r)1645 1646 Divides register dividend (converted to number) by1647 register divisor (converted to number), and puts the1648 remainder in register dst.1649 */1650 int dst = (++vPC)->u.operand;1651 int dividend = (++vPC)->u.operand;1652 int divisor = (++vPC)->u.operand;1653 1654 JSValuePtr dividendValue = callFrame[dividend].jsValue(callFrame);1655 JSValuePtr divisorValue = callFrame[divisor].jsValue(callFrame);1656 1657 if (JSValuePtr::areBothInt32Fast(dividendValue, divisorValue) && divisorValue != js0()) {1658 // We expect the result of the modulus of a number that was representable as an int32 to also be representable1659 // as an int32.1660 JSValuePtr result = JSValuePtr::makeInt32Fast(dividendValue.getInt32Fast() % divisorValue.getInt32Fast());1661 ASSERT(result);1662 callFrame[dst] = result;1663 ++vPC;1664 NEXT_INSTRUCTION();1665 }1666 1667 double d = dividendValue.toNumber(callFrame);1668 JSValuePtr result = jsNumber(callFrame, fmod(d, divisorValue.toNumber(callFrame)));1669 CHECK_FOR_EXCEPTION();1670 callFrame[dst] = result;1671 ++vPC;1672 NEXT_INSTRUCTION();1673 }1674 DEFINE_OPCODE(op_sub) {1675 /* sub dst(r) src1(r) src2(r)1676 1677 Subtracts register src2 (converted to number) from register1678 src1 (converted to number), and puts the difference in1679 register dst.1680 */1681 int dst = (++vPC)->u.operand;1682 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1683 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1684 double left;1685 double right;1686 if (JSFastMath::canDoFastAdditiveOperations(src1, src2))1687 callFrame[dst] = JSValuePtr(JSFastMath::subImmediateNumbers(src1, src2));1688 else if (src1.getNumber(left) && src2.getNumber(right))1689 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left - right));1690 else {1691 JSValuePtr result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));1692 CHECK_FOR_EXCEPTION();1693 callFrame[dst] = result;1694 }1695 vPC += 2;1696 NEXT_INSTRUCTION();1697 }1698 DEFINE_OPCODE(op_lshift) {1699 /* lshift dst(r) val(r) shift(r)1700 1701 Performs left shift of register val (converted to int32) by1702 register shift (converted to uint32), and puts the result1703 in register dst.1704 */1705 int dst = (++vPC)->u.operand;1706 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);1707 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);1708 int32_t left;1709 uint32_t right;1710 if (JSValuePtr::areBothInt32Fast(val, shift))1711 callFrame[dst] = JSValuePtr(jsNumber(callFrame, val.getInt32Fast() << (shift.getInt32Fast() & 0x1f)));1712 else if (val.numberToInt32(left) && shift.numberToUInt32(right))1713 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left << (right & 0x1f)));1714 else {1715 JSValuePtr result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));1716 CHECK_FOR_EXCEPTION();1717 callFrame[dst] = result;1718 }1719 1720 ++vPC;1721 NEXT_INSTRUCTION();1722 }1723 DEFINE_OPCODE(op_rshift) {1724 /* rshift dst(r) val(r) shift(r)1725 1726 Performs arithmetic right shift of register val (converted1727 to int32) by register shift (converted to1728 uint32), and puts the result in register dst.1729 */1730 int dst = (++vPC)->u.operand;1731 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);1732 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);1733 int32_t left;1734 uint32_t right;1735 if (JSFastMath::canDoFastRshift(val, shift))1736 callFrame[dst] = JSValuePtr(JSFastMath::rightShiftImmediateNumbers(val, shift));1737 else if (val.numberToInt32(left) && shift.numberToUInt32(right))1738 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left >> (right & 0x1f)));1739 else {1740 JSValuePtr result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));1741 CHECK_FOR_EXCEPTION();1742 callFrame[dst] = result;1743 }1744 1745 ++vPC;1746 NEXT_INSTRUCTION();1747 }1748 DEFINE_OPCODE(op_urshift) {1749 /* rshift dst(r) val(r) shift(r)1750 1751 Performs logical right shift of register val (converted1752 to uint32) by register shift (converted to1753 uint32), and puts the result in register dst.1754 */1755 int dst = (++vPC)->u.operand;1756 JSValuePtr val = callFrame[(++vPC)->u.operand].jsValue(callFrame);1757 JSValuePtr shift = callFrame[(++vPC)->u.operand].jsValue(callFrame);1758 if (JSFastMath::canDoFastUrshift(val, shift))1759 callFrame[dst] = JSValuePtr(JSFastMath::rightShiftImmediateNumbers(val, shift));1760 else {1761 JSValuePtr result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));1762 CHECK_FOR_EXCEPTION();1763 callFrame[dst] = result;1764 }1765 1766 ++vPC;1767 NEXT_INSTRUCTION();1768 }1769 DEFINE_OPCODE(op_bitand) {1770 /* bitand dst(r) src1(r) src2(r)1771 1772 Computes bitwise AND of register src1 (converted to int32)1773 and register src2 (converted to int32), and puts the result1774 in register dst.1775 */1776 int dst = (++vPC)->u.operand;1777 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1778 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1779 int32_t left;1780 int32_t right;1781 if (JSFastMath::canDoFastBitwiseOperations(src1, src2))1782 callFrame[dst] = JSValuePtr(JSFastMath::andImmediateNumbers(src1, src2));1783 else if (src1.numberToInt32(left) && src2.numberToInt32(right))1784 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left & right));1785 else {1786 JSValuePtr result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));1787 CHECK_FOR_EXCEPTION();1788 callFrame[dst] = result;1789 }1790 1791 vPC += 2;1792 NEXT_INSTRUCTION();1793 }1794 DEFINE_OPCODE(op_bitxor) {1795 /* bitxor dst(r) src1(r) src2(r)1796 1797 Computes bitwise XOR of register src1 (converted to int32)1798 and register src2 (converted to int32), and puts the result1799 in register dst.1800 */1801 int dst = (++vPC)->u.operand;1802 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1803 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1804 int32_t left;1805 int32_t right;1806 if (JSFastMath::canDoFastBitwiseOperations(src1, src2))1807 callFrame[dst] = JSValuePtr(JSFastMath::xorImmediateNumbers(src1, src2));1808 else if (src1.numberToInt32(left) && src2.numberToInt32(right))1809 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left ^ right));1810 else {1811 JSValuePtr result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));1812 CHECK_FOR_EXCEPTION();1813 callFrame[dst] = result;1814 }1815 1816 vPC += 2;1817 NEXT_INSTRUCTION();1818 }1819 DEFINE_OPCODE(op_bitor) {1820 /* bitor dst(r) src1(r) src2(r)1821 1822 Computes bitwise OR of register src1 (converted to int32)1823 and register src2 (converted to int32), and puts the1824 result in register dst.1825 */1826 int dst = (++vPC)->u.operand;1827 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1828 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);1829 int32_t left;1830 int32_t right;1831 if (JSFastMath::canDoFastBitwiseOperations(src1, src2))1832 callFrame[dst] = JSValuePtr(JSFastMath::orImmediateNumbers(src1, src2));1833 else if (src1.numberToInt32(left) && src2.numberToInt32(right))1834 callFrame[dst] = JSValuePtr(jsNumber(callFrame, left | right));1835 else {1836 JSValuePtr result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));1837 CHECK_FOR_EXCEPTION();1838 callFrame[dst] = result;1839 }1840 1841 vPC += 2;1842 NEXT_INSTRUCTION();1843 }1844 DEFINE_OPCODE(op_bitnot) {1845 /* bitnot dst(r) src(r)1846 1847 Computes bitwise NOT of register src1 (converted to int32),1848 and puts the result in register dst.1849 */1850 int dst = (++vPC)->u.operand;1851 JSValuePtr src = callFrame[(++vPC)->u.operand].jsValue(callFrame);1852 int32_t value;1853 if (src.numberToInt32(value))1854 callFrame[dst] = JSValuePtr(jsNumber(callFrame, ~value));1855 else {1856 JSValuePtr result = jsNumber(callFrame, ~src.toInt32(callFrame));1857 CHECK_FOR_EXCEPTION();1858 callFrame[dst] = result;1859 }1860 ++vPC;1861 NEXT_INSTRUCTION();1862 }1863 DEFINE_OPCODE(op_not) {1864 /* not dst(r) src(r)1865 1866 Computes logical NOT of register src (converted to1867 boolean), and puts the result in register dst.1868 */1869 int dst = (++vPC)->u.operand;1870 int src = (++vPC)->u.operand;1871 JSValuePtr result = jsBoolean(!callFrame[src].jsValue(callFrame).toBoolean(callFrame));1872 CHECK_FOR_EXCEPTION();1873 callFrame[dst] = result;1874 1875 ++vPC;1876 NEXT_INSTRUCTION();1877 }1878 DEFINE_OPCODE(op_instanceof) {1879 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)1880 1881 Tests whether register value is an instance of register1882 constructor, and puts the boolean result in register1883 dst. Register constructorProto must contain the "prototype"1884 property (not the actual prototype) of the object in1885 register constructor. This lookup is separated so that1886 polymorphic inline caching can apply.1887 1888 Raises an exception if register constructor is not an1889 object.1890 */1891 int dst = vPC[1].u.operand;1892 int value = vPC[2].u.operand;1893 int base = vPC[3].u.operand;1894 int baseProto = vPC[4].u.operand;1895 1896 JSValuePtr baseVal = callFrame[base].jsValue(callFrame);1897 1898 if (isNotObject(callFrame, true, callFrame->codeBlock(), vPC, baseVal, exceptionValue))1899 goto vm_throw;1900 1901 JSObject* baseObj = asObject(baseVal);1902 callFrame[dst] = jsBoolean(baseObj->structure()->typeInfo().implementsHasInstance() ? baseObj->hasInstance(callFrame, callFrame[value].jsValue(callFrame), callFrame[baseProto].jsValue(callFrame)) : false);1903 1904 vPC += 5;1905 NEXT_INSTRUCTION();1906 }1907 DEFINE_OPCODE(op_typeof) {1908 /* typeof dst(r) src(r)1909 1910 Determines the type string for src according to ECMAScript1911 rules, and puts the result in register dst.1912 */1913 int dst = (++vPC)->u.operand;1914 int src = (++vPC)->u.operand;1915 callFrame[dst] = JSValuePtr(jsTypeStringForValue(callFrame, callFrame[src].jsValue(callFrame)));1916 1917 ++vPC;1918 NEXT_INSTRUCTION();1919 }1920 DEFINE_OPCODE(op_is_undefined) {1921 /* is_undefined dst(r) src(r)1922 1923 Determines whether the type string for src according to1924 the ECMAScript rules is "undefined", and puts the result1925 in register dst.1926 */1927 int dst = (++vPC)->u.operand;1928 int src = (++vPC)->u.operand;1929 JSValuePtr v = callFrame[src].jsValue(callFrame);1930 callFrame[dst] = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());1931 1932 ++vPC;1933 NEXT_INSTRUCTION();1934 }1935 DEFINE_OPCODE(op_is_boolean) {1936 /* is_boolean dst(r) src(r)1937 1938 Determines whether the type string for src according to1939 the ECMAScript rules is "boolean", and puts the result1940 in register dst.1941 */1942 int dst = (++vPC)->u.operand;1943 int src = (++vPC)->u.operand;1944 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame).isBoolean());1945 1946 ++vPC;1947 NEXT_INSTRUCTION();1948 }1949 DEFINE_OPCODE(op_is_number) {1950 /* is_number dst(r) src(r)1951 1952 Determines whether the type string for src according to1953 the ECMAScript rules is "number", and puts the result1954 in register dst.1955 */1956 int dst = (++vPC)->u.operand;1957 int src = (++vPC)->u.operand;1958 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame).isNumber());1959 1960 ++vPC;1961 NEXT_INSTRUCTION();1962 }1963 DEFINE_OPCODE(op_is_string) {1964 /* is_string dst(r) src(r)1965 1966 Determines whether the type string for src according to1967 the ECMAScript rules is "string", and puts the result1968 in register dst.1969 */1970 int dst = (++vPC)->u.operand;1971 int src = (++vPC)->u.operand;1972 callFrame[dst] = jsBoolean(callFrame[src].jsValue(callFrame).isString());1973 1974 ++vPC;1975 NEXT_INSTRUCTION();1976 }1977 DEFINE_OPCODE(op_is_object) {1978 /* is_object dst(r) src(r)1979 1980 Determines whether the type string for src according to1981 the ECMAScript rules is "object", and puts the result1982 in register dst.1983 */1984 int dst = (++vPC)->u.operand;1985 int src = (++vPC)->u.operand;1986 callFrame[dst] = jsBoolean(jsIsObjectType(callFrame[src].jsValue(callFrame)));1987 1988 ++vPC;1989 NEXT_INSTRUCTION();1990 }1991 DEFINE_OPCODE(op_is_function) {1992 /* is_function dst(r) src(r)1993 1994 Determines whether the type string for src according to1995 the ECMAScript rules is "function", and puts the result1996 in register dst.1997 */1998 int dst = (++vPC)->u.operand;1999 int src = (++vPC)->u.operand;2000 callFrame[dst] = jsBoolean(jsIsFunctionType(callFrame[src].jsValue(callFrame)));2001 2002 ++vPC;2003 NEXT_INSTRUCTION();2004 }2005 DEFINE_OPCODE(op_in) {2006 /* in dst(r) property(r) base(r)2007 2008 Tests whether register base has a property named register2009 property, and puts the boolean result in register dst.2010 2011 Raises an exception if register constructor is not an2012 object.2013 */2014 int dst = (++vPC)->u.operand;2015 int property = (++vPC)->u.operand;2016 int base = (++vPC)->u.operand;2017 2018 JSValuePtr baseVal = callFrame[base].jsValue(callFrame);2019 if (isNotObject(callFrame, false, callFrame->codeBlock(), vPC, baseVal, exceptionValue))2020 goto vm_throw;2021 2022 JSObject* baseObj = asObject(baseVal);2023 2024 JSValuePtr propName = callFrame[property].jsValue(callFrame);2025 2026 uint32_t i;2027 if (propName.getUInt32(i))2028 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, i));2029 else {2030 Identifier property(callFrame, propName.toString(callFrame));2031 CHECK_FOR_EXCEPTION();2032 callFrame[dst] = jsBoolean(baseObj->hasProperty(callFrame, property));2033 }2034 2035 ++vPC;2036 NEXT_INSTRUCTION();2037 }2038 DEFINE_OPCODE(op_resolve) {2039 /* resolve dst(r) property(id)2040 2041 Looks up the property named by identifier property in the2042 scope chain, and writes the resulting value to register2043 dst. If the property is not found, raises an exception.2044 */2045 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))2046 goto vm_throw;2047 2048 vPC += 3;2049 NEXT_INSTRUCTION();2050 }2051 DEFINE_OPCODE(op_resolve_skip) {2052 /* resolve_skip dst(r) property(id) skip(n)2053 2054 Looks up the property named by identifier property in the2055 scope chain skipping the top 'skip' levels, and writes the resulting2056 value to register dst. If the property is not found, raises an exception.2057 */2058 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))2059 goto vm_throw;2060 2061 vPC += 4;2062 2063 NEXT_INSTRUCTION();2064 }2065 DEFINE_OPCODE(op_resolve_global) {2066 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)2067 2068 Performs a dynamic property lookup for the given property, on the provided2069 global object. If structure matches the Structure of the global then perform2070 a fast lookup using the case offset, otherwise fall back to a full resolve and2071 cache the new structure and offset2072 */2073 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))2074 goto vm_throw;2075 2076 vPC += 6;2077 2078 NEXT_INSTRUCTION();2079 }2080 DEFINE_OPCODE(op_get_global_var) {2081 /* get_global_var dst(r) globalObject(c) index(n)2082 2083 Gets the global var at global slot index and places it in register dst.2084 */2085 int dst = (++vPC)->u.operand;2086 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);2087 ASSERT(scope->isGlobalObject());2088 int index = (++vPC)->u.operand;2089 2090 callFrame[dst] = scope->registerAt(index);2091 ++vPC;2092 NEXT_INSTRUCTION();2093 }2094 DEFINE_OPCODE(op_put_global_var) {2095 /* put_global_var globalObject(c) index(n) value(r)2096 2097 Puts value into global slot index.2098 */2099 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);2100 ASSERT(scope->isGlobalObject());2101 int index = (++vPC)->u.operand;2102 int value = (++vPC)->u.operand;2103 2104 scope->registerAt(index) = JSValuePtr(callFrame[value].jsValue(callFrame));2105 ++vPC;2106 NEXT_INSTRUCTION();2107 }2108 DEFINE_OPCODE(op_get_scoped_var) {2109 /* get_scoped_var dst(r) index(n) skip(n)2110 2111 Loads the contents of the index-th local from the scope skip nodes from2112 the top of the scope chain, and places it in register dst2113 */2114 int dst = (++vPC)->u.operand;2115 int index = (++vPC)->u.operand;2116 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();2117 2118 ScopeChainNode* scopeChain = callFrame->scopeChain();2119 ScopeChainIterator iter = scopeChain->begin();2120 ScopeChainIterator end = scopeChain->end();2121 ASSERT(iter != end);2122 while (skip--) {2123 ++iter;2124 ASSERT(iter != end);2125 }2126 2127 ASSERT((*iter)->isVariableObject());2128 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);2129 callFrame[dst] = scope->registerAt(index);2130 ++vPC;2131 NEXT_INSTRUCTION();2132 }2133 DEFINE_OPCODE(op_put_scoped_var) {2134 /* put_scoped_var index(n) skip(n) value(r)2135 2136 */2137 int index = (++vPC)->u.operand;2138 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();2139 int value = (++vPC)->u.operand;2140 2141 ScopeChainNode* scopeChain = callFrame->scopeChain();2142 ScopeChainIterator iter = scopeChain->begin();2143 ScopeChainIterator end = scopeChain->end();2144 ASSERT(iter != end);2145 while (skip--) {2146 ++iter;2147 ASSERT(iter != end);2148 }2149 2150 ASSERT((*iter)->isVariableObject());2151 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);2152 scope->registerAt(index) = JSValuePtr(callFrame[value].jsValue(callFrame));2153 ++vPC;2154 NEXT_INSTRUCTION();2155 }2156 DEFINE_OPCODE(op_resolve_base) {2157 /* resolve_base dst(r) property(id)2158 2159 Searches the scope chain for an object containing2160 identifier property, and if one is found, writes it to2161 register dst. If none is found, the outermost scope (which2162 will be the global object) is stored in register dst.2163 */2164 resolveBase(callFrame, vPC);2165 2166 vPC += 3;2167 NEXT_INSTRUCTION();2168 }2169 DEFINE_OPCODE(op_resolve_with_base) {2170 /* resolve_with_base baseDst(r) propDst(r) property(id)2171 2172 Searches the scope chain for an object containing2173 identifier property, and if one is found, writes it to2174 register srcDst, and the retrieved property value to register2175 propDst. If the property is not found, raises an exception.2176 2177 This is more efficient than doing resolve_base followed by2178 resolve, or resolve_base followed by get_by_id, as it2179 avoids duplicate hash lookups.2180 */2181 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))2182 goto vm_throw;2183 2184 vPC += 4;2185 NEXT_INSTRUCTION();2186 }2187 DEFINE_OPCODE(op_resolve_func) {2188 /* resolve_func baseDst(r) funcDst(r) property(id)2189 2190 Searches the scope chain for an object containing2191 identifier property, and if one is found, writes the2192 appropriate object to use as "this" when calling its2193 properties to register baseDst; and the retrieved property2194 value to register propDst. If the property is not found,2195 raises an exception.2196 2197 This differs from resolve_with_base, because the2198 global this value will be substituted for activations or2199 the global object, which is the right behavior for function2200 calls but not for other property lookup.2201 */2202 if (UNLIKELY(!resolveBaseAndFunc(callFrame, vPC, exceptionValue)))2203 goto vm_throw;2204 2205 vPC += 4;2206 NEXT_INSTRUCTION();2207 }2208 DEFINE_OPCODE(op_get_by_id) {2209 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)2210 2211 Generic property access: Gets the property named by identifier2212 property from the value base, and puts the result in register dst.2213 */2214 int dst = vPC[1].u.operand;2215 int base = vPC[2].u.operand;2216 int property = vPC[3].u.operand;2217 2218 CodeBlock* codeBlock = callFrame->codeBlock();2219 Identifier& ident = codeBlock->identifier(property);2220 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2221 PropertySlot slot(baseValue);2222 JSValuePtr result = baseValue.get(callFrame, ident, slot);2223 CHECK_FOR_EXCEPTION();2224 2225 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);2226 2227 callFrame[dst] = result;2228 vPC += 8;2229 NEXT_INSTRUCTION();2230 }2231 DEFINE_OPCODE(op_get_by_id_self) {2232 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)2233 2234 Cached property access: Attempts to get a cached property from the2235 value base. If the cache misses, op_get_by_id_self reverts to2236 op_get_by_id.2237 */2238 int base = vPC[2].u.operand;2239 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2240 2241 if (LIKELY(baseValue.isCell())) {2242 JSCell* baseCell = asCell(baseValue);2243 Structure* structure = vPC[4].u.structure;2244 2245 if (LIKELY(baseCell->structure() == structure)) {2246 ASSERT(baseCell->isObject());2247 JSObject* baseObject = asObject(baseCell);2248 int dst = vPC[1].u.operand;2249 int offset = vPC[5].u.operand;2250 2251 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));2252 callFrame[dst] = JSValuePtr(baseObject->getDirectOffset(offset));2253 2254 vPC += 8;2255 NEXT_INSTRUCTION();2256 }2257 }2258 2259 uncacheGetByID(callFrame->codeBlock(), vPC);2260 NEXT_INSTRUCTION();2261 }2262 DEFINE_OPCODE(op_get_by_id_proto) {2263 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)2264 2265 Cached property access: Attempts to get a cached property from the2266 value base's prototype. If the cache misses, op_get_by_id_proto2267 reverts to op_get_by_id.2268 */2269 int base = vPC[2].u.operand;2270 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2271 2272 if (LIKELY(baseValue.isCell())) {2273 JSCell* baseCell = asCell(baseValue);2274 Structure* structure = vPC[4].u.structure;2275 2276 if (LIKELY(baseCell->structure() == structure)) {2277 ASSERT(structure->prototypeForLookup(callFrame).isObject());2278 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));2279 Structure* prototypeStructure = vPC[5].u.structure;2280 2281 if (LIKELY(protoObject->structure() == prototypeStructure)) {2282 int dst = vPC[1].u.operand;2283 int offset = vPC[6].u.operand;2284 2285 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));2286 callFrame[dst] = JSValuePtr(protoObject->getDirectOffset(offset));2287 2288 vPC += 8;2289 NEXT_INSTRUCTION();2290 }2291 }2292 }2293 2294 uncacheGetByID(callFrame->codeBlock(), vPC);2295 NEXT_INSTRUCTION();2296 }2297 DEFINE_OPCODE(op_get_by_id_self_list) {2298 // Polymorphic self access caching currently only supported when JITting.2299 ASSERT_NOT_REACHED();2300 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!2301 vPC += 8;2302 NEXT_INSTRUCTION();2303 }2304 DEFINE_OPCODE(op_get_by_id_proto_list) {2305 // Polymorphic prototype access caching currently only supported when JITting.2306 ASSERT_NOT_REACHED();2307 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!2308 vPC += 8;2309 NEXT_INSTRUCTION();2310 }2311 DEFINE_OPCODE(op_get_by_id_chain) {2312 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)2313 2314 Cached property access: Attempts to get a cached property from the2315 value base's prototype chain. If the cache misses, op_get_by_id_chain2316 reverts to op_get_by_id.2317 */2318 int base = vPC[2].u.operand;2319 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2320 2321 if (LIKELY(baseValue.isCell())) {2322 JSCell* baseCell = asCell(baseValue);2323 Structure* structure = vPC[4].u.structure;2324 2325 if (LIKELY(baseCell->structure() == structure)) {2326 RefPtr<Structure>* it = vPC[5].u.structureChain->head();2327 size_t count = vPC[6].u.operand;2328 RefPtr<Structure>* end = it + count;2329 2330 while (true) {2331 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));2332 2333 if (UNLIKELY(baseObject->structure() != (*it).get()))2334 break;2335 2336 if (++it == end) {2337 int dst = vPC[1].u.operand;2338 int offset = vPC[7].u.operand;2339 2340 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));2341 callFrame[dst] = JSValuePtr(baseObject->getDirectOffset(offset));2342 2343 vPC += 8;2344 NEXT_INSTRUCTION();2345 }2346 2347 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.2348 baseCell = baseObject;2349 }2350 }2351 }2352 2353 uncacheGetByID(callFrame->codeBlock(), vPC);2354 NEXT_INSTRUCTION();2355 }2356 DEFINE_OPCODE(op_get_by_id_generic) {2357 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)2358 2359 Generic property access: Gets the property named by identifier2360 property from the value base, and puts the result in register dst.2361 */2362 int dst = vPC[1].u.operand;2363 int base = vPC[2].u.operand;2364 int property = vPC[3].u.operand;2365 2366 Identifier& ident = callFrame->codeBlock()->identifier(property);2367 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2368 PropertySlot slot(baseValue);2369 JSValuePtr result = baseValue.get(callFrame, ident, slot);2370 CHECK_FOR_EXCEPTION();2371 2372 callFrame[dst] = result;2373 vPC += 8;2374 NEXT_INSTRUCTION();2375 }2376 DEFINE_OPCODE(op_get_array_length) {2377 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)2378 2379 Cached property access: Gets the length of the array in register base,2380 and puts the result in register dst. If register base does not hold2381 an array, op_get_array_length reverts to op_get_by_id.2382 */2383 2384 int base = vPC[2].u.operand;2385 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2386 if (LIKELY(isJSArray(baseValue))) {2387 int dst = vPC[1].u.operand;2388 callFrame[dst] = JSValuePtr(jsNumber(callFrame, asArray(baseValue)->length()));2389 vPC += 8;2390 NEXT_INSTRUCTION();2391 }2392 2393 uncacheGetByID(callFrame->codeBlock(), vPC);2394 NEXT_INSTRUCTION();2395 }2396 DEFINE_OPCODE(op_get_string_length) {2397 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)2398 2399 Cached property access: Gets the length of the string in register base,2400 and puts the result in register dst. If register base does not hold2401 a string, op_get_string_length reverts to op_get_by_id.2402 */2403 2404 int base = vPC[2].u.operand;2405 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2406 if (LIKELY(isJSString(baseValue))) {2407 int dst = vPC[1].u.operand;2408 callFrame[dst] = JSValuePtr(jsNumber(callFrame, asString(baseValue)->value().size()));2409 vPC += 8;2410 NEXT_INSTRUCTION();2411 }2412 2413 uncacheGetByID(callFrame->codeBlock(), vPC);2414 NEXT_INSTRUCTION();2415 }2416 DEFINE_OPCODE(op_put_by_id) {2417 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)2418 2419 Generic property access: Sets the property named by identifier2420 property, belonging to register base, to register value.2421 2422 Unlike many opcodes, this one does not write any output to2423 the register file.2424 */2425 2426 int base = vPC[1].u.operand;2427 int property = vPC[2].u.operand;2428 int value = vPC[3].u.operand;2429 2430 CodeBlock* codeBlock = callFrame->codeBlock();2431 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2432 Identifier& ident = codeBlock->identifier(property);2433 PutPropertySlot slot;2434 baseValue.put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);2435 CHECK_FOR_EXCEPTION();2436 2437 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);2438 2439 vPC += 8;2440 NEXT_INSTRUCTION();2441 }2442 DEFINE_OPCODE(op_put_by_id_transition) {2443 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)2444 2445 Cached property access: Attempts to set a new property with a cached transition2446 property named by identifier property, belonging to register base,2447 to register value. If the cache misses, op_put_by_id_transition2448 reverts to op_put_by_id_generic.2449 2450 Unlike many opcodes, this one does not write any output to2451 the register file.2452 */2453 int base = vPC[1].u.operand;2454 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2455 2456 if (LIKELY(baseValue.isCell())) {2457 JSCell* baseCell = asCell(baseValue);2458 Structure* oldStructure = vPC[4].u.structure;2459 Structure* newStructure = vPC[5].u.structure;2460 2461 if (LIKELY(baseCell->structure() == oldStructure)) {2462 ASSERT(baseCell->isObject());2463 JSObject* baseObject = asObject(baseCell);2464 2465 RefPtr<Structure>* it = vPC[6].u.structureChain->head();2466 2467 JSValuePtr proto = baseObject->structure()->prototypeForLookup(callFrame);2468 while (!proto.isNull()) {2469 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {2470 uncachePutByID(callFrame->codeBlock(), vPC);2471 NEXT_INSTRUCTION();2472 }2473 ++it;2474 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);2475 }2476 2477 baseObject->transitionTo(newStructure);2478 2479 int value = vPC[3].u.operand;2480 unsigned offset = vPC[7].u.operand;2481 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);2482 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));2483 2484 vPC += 8;2485 NEXT_INSTRUCTION();2486 }2487 }2488 2489 uncachePutByID(callFrame->codeBlock(), vPC);2490 NEXT_INSTRUCTION();2491 }2492 DEFINE_OPCODE(op_put_by_id_replace) {2493 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)2494 2495 Cached property access: Attempts to set a pre-existing, cached2496 property named by identifier property, belonging to register base,2497 to register value. If the cache misses, op_put_by_id_replace2498 reverts to op_put_by_id.2499 2500 Unlike many opcodes, this one does not write any output to2501 the register file.2502 */2503 int base = vPC[1].u.operand;2504 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2505 2506 if (LIKELY(baseValue.isCell())) {2507 JSCell* baseCell = asCell(baseValue);2508 Structure* structure = vPC[4].u.structure;2509 2510 if (LIKELY(baseCell->structure() == structure)) {2511 ASSERT(baseCell->isObject());2512 JSObject* baseObject = asObject(baseCell);2513 int value = vPC[3].u.operand;2514 unsigned offset = vPC[5].u.operand;2515 2516 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);2517 baseObject->putDirectOffset(offset, callFrame[value].jsValue(callFrame));2518 2519 vPC += 8;2520 NEXT_INSTRUCTION();2521 }2522 }2523 2524 uncachePutByID(callFrame->codeBlock(), vPC);2525 NEXT_INSTRUCTION();2526 }2527 DEFINE_OPCODE(op_put_by_id_generic) {2528 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)2529 2530 Generic property access: Sets the property named by identifier2531 property, belonging to register base, to register value.2532 2533 Unlike many opcodes, this one does not write any output to2534 the register file.2535 */2536 int base = vPC[1].u.operand;2537 int property = vPC[2].u.operand;2538 int value = vPC[3].u.operand;2539 2540 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2541 Identifier& ident = callFrame->codeBlock()->identifier(property);2542 PutPropertySlot slot;2543 baseValue.put(callFrame, ident, callFrame[value].jsValue(callFrame), slot);2544 CHECK_FOR_EXCEPTION();2545 2546 vPC += 8;2547 NEXT_INSTRUCTION();2548 }2549 DEFINE_OPCODE(op_del_by_id) {2550 /* del_by_id dst(r) base(r) property(id)2551 2552 Converts register base to Object, deletes the property2553 named by identifier property from the object, and writes a2554 boolean indicating success (if true) or failure (if false)2555 to register dst.2556 */2557 int dst = (++vPC)->u.operand;2558 int base = (++vPC)->u.operand;2559 int property = (++vPC)->u.operand;2560 2561 JSObject* baseObj = callFrame[base].jsValue(callFrame).toObject(callFrame);2562 Identifier& ident = callFrame->codeBlock()->identifier(property);2563 JSValuePtr result = jsBoolean(baseObj->deleteProperty(callFrame, ident));2564 CHECK_FOR_EXCEPTION();2565 callFrame[dst] = result;2566 ++vPC;2567 NEXT_INSTRUCTION();2568 }2569 DEFINE_OPCODE(op_get_by_val) {2570 /* get_by_val dst(r) base(r) property(r)2571 2572 Converts register base to Object, gets the property named2573 by register property from the object, and puts the result2574 in register dst. property is nominally converted to string2575 but numbers are treated more efficiently.2576 */2577 int dst = (++vPC)->u.operand;2578 int base = (++vPC)->u.operand;2579 int property = (++vPC)->u.operand;2580 2581 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2582 JSValuePtr subscript = callFrame[property].jsValue(callFrame);2583 2584 JSValuePtr result;2585 2586 if (LIKELY(subscript.isUInt32Fast())) {2587 uint32_t i = subscript.getUInt32Fast();2588 if (isJSArray(baseValue)) {2589 JSArray* jsArray = asArray(baseValue);2590 if (jsArray->canGetIndex(i))2591 result = jsArray->getIndex(i);2592 else2593 result = jsArray->JSArray::get(callFrame, i);2594 } else if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))2595 result = asString(baseValue)->getIndex(&callFrame->globalData(), i);2596 else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i))2597 result = asByteArray(baseValue)->getIndex(callFrame, i);2598 else2599 result = baseValue.get(callFrame, i);2600 } else {2601 Identifier property(callFrame, subscript.toString(callFrame));2602 result = baseValue.get(callFrame, property);2603 }2604 2605 CHECK_FOR_EXCEPTION();2606 callFrame[dst] = result;2607 ++vPC;2608 NEXT_INSTRUCTION();2609 }2610 DEFINE_OPCODE(op_put_by_val) {2611 /* put_by_val base(r) property(r) value(r)2612 2613 Sets register value on register base as the property named2614 by register property. Base is converted to object2615 first. register property is nominally converted to string2616 but numbers are treated more efficiently.2617 2618 Unlike many opcodes, this one does not write any output to2619 the register file.2620 */2621 int base = (++vPC)->u.operand;2622 int property = (++vPC)->u.operand;2623 int value = (++vPC)->u.operand;2624 2625 JSValuePtr baseValue = callFrame[base].jsValue(callFrame);2626 JSValuePtr subscript = callFrame[property].jsValue(callFrame);2627 2628 if (LIKELY(subscript.isUInt32Fast())) {2629 uint32_t i = subscript.getUInt32Fast();2630 if (isJSArray(baseValue)) {2631 JSArray* jsArray = asArray(baseValue);2632 if (jsArray->canSetIndex(i))2633 jsArray->setIndex(i, callFrame[value].jsValue(callFrame));2634 else2635 jsArray->JSArray::put(callFrame, i, callFrame[value].jsValue(callFrame));2636 } else if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {2637 JSByteArray* jsByteArray = asByteArray(baseValue);2638 double dValue = 0;2639 JSValuePtr jsValue = callFrame[value].jsValue(callFrame);2640 if (jsValue.isInt32Fast())2641 jsByteArray->setIndex(i, jsValue.getInt32Fast());2642 else if (jsValue.getNumber(dValue))2643 jsByteArray->setIndex(i, dValue);2644 else2645 baseValue.put(callFrame, i, jsValue);2646 } else2647 baseValue.put(callFrame, i, callFrame[value].jsValue(callFrame));2648 } else {2649 Identifier property(callFrame, subscript.toString(callFrame));2650 if (!globalData->exception) { // Don't put to an object if toString threw an exception.2651 PutPropertySlot slot;2652 baseValue.put(callFrame, property, callFrame[value].jsValue(callFrame), slot);2653 }2654 }2655 2656 CHECK_FOR_EXCEPTION();2657 ++vPC;2658 NEXT_INSTRUCTION();2659 }2660 DEFINE_OPCODE(op_del_by_val) {2661 /* del_by_val dst(r) base(r) property(r)2662 2663 Converts register base to Object, deletes the property2664 named by register property from the object, and writes a2665 boolean indicating success (if true) or failure (if false)2666 to register dst.2667 */2668 int dst = (++vPC)->u.operand;2669 int base = (++vPC)->u.operand;2670 int property = (++vPC)->u.operand;2671 2672 JSObject* baseObj = callFrame[base].jsValue(callFrame).toObject(callFrame); // may throw2673 2674 JSValuePtr subscript = callFrame[property].jsValue(callFrame);2675 JSValuePtr result;2676 uint32_t i;2677 if (subscript.getUInt32(i))2678 result = jsBoolean(baseObj->deleteProperty(callFrame, i));2679 else {2680 CHECK_FOR_EXCEPTION();2681 Identifier property(callFrame, subscript.toString(callFrame));2682 CHECK_FOR_EXCEPTION();2683 result = jsBoolean(baseObj->deleteProperty(callFrame, property));2684 }2685 2686 CHECK_FOR_EXCEPTION();2687 callFrame[dst] = result;2688 ++vPC;2689 NEXT_INSTRUCTION();2690 }2691 DEFINE_OPCODE(op_put_by_index) {2692 /* put_by_index base(r) property(n) value(r)2693 2694 Sets register value on register base as the property named2695 by the immediate number property. Base is converted to2696 object first.2697 2698 Unlike many opcodes, this one does not write any output to2699 the register file.2700 2701 This opcode is mainly used to initialize array literals.2702 */2703 int base = (++vPC)->u.operand;2704 unsigned property = (++vPC)->u.operand;2705 int value = (++vPC)->u.operand;2706 2707 callFrame[base].jsValue(callFrame).put(callFrame, property, callFrame[value].jsValue(callFrame));2708 2709 ++vPC;2710 NEXT_INSTRUCTION();2711 }2712 DEFINE_OPCODE(op_loop) {2713 /* loop target(offset)2714 2715 Jumps unconditionally to offset target from the current2716 instruction.2717 2718 Additionally this loop instruction may terminate JS execution is2719 the JS timeout is reached.2720 */2721 #if ENABLE(OPCODE_STATS)2722 OpcodeStats::resetLastInstruction();2723 #endif2724 int target = (++vPC)->u.operand;2725 CHECK_FOR_TIMEOUT();2726 vPC += target;2727 NEXT_INSTRUCTION();2728 }2729 DEFINE_OPCODE(op_jmp) {2730 /* jmp target(offset)2731 2732 Jumps unconditionally to offset target from the current2733 instruction.2734 */2735 #if ENABLE(OPCODE_STATS)2736 OpcodeStats::resetLastInstruction();2737 #endif2738 int target = (++vPC)->u.operand;2739 2740 vPC += target;2741 NEXT_INSTRUCTION();2742 }2743 DEFINE_OPCODE(op_loop_if_true) {2744 /* loop_if_true cond(r) target(offset)2745 2746 Jumps to offset target from the current instruction, if and2747 only if register cond converts to boolean as true.2748 2749 Additionally this loop instruction may terminate JS execution is2750 the JS timeout is reached.2751 */2752 int cond = (++vPC)->u.operand;2753 int target = (++vPC)->u.operand;2754 if (callFrame[cond].jsValue(callFrame).toBoolean(callFrame)) {2755 vPC += target;2756 CHECK_FOR_TIMEOUT();2757 NEXT_INSTRUCTION();2758 }2759 2760 ++vPC;2761 NEXT_INSTRUCTION();2762 }2763 DEFINE_OPCODE(op_jtrue) {2764 /* jtrue cond(r) target(offset)2765 2766 Jumps to offset target from the current instruction, if and2767 only if register cond converts to boolean as true.2768 */2769 int cond = (++vPC)->u.operand;2770 int target = (++vPC)->u.operand;2771 if (callFrame[cond].jsValue(callFrame).toBoolean(callFrame)) {2772 vPC += target;2773 NEXT_INSTRUCTION();2774 }2775 2776 ++vPC;2777 NEXT_INSTRUCTION();2778 }2779 DEFINE_OPCODE(op_jfalse) {2780 /* jfalse cond(r) target(offset)2781 2782 Jumps to offset target from the current instruction, if and2783 only if register cond converts to boolean as false.2784 */2785 int cond = (++vPC)->u.operand;2786 int target = (++vPC)->u.operand;2787 if (!callFrame[cond].jsValue(callFrame).toBoolean(callFrame)) {2788 vPC += target;2789 NEXT_INSTRUCTION();2790 }2791 2792 ++vPC;2793 NEXT_INSTRUCTION();2794 }2795 DEFINE_OPCODE(op_jeq_null) {2796 /* jeq_null src(r) target(offset)2797 2798 Jumps to offset target from the current instruction, if and2799 only if register src is null.2800 */2801 int src = (++vPC)->u.operand;2802 int target = (++vPC)->u.operand;2803 JSValuePtr srcValue = callFrame[src].jsValue(callFrame);2804 2805 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {2806 vPC += target;2807 NEXT_INSTRUCTION();2808 }2809 2810 ++vPC;2811 NEXT_INSTRUCTION();2812 }2813 DEFINE_OPCODE(op_jneq_null) {2814 /* jneq_null src(r) target(offset)2815 2816 Jumps to offset target from the current instruction, if and2817 only if register src is not null.2818 */2819 int src = (++vPC)->u.operand;2820 int target = (++vPC)->u.operand;2821 JSValuePtr srcValue = callFrame[src].jsValue(callFrame);2822 2823 if (!srcValue.isUndefinedOrNull() || (srcValue.isCell() && !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {2824 vPC += target;2825 NEXT_INSTRUCTION();2826 }2827 2828 ++vPC;2829 NEXT_INSTRUCTION();2830 }2831 DEFINE_OPCODE(op_loop_if_less) {2832 /* loop_if_less src1(r) src2(r) target(offset)2833 2834 Checks whether register src1 is less than register src2, as2835 with the ECMAScript '<' operator, and then jumps to offset2836 target from the current instruction, if and only if the2837 result of the comparison is true.2838 2839 Additionally this loop instruction may terminate JS execution is2840 the JS timeout is reached.2841 */2842 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2843 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2844 int target = (++vPC)->u.operand;2845 2846 bool result = jsLess(callFrame, src1, src2);2847 CHECK_FOR_EXCEPTION();2848 2849 if (result) {2850 vPC += target;2851 CHECK_FOR_TIMEOUT();2852 NEXT_INSTRUCTION();2853 }2854 2855 ++vPC;2856 NEXT_INSTRUCTION();2857 }2858 DEFINE_OPCODE(op_loop_if_lesseq) {2859 /* loop_if_lesseq src1(r) src2(r) target(offset)2860 2861 Checks whether register src1 is less than or equal to register2862 src2, as with the ECMAScript '<=' operator, and then jumps to2863 offset target from the current instruction, if and only if the2864 result of the comparison is true.2865 2866 Additionally this loop instruction may terminate JS execution is2867 the JS timeout is reached.2868 */2869 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2870 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2871 int target = (++vPC)->u.operand;2872 2873 bool result = jsLessEq(callFrame, src1, src2);2874 CHECK_FOR_EXCEPTION();2875 2876 if (result) {2877 vPC += target;2878 CHECK_FOR_TIMEOUT();2879 NEXT_INSTRUCTION();2880 }2881 2882 ++vPC;2883 NEXT_INSTRUCTION();2884 }2885 DEFINE_OPCODE(op_jnless) {2886 /* jnless src1(r) src2(r) target(offset)2887 2888 Checks whether register src1 is less than register src2, as2889 with the ECMAScript '<' operator, and then jumps to offset2890 target from the current instruction, if and only if the2891 result of the comparison is false.2892 */2893 JSValuePtr src1 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2894 JSValuePtr src2 = callFrame[(++vPC)->u.operand].jsValue(callFrame);2895 int target = (++vPC)->u.operand;2896 2897 bool result = jsLess(callFrame, src1, src2);2898 CHECK_FOR_EXCEPTION();2899 2900 if (!result) {2901 vPC += target;2902 NEXT_INSTRUCTION();2903 }2904 2905 ++vPC;2906 NEXT_INSTRUCTION();2907 }2908 DEFINE_OPCODE(op_switch_imm) {2909 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)2910 2911 Performs a range checked switch on the scrutinee value, using2912 the tableIndex-th immediate switch jump table. If the scrutinee value2913 is an immediate number in the range covered by the referenced jump2914 table, and the value at jumpTable[scrutinee value] is non-zero, then2915 that value is used as the jump offset, otherwise defaultOffset is used.2916 */2917 int tableIndex = (++vPC)->u.operand;2918 int defaultOffset = (++vPC)->u.operand;2919 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);2920 if (scrutinee.isInt32Fast())2921 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.getInt32Fast(), defaultOffset);2922 else {2923 int32_t value;2924 if (scrutinee.numberToInt32(value))2925 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(value, defaultOffset);2926 else2927 vPC += defaultOffset;2928 }2929 NEXT_INSTRUCTION();2930 }2931 DEFINE_OPCODE(op_switch_char) {2932 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)2933 2934 Performs a range checked switch on the scrutinee value, using2935 the tableIndex-th character switch jump table. If the scrutinee value2936 is a single character string in the range covered by the referenced jump2937 table, and the value at jumpTable[scrutinee value] is non-zero, then2938 that value is used as the jump offset, otherwise defaultOffset is used.2939 */2940 int tableIndex = (++vPC)->u.operand;2941 int defaultOffset = (++vPC)->u.operand;2942 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);2943 if (!scrutinee.isString())2944 vPC += defaultOffset;2945 else {2946 UString::Rep* value = asString(scrutinee)->value().rep();2947 if (value->size() != 1)2948 vPC += defaultOffset;2949 else2950 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);2951 }2952 NEXT_INSTRUCTION();2953 }2954 DEFINE_OPCODE(op_switch_string) {2955 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)2956 2957 Performs a sparse hashmap based switch on the value in the scrutinee2958 register, using the tableIndex-th string switch jump table. If the2959 scrutinee value is a string that exists as a key in the referenced2960 jump table, then the value associated with the string is used as the2961 jump offset, otherwise defaultOffset is used.2962 */2963 int tableIndex = (++vPC)->u.operand;2964 int defaultOffset = (++vPC)->u.operand;2965 JSValuePtr scrutinee = callFrame[(++vPC)->u.operand].jsValue(callFrame);2966 if (!scrutinee.isString())2967 vPC += defaultOffset;2968 else2969 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset);2970 NEXT_INSTRUCTION();2971 }2972 DEFINE_OPCODE(op_new_func) {2973 /* new_func dst(r) func(f)2974 2975 Constructs a new Function instance from function func and2976 the current scope chain using the original Function2977 constructor, using the rules for function declarations, and2978 puts the result in register dst.2979 */2980 int dst = (++vPC)->u.operand;2981 int func = (++vPC)->u.operand;2982 2983 callFrame[dst] = callFrame->codeBlock()->function(func)->makeFunction(callFrame, callFrame->scopeChain());2984 2985 ++vPC;2986 NEXT_INSTRUCTION();2987 }2988 DEFINE_OPCODE(op_new_func_exp) {2989 /* new_func_exp dst(r) func(f)2990 2991 Constructs a new Function instance from function func and2992 the current scope chain using the original Function2993 constructor, using the rules for function expressions, and2994 puts the result in register dst.2995 */2996 int dst = (++vPC)->u.operand;2997 int func = (++vPC)->u.operand;2998 2999 callFrame[dst] = callFrame->codeBlock()->functionExpression(func)->makeFunction(callFrame, callFrame->scopeChain());3000 3001 ++vPC;3002 NEXT_INSTRUCTION();3003 }3004 DEFINE_OPCODE(op_call_eval) {3005 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)3006 3007 Call a function named "eval" with no explicit "this" value3008 (which may therefore be the eval operator). If register3009 thisVal is the global object, and register func contains3010 that global object's original global eval function, then3011 perform the eval operator in local scope (interpreting3012 the argument registers as for the "call"3013 opcode). Otherwise, act exactly as the "call" opcode would.3014 */3015 3016 int dst = vPC[1].u.operand;3017 int func = vPC[2].u.operand;3018 int argCount = vPC[3].u.operand;3019 int registerOffset = vPC[4].u.operand;3020 3021 JSValuePtr funcVal = callFrame[func].jsValue(callFrame);3022 3023 Register* newCallFrame = callFrame->registers() + registerOffset;3024 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;3025 JSValuePtr thisValue = argv[0].jsValue(callFrame);3026 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();3027 3028 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {3029 JSValuePtr result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);3030 if (exceptionValue)3031 goto vm_throw;3032 callFrame[dst] = result;3033 3034 vPC += 5;3035 NEXT_INSTRUCTION();3036 }3037 3038 // We didn't find the blessed version of eval, so process this3039 // instruction as a normal function call.3040 // fall through to op_call3041 }3042 DEFINE_OPCODE(op_call) {3043 /* call dst(r) func(r) argCount(n) registerOffset(n)3044 3045 Perform a function call.3046 3047 registerOffset is the distance the callFrame pointer should move3048 before the VM initializes the new call frame's header.3049 3050 dst is where op_ret should store its result.3051 */3052 3053 int dst = vPC[1].u.operand;3054 int func = vPC[2].u.operand;3055 int argCount = vPC[3].u.operand;3056 int registerOffset = vPC[4].u.operand;3057 3058 JSValuePtr v = callFrame[func].jsValue(callFrame);3059 3060 CallData callData;3061 CallType callType = v.getCallData(callData);3062 3063 if (callType == CallTypeJS) {3064 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;3065 FunctionBodyNode* functionBodyNode = callData.js.functionBody;3066 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);3067 3068 CallFrame* previousCallFrame = callFrame;3069 3070 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);3071 if (UNLIKELY(!callFrame)) {3072 callFrame = previousCallFrame;3073 exceptionValue = createStackOverflowError(callFrame);3074 goto vm_throw;3075 }3076 3077 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));3078 vPC = newCodeBlock->instructions().begin();3079 3080 #if ENABLE(OPCODE_STATS)3081 OpcodeStats::resetLastInstruction();3082 #endif3083 3084 NEXT_INSTRUCTION();3085 }3086 3087 if (callType == CallTypeHost) {3088 ScopeChainNode* scopeChain = callFrame->scopeChain();3089 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);3090 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);3091 3092 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;3093 ArgList args(thisRegister + 1, argCount - 1);3094 3095 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.3096 JSValuePtr thisValue = thisRegister->jsValue(callFrame);3097 if (thisValue == jsNull())3098 thisValue = callFrame->globalThisValue();3099 3100 JSValuePtr returnValue;3101 {3102 SamplingTool::HostCallRecord callRecord(m_sampler);3103 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);3104 }3105 CHECK_FOR_EXCEPTION();3106 3107 callFrame[dst] = JSValuePtr(returnValue);3108 3109 vPC += 5;3110 NEXT_INSTRUCTION();3111 }3112 3113 ASSERT(callType == CallTypeNone);3114 3115 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());3116 goto vm_throw;3117 }3118 DEFINE_OPCODE(op_tear_off_activation) {3119 /* tear_off_activation activation(r)3120 3121 Copy all locals and parameters to new memory allocated on3122 the heap, and make the passed activation use this memory3123 in the future when looking up entries in the symbol table.3124 If there is an 'arguments' object, then it will also use3125 this memory for storing the named parameters, but not any3126 extra arguments.3127 3128 This opcode should only be used immediately before op_ret.3129 */3130 3131 int src = (++vPC)->u.operand;3132 ASSERT(callFrame->codeBlock()->needsFullScopeChain());3133 3134 asActivation(callFrame[src].getJSValue())->copyRegisters(callFrame->optionalCalleeArguments());3135 3136 ++vPC;3137 NEXT_INSTRUCTION();3138 }3139 DEFINE_OPCODE(op_tear_off_arguments) {3140 /* tear_off_arguments3141 3142 Copy all arguments to new memory allocated on the heap,3143 and make the 'arguments' object use this memory in the3144 future when looking up named parameters, but not any3145 extra arguments. If an activation object exists for the3146 current function context, then the tear_off_activation3147 opcode should be used instead.3148 3149 This opcode should only be used immediately before op_ret.3150 */3151 3152 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());3153 3154 callFrame->optionalCalleeArguments()->copyRegisters();3155 3156 ++vPC;3157 NEXT_INSTRUCTION();3158 }3159 DEFINE_OPCODE(op_ret) {3160 /* ret result(r)3161 3162 Return register result as the return value of the current3163 function call, writing it into the caller's expected return3164 value register. In addition, unwind one call frame and3165 restore the scope chain, code block instruction pointer and3166 register base to those of the calling function.3167 */3168 3169 int result = (++vPC)->u.operand;3170 3171 if (callFrame->codeBlock()->needsFullScopeChain())3172 callFrame->scopeChain()->deref();3173 3174 JSValuePtr returnValue = callFrame[result].jsValue(callFrame);3175 3176 vPC = callFrame->returnPC();3177 int dst = callFrame->returnValueRegister();3178 callFrame = callFrame->callerFrame();3179 3180 if (callFrame->hasHostCallFrameFlag())3181 return returnValue;3182 3183 callFrame[dst] = JSValuePtr(returnValue);3184 3185 NEXT_INSTRUCTION();3186 }3187 DEFINE_OPCODE(op_enter) {3188 /* enter3189 3190 Initializes local variables to undefined and fills constant3191 registers with their values. If the code block requires an3192 activation, enter_with_activation should be used instead.3193 3194 This opcode should only be used at the beginning of a code3195 block.3196 */3197 3198 size_t i = 0;3199 CodeBlock* codeBlock = callFrame->codeBlock();3200 3201 for (size_t count = codeBlock->m_numVars; i < count; ++i)3202 callFrame[i] = jsUndefined();3203 3204 for (size_t count = codeBlock->numberOfConstantRegisters(), j = 0; j < count; ++i, ++j)3205 callFrame[i] = codeBlock->constantRegister(j);3206 3207 ++vPC;3208 NEXT_INSTRUCTION();3209 }3210 DEFINE_OPCODE(op_enter_with_activation) {3211 /* enter_with_activation dst(r)3212 3213 Initializes local variables to undefined, fills constant3214 registers with their values, creates an activation object,3215 and places the new activation both in dst and at the top3216 of the scope chain. If the code block does not require an3217 activation, enter should be used instead.3218 3219 This opcode should only be used at the beginning of a code3220 block.3221 */3222 3223 size_t i = 0;3224 CodeBlock* codeBlock = callFrame->codeBlock();3225 3226 for (size_t count = codeBlock->m_numVars; i < count; ++i)3227 callFrame[i] = jsUndefined();3228 3229 for (size_t count = codeBlock->numberOfConstantRegisters(), j = 0; j < count; ++i, ++j)3230 callFrame[i] = codeBlock->constantRegister(j);3231 3232 int dst = (++vPC)->u.operand;3233 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionBodyNode*>(codeBlock->ownerNode()));3234 callFrame[dst] = activation;3235 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));3236 3237 ++vPC;3238 NEXT_INSTRUCTION();3239 }3240 DEFINE_OPCODE(op_convert_this) {3241 /* convert_this this(r)3242 3243 Takes the value in the 'this' register, converts it to a3244 value that is suitable for use as the 'this' value, and3245 stores it in the 'this' register. This opcode is emitted3246 to avoid doing the conversion in the caller unnecessarily.3247 3248 This opcode should only be used at the beginning of a code3249 block.3250 */3251 3252 int thisRegister = (++vPC)->u.operand;3253 JSValuePtr thisVal = callFrame[thisRegister].getJSValue();3254 if (thisVal.needsThisConversion())3255 callFrame[thisRegister] = JSValuePtr(thisVal.toThisObject(callFrame));3256 3257 ++vPC;3258 NEXT_INSTRUCTION();3259 }3260 DEFINE_OPCODE(op_create_arguments) {3261 /* create_arguments3262 3263 Creates the 'arguments' object and places it in both the3264 'arguments' call frame slot and the local 'arguments'3265 register.3266 3267 This opcode should only be used at the beginning of a code3268 block.3269 */3270 3271 Arguments* arguments = new (globalData) Arguments(callFrame);3272 callFrame->setCalleeArguments(arguments);3273 callFrame[RegisterFile::ArgumentsRegister] = arguments;3274 3275 ++vPC;3276 NEXT_INSTRUCTION();3277 }3278 DEFINE_OPCODE(op_construct) {3279 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)3280 3281 Invoke register "func" as a constructor. For JS3282 functions, the calling convention is exactly as for the3283 "call" opcode, except that the "this" value is a newly3284 created Object. For native constructors, no "this"3285 value is passed. In either case, the argCount and registerOffset3286 registers are interpreted as for the "call" opcode.3287 3288 Register proto must contain the prototype property of3289 register func. This is to enable polymorphic inline3290 caching of this lookup.3291 */3292 3293 int dst = vPC[1].u.operand;3294 int func = vPC[2].u.operand;3295 int argCount = vPC[3].u.operand;3296 int registerOffset = vPC[4].u.operand;3297 int proto = vPC[5].u.operand;3298 int thisRegister = vPC[6].u.operand;3299 3300 JSValuePtr v = callFrame[func].jsValue(callFrame);3301 3302 ConstructData constructData;3303 ConstructType constructType = v.getConstructData(constructData);3304 3305 if (constructType == ConstructTypeJS) {3306 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;3307 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;3308 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);3309 3310 Structure* structure;3311 JSValuePtr prototype = callFrame[proto].jsValue(callFrame);3312 if (prototype.isObject())3313 structure = asObject(prototype)->inheritorID();3314 else3315 structure = callDataScopeChain->globalObject()->emptyObjectStructure();3316 JSObject* newObject = new (globalData) JSObject(structure);3317 3318 callFrame[thisRegister] = JSValuePtr(newObject); // "this" value3319 3320 CallFrame* previousCallFrame = callFrame;3321 3322 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);3323 if (UNLIKELY(!callFrame)) {3324 callFrame = previousCallFrame;3325 exceptionValue = createStackOverflowError(callFrame);3326 goto vm_throw;3327 }3328 3329 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));3330 vPC = newCodeBlock->instructions().begin();3331 3332 #if ENABLE(OPCODE_STATS)3333 OpcodeStats::resetLastInstruction();3334 #endif3335 3336 NEXT_INSTRUCTION();3337 }3338 3339 if (constructType == ConstructTypeHost) {3340 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);3341 3342 ScopeChainNode* scopeChain = callFrame->scopeChain();3343 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);3344 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);3345 3346 JSValuePtr returnValue;3347 {3348 SamplingTool::HostCallRecord callRecord(m_sampler);3349 returnValue = constructData.native.function(newCallFrame, asObject(v), args);3350 }3351 CHECK_FOR_EXCEPTION();3352 callFrame[dst] = JSValuePtr(returnValue);3353 3354 vPC += 7;3355 NEXT_INSTRUCTION();3356 }3357 3358 ASSERT(constructType == ConstructTypeNone);3359 3360 exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());3361 goto vm_throw;3362 }3363 DEFINE_OPCODE(op_construct_verify) {3364 /* construct_verify dst(r) override(r)3365 3366 Verifies that register dst holds an object. If not, moves3367 the object in register override to register dst.3368 */3369 3370 int dst = vPC[1].u.operand;3371 if (LIKELY(callFrame[dst].jsValue(callFrame).isObject())) {3372 vPC += 3;3373 NEXT_INSTRUCTION();3374 }3375 3376 int override = vPC[2].u.operand;3377 callFrame[dst] = callFrame[override];3378 3379 vPC += 3;3380 NEXT_INSTRUCTION();3381 }3382 DEFINE_OPCODE(op_push_scope) {3383 /* push_scope scope(r)3384 3385 Converts register scope to object, and pushes it onto the top3386 of the current scope chain. The contents of the register scope3387 are replaced by the result of toObject conversion of the scope.3388 */3389 int scope = (++vPC)->u.operand;3390 JSValuePtr v = callFrame[scope].jsValue(callFrame);3391 JSObject* o = v.toObject(callFrame);3392 CHECK_FOR_EXCEPTION();3393 3394 callFrame[scope] = JSValuePtr(o);3395 callFrame->setScopeChain(callFrame->scopeChain()->push(o));3396 3397 ++vPC;3398 NEXT_INSTRUCTION();3399 }3400 DEFINE_OPCODE(op_pop_scope) {3401 /* pop_scope3402 3403 Removes the top item from the current scope chain.3404 */3405 callFrame->setScopeChain(callFrame->scopeChain()->pop());3406 3407 ++vPC;3408 NEXT_INSTRUCTION();3409 }3410 DEFINE_OPCODE(op_get_pnames) {3411 /* get_pnames dst(r) base(r)3412 3413 Creates a property name list for register base and puts it3414 in register dst. This is not a true JavaScript value, just3415 a synthetic value used to keep the iteration state in a3416 register.3417 */3418 int dst = (++vPC)->u.operand;3419 int base = (++vPC)->u.operand;3420 3421 callFrame[dst] = JSPropertyNameIterator::create(callFrame, callFrame[base].jsValue(callFrame));3422 ++vPC;3423 NEXT_INSTRUCTION();3424 }3425 DEFINE_OPCODE(op_next_pname) {3426 /* next_pname dst(r) iter(r) target(offset)3427 3428 Tries to copies the next name from property name list in3429 register iter. If there are names left, then copies one to3430 register dst, and jumps to offset target. If there are none3431 left, invalidates the iterator and continues to the next3432 instruction.3433 */3434 int dst = (++vPC)->u.operand;3435 int iter = (++vPC)->u.operand;3436 int target = (++vPC)->u.operand;3437 3438 JSPropertyNameIterator* it = callFrame[iter].propertyNameIterator();3439 if (JSValuePtr temp = it->next(callFrame)) {3440 CHECK_FOR_TIMEOUT();3441 callFrame[dst] = JSValuePtr(temp);3442 vPC += target;3443 NEXT_INSTRUCTION();3444 }3445 it->invalidate();3446 3447 ++vPC;3448 NEXT_INSTRUCTION();3449 }3450 DEFINE_OPCODE(op_jmp_scopes) {3451 /* jmp_scopes count(n) target(offset)3452 3453 Removes the a number of items from the current scope chain3454 specified by immediate number count, then jumps to offset3455 target.3456 */3457 int count = (++vPC)->u.operand;3458 int target = (++vPC)->u.operand;3459 3460 ScopeChainNode* tmp = callFrame->scopeChain();3461 while (count--)3462 tmp = tmp->pop();3463 callFrame->setScopeChain(tmp);3464 3465 vPC += target;3466 NEXT_INSTRUCTION();3467 }3468 #if HAVE(COMPUTED_GOTO)3469 // Appease GCC3470 goto *(&&skip_new_scope);3471 #endif3472 DEFINE_OPCODE(op_push_new_scope) {3473 /* new_scope dst(r) property(id) value(r)3474 3475 Constructs a new StaticScopeObject with property set to value. That scope3476 object is then pushed onto the ScopeChain. The scope object is then stored3477 in dst for GC.3478 */3479 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));3480 3481 vPC += 4;3482 NEXT_INSTRUCTION();3483 }3484 #if HAVE(COMPUTED_GOTO)3485 skip_new_scope:3486 #endif3487 DEFINE_OPCODE(op_catch) {3488 /* catch ex(r)3489 3490 Retrieves the VM's current exception and puts it in register3491 ex. This is only valid after an exception has been raised,3492 and usually forms the beginning of an exception handler.3493 */3494 ASSERT(exceptionValue);3495 ASSERT(!globalData->exception);3496 int ex = (++vPC)->u.operand;3497 callFrame[ex] = exceptionValue;3498 exceptionValue = noValue();3499 3500 ++vPC;3501 NEXT_INSTRUCTION();3502 }3503 DEFINE_OPCODE(op_throw) {3504 /* throw ex(r)3505 3506 Throws register ex as an exception. This involves three3507 steps: first, it is set as the current exception in the3508 VM's internal state, then the stack is unwound until an3509 exception handler or a native code boundary is found, and3510 then control resumes at the exception handler if any or3511 else the script returns control to the nearest native caller.3512 */3513 3514 int ex = (++vPC)->u.operand;3515 exceptionValue = callFrame[ex].jsValue(callFrame);3516 3517 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);3518 if (!handler) {3519 *exception = exceptionValue;3520 return jsNull();3521 }3522 3523 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;3524 NEXT_INSTRUCTION();3525 }3526 DEFINE_OPCODE(op_unexpected_load) {3527 /* unexpected_load load dst(r) src(k)3528 3529 Copies constant src to register dst.3530 */3531 int dst = (++vPC)->u.operand;3532 int src = (++vPC)->u.operand;3533 callFrame[dst] = JSValuePtr(callFrame->codeBlock()->unexpectedConstant(src));3534 3535 ++vPC;3536 NEXT_INSTRUCTION();3537 }3538 DEFINE_OPCODE(op_new_error) {3539 /* new_error dst(r) type(n) message(k)3540 3541 Constructs a new Error instance using the original3542 constructor, using immediate number n as the type and3543 constant message as the message string. The result is3544 written to register dst.3545 */3546 int dst = (++vPC)->u.operand;3547 int type = (++vPC)->u.operand;3548 int message = (++vPC)->u.operand;3549 3550 CodeBlock* codeBlock = callFrame->codeBlock();3551 callFrame[dst] = JSValuePtr(Error::create(callFrame, (ErrorType)type, codeBlock->unexpectedConstant(message).toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()));3552 3553 ++vPC;3554 NEXT_INSTRUCTION();3555 }3556 DEFINE_OPCODE(op_end) {3557 /* end result(r)3558 3559 Return register result as the value of a global or eval3560 program. Return control to the calling native code.3561 */3562 3563 if (callFrame->codeBlock()->needsFullScopeChain()) {3564 ScopeChainNode* scopeChain = callFrame->scopeChain();3565 ASSERT(scopeChain->refCount > 1);3566 scopeChain->deref();3567 }3568 int result = (++vPC)->u.operand;3569 return callFrame[result].jsValue(callFrame);3570 }3571 DEFINE_OPCODE(op_put_getter) {3572 /* put_getter base(r) property(id) function(r)3573 3574 Sets register function on register base as the getter named3575 by identifier property. Base and function are assumed to be3576 objects as this op should only be used for getters defined3577 in object literal form.3578 3579 Unlike many opcodes, this one does not write any output to3580 the register file.3581 */3582 int base = (++vPC)->u.operand;3583 int property = (++vPC)->u.operand;3584 int function = (++vPC)->u.operand;3585 3586 ASSERT(callFrame[base].jsValue(callFrame).isObject());3587 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));3588 Identifier& ident = callFrame->codeBlock()->identifier(property);3589 ASSERT(callFrame[function].jsValue(callFrame).isObject());3590 baseObj->defineGetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));3591 3592 ++vPC;3593 NEXT_INSTRUCTION();3594 }3595 DEFINE_OPCODE(op_put_setter) {3596 /* put_setter base(r) property(id) function(r)3597 3598 Sets register function on register base as the setter named3599 by identifier property. Base and function are assumed to be3600 objects as this op should only be used for setters defined3601 in object literal form.3602 3603 Unlike many opcodes, this one does not write any output to3604 the register file.3605 */3606 int base = (++vPC)->u.operand;3607 int property = (++vPC)->u.operand;3608 int function = (++vPC)->u.operand;3609 3610 ASSERT(callFrame[base].jsValue(callFrame).isObject());3611 JSObject* baseObj = asObject(callFrame[base].jsValue(callFrame));3612 Identifier& ident = callFrame->codeBlock()->identifier(property);3613 ASSERT(callFrame[function].jsValue(callFrame).isObject());3614 baseObj->defineSetter(callFrame, ident, asObject(callFrame[function].jsValue(callFrame)));3615 3616 ++vPC;3617 NEXT_INSTRUCTION();3618 }3619 DEFINE_OPCODE(op_jsr) {3620 /* jsr retAddrDst(r) target(offset)3621 3622 Places the address of the next instruction into the retAddrDst3623 register and jumps to offset target from the current instruction.3624 */3625 int retAddrDst = (++vPC)->u.operand;3626 int target = (++vPC)->u.operand;3627 callFrame[retAddrDst] = vPC + 1;3628 3629 vPC += target;3630 NEXT_INSTRUCTION();3631 }3632 DEFINE_OPCODE(op_sret) {3633 /* sret retAddrSrc(r)3634 3635 Jumps to the address stored in the retAddrSrc register. This3636 differs from op_jmp because the target address is stored in a3637 register, not as an immediate.3638 */3639 int retAddrSrc = (++vPC)->u.operand;3640 vPC = callFrame[retAddrSrc].vPC();3641 NEXT_INSTRUCTION();3642 }3643 DEFINE_OPCODE(op_debug) {3644 /* debug debugHookID(n) firstLine(n) lastLine(n)3645 3646 Notifies the debugger of the current state of execution. This opcode3647 is only generated while the debugger is attached.3648 */3649 int debugHookID = (++vPC)->u.operand;3650 int firstLine = (++vPC)->u.operand;3651 int lastLine = (++vPC)->u.operand;3652 3653 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);3654 3655 ++vPC;3656 NEXT_INSTRUCTION();3657 }3658 DEFINE_OPCODE(op_profile_will_call) {3659 /* op_profile_will_call function(r)3660 3661 Notifies the profiler of the beginning of a function call. This opcode3662 is only generated if developer tools are enabled.3663 */3664 int function = vPC[1].u.operand;3665 3666 if (*enabledProfilerReference)3667 (*enabledProfilerReference)->willExecute(callFrame, callFrame[function].jsValue(callFrame));3668 3669 vPC += 2;3670 NEXT_INSTRUCTION();3671 }3672 DEFINE_OPCODE(op_profile_did_call) {3673 /* op_profile_did_call function(r)3674 3675 Notifies the profiler of the end of a function call. This opcode3676 is only generated if developer tools are enabled.3677 */3678 int function = vPC[1].u.operand;3679 3680 if (*enabledProfilerReference)3681 (*enabledProfilerReference)->didExecute(callFrame, callFrame[function].jsValue(callFrame));3682 3683 vPC += 2;3684 NEXT_INSTRUCTION();3685 }3686 vm_throw: {3687 globalData->exception = noValue();3688 if (!tickCount) {3689 // The exceptionValue is a lie! (GCC produces bad code for reasons I3690 // cannot fathom if we don't assign to the exceptionValue before branching)3691 exceptionValue = createInterruptedExecutionException(globalData);3692 }3693 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);3694 if (!handler) {3695 *exception = exceptionValue;3696 return jsNull();3697 }3698 3699 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;3700 NEXT_INSTRUCTION();3701 }3702 }3703 #if !HAVE(COMPUTED_GOTO)3704 } // iterator loop ends3705 #endif3706 #undef NEXT_INSTRUCTION3707 #undef DEFINE_OPCODE3708 #undef CHECK_FOR_EXCEPTION3709 #undef CHECK_FOR_TIMEOUT3710 }3711 3712 JSValuePtr Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const3713 {3714 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);3715 if (!functionCallFrame)3716 return jsNull();3717 3718 CodeBlock* codeBlock = functionCallFrame->codeBlock();3719 if (codeBlock->usesArguments()) {3720 ASSERT(codeBlock->codeType() == FunctionCode);3721 SymbolTable& symbolTable = codeBlock->symbolTable();3722 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();3723 return functionCallFrame[argumentsIndex].jsValue(callFrame);3724 }3725 3726 Arguments* arguments = functionCallFrame->optionalCalleeArguments();3727 if (!arguments) {3728 arguments = new (functionCallFrame) Arguments(functionCallFrame);3729 arguments->copyRegisters();3730 callFrame->setCalleeArguments(arguments);3731 }3732 3733 return arguments;3734 }3735 3736 JSValuePtr Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const3737 {3738 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);3739 if (!functionCallFrame)3740 return jsNull();3741 3742 CallFrame* callerFrame = functionCallFrame->callerFrame();3743 if (callerFrame->hasHostCallFrameFlag())3744 return jsNull();3745 3746 JSValuePtr caller = callerFrame->callee();3747 if (!caller)3748 return jsNull();3749 3750 return caller;3751 }3752 3753 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValuePtr& function) const3754 {3755 function = noValue();3756 lineNumber = -1;3757 sourceURL = UString();3758 3759 CallFrame* callerFrame = callFrame->callerFrame();3760 if (callerFrame->hasHostCallFrameFlag())3761 return;3762 3763 CodeBlock* callerCodeBlock = callerFrame->codeBlock();3764 if (!callerCodeBlock)3765 return;3766 3767 unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());3768 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);3769 sourceID = callerCodeBlock->ownerNode()->sourceID();3770 sourceURL = callerCodeBlock->ownerNode()->sourceURL();3771 function = callerFrame->callee();3772 }3773 3774 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)3775 {3776 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {3777 if (candidate->callee() == function)3778 return candidate;3779 }3780 return 0;3781 }3782 3783 154 } // namespace JSC
Note:
See TracChangeset
for help on using the changeset viewer.