1 /* 2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich (at) uwaterloo.ca> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "Interpreter.h" 32 33 #include "Arguments.h" 34 #include "BatchedTransitionOptimizer.h" 35 #include "CallFrame.h" 36 #include "CallFrameClosure.h" 37 #include "CodeBlock.h" 38 #include "Collector.h" 39 #include "Debugger.h" 40 #include "DebuggerCallFrame.h" 41 #include "EvalCodeCache.h" 42 #include "ExceptionHelpers.h" 43 #include "GlobalEvalFunction.h" 44 #include "JSActivation.h" 45 #include "JSArray.h" 46 #include "JSByteArray.h" 47 #include "JSFunction.h" 48 #include "JSNotAnObject.h" 49 #include "JSPropertyNameIterator.h" 50 #include "LiteralParser.h" 51 #include "JSStaticScopeObject.h" 52 #include "JSString.h" 53 #include "ObjectPrototype.h" 54 #include "Operations.h" 55 #include "Parser.h" 56 #include "Profiler.h" 57 #include "RegExpObject.h" 58 #include "RegExpPrototype.h" 59 #include "Register.h" 60 #include "SamplingTool.h" 61 #include <limits.h> 62 #include <stdio.h> 63 #include <wtf/Threading.h> 64 65 #if ENABLE(JIT) 66 #include "JIT.h" 67 #endif 68 69 using namespace std; 70 71 namespace JSC { 72 73 static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc) 74 { 75 #if ENABLE(JIT) 76 return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(pc)); 77 #else 78 UNUSED_PARAM(callFrame); 79 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin(); 80 #endif 81 } 82 83 // Returns the depth of the scope chain within a given call frame. 84 static int depth(CodeBlock* codeBlock, ScopeChain& sc) 85 { 86 if (!codeBlock->needsFullScopeChain()) 87 return 0; 88 return sc.localDepth(); 89 } 90 91 #if USE(INTERPRETER) 92 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) 93 { 94 int dst = vPC[1].u.operand; 95 int property = vPC[2].u.operand; 96 97 ScopeChainNode* scopeChain = callFrame->scopeChain(); 98 ScopeChainIterator iter = scopeChain->begin(); 99 ScopeChainIterator end = scopeChain->end(); 100 ASSERT(iter != end); 101 102 CodeBlock* codeBlock = callFrame->codeBlock(); 103 Identifier& ident = codeBlock->identifier(property); 104 do { 105 JSObject* o = *iter; 106 PropertySlot slot(o); 107 if (o->getPropertySlot(callFrame, ident, slot)) { 108 JSValue result = slot.getValue(callFrame, ident); 109 exceptionValue = callFrame->globalData().exception; 110 if (exceptionValue) 111 return false; 112 callFrame->r(dst) = JSValue(result); 113 return true; 114 } 115 } while (++iter != end); 116 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 117 return false; 118 } 119 120 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) 121 { 122 CodeBlock* codeBlock = callFrame->codeBlock(); 123 124 int dst = vPC[1].u.operand; 125 int property = vPC[2].u.operand; 126 int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain(); 127 128 ScopeChainNode* scopeChain = callFrame->scopeChain(); 129 ScopeChainIterator iter = scopeChain->begin(); 130 ScopeChainIterator end = scopeChain->end(); 131 ASSERT(iter != end); 132 while (skip--) { 133 ++iter; 134 ASSERT(iter != end); 135 } 136 Identifier& ident = codeBlock->identifier(property); 137 do { 138 JSObject* o = *iter; 139 PropertySlot slot(o); 140 if (o->getPropertySlot(callFrame, ident, slot)) { 141 JSValue result = slot.getValue(callFrame, ident); 142 exceptionValue = callFrame->globalData().exception; 143 if (exceptionValue) 144 return false; 145 callFrame->r(dst) = JSValue(result); 146 return true; 147 } 148 } while (++iter != end); 149 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 150 return false; 151 } 152 153 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) 154 { 155 int dst = vPC[1].u.operand; 156 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell); 157 ASSERT(globalObject->isGlobalObject()); 158 int property = vPC[3].u.operand; 159 Structure* structure = vPC[4].u.structure; 160 int offset = vPC[5].u.operand; 161 162 if (structure == globalObject->structure()) { 163 callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset)); 164 return true; 165 } 166 167 CodeBlock* codeBlock = callFrame->codeBlock(); 168 Identifier& ident = codeBlock->identifier(property); 169 PropertySlot slot(globalObject); 170 if (globalObject->getPropertySlot(callFrame, ident, slot)) { 171 JSValue result = slot.getValue(callFrame, ident); 172 if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { 173 if (vPC[4].u.structure) 174 vPC[4].u.structure->deref(); 175 globalObject->structure()->ref(); 176 vPC[4] = globalObject->structure(); 177 vPC[5] = slot.cachedOffset(); 178 callFrame->r(dst) = JSValue(result); 179 return true; 180 } 181 182 exceptionValue = callFrame->globalData().exception; 183 if (exceptionValue) 184 return false; 185 callFrame->r(dst) = JSValue(result); 186 return true; 187 } 188 189 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 190 return false; 191 } 192 193 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC) 194 { 195 int dst = vPC[1].u.operand; 196 int property = vPC[2].u.operand; 197 callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain())); 198 } 199 200 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) 201 { 202 int baseDst = vPC[1].u.operand; 203 int propDst = vPC[2].u.operand; 204 int property = vPC[3].u.operand; 205 206 ScopeChainNode* scopeChain = callFrame->scopeChain(); 207 ScopeChainIterator iter = scopeChain->begin(); 208 ScopeChainIterator end = scopeChain->end(); 209 210 // FIXME: add scopeDepthIsZero optimization 211 212 ASSERT(iter != end); 213 214 CodeBlock* codeBlock = callFrame->codeBlock(); 215 Identifier& ident = codeBlock->identifier(property); 216 JSObject* base; 217 do { 218 base = *iter; 219 PropertySlot slot(base); 220 if (base->getPropertySlot(callFrame, ident, slot)) { 221 JSValue result = slot.getValue(callFrame, ident); 222 exceptionValue = callFrame->globalData().exception; 223 if (exceptionValue) 224 return false; 225 callFrame->r(propDst) = JSValue(result); 226 callFrame->r(baseDst) = JSValue(base); 227 return true; 228 } 229 ++iter; 230 } while (iter != end); 231 232 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); 233 return false; 234 } 235 236 #endif // USE(INTERPRETER) 237 238 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc) 239 { 240 Register* r = callFrame->registers(); 241 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters; 242 243 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments 244 if (UNLIKELY(!registerFile->grow(newEnd))) 245 return 0; 246 r += registerOffset; 247 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks 248 size_t omittedArgCount = newCodeBlock->m_numParameters - argc; 249 registerOffset += omittedArgCount; 250 newEnd += omittedArgCount; 251 if (!registerFile->grow(newEnd)) 252 return 0; 253 r += registerOffset; 254 255 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; 256 for (size_t i = 0; i < omittedArgCount; ++i) 257 argv[i] = jsUndefined(); 258 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind 259 size_t numParameters = newCodeBlock->m_numParameters; 260 registerOffset += numParameters; 261 newEnd += numParameters; 262 263 if (!registerFile->grow(newEnd)) 264 return 0; 265 r += registerOffset; 266 267 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc; 268 for (size_t i = 0; i < numParameters; ++i) 269 argv[i + argc] = argv[i]; 270 } 271 272 return CallFrame::create(r); 273 } 274 275 #if USE(INTERPRETER) 276 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData) 277 { 278 if (value.isObject()) 279 return false; 280 exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock); 281 return true; 282 } 283 284 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData) 285 { 286 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance()) 287 return false; 288 exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock); 289 return true; 290 } 291 #endif 292 293 NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue) 294 { 295 if (argc < 2) 296 return jsUndefined(); 297 298 JSValue program = argv[1].jsValue(); 299 300 if (!program.isString()) 301 return program; 302 303 UString programSource = asString(program)->value(callFrame); 304 305 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); 306 if (JSValue parsedObject = preparser.tryLiteralParse()) 307 return parsedObject; 308 309 ScopeChainNode* scopeChain = callFrame->scopeChain(); 310 CodeBlock* codeBlock = callFrame->codeBlock(); 311 RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); 312 313 JSValue result = jsUndefined(); 314 if (eval) 315 result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); 316 317 return result; 318 } 319 320 Interpreter::Interpreter() 321 : m_sampleEntryDepth(0) 322 , m_reentryDepth(0) 323 { 324 #if HAVE(COMPUTED_GOTO) 325 privateExecute(InitializeAndReturn, 0, 0, 0); 326 327 for (int i = 0; i < numOpcodeIDs; ++i) 328 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); 329 #endif // HAVE(COMPUTED_GOTO) 330 331 #if ENABLE(OPCODE_SAMPLING) 332 enableSampler(); 333 #endif 334 } 335 336 #ifndef NDEBUG 337 338 void Interpreter::dumpCallFrame(CallFrame* callFrame) 339 { 340 callFrame->codeBlock()->dump(callFrame); 341 dumpRegisters(callFrame); 342 } 343 344 void Interpreter::dumpRegisters(CallFrame* callFrame) 345 { 346 printf("Register frame: \n\n"); 347 printf("-----------------------------------------------------------------------------\n"); 348 printf(" use | address | value \n"); 349 printf("-----------------------------------------------------------------------------\n"); 350 351 CodeBlock* codeBlock = callFrame->codeBlock(); 352 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile(); 353 const Register* it; 354 const Register* end; 355 JSValue v; 356 357 if (codeBlock->codeType() == GlobalCode) { 358 it = registerFile->lastGlobal(); 359 end = it + registerFile->numGlobals(); 360 while (it != end) { 361 v = (*it).jsValue(); 362 #if USE(JSVALUE32_64) 363 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); 364 #else 365 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); 366 #endif 367 ++it; 368 } 369 printf("-----------------------------------------------------------------------------\n"); 370 } 371 372 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters; 373 v = (*it).jsValue(); 374 #if USE(JSVALUE32_64) 375 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it; 376 #else 377 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it; 378 #endif 379 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this" 380 if (it != end) { 381 do { 382 v = (*it).jsValue(); 383 #if USE(JSVALUE32_64) 384 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); 385 #else 386 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); 387 #endif 388 ++it; 389 } while (it != end); 390 } 391 printf("-----------------------------------------------------------------------------\n"); 392 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it; 393 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it; 394 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it; 395 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it; 396 printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it; 397 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it; 398 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it; 399 printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it; 400 printf("-----------------------------------------------------------------------------\n"); 401 402 int registerCount = 0; 403 404 end = it + codeBlock->m_numVars; 405 if (it != end) { 406 do { 407 v = (*it).jsValue(); 408 #if USE(JSVALUE32_64) 409 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); 410 #else 411 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); 412 #endif 413 ++it; 414 ++registerCount; 415 } while (it != end); 416 } 417 printf("-----------------------------------------------------------------------------\n"); 418 419 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars; 420 if (it != end) { 421 do { 422 v = (*it).jsValue(); 423 #if USE(JSVALUE32_64) 424 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); 425 #else 426 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); 427 #endif 428 ++it; 429 ++registerCount; 430 } while (it != end); 431 } 432 printf("-----------------------------------------------------------------------------\n"); 433 } 434 435 #endif 436 437 bool Interpreter::isOpcode(Opcode opcode) 438 { 439 #if HAVE(COMPUTED_GOTO) 440 return opcode != HashTraits<Opcode>::emptyValue() 441 && !HashTraits<Opcode>::isDeletedValue(opcode) 442 && m_opcodeIDTable.contains(opcode); 443 #else 444 return opcode >= 0 && opcode <= op_end; 445 #endif 446 } 447 448 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock) 449 { 450 CodeBlock* oldCodeBlock = codeBlock; 451 ScopeChainNode* scopeChain = callFrame->scopeChain(); 452 453 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { 454 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); 455 if (callFrame->callee()) 456 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine()); 457 else 458 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine()); 459 } 460 461 if (Profiler* profiler = *Profiler::enabledProfilerReference()) { 462 if (callFrame->callee()) 463 profiler->didExecute(callFrame, callFrame->callee()); 464 else 465 profiler->didExecute(callFrame, codeBlock->ownerExecutable()->sourceURL(), codeBlock->ownerExecutable()->lineNo()); 466 } 467 468 // If this call frame created an activation or an 'arguments' object, tear it off. 469 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { 470 while (!scopeChain->object->inherits(&JSActivation::info)) 471 scopeChain = scopeChain->pop(); 472 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments()); 473 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) { 474 if (!arguments->isTornOff()) 475 arguments->copyRegisters(); 476 } 477 478 if (oldCodeBlock->needsFullScopeChain()) 479 scopeChain->deref(); 480 481 void* returnPC = callFrame->returnPC(); 482 callFrame = callFrame->callerFrame(); 483 if (callFrame->hasHostCallFrameFlag()) 484 return false; 485 486 codeBlock = callFrame->codeBlock(); 487 bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC); 488 return true; 489 } 490 491 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow) 492 { 493 // Set up the exception object 494 495 CodeBlock* codeBlock = callFrame->codeBlock(); 496 if (exceptionValue.isObject()) { 497 JSObject* exception = asObject(exceptionValue); 498 if (exception->isNotAnObjectErrorStub()) { 499 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock); 500 exceptionValue = exception; 501 } else { 502 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) && 503 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) && 504 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) && 505 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) && 506 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) && 507 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) { 508 if (explicitThrow) { 509 int startOffset = 0; 510 int endOffset = 0; 511 int divotPoint = 0; 512 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset); 513 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete); 514 515 // We only hit this path for error messages and throw statements, which don't have a specific failure position 516 // So we just give the full range of the error/throw statement. 517 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete); 518 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete); 519 } else 520 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete); 521 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete); 522 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete); 523 } 524 525 if (exception->isWatchdogException()) { 526 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) { 527 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. 528 } 529 return 0; 530 } 531 } 532 } 533 534 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { 535 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); 536 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); 537 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler); 538 } 539 540 // If we throw in the middle of a call instruction, we need to notify 541 // the profiler manually that the call instruction has returned, since 542 // we'll never reach the relevant op_profile_did_call. 543 if (Profiler* profiler = *Profiler::enabledProfilerReference()) { 544 #if !ENABLE(JIT) 545 if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode)) 546 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue()); 547 else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) 548 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue()); 549 #else 550 int functionRegisterIndex; 551 if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex)) 552 profiler->didExecute(callFrame, callFrame->r(functionRegisterIndex).jsValue()); 553 #endif 554 } 555 556 // Calculate an exception handler vPC, unwinding call frames as necessary. 557 558 HandlerInfo* handler = 0; 559 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { 560 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) 561 return 0; 562 } 563 564 // Now unwind the scope chain within the exception handler's call frame. 565 566 ScopeChainNode* scopeChain = callFrame->scopeChain(); 567 ScopeChain sc(scopeChain); 568 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth; 569 ASSERT(scopeDelta >= 0); 570 while (scopeDelta--) 571 scopeChain = scopeChain->pop(); 572 callFrame->setScopeChain(scopeChain); 573 574 return handler; 575 } 576 577 JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception) 578 { 579 ASSERT(!scopeChain->globalData->exception); 580 581 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) { 582 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) { 583 *exception = createStackOverflowError(callFrame); 584 return jsNull(); 585 } 586 } 587 588 CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain); 589 590 Register* oldEnd = m_registerFile.end(); 591 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; 592 if (!m_registerFile.grow(newEnd)) { 593 *exception = createStackOverflowError(callFrame); 594 return jsNull(); 595 } 596 597 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); 598 599 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject(); 600 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject(); 601 globalObject->copyGlobalsTo(m_registerFile); 602 603 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize); 604 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj); 605 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0); 606 607 if (codeBlock->needsFullScopeChain()) 608 scopeChain->ref(); 609 610 Profiler** profiler = Profiler::enabledProfilerReference(); 611 if (*profiler) 612 (*profiler)->willExecute(newCallFrame, program->sourceURL(), program->lineNo()); 613 614 JSValue result; 615 { 616 SamplingTool::CallRecord callRecord(m_sampler.get()); 617 618 m_reentryDepth++; 619 #if ENABLE(JIT) 620 result = program->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 621 #else 622 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 623 #endif 624 m_reentryDepth--; 625 } 626 627 if (*profiler) 628 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo()); 629 630 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject) 631 lastGlobalObject->copyGlobalsTo(m_registerFile); 632 633 m_registerFile.shrink(oldEnd); 634 635 return result; 636 } 637 638 JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception) 639 { 640 ASSERT(!scopeChain->globalData->exception); 641 642 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) { 643 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) { 644 *exception = createStackOverflowError(callFrame); 645 return jsNull(); 646 } 647 } 648 649 Register* oldEnd = m_registerFile.end(); 650 int argc = 1 + args.size(); // implicit "this" parameter 651 652 if (!m_registerFile.grow(oldEnd + argc)) { 653 *exception = createStackOverflowError(callFrame); 654 return jsNull(); 655 } 656 657 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); 658 659 CallFrame* newCallFrame = CallFrame::create(oldEnd); 660 size_t dst = 0; 661 newCallFrame->r(0) = JSValue(thisObj); 662 ArgList::const_iterator end = args.end(); 663 for (ArgList::const_iterator it = args.begin(); it != end; ++it) 664 newCallFrame->r(++dst) = *it; 665 666 CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain); 667 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); 668 if (UNLIKELY(!newCallFrame)) { 669 *exception = createStackOverflowError(callFrame); 670 m_registerFile.shrink(oldEnd); 671 return jsNull(); 672 } 673 // a 0 codeBlock indicates a built-in caller 674 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function); 675 676 Profiler** profiler = Profiler::enabledProfilerReference(); 677 if (*profiler) 678 (*profiler)->willExecute(callFrame, function); 679 680 JSValue result; 681 { 682 SamplingTool::CallRecord callRecord(m_sampler.get()); 683 684 m_reentryDepth++; 685 #if ENABLE(JIT) 686 result = functionExecutable->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 687 #else 688 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 689 #endif 690 m_reentryDepth--; 691 } 692 693 if (*profiler) 694 (*profiler)->didExecute(callFrame, function); 695 696 m_registerFile.shrink(oldEnd); 697 return result; 698 } 699 700 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception) 701 { 702 ASSERT(!scopeChain->globalData->exception); 703 704 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) { 705 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) { 706 *exception = createStackOverflowError(callFrame); 707 return CallFrameClosure(); 708 } 709 } 710 711 Register* oldEnd = m_registerFile.end(); 712 int argc = 1 + argCount; // implicit "this" parameter 713 714 if (!m_registerFile.grow(oldEnd + argc)) { 715 *exception = createStackOverflowError(callFrame); 716 return CallFrameClosure(); 717 } 718 719 CallFrame* newCallFrame = CallFrame::create(oldEnd); 720 size_t dst = 0; 721 for (int i = 0; i < argc; ++i) 722 newCallFrame->r(++dst) = jsUndefined(); 723 724 CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain); 725 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); 726 if (UNLIKELY(!newCallFrame)) { 727 *exception = createStackOverflowError(callFrame); 728 m_registerFile.shrink(oldEnd); 729 return CallFrameClosure(); 730 } 731 // a 0 codeBlock indicates a built-in caller 732 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function); 733 #if ENABLE(JIT) 734 FunctionExecutable->jitCode(newCallFrame, scopeChain); 735 #endif 736 737 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc }; 738 return result; 739 } 740 741 JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception) 742 { 743 closure.resetCallFrame(); 744 Profiler** profiler = Profiler::enabledProfilerReference(); 745 if (*profiler) 746 (*profiler)->willExecute(closure.oldCallFrame, closure.function); 747 748 JSValue result; 749 { 750 SamplingTool::CallRecord callRecord(m_sampler.get()); 751 752 m_reentryDepth++; 753 #if ENABLE(JIT) 754 result = closure.functionExecutable->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception); 755 #else 756 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception); 757 #endif 758 m_reentryDepth--; 759 } 760 761 if (*profiler) 762 (*profiler)->didExecute(closure.oldCallFrame, closure.function); 763 return result; 764 } 765 766 void Interpreter::endRepeatCall(CallFrameClosure& closure) 767 { 768 m_registerFile.shrink(closure.oldEnd); 769 } 770 771 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception) 772 { 773 return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception); 774 } 775 776 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception) 777 { 778 ASSERT(!scopeChain->globalData->exception); 779 780 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) { 781 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) { 782 *exception = createStackOverflowError(callFrame); 783 return jsNull(); 784 } 785 } 786 787 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); 788 789 EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain); 790 791 JSVariableObject* variableObject; 792 for (ScopeChainNode* node = scopeChain; ; node = node->next) { 793 ASSERT(node); 794 if (node->object->isVariableObject()) { 795 variableObject = static_cast<JSVariableObject*>(node->object); 796 break; 797 } 798 } 799 800 { // Scope for BatchedTransitionOptimizer 801 802 BatchedTransitionOptimizer optimizer(variableObject); 803 804 unsigned numVariables = codeBlock->numVariables(); 805 for (unsigned i = 0; i < numVariables; ++i) { 806 const Identifier& ident = codeBlock->variable(i); 807 if (!variableObject->hasProperty(callFrame, ident)) { 808 PutPropertySlot slot; 809 variableObject->put(callFrame, ident, jsUndefined(), slot); 810 } 811 } 812 813 int numFunctions = codeBlock->numberOfFunctionDecls(); 814 for (int i = 0; i < numFunctions; ++i) { 815 FunctionExecutable* function = codeBlock->functionDecl(i); 816 PutPropertySlot slot; 817 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot); 818 } 819 820 } 821 822 Register* oldEnd = m_registerFile.end(); 823 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters; 824 if (!m_registerFile.grow(newEnd)) { 825 *exception = createStackOverflowError(callFrame); 826 return jsNull(); 827 } 828 829 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset); 830 831 // a 0 codeBlock indicates a built-in caller 832 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj); 833 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0); 834 835 if (codeBlock->needsFullScopeChain()) 836 scopeChain->ref(); 837 838 Profiler** profiler = Profiler::enabledProfilerReference(); 839 if (*profiler) 840 (*profiler)->willExecute(newCallFrame, eval->sourceURL(), eval->lineNo()); 841 842 JSValue result; 843 { 844 SamplingTool::CallRecord callRecord(m_sampler.get()); 845 846 m_reentryDepth++; 847 #if ENABLE(JIT) 848 result = eval->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); 849 #else 850 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); 851 #endif 852 m_reentryDepth--; 853 } 854 855 if (*profiler) 856 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); 857 858 m_registerFile.shrink(oldEnd); 859 return result; 860 } 861 862 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine) 863 { 864 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger(); 865 if (!debugger) 866 return; 867 868 switch (debugHookID) { 869 case DidEnterCallFrame: 870 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); 871 return; 872 case WillLeaveCallFrame: 873 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); 874 return; 875 case WillExecuteStatement: 876 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); 877 return; 878 case WillExecuteProgram: 879 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); 880 return; 881 case DidExecuteProgram: 882 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); 883 return; 884 case DidReachBreakpoint: 885 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); 886 return; 887 } 888 } 889 890 #if USE(INTERPRETER) 891 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC) 892 { 893 int dst = vPC[1].u.operand; 894 CodeBlock* codeBlock = callFrame->codeBlock(); 895 Identifier& property = codeBlock->identifier(vPC[2].u.operand); 896 JSValue value = callFrame->r(vPC[3].u.operand).jsValue(); 897 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete); 898 callFrame->r(dst) = JSValue(scope); 899 900 return callFrame->scopeChain()->push(scope); 901 } 902 903 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot) 904 { 905 // Recursive invocation may already have specialized this instruction. 906 if (vPC[0].u.opcode != getOpcode(op_put_by_id)) 907 return; 908 909 if (!baseValue.isCell()) 910 return; 911 912 // Uncacheable: give up. 913 if (!slot.isCacheable()) { 914 vPC[0] = getOpcode(op_put_by_id_generic); 915 return; 916 } 917 918 JSCell* baseCell = asCell(baseValue); 919 Structure* structure = baseCell->structure(); 920 921 if (structure->isUncacheableDictionary()) { 922 vPC[0] = getOpcode(op_put_by_id_generic); 923 return; 924 } 925 926 // Cache miss: record Structure to compare against next time. 927 Structure* lastStructure = vPC[4].u.structure; 928 if (structure != lastStructure) { 929 // First miss: record Structure to compare against next time. 930 if (!lastStructure) { 931 vPC[4] = structure; 932 return; 933 } 934 935 // Second miss: give up. 936 vPC[0] = getOpcode(op_put_by_id_generic); 937 return; 938 } 939 940 // Cache hit: Specialize instruction and ref Structures. 941 942 // If baseCell != slot.base(), then baseCell must be a proxy for another object. 943 if (baseCell != slot.base()) { 944 vPC[0] = getOpcode(op_put_by_id_generic); 945 return; 946 } 947 948 // Structure transition, cache transition info 949 if (slot.type() == PutPropertySlot::NewProperty) { 950 if (structure->isDictionary()) { 951 vPC[0] = getOpcode(op_put_by_id_generic); 952 return; 953 } 954 955 // put_by_id_transition checks the prototype chain for setters. 956 normalizePrototypeChain(callFrame, baseCell); 957 958 vPC[0] = getOpcode(op_put_by_id_transition); 959 vPC[4] = structure->previousID(); 960 vPC[5] = structure; 961 vPC[6] = structure->prototypeChain(callFrame); 962 vPC[7] = slot.cachedOffset(); 963 codeBlock->refStructures(vPC); 964 return; 965 } 966 967 vPC[0] = getOpcode(op_put_by_id_replace); 968 vPC[5] = slot.cachedOffset(); 969 codeBlock->refStructures(vPC); 970 } 971 972 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC) 973 { 974 codeBlock->derefStructures(vPC); 975 vPC[0] = getOpcode(op_put_by_id); 976 vPC[4] = 0; 977 } 978 979 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot) 980 { 981 // Recursive invocation may already have specialized this instruction. 982 if (vPC[0].u.opcode != getOpcode(op_get_by_id)) 983 return; 984 985 // FIXME: Cache property access for immediates. 986 if (!baseValue.isCell()) { 987 vPC[0] = getOpcode(op_get_by_id_generic); 988 return; 989 } 990 991 JSGlobalData* globalData = &callFrame->globalData(); 992 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { 993 vPC[0] = getOpcode(op_get_array_length); 994 return; 995 } 996 997 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) { 998 vPC[0] = getOpcode(op_get_string_length); 999 return; 1000 } 1001 1002 // Uncacheable: give up. 1003 if (!slot.isCacheable()) { 1004 vPC[0] = getOpcode(op_get_by_id_generic); 1005 return; 1006 } 1007 1008 Structure* structure = asCell(baseValue)->structure(); 1009 1010 if (structure->isUncacheableDictionary()) { 1011 vPC[0] = getOpcode(op_get_by_id_generic); 1012 return; 1013 } 1014 1015 // Cache miss 1016 Structure* lastStructure = vPC[4].u.structure; 1017 if (structure != lastStructure) { 1018 // First miss: record Structure to compare against next time. 1019 if (!lastStructure) { 1020 vPC[4] = structure; 1021 return; 1022 } 1023 1024 // Second miss: give up. 1025 vPC[0] = getOpcode(op_get_by_id_generic); 1026 return; 1027 } 1028 1029 // Cache hit: Specialize instruction and ref Structures. 1030 1031 if (slot.slotBase() == baseValue) { 1032 vPC[0] = getOpcode(op_get_by_id_self); 1033 vPC[5] = slot.cachedOffset(); 1034 1035 codeBlock->refStructures(vPC); 1036 return; 1037 } 1038 1039 if (structure->isDictionary()) { 1040 vPC[0] = getOpcode(op_get_by_id_generic); 1041 return; 1042 } 1043 1044 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { 1045 ASSERT(slot.slotBase().isObject()); 1046 1047 JSObject* baseObject = asObject(slot.slotBase()); 1048 size_t offset = slot.cachedOffset(); 1049 1050 // Since we're accessing a prototype in a loop, it's a good bet that it 1051 // should not be treated as a dictionary. 1052 if (baseObject->structure()->isDictionary()) { 1053 baseObject->flattenDictionaryObject(); 1054 offset = baseObject->structure()->get(propertyName); 1055 } 1056 1057 ASSERT(!baseObject->structure()->isUncacheableDictionary()); 1058 1059 vPC[0] = getOpcode(op_get_by_id_proto); 1060 vPC[5] = baseObject->structure(); 1061 vPC[6] = offset; 1062 1063 codeBlock->refStructures(vPC); 1064 return; 1065 } 1066 1067 size_t offset = slot.cachedOffset(); 1068 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset); 1069 if (!count) { 1070 vPC[0] = getOpcode(op_get_by_id_generic); 1071 return; 1072 } 1073 1074 vPC[0] = getOpcode(op_get_by_id_chain); 1075 vPC[4] = structure; 1076 vPC[5] = structure->prototypeChain(callFrame); 1077 vPC[6] = count; 1078 vPC[7] = offset; 1079 codeBlock->refStructures(vPC); 1080 } 1081 1082 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC) 1083 { 1084 codeBlock->derefStructures(vPC); 1085 vPC[0] = getOpcode(op_get_by_id); 1086 vPC[4] = 0; 1087 } 1088 1089 #endif // USE(INTERPRETER) 1090 1091 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception) 1092 { 1093 // One-time initialization of our address tables. We have to put this code 1094 // here because our labels are only in scope inside this function. 1095 if (UNLIKELY(flag == InitializeAndReturn)) { 1096 #if HAVE(COMPUTED_GOTO) 1097 #define LIST_OPCODE_LABEL(id, length) &&id, 1098 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) }; 1099 for (size_t i = 0; i < sizeof(labels) / sizeof(Opcode); ++i) 1100 m_opcodeTable[i] = labels[i]; 1101 #undef LIST_OPCODE_LABEL 1102 #endif // HAVE(COMPUTED_GOTO) 1103 return JSValue(); 1104 } 1105 1106 #if ENABLE(JIT) 1107 // Mixing Interpreter + JIT is not supported. 1108 ASSERT_NOT_REACHED(); 1109 #endif 1110 #if !USE(INTERPRETER) 1111 UNUSED_PARAM(registerFile); 1112 UNUSED_PARAM(callFrame); 1113 UNUSED_PARAM(exception); 1114 return JSValue(); 1115 #else 1116 1117 JSGlobalData* globalData = &callFrame->globalData(); 1118 JSValue exceptionValue; 1119 HandlerInfo* handler = 0; 1120 1121 Instruction* vPC = callFrame->codeBlock()->instructions().begin(); 1122 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference(); 1123 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); 1124 1125 #define CHECK_FOR_EXCEPTION() \ 1126 do { \ 1127 if (UNLIKELY(globalData->exception != JSValue())) { \ 1128 exceptionValue = globalData->exception; \ 1129 goto vm_throw; \ 1130 } \ 1131 } while (0) 1132 1133 #if ENABLE(OPCODE_STATS) 1134 OpcodeStats::resetLastInstruction(); 1135 #endif 1136 1137 #define CHECK_FOR_TIMEOUT() \ 1138 if (!--tickCount) { \ 1139 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \ 1140 exceptionValue = jsNull(); \ 1141 goto vm_throw; \ 1142 } \ 1143 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \ 1144 } 1145 1146 #if ENABLE(OPCODE_SAMPLING) 1147 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC) 1148 #else 1149 #define SAMPLE(codeBlock, vPC) 1150 #endif 1151 1152 #if HAVE(COMPUTED_GOTO) 1153 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode 1154 #if ENABLE(OPCODE_STATS) 1155 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode); 1156 #else 1157 #define DEFINE_OPCODE(opcode) opcode: 1158 #endif 1159 NEXT_INSTRUCTION(); 1160 #else 1161 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart 1162 #if ENABLE(OPCODE_STATS) 1163 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode); 1164 #else 1165 #define DEFINE_OPCODE(opcode) case opcode: 1166 #endif 1167 while (1) { // iterator loop begins 1168 interpreterLoopStart:; 1169 switch (vPC->u.opcode) 1170 #endif 1171 { 1172 DEFINE_OPCODE(op_new_object) { 1173 /* new_object dst(r) 1174 1175 Constructs a new empty Object instance using the original 1176 constructor, and puts the result in register dst. 1177 */ 1178 int dst = vPC[1].u.operand; 1179 callFrame->r(dst) = JSValue(constructEmptyObject(callFrame)); 1180 1181 vPC += OPCODE_LENGTH(op_new_object); 1182 NEXT_INSTRUCTION(); 1183 } 1184 DEFINE_OPCODE(op_new_array) { 1185 /* new_array dst(r) firstArg(r) argCount(n) 1186 1187 Constructs a new Array instance using the original 1188 constructor, and puts the result in register dst. 1189 The array will contain argCount elements with values 1190 taken from registers starting at register firstArg. 1191 */ 1192 int dst = vPC[1].u.operand; 1193 int firstArg = vPC[2].u.operand; 1194 int argCount = vPC[3].u.operand; 1195 ArgList args(callFrame->registers() + firstArg, argCount); 1196 callFrame->r(dst) = JSValue(constructArray(callFrame, args)); 1197 1198 vPC += OPCODE_LENGTH(op_new_array); 1199 NEXT_INSTRUCTION(); 1200 } 1201 DEFINE_OPCODE(op_new_regexp) { 1202 /* new_regexp dst(r) regExp(re) 1203 1204 Constructs a new RegExp instance using the original 1205 constructor from regexp regExp, and puts the result in 1206 register dst. 1207 */ 1208 int dst = vPC[1].u.operand; 1209 int regExp = vPC[2].u.operand; 1210 callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp))); 1211 1212 vPC += OPCODE_LENGTH(op_new_regexp); 1213 NEXT_INSTRUCTION(); 1214 } 1215 DEFINE_OPCODE(op_mov) { 1216 /* mov dst(r) src(r) 1217 1218 Copies register src to register dst. 1219 */ 1220 int dst = vPC[1].u.operand; 1221 int src = vPC[2].u.operand; 1222 callFrame->r(dst) = callFrame->r(src); 1223 1224 vPC += OPCODE_LENGTH(op_mov); 1225 NEXT_INSTRUCTION(); 1226 } 1227 DEFINE_OPCODE(op_eq) { 1228 /* eq dst(r) src1(r) src2(r) 1229 1230 Checks whether register src1 and register src2 are equal, 1231 as with the ECMAScript '==' operator, and puts the result 1232 as a boolean in register dst. 1233 */ 1234 int dst = vPC[1].u.operand; 1235 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1236 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1237 if (src1.isInt32() && src2.isInt32()) 1238 callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32()); 1239 else { 1240 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2)); 1241 CHECK_FOR_EXCEPTION(); 1242 callFrame->r(dst) = result; 1243 } 1244 1245 vPC += OPCODE_LENGTH(op_eq); 1246 NEXT_INSTRUCTION(); 1247 } 1248 DEFINE_OPCODE(op_eq_null) { 1249 /* eq_null dst(r) src(r) 1250 1251 Checks whether register src is null, as with the ECMAScript '!=' 1252 operator, and puts the result as a boolean in register dst. 1253 */ 1254 int dst = vPC[1].u.operand; 1255 JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); 1256 1257 if (src.isUndefinedOrNull()) { 1258 callFrame->r(dst) = jsBoolean(true); 1259 vPC += OPCODE_LENGTH(op_eq_null); 1260 NEXT_INSTRUCTION(); 1261 } 1262 1263 callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined()); 1264 vPC += OPCODE_LENGTH(op_eq_null); 1265 NEXT_INSTRUCTION(); 1266 } 1267 DEFINE_OPCODE(op_neq) { 1268 /* neq dst(r) src1(r) src2(r) 1269 1270 Checks whether register src1 and register src2 are not 1271 equal, as with the ECMAScript '!=' operator, and puts the 1272 result as a boolean in register dst. 1273 */ 1274 int dst = vPC[1].u.operand; 1275 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1276 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1277 if (src1.isInt32() && src2.isInt32()) 1278 callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32()); 1279 else { 1280 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2)); 1281 CHECK_FOR_EXCEPTION(); 1282 callFrame->r(dst) = result; 1283 } 1284 1285 vPC += OPCODE_LENGTH(op_neq); 1286 NEXT_INSTRUCTION(); 1287 } 1288 DEFINE_OPCODE(op_neq_null) { 1289 /* neq_null dst(r) src(r) 1290 1291 Checks whether register src is not null, as with the ECMAScript '!=' 1292 operator, and puts the result as a boolean in register dst. 1293 */ 1294 int dst = vPC[1].u.operand; 1295 JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); 1296 1297 if (src.isUndefinedOrNull()) { 1298 callFrame->r(dst) = jsBoolean(false); 1299 vPC += OPCODE_LENGTH(op_neq_null); 1300 NEXT_INSTRUCTION(); 1301 } 1302 1303 callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined()); 1304 vPC += OPCODE_LENGTH(op_neq_null); 1305 NEXT_INSTRUCTION(); 1306 } 1307 DEFINE_OPCODE(op_stricteq) { 1308 /* stricteq dst(r) src1(r) src2(r) 1309 1310 Checks whether register src1 and register src2 are strictly 1311 equal, as with the ECMAScript '===' operator, and puts the 1312 result as a boolean in register dst. 1313 */ 1314 int dst = vPC[1].u.operand; 1315 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1316 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1317 callFrame->r(dst) = jsBoolean(JSValue::strictEqual(callFrame, src1, src2)); 1318 1319 vPC += OPCODE_LENGTH(op_stricteq); 1320 NEXT_INSTRUCTION(); 1321 } 1322 DEFINE_OPCODE(op_nstricteq) { 1323 /* nstricteq dst(r) src1(r) src2(r) 1324 1325 Checks whether register src1 and register src2 are not 1326 strictly equal, as with the ECMAScript '!==' operator, and 1327 puts the result as a boolean in register dst. 1328 */ 1329 int dst = vPC[1].u.operand; 1330 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1331 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1332 callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(callFrame, src1, src2)); 1333 1334 vPC += OPCODE_LENGTH(op_nstricteq); 1335 NEXT_INSTRUCTION(); 1336 } 1337 DEFINE_OPCODE(op_less) { 1338 /* less dst(r) src1(r) src2(r) 1339 1340 Checks whether register src1 is less than register src2, as 1341 with the ECMAScript '<' operator, and puts the result as 1342 a boolean in register dst. 1343 */ 1344 int dst = vPC[1].u.operand; 1345 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1346 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1347 JSValue result = jsBoolean(jsLess(callFrame, src1, src2)); 1348 CHECK_FOR_EXCEPTION(); 1349 callFrame->r(dst) = result; 1350 1351 vPC += OPCODE_LENGTH(op_less); 1352 NEXT_INSTRUCTION(); 1353 } 1354 DEFINE_OPCODE(op_lesseq) { 1355 /* lesseq dst(r) src1(r) src2(r) 1356 1357 Checks whether register src1 is less than or equal to 1358 register src2, as with the ECMAScript '<=' operator, and 1359 puts the result as a boolean in register dst. 1360 */ 1361 int dst = vPC[1].u.operand; 1362 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1363 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1364 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2)); 1365 CHECK_FOR_EXCEPTION(); 1366 callFrame->r(dst) = result; 1367 1368 vPC += OPCODE_LENGTH(op_lesseq); 1369 NEXT_INSTRUCTION(); 1370 } 1371 DEFINE_OPCODE(op_pre_inc) { 1372 /* pre_inc srcDst(r) 1373 1374 Converts register srcDst to number, adds one, and puts the result 1375 back in register srcDst. 1376 */ 1377 int srcDst = vPC[1].u.operand; 1378 JSValue v = callFrame->r(srcDst).jsValue(); 1379 if (v.isInt32() && v.asInt32() < INT_MAX) 1380 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1); 1381 else { 1382 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1); 1383 CHECK_FOR_EXCEPTION(); 1384 callFrame->r(srcDst) = result; 1385 } 1386 1387 vPC += OPCODE_LENGTH(op_pre_inc); 1388 NEXT_INSTRUCTION(); 1389 } 1390 DEFINE_OPCODE(op_pre_dec) { 1391 /* pre_dec srcDst(r) 1392 1393 Converts register srcDst to number, subtracts one, and puts the result 1394 back in register srcDst. 1395 */ 1396 int srcDst = vPC[1].u.operand; 1397 JSValue v = callFrame->r(srcDst).jsValue(); 1398 if (v.isInt32() && v.asInt32() > INT_MIN) 1399 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1); 1400 else { 1401 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1); 1402 CHECK_FOR_EXCEPTION(); 1403 callFrame->r(srcDst) = result; 1404 } 1405 1406 vPC += OPCODE_LENGTH(op_pre_dec); 1407 NEXT_INSTRUCTION(); 1408 } 1409 DEFINE_OPCODE(op_post_inc) { 1410 /* post_inc dst(r) srcDst(r) 1411 1412 Converts register srcDst to number. The number itself is 1413 written to register dst, and the number plus one is written 1414 back to register srcDst. 1415 */ 1416 int dst = vPC[1].u.operand; 1417 int srcDst = vPC[2].u.operand; 1418 JSValue v = callFrame->r(srcDst).jsValue(); 1419 if (v.isInt32() && v.asInt32() < INT_MAX) { 1420 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1); 1421 callFrame->r(dst) = v; 1422 } else { 1423 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame); 1424 CHECK_FOR_EXCEPTION(); 1425 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1); 1426 callFrame->r(dst) = number; 1427 } 1428 1429 vPC += OPCODE_LENGTH(op_post_inc); 1430 NEXT_INSTRUCTION(); 1431 } 1432 DEFINE_OPCODE(op_post_dec) { 1433 /* post_dec dst(r) srcDst(r) 1434 1435 Converts register srcDst to number. The number itself is 1436 written to register dst, and the number minus one is written 1437 back to register srcDst. 1438 */ 1439 int dst = vPC[1].u.operand; 1440 int srcDst = vPC[2].u.operand; 1441 JSValue v = callFrame->r(srcDst).jsValue(); 1442 if (v.isInt32() && v.asInt32() > INT_MIN) { 1443 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1); 1444 callFrame->r(dst) = v; 1445 } else { 1446 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame); 1447 CHECK_FOR_EXCEPTION(); 1448 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1); 1449 callFrame->r(dst) = number; 1450 } 1451 1452 vPC += OPCODE_LENGTH(op_post_dec); 1453 NEXT_INSTRUCTION(); 1454 } 1455 DEFINE_OPCODE(op_to_jsnumber) { 1456 /* to_jsnumber dst(r) src(r) 1457 1458 Converts register src to number, and puts the result 1459 in register dst. 1460 */ 1461 int dst = vPC[1].u.operand; 1462 int src = vPC[2].u.operand; 1463 1464 JSValue srcVal = callFrame->r(src).jsValue(); 1465 1466 if (LIKELY(srcVal.isNumber())) 1467 callFrame->r(dst) = callFrame->r(src); 1468 else { 1469 JSValue result = srcVal.toJSNumber(callFrame); 1470 CHECK_FOR_EXCEPTION(); 1471 callFrame->r(dst) = result; 1472 } 1473 1474 vPC += OPCODE_LENGTH(op_to_jsnumber); 1475 NEXT_INSTRUCTION(); 1476 } 1477 DEFINE_OPCODE(op_negate) { 1478 /* negate dst(r) src(r) 1479 1480 Converts register src to number, negates it, and puts the 1481 result in register dst. 1482 */ 1483 int dst = vPC[1].u.operand; 1484 JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); 1485 if (src.isInt32() && src.asInt32()) 1486 callFrame->r(dst) = jsNumber(callFrame, -src.asInt32()); 1487 else { 1488 JSValue result = jsNumber(callFrame, -src.toNumber(callFrame)); 1489 CHECK_FOR_EXCEPTION(); 1490 callFrame->r(dst) = result; 1491 } 1492 1493 vPC += OPCODE_LENGTH(op_negate); 1494 NEXT_INSTRUCTION(); 1495 } 1496 DEFINE_OPCODE(op_add) { 1497 /* add dst(r) src1(r) src2(r) 1498 1499 Adds register src1 and register src2, and puts the result 1500 in register dst. (JS add may be string concatenation or 1501 numeric add, depending on the types of the operands.) 1502 */ 1503 int dst = vPC[1].u.operand; 1504 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1505 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1506 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow 1507 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32()); 1508 else { 1509 JSValue result = jsAdd(callFrame, src1, src2); 1510 CHECK_FOR_EXCEPTION(); 1511 callFrame->r(dst) = result; 1512 } 1513 vPC += OPCODE_LENGTH(op_add); 1514 NEXT_INSTRUCTION(); 1515 } 1516 DEFINE_OPCODE(op_mul) { 1517 /* mul dst(r) src1(r) src2(r) 1518 1519 Multiplies register src1 and register src2 (converted to 1520 numbers), and puts the product in register dst. 1521 */ 1522 int dst = vPC[1].u.operand; 1523 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1524 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1525 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow 1526 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32()); 1527 else { 1528 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame)); 1529 CHECK_FOR_EXCEPTION(); 1530 callFrame->r(dst) = result; 1531 } 1532 1533 vPC += OPCODE_LENGTH(op_mul); 1534 NEXT_INSTRUCTION(); 1535 } 1536 DEFINE_OPCODE(op_div) { 1537 /* div dst(r) dividend(r) divisor(r) 1538 1539 Divides register dividend (converted to number) by the 1540 register divisor (converted to number), and puts the 1541 quotient in register dst. 1542 */ 1543 int dst = vPC[1].u.operand; 1544 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue(); 1545 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue(); 1546 1547 JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame)); 1548 CHECK_FOR_EXCEPTION(); 1549 callFrame->r(dst) = result; 1550 1551 vPC += OPCODE_LENGTH(op_div); 1552 NEXT_INSTRUCTION(); 1553 } 1554 DEFINE_OPCODE(op_mod) { 1555 /* mod dst(r) dividend(r) divisor(r) 1556 1557 Divides register dividend (converted to number) by 1558 register divisor (converted to number), and puts the 1559 remainder in register dst. 1560 */ 1561 int dst = vPC[1].u.operand; 1562 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue(); 1563 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue(); 1564 1565 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) { 1566 JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32()); 1567 ASSERT(result); 1568 callFrame->r(dst) = result; 1569 vPC += OPCODE_LENGTH(op_mod); 1570 NEXT_INSTRUCTION(); 1571 } 1572 1573 // Conversion to double must happen outside the call to fmod since the 1574 // order of argument evaluation is not guaranteed. 1575 double d1 = dividend.toNumber(callFrame); 1576 double d2 = divisor.toNumber(callFrame); 1577 JSValue result = jsNumber(callFrame, fmod(d1, d2)); 1578 CHECK_FOR_EXCEPTION(); 1579 callFrame->r(dst) = result; 1580 vPC += OPCODE_LENGTH(op_mod); 1581 NEXT_INSTRUCTION(); 1582 } 1583 DEFINE_OPCODE(op_sub) { 1584 /* sub dst(r) src1(r) src2(r) 1585 1586 Subtracts register src2 (converted to number) from register 1587 src1 (converted to number), and puts the difference in 1588 register dst. 1589 */ 1590 int dst = vPC[1].u.operand; 1591 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1592 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1593 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow 1594 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32()); 1595 else { 1596 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame)); 1597 CHECK_FOR_EXCEPTION(); 1598 callFrame->r(dst) = result; 1599 } 1600 vPC += OPCODE_LENGTH(op_sub); 1601 NEXT_INSTRUCTION(); 1602 } 1603 DEFINE_OPCODE(op_lshift) { 1604 /* lshift dst(r) val(r) shift(r) 1605 1606 Performs left shift of register val (converted to int32) by 1607 register shift (converted to uint32), and puts the result 1608 in register dst. 1609 */ 1610 int dst = vPC[1].u.operand; 1611 JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); 1612 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); 1613 1614 if (val.isInt32() && shift.isInt32()) 1615 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f)); 1616 else { 1617 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f)); 1618 CHECK_FOR_EXCEPTION(); 1619 callFrame->r(dst) = result; 1620 } 1621 1622 vPC += OPCODE_LENGTH(op_lshift); 1623 NEXT_INSTRUCTION(); 1624 } 1625 DEFINE_OPCODE(op_rshift) { 1626 /* rshift dst(r) val(r) shift(r) 1627 1628 Performs arithmetic right shift of register val (converted 1629 to int32) by register shift (converted to 1630 uint32), and puts the result in register dst. 1631 */ 1632 int dst = vPC[1].u.operand; 1633 JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); 1634 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); 1635 1636 if (val.isInt32() && shift.isInt32()) 1637 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f)); 1638 else { 1639 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); 1640 CHECK_FOR_EXCEPTION(); 1641 callFrame->r(dst) = result; 1642 } 1643 1644 vPC += OPCODE_LENGTH(op_rshift); 1645 NEXT_INSTRUCTION(); 1646 } 1647 DEFINE_OPCODE(op_urshift) { 1648 /* rshift dst(r) val(r) shift(r) 1649 1650 Performs logical right shift of register val (converted 1651 to uint32) by register shift (converted to 1652 uint32), and puts the result in register dst. 1653 */ 1654 int dst = vPC[1].u.operand; 1655 JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); 1656 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); 1657 if (val.isUInt32() && shift.isInt32()) 1658 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f)); 1659 else { 1660 JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f)); 1661 CHECK_FOR_EXCEPTION(); 1662 callFrame->r(dst) = result; 1663 } 1664 1665 vPC += OPCODE_LENGTH(op_urshift); 1666 NEXT_INSTRUCTION(); 1667 } 1668 DEFINE_OPCODE(op_bitand) { 1669 /* bitand dst(r) src1(r) src2(r) 1670 1671 Computes bitwise AND of register src1 (converted to int32) 1672 and register src2 (converted to int32), and puts the result 1673 in register dst. 1674 */ 1675 int dst = vPC[1].u.operand; 1676 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1677 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1678 if (src1.isInt32() && src2.isInt32()) 1679 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32()); 1680 else { 1681 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame)); 1682 CHECK_FOR_EXCEPTION(); 1683 callFrame->r(dst) = result; 1684 } 1685 1686 vPC += OPCODE_LENGTH(op_bitand); 1687 NEXT_INSTRUCTION(); 1688 } 1689 DEFINE_OPCODE(op_bitxor) { 1690 /* bitxor dst(r) src1(r) src2(r) 1691 1692 Computes bitwise XOR of register src1 (converted to int32) 1693 and register src2 (converted to int32), and puts the result 1694 in register dst. 1695 */ 1696 int dst = vPC[1].u.operand; 1697 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1698 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1699 if (src1.isInt32() && src2.isInt32()) 1700 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32()); 1701 else { 1702 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame)); 1703 CHECK_FOR_EXCEPTION(); 1704 callFrame->r(dst) = result; 1705 } 1706 1707 vPC += OPCODE_LENGTH(op_bitxor); 1708 NEXT_INSTRUCTION(); 1709 } 1710 DEFINE_OPCODE(op_bitor) { 1711 /* bitor dst(r) src1(r) src2(r) 1712 1713 Computes bitwise OR of register src1 (converted to int32) 1714 and register src2 (converted to int32), and puts the 1715 result in register dst. 1716 */ 1717 int dst = vPC[1].u.operand; 1718 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); 1719 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); 1720 if (src1.isInt32() && src2.isInt32()) 1721 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32()); 1722 else { 1723 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame)); 1724 CHECK_FOR_EXCEPTION(); 1725 callFrame->r(dst) = result; 1726 } 1727 1728 vPC += OPCODE_LENGTH(op_bitor); 1729 NEXT_INSTRUCTION(); 1730 } 1731 DEFINE_OPCODE(op_bitnot) { 1732 /* bitnot dst(r) src(r) 1733 1734 Computes bitwise NOT of register src1 (converted to int32), 1735 and puts the result in register dst. 1736 */ 1737 int dst = vPC[1].u.operand; 1738 JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); 1739 if (src.isInt32()) 1740 callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32()); 1741 else { 1742 JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame)); 1743 CHECK_FOR_EXCEPTION(); 1744 callFrame->r(dst) = result; 1745 } 1746 vPC += OPCODE_LENGTH(op_bitnot); 1747 NEXT_INSTRUCTION(); 1748 } 1749 DEFINE_OPCODE(op_not) { 1750 /* not dst(r) src(r) 1751 1752 Computes logical NOT of register src (converted to 1753 boolean), and puts the result in register dst. 1754 */ 1755 int dst = vPC[1].u.operand; 1756 int src = vPC[2].u.operand; 1757 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame)); 1758 CHECK_FOR_EXCEPTION(); 1759 callFrame->r(dst) = result; 1760 1761 vPC += OPCODE_LENGTH(op_not); 1762 NEXT_INSTRUCTION(); 1763 } 1764 DEFINE_OPCODE(op_instanceof) { 1765 /* instanceof dst(r) value(r) constructor(r) constructorProto(r) 1766 1767 Tests whether register value is an instance of register 1768 constructor, and puts the boolean result in register 1769 dst. Register constructorProto must contain the "prototype" 1770 property (not the actual prototype) of the object in 1771 register constructor. This lookup is separated so that 1772 polymorphic inline caching can apply. 1773 1774 Raises an exception if register constructor is not an 1775 object. 1776 */ 1777 int dst = vPC[1].u.operand; 1778 int value = vPC[2].u.operand; 1779 int base = vPC[3].u.operand; 1780 int baseProto = vPC[4].u.operand; 1781 1782 JSValue baseVal = callFrame->r(base).jsValue(); 1783 1784 if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue)) 1785 goto vm_throw; 1786 1787 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue()); 1788 CHECK_FOR_EXCEPTION(); 1789 callFrame->r(dst) = jsBoolean(result); 1790 1791 vPC += OPCODE_LENGTH(op_instanceof); 1792 NEXT_INSTRUCTION(); 1793 } 1794 DEFINE_OPCODE(op_typeof) { 1795 /* typeof dst(r) src(r) 1796 1797 Determines the type string for src according to ECMAScript 1798 rules, and puts the result in register dst. 1799 */ 1800 int dst = vPC[1].u.operand; 1801 int src = vPC[2].u.operand; 1802 callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue())); 1803 1804 vPC += OPCODE_LENGTH(op_typeof); 1805 NEXT_INSTRUCTION(); 1806 } 1807 DEFINE_OPCODE(op_is_undefined) { 1808 /* is_undefined dst(r) src(r) 1809 1810 Determines whether the type string for src according to 1811 the ECMAScript rules is "undefined", and puts the result 1812 in register dst. 1813 */ 1814 int dst = vPC[1].u.operand; 1815 int src = vPC[2].u.operand; 1816 JSValue v = callFrame->r(src).jsValue(); 1817 callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined()); 1818 1819 vPC += OPCODE_LENGTH(op_is_undefined); 1820 NEXT_INSTRUCTION(); 1821 } 1822 DEFINE_OPCODE(op_is_boolean) { 1823 /* is_boolean dst(r) src(r) 1824 1825 Determines whether the type string for src according to 1826 the ECMAScript rules is "boolean", and puts the result 1827 in register dst. 1828 */ 1829 int dst = vPC[1].u.operand; 1830 int src = vPC[2].u.operand; 1831 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean()); 1832 1833 vPC += OPCODE_LENGTH(op_is_boolean); 1834 NEXT_INSTRUCTION(); 1835 } 1836 DEFINE_OPCODE(op_is_number) { 1837 /* is_number dst(r) src(r) 1838 1839 Determines whether the type string for src according to 1840 the ECMAScript rules is "number", and puts the result 1841 in register dst. 1842 */ 1843 int dst = vPC[1].u.operand; 1844 int src = vPC[2].u.operand; 1845 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber()); 1846 1847 vPC += OPCODE_LENGTH(op_is_number); 1848 NEXT_INSTRUCTION(); 1849 } 1850 DEFINE_OPCODE(op_is_string) { 1851 /* is_string dst(r) src(r) 1852 1853 Determines whether the type string for src according to 1854 the ECMAScript rules is "string", and puts the result 1855 in register dst. 1856 */ 1857 int dst = vPC[1].u.operand; 1858 int src = vPC[2].u.operand; 1859 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString()); 1860 1861 vPC += OPCODE_LENGTH(op_is_string); 1862 NEXT_INSTRUCTION(); 1863 } 1864 DEFINE_OPCODE(op_is_object) { 1865 /* is_object dst(r) src(r) 1866 1867 Determines whether the type string for src according to 1868 the ECMAScript rules is "object", and puts the result 1869 in register dst. 1870 */ 1871 int dst = vPC[1].u.operand; 1872 int src = vPC[2].u.operand; 1873 callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue())); 1874 1875 vPC += OPCODE_LENGTH(op_is_object); 1876 NEXT_INSTRUCTION(); 1877 } 1878 DEFINE_OPCODE(op_is_function) { 1879 /* is_function dst(r) src(r) 1880 1881 Determines whether the type string for src according to 1882 the ECMAScript rules is "function", and puts the result 1883 in register dst. 1884 */ 1885 int dst = vPC[1].u.operand; 1886 int src = vPC[2].u.operand; 1887 callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue())); 1888 1889 vPC += OPCODE_LENGTH(op_is_function); 1890 NEXT_INSTRUCTION(); 1891 } 1892 DEFINE_OPCODE(op_in) { 1893 /* in dst(r) property(r) base(r) 1894 1895 Tests whether register base has a property named register 1896 property, and puts the boolean result in register dst. 1897 1898 Raises an exception if register constructor is not an 1899 object. 1900 */ 1901 int dst = vPC[1].u.operand; 1902 int property = vPC[2].u.operand; 1903 int base = vPC[3].u.operand; 1904 1905 JSValue baseVal = callFrame->r(base).jsValue(); 1906 if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue)) 1907 goto vm_throw; 1908 1909 JSObject* baseObj = asObject(baseVal); 1910 1911 JSValue propName = callFrame->r(property).jsValue(); 1912 1913 uint32_t i; 1914 if (propName.getUInt32(i)) 1915 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i)); 1916 else { 1917 Identifier property(callFrame, propName.toString(callFrame)); 1918 CHECK_FOR_EXCEPTION(); 1919 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property)); 1920 } 1921 1922 vPC += OPCODE_LENGTH(op_in); 1923 NEXT_INSTRUCTION(); 1924 } 1925 DEFINE_OPCODE(op_resolve) { 1926 /* resolve dst(r) property(id) 1927 1928 Looks up the property named by identifier property in the 1929 scope chain, and writes the resulting value to register 1930 dst. If the property is not found, raises an exception. 1931 */ 1932 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue))) 1933 goto vm_throw; 1934 1935 vPC += OPCODE_LENGTH(op_resolve); 1936 NEXT_INSTRUCTION(); 1937 } 1938 DEFINE_OPCODE(op_resolve_skip) { 1939 /* resolve_skip dst(r) property(id) skip(n) 1940 1941 Looks up the property named by identifier property in the 1942 scope chain skipping the top 'skip' levels, and writes the resulting 1943 value to register dst. If the property is not found, raises an exception. 1944 */ 1945 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue))) 1946 goto vm_throw; 1947 1948 vPC += OPCODE_LENGTH(op_resolve_skip); 1949 1950 NEXT_INSTRUCTION(); 1951 } 1952 DEFINE_OPCODE(op_resolve_global) { 1953 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n) 1954 1955 Performs a dynamic property lookup for the given property, on the provided 1956 global object. If structure matches the Structure of the global then perform 1957 a fast lookup using the case offset, otherwise fall back to a full resolve and 1958 cache the new structure and offset 1959 */ 1960 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue))) 1961 goto vm_throw; 1962 1963 vPC += OPCODE_LENGTH(op_resolve_global); 1964 1965 NEXT_INSTRUCTION(); 1966 } 1967 DEFINE_OPCODE(op_get_global_var) { 1968 /* get_global_var dst(r) globalObject(c) index(n) 1969 1970 Gets the global var at global slot index and places it in register dst. 1971 */ 1972 int dst = vPC[1].u.operand; 1973 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell); 1974 ASSERT(scope->isGlobalObject()); 1975 int index = vPC[3].u.operand; 1976 1977 callFrame->r(dst) = scope->registerAt(index); 1978 vPC += OPCODE_LENGTH(op_get_global_var); 1979 NEXT_INSTRUCTION(); 1980 } 1981 DEFINE_OPCODE(op_put_global_var) { 1982 /* put_global_var globalObject(c) index(n) value(r) 1983 1984 Puts value into global slot index. 1985 */ 1986 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell); 1987 ASSERT(scope->isGlobalObject()); 1988 int index = vPC[2].u.operand; 1989 int value = vPC[3].u.operand; 1990 1991 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue()); 1992 vPC += OPCODE_LENGTH(op_put_global_var); 1993 NEXT_INSTRUCTION(); 1994 } 1995 DEFINE_OPCODE(op_get_scoped_var) { 1996 /* get_scoped_var dst(r) index(n) skip(n) 1997 1998 Loads the contents of the index-th local from the scope skip nodes from 1999 the top of the scope chain, and places it in register dst 2000 */ 2001 int dst = vPC[1].u.operand; 2002 int index = vPC[2].u.operand; 2003 int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain(); 2004 2005 ScopeChainNode* scopeChain = callFrame->scopeChain(); 2006 ScopeChainIterator iter = scopeChain->begin(); 2007 ScopeChainIterator end = scopeChain->end(); 2008 ASSERT(iter != end); 2009 while (skip--) { 2010 ++iter; 2011 ASSERT(iter != end); 2012 } 2013 2014 ASSERT((*iter)->isVariableObject()); 2015 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); 2016 callFrame->r(dst) = scope->registerAt(index); 2017 vPC += OPCODE_LENGTH(op_get_scoped_var); 2018 NEXT_INSTRUCTION(); 2019 } 2020 DEFINE_OPCODE(op_put_scoped_var) { 2021 /* put_scoped_var index(n) skip(n) value(r) 2022 2023 */ 2024 int index = vPC[1].u.operand; 2025 int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain(); 2026 int value = vPC[3].u.operand; 2027 2028 ScopeChainNode* scopeChain = callFrame->scopeChain(); 2029 ScopeChainIterator iter = scopeChain->begin(); 2030 ScopeChainIterator end = scopeChain->end(); 2031 ASSERT(iter != end); 2032 while (skip--) { 2033 ++iter; 2034 ASSERT(iter != end); 2035 } 2036 2037 ASSERT((*iter)->isVariableObject()); 2038 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); 2039 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue()); 2040 vPC += OPCODE_LENGTH(op_put_scoped_var); 2041 NEXT_INSTRUCTION(); 2042 } 2043 DEFINE_OPCODE(op_resolve_base) { 2044 /* resolve_base dst(r) property(id) 2045 2046 Searches the scope chain for an object containing 2047 identifier property, and if one is found, writes it to 2048 register dst. If none is found, the outermost scope (which 2049 will be the global object) is stored in register dst. 2050 */ 2051 resolveBase(callFrame, vPC); 2052 2053 vPC += OPCODE_LENGTH(op_resolve_base); 2054 NEXT_INSTRUCTION(); 2055 } 2056 DEFINE_OPCODE(op_resolve_with_base) { 2057 /* resolve_with_base baseDst(r) propDst(r) property(id) 2058 2059 Searches the scope chain for an object containing 2060 identifier property, and if one is found, writes it to 2061 register srcDst, and the retrieved property value to register 2062 propDst. If the property is not found, raises an exception. 2063 2064 This is more efficient than doing resolve_base followed by 2065 resolve, or resolve_base followed by get_by_id, as it 2066 avoids duplicate hash lookups. 2067 */ 2068 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue))) 2069 goto vm_throw; 2070 2071 vPC += OPCODE_LENGTH(op_resolve_with_base); 2072 NEXT_INSTRUCTION(); 2073 } 2074 DEFINE_OPCODE(op_get_by_id) { 2075 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n) 2076 2077 Generic property access: Gets the property named by identifier 2078 property from the value base, and puts the result in register dst. 2079 */ 2080 int dst = vPC[1].u.operand; 2081 int base = vPC[2].u.operand; 2082 int property = vPC[3].u.operand; 2083 2084 CodeBlock* codeBlock = callFrame->codeBlock(); 2085 Identifier& ident = codeBlock->identifier(property); 2086 JSValue baseValue = callFrame->r(base).jsValue(); 2087 PropertySlot slot(baseValue); 2088 JSValue result = baseValue.get(callFrame, ident, slot); 2089 CHECK_FOR_EXCEPTION(); 2090 2091 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot); 2092 2093 callFrame->r(dst) = result; 2094 vPC += OPCODE_LENGTH(op_get_by_id); 2095 NEXT_INSTRUCTION(); 2096 } 2097 DEFINE_OPCODE(op_get_by_id_self) { 2098 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n) 2099 2100 Cached property access: Attempts to get a cached property from the 2101 value base. If the cache misses, op_get_by_id_self reverts to 2102 op_get_by_id. 2103 */ 2104 int base = vPC[2].u.operand; 2105 JSValue baseValue = callFrame->r(base).jsValue(); 2106 2107 if (LIKELY(baseValue.isCell())) { 2108 JSCell* baseCell = asCell(baseValue); 2109 Structure* structure = vPC[4].u.structure; 2110 2111 if (LIKELY(baseCell->structure() == structure)) { 2112 ASSERT(baseCell->isObject()); 2113 JSObject* baseObject = asObject(baseCell); 2114 int dst = vPC[1].u.operand; 2115 int offset = vPC[5].u.operand; 2116 2117 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); 2118 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset)); 2119 2120 vPC += OPCODE_LENGTH(op_get_by_id_self); 2121 NEXT_INSTRUCTION(); 2122 } 2123 } 2124 2125 uncacheGetByID(callFrame->codeBlock(), vPC); 2126 NEXT_INSTRUCTION(); 2127 } 2128 DEFINE_OPCODE(op_get_by_id_proto) { 2129 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n) 2130 2131 Cached property access: Attempts to get a cached property from the 2132 value base's prototype. If the cache misses, op_get_by_id_proto 2133 reverts to op_get_by_id. 2134 */ 2135 int base = vPC[2].u.operand; 2136 JSValue baseValue = callFrame->r(base).jsValue(); 2137 2138 if (LIKELY(baseValue.isCell())) { 2139 JSCell* baseCell = asCell(baseValue); 2140 Structure* structure = vPC[4].u.structure; 2141 2142 if (LIKELY(baseCell->structure() == structure)) { 2143 ASSERT(structure->prototypeForLookup(callFrame).isObject()); 2144 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame)); 2145 Structure* prototypeStructure = vPC[5].u.structure; 2146 2147 if (LIKELY(protoObject->structure() == prototypeStructure)) { 2148 int dst = vPC[1].u.operand; 2149 int offset = vPC[6].u.operand; 2150 2151 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset)); 2152 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset)); 2153 callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset)); 2154 2155 vPC += OPCODE_LENGTH(op_get_by_id_proto); 2156 NEXT_INSTRUCTION(); 2157 } 2158 } 2159 } 2160 2161 uncacheGetByID(callFrame->codeBlock(), vPC); 2162 NEXT_INSTRUCTION(); 2163 } 2164 DEFINE_OPCODE(op_get_by_id_self_list) { 2165 // Polymorphic self access caching currently only supported when JITting. 2166 ASSERT_NOT_REACHED(); 2167 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)! 2168 vPC += OPCODE_LENGTH(op_get_by_id_self_list); 2169 NEXT_INSTRUCTION(); 2170 } 2171 DEFINE_OPCODE(op_get_by_id_proto_list) { 2172 // Polymorphic prototype access caching currently only supported when JITting. 2173 ASSERT_NOT_REACHED(); 2174 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)! 2175 vPC += OPCODE_LENGTH(op_get_by_id_proto_list); 2176 NEXT_INSTRUCTION(); 2177 } 2178 DEFINE_OPCODE(op_get_by_id_chain) { 2179 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n) 2180 2181 Cached property access: Attempts to get a cached property from the 2182 value base's prototype chain. If the cache misses, op_get_by_id_chain 2183 reverts to op_get_by_id. 2184 */ 2185 int base = vPC[2].u.operand; 2186 JSValue baseValue = callFrame->r(base).jsValue(); 2187 2188 if (LIKELY(baseValue.isCell())) { 2189 JSCell* baseCell = asCell(baseValue); 2190 Structure* structure = vPC[4].u.structure; 2191 2192 if (LIKELY(baseCell->structure() == structure)) { 2193 RefPtr<Structure>* it = vPC[5].u.structureChain->head(); 2194 size_t count = vPC[6].u.operand; 2195 RefPtr<Structure>* end = it + count; 2196 2197 while (true) { 2198 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame)); 2199 2200 if (UNLIKELY(baseObject->structure() != (*it).get())) 2201 break; 2202 2203 if (++it == end) { 2204 int dst = vPC[1].u.operand; 2205 int offset = vPC[7].u.operand; 2206 2207 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); 2208 ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); 2209 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset)); 2210 2211 vPC += OPCODE_LENGTH(op_get_by_id_chain); 2212 NEXT_INSTRUCTION(); 2213 } 2214 2215 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype. 2216 baseCell = baseObject; 2217 } 2218 } 2219 } 2220 2221 uncacheGetByID(callFrame->codeBlock(), vPC); 2222 NEXT_INSTRUCTION(); 2223 } 2224 DEFINE_OPCODE(op_get_by_id_generic) { 2225 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n) 2226 2227 Generic property access: Gets the property named by identifier 2228 property from the value base, and puts the result in register dst. 2229 */ 2230 int dst = vPC[1].u.operand; 2231 int base = vPC[2].u.operand; 2232 int property = vPC[3].u.operand; 2233 2234 Identifier& ident = callFrame->codeBlock()->identifier(property); 2235 JSValue baseValue = callFrame->r(base).jsValue(); 2236 PropertySlot slot(baseValue); 2237 JSValue result = baseValue.get(callFrame, ident, slot); 2238 CHECK_FOR_EXCEPTION(); 2239 2240 callFrame->r(dst) = result; 2241 vPC += OPCODE_LENGTH(op_get_by_id_generic); 2242 NEXT_INSTRUCTION(); 2243 } 2244 DEFINE_OPCODE(op_get_array_length) { 2245 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n) 2246 2247 Cached property access: Gets the length of the array in register base, 2248 and puts the result in register dst. If register base does not hold 2249 an array, op_get_array_length reverts to op_get_by_id. 2250 */ 2251 2252 int base = vPC[2].u.operand; 2253 JSValue baseValue = callFrame->r(base).jsValue(); 2254 if (LIKELY(isJSArray(globalData, baseValue))) { 2255 int dst = vPC[1].u.operand; 2256 callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length()); 2257 vPC += OPCODE_LENGTH(op_get_array_length); 2258 NEXT_INSTRUCTION(); 2259 } 2260 2261 uncacheGetByID(callFrame->codeBlock(), vPC); 2262 NEXT_INSTRUCTION(); 2263 } 2264 DEFINE_OPCODE(op_get_string_length) { 2265 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n) 2266 2267 Cached property access: Gets the length of the string in register base, 2268 and puts the result in register dst. If register base does not hold 2269 a string, op_get_string_length reverts to op_get_by_id. 2270 */ 2271 2272 int base = vPC[2].u.operand; 2273 JSValue baseValue = callFrame->r(base).jsValue(); 2274 if (LIKELY(isJSString(globalData, baseValue))) { 2275 int dst = vPC[1].u.operand; 2276 callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length()); 2277 vPC += OPCODE_LENGTH(op_get_string_length); 2278 NEXT_INSTRUCTION(); 2279 } 2280 2281 uncacheGetByID(callFrame->codeBlock(), vPC); 2282 NEXT_INSTRUCTION(); 2283 } 2284 DEFINE_OPCODE(op_put_by_id) { 2285 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) 2286 2287 Generic property access: Sets the property named by identifier 2288 property, belonging to register base, to register value. 2289 2290 Unlike many opcodes, this one does not write any output to 2291 the register file. 2292 */ 2293 2294 int base = vPC[1].u.operand; 2295 int property = vPC[2].u.operand; 2296 int value = vPC[3].u.operand; 2297 2298 CodeBlock* codeBlock = callFrame->codeBlock(); 2299 JSValue baseValue = callFrame->r(base).jsValue(); 2300 Identifier& ident = codeBlock->identifier(property); 2301 PutPropertySlot slot; 2302 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot); 2303 CHECK_FOR_EXCEPTION(); 2304 2305 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot); 2306 2307 vPC += OPCODE_LENGTH(op_put_by_id); 2308 NEXT_INSTRUCTION(); 2309 } 2310 DEFINE_OPCODE(op_put_by_id_transition) { 2311 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) 2312 2313 Cached property access: Attempts to set a new property with a cached transition 2314 property named by identifier property, belonging to register base, 2315 to register value. If the cache misses, op_put_by_id_transition 2316 reverts to op_put_by_id_generic. 2317 2318 Unlike many opcodes, this one does not write any output to 2319 the register file. 2320 */ 2321 int base = vPC[1].u.operand; 2322 JSValue baseValue = callFrame->r(base).jsValue(); 2323 2324 if (LIKELY(baseValue.isCell())) { 2325 JSCell* baseCell = asCell(baseValue); 2326 Structure* oldStructure = vPC[4].u.structure; 2327 Structure* newStructure = vPC[5].u.structure; 2328 2329 if (LIKELY(baseCell->structure() == oldStructure)) { 2330 ASSERT(baseCell->isObject()); 2331 JSObject* baseObject = asObject(baseCell); 2332 2333 RefPtr<Structure>* it = vPC[6].u.structureChain->head(); 2334 2335 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame); 2336 while (!proto.isNull()) { 2337 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) { 2338 uncachePutByID(callFrame->codeBlock(), vPC); 2339 NEXT_INSTRUCTION(); 2340 } 2341 ++it; 2342 proto = asObject(proto)->structure()->prototypeForLookup(callFrame); 2343 } 2344 2345 baseObject->transitionTo(newStructure); 2346 2347 int value = vPC[3].u.operand; 2348 unsigned offset = vPC[7].u.operand; 2349 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset); 2350 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue()); 2351 2352 vPC += OPCODE_LENGTH(op_put_by_id_transition); 2353 NEXT_INSTRUCTION(); 2354 } 2355 } 2356 2357 uncachePutByID(callFrame->codeBlock(), vPC); 2358 NEXT_INSTRUCTION(); 2359 } 2360 DEFINE_OPCODE(op_put_by_id_replace) { 2361 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) 2362 2363 Cached property access: Attempts to set a pre-existing, cached 2364 property named by identifier property, belonging to register base, 2365 to register value. If the cache misses, op_put_by_id_replace 2366 reverts to op_put_by_id. 2367 2368 Unlike many opcodes, this one does not write any output to 2369 the register file. 2370 */ 2371 int base = vPC[1].u.operand; 2372 JSValue baseValue = callFrame->r(base).jsValue(); 2373 2374 if (LIKELY(baseValue.isCell())) { 2375 JSCell* baseCell = asCell(baseValue); 2376 Structure* structure = vPC[4].u.structure; 2377 2378 if (LIKELY(baseCell->structure() == structure)) { 2379 ASSERT(baseCell->isObject()); 2380 JSObject* baseObject = asObject(baseCell); 2381 int value = vPC[3].u.operand; 2382 unsigned offset = vPC[5].u.operand; 2383 2384 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset); 2385 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue()); 2386 2387 vPC += OPCODE_LENGTH(op_put_by_id_replace); 2388 NEXT_INSTRUCTION(); 2389 } 2390 } 2391 2392 uncachePutByID(callFrame->codeBlock(), vPC); 2393 NEXT_INSTRUCTION(); 2394 } 2395 DEFINE_OPCODE(op_put_by_id_generic) { 2396 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) 2397 2398 Generic property access: Sets the property named by identifier 2399 property, belonging to register base, to register value. 2400 2401 Unlike many opcodes, this one does not write any output to 2402 the register file. 2403 */ 2404 int base = vPC[1].u.operand; 2405 int property = vPC[2].u.operand; 2406 int value = vPC[3].u.operand; 2407 2408 JSValue baseValue = callFrame->r(base).jsValue(); 2409 Identifier& ident = callFrame->codeBlock()->identifier(property); 2410 PutPropertySlot slot; 2411 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot); 2412 CHECK_FOR_EXCEPTION(); 2413 2414 vPC += OPCODE_LENGTH(op_put_by_id_generic); 2415 NEXT_INSTRUCTION(); 2416 } 2417 DEFINE_OPCODE(op_del_by_id) { 2418 /* del_by_id dst(r) base(r) property(id) 2419 2420 Converts register base to Object, deletes the property 2421 named by identifier property from the object, and writes a 2422 boolean indicating success (if true) or failure (if false) 2423 to register dst. 2424 */ 2425 int dst = vPC[1].u.operand; 2426 int base = vPC[2].u.operand; 2427 int property = vPC[3].u.operand; 2428 2429 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); 2430 Identifier& ident = callFrame->codeBlock()->identifier(property); 2431 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident)); 2432 CHECK_FOR_EXCEPTION(); 2433 callFrame->r(dst) = result; 2434 vPC += OPCODE_LENGTH(op_del_by_id); 2435 NEXT_INSTRUCTION(); 2436 } 2437 DEFINE_OPCODE(op_get_by_pname) { 2438 int dst = vPC[1].u.operand; 2439 int base = vPC[2].u.operand; 2440 int property = vPC[3].u.operand; 2441 int expected = vPC[4].u.operand; 2442 int iter = vPC[5].u.operand; 2443 int i = vPC[6].u.operand; 2444 2445 JSValue baseValue = callFrame->r(base).jsValue(); 2446 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator(); 2447 JSValue subscript = callFrame->r(property).jsValue(); 2448 JSValue expectedSubscript = callFrame->r(expected).jsValue(); 2449 int index = callFrame->r(i).i() - 1; 2450 JSValue result; 2451 int offset = 0; 2452 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) { 2453 callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset); 2454 vPC += OPCODE_LENGTH(op_get_by_pname); 2455 NEXT_INSTRUCTION(); 2456 } 2457 Identifier propertyName(callFrame, subscript.toString(callFrame)); 2458 result = baseValue.get(callFrame, propertyName); 2459 CHECK_FOR_EXCEPTION(); 2460 callFrame->r(dst) = result; 2461 vPC += OPCODE_LENGTH(op_get_by_pname); 2462 NEXT_INSTRUCTION(); 2463 } 2464 DEFINE_OPCODE(op_get_by_val) { 2465 /* get_by_val dst(r) base(r) property(r) 2466 2467 Converts register base to Object, gets the property named 2468 by register property from the object, and puts the result 2469 in register dst. property is nominally converted to string 2470 but numbers are treated more efficiently. 2471 */ 2472 int dst = vPC[1].u.operand; 2473 int base = vPC[2].u.operand; 2474 int property = vPC[3].u.operand; 2475 2476 JSValue baseValue = callFrame->r(base).jsValue(); 2477 JSValue subscript = callFrame->r(property).jsValue(); 2478 2479 JSValue result; 2480 2481 if (LIKELY(subscript.isUInt32())) { 2482 uint32_t i = subscript.asUInt32(); 2483 if (isJSArray(globalData, baseValue)) { 2484 JSArray* jsArray = asArray(baseValue); 2485 if (jsArray->canGetIndex(i)) 2486 result = jsArray->getIndex(i); 2487 else 2488 result = jsArray->JSArray::get(callFrame, i); 2489 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) 2490 result = asString(baseValue)->getIndex(callFrame, i); 2491 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) 2492 result = asByteArray(baseValue)->getIndex(callFrame, i); 2493 else 2494 result = baseValue.get(callFrame, i); 2495 } else { 2496 Identifier property(callFrame, subscript.toString(callFrame)); 2497 result = baseValue.get(callFrame, property); 2498 } 2499 2500 CHECK_FOR_EXCEPTION(); 2501 callFrame->r(dst) = result; 2502 vPC += OPCODE_LENGTH(op_get_by_val); 2503 NEXT_INSTRUCTION(); 2504 } 2505 DEFINE_OPCODE(op_put_by_val) { 2506 /* put_by_val base(r) property(r) value(r) 2507 2508 Sets register value on register base as the property named 2509 by register property. Base is converted to object 2510 first. register property is nominally converted to string 2511 but numbers are treated more efficiently. 2512 2513 Unlike many opcodes, this one does not write any output to 2514 the register file. 2515 */ 2516 int base = vPC[1].u.operand; 2517 int property = vPC[2].u.operand; 2518 int value = vPC[3].u.operand; 2519 2520 JSValue baseValue = callFrame->r(base).jsValue(); 2521 JSValue subscript = callFrame->r(property).jsValue(); 2522 2523 if (LIKELY(subscript.isUInt32())) { 2524 uint32_t i = subscript.asUInt32(); 2525 if (isJSArray(globalData, baseValue)) { 2526 JSArray* jsArray = asArray(baseValue); 2527 if (jsArray->canSetIndex(i)) 2528 jsArray->setIndex(i, callFrame->r(value).jsValue()); 2529 else 2530 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue()); 2531 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 2532 JSByteArray* jsByteArray = asByteArray(baseValue); 2533 double dValue = 0; 2534 JSValue jsValue = callFrame->r(value).jsValue(); 2535 if (jsValue.isInt32()) 2536 jsByteArray->setIndex(i, jsValue.asInt32()); 2537 else if (jsValue.getNumber(dValue)) 2538 jsByteArray->setIndex(i, dValue); 2539 else 2540 baseValue.put(callFrame, i, jsValue); 2541 } else 2542 baseValue.put(callFrame, i, callFrame->r(value).jsValue()); 2543 } else { 2544 Identifier property(callFrame, subscript.toString(callFrame)); 2545 if (!globalData->exception) { // Don't put to an object if toString threw an exception. 2546 PutPropertySlot slot; 2547 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot); 2548 } 2549 } 2550 2551 CHECK_FOR_EXCEPTION(); 2552 vPC += OPCODE_LENGTH(op_put_by_val); 2553 NEXT_INSTRUCTION(); 2554 } 2555 DEFINE_OPCODE(op_del_by_val) { 2556 /* del_by_val dst(r) base(r) property(r) 2557 2558 Converts register base to Object, deletes the property 2559 named by register property from the object, and writes a 2560 boolean indicating success (if true) or failure (if false) 2561 to register dst. 2562 */ 2563 int dst = vPC[1].u.operand; 2564 int base = vPC[2].u.operand; 2565 int property = vPC[3].u.operand; 2566 2567 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw 2568 2569 JSValue subscript = callFrame->r(property).jsValue(); 2570 JSValue result; 2571 uint32_t i; 2572 if (subscript.getUInt32(i)) 2573 result = jsBoolean(baseObj->deleteProperty(callFrame, i)); 2574 else { 2575 CHECK_FOR_EXCEPTION(); 2576 Identifier property(callFrame, subscript.toString(callFrame)); 2577 CHECK_FOR_EXCEPTION(); 2578 result = jsBoolean(baseObj->deleteProperty(callFrame, property)); 2579 } 2580 2581 CHECK_FOR_EXCEPTION(); 2582 callFrame->r(dst) = result; 2583 vPC += OPCODE_LENGTH(op_del_by_val); 2584 NEXT_INSTRUCTION(); 2585 } 2586 DEFINE_OPCODE(op_put_by_index) { 2587 /* put_by_index base(r) property(n) value(r) 2588 2589 Sets register value on register base as the property named 2590 by the immediate number property. Base is converted to 2591 object first. 2592 2593 Unlike many opcodes, this one does not write any output to 2594 the register file. 2595 2596 This opcode is mainly used to initialize array literals. 2597 */ 2598 int base = vPC[1].u.operand; 2599 unsigned property = vPC[2].u.operand; 2600 int value = vPC[3].u.operand; 2601 2602 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue()); 2603 2604 vPC += OPCODE_LENGTH(op_put_by_index); 2605 NEXT_INSTRUCTION(); 2606 } 2607 DEFINE_OPCODE(op_loop) { 2608 /* loop target(offset) 2609 2610 Jumps unconditionally to offset target from the current 2611 instruction. 2612 2613 Additionally this loop instruction may terminate JS execution is 2614 the JS timeout is reached. 2615 */ 2616 #if ENABLE(OPCODE_STATS) 2617 OpcodeStats::resetLastInstruction(); 2618 #endif 2619 int target = vPC[1].u.operand; 2620 CHECK_FOR_TIMEOUT(); 2621 vPC += target; 2622 NEXT_INSTRUCTION(); 2623 } 2624 DEFINE_OPCODE(op_jmp) { 2625 /* jmp target(offset) 2626 2627 Jumps unconditionally to offset target from the current 2628 instruction. 2629 */ 2630 #if ENABLE(OPCODE_STATS) 2631 OpcodeStats::resetLastInstruction(); 2632 #endif 2633 int target = vPC[1].u.operand; 2634 2635 vPC += target; 2636 NEXT_INSTRUCTION(); 2637 } 2638 DEFINE_OPCODE(op_loop_if_true) { 2639 /* loop_if_true cond(r) target(offset) 2640 2641 Jumps to offset target from the current instruction, if and 2642 only if register cond converts to boolean as true. 2643 2644 Additionally this loop instruction may terminate JS execution is 2645 the JS timeout is reached. 2646 */ 2647 int cond = vPC[1].u.operand; 2648 int target = vPC[2].u.operand; 2649 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) { 2650 vPC += target; 2651 CHECK_FOR_TIMEOUT(); 2652 NEXT_INSTRUCTION(); 2653 } 2654 2655 vPC += OPCODE_LENGTH(op_loop_if_true); 2656 NEXT_INSTRUCTION(); 2657 } 2658 DEFINE_OPCODE(op_loop_if_false) { 2659 /* loop_if_true cond(r) target(offset) 2660 2661 Jumps to offset target from the current instruction, if and 2662 only if register cond converts to boolean as false. 2663 2664 Additionally this loop instruction may terminate JS execution is 2665 the JS timeout is reached. 2666 */ 2667 int cond = vPC[1].u.operand; 2668 int target = vPC[2].u.operand; 2669 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) { 2670 vPC += target; 2671 CHECK_FOR_TIMEOUT(); 2672 NEXT_INSTRUCTION(); 2673 } 2674 2675 vPC += OPCODE_LENGTH(op_loop_if_true); 2676 NEXT_INSTRUCTION(); 2677 } 2678 DEFINE_OPCODE(op_jtrue) { 2679 /* jtrue cond(r) target(offset) 2680 2681 Jumps to offset target from the current instruction, if and 2682 only if register cond converts to boolean as true. 2683 */ 2684 int cond = vPC[1].u.operand; 2685 int target = vPC[2].u.operand; 2686 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) { 2687 vPC += target; 2688 NEXT_INSTRUCTION(); 2689 } 2690 2691 vPC += OPCODE_LENGTH(op_jtrue); 2692 NEXT_INSTRUCTION(); 2693 } 2694 DEFINE_OPCODE(op_jfalse) { 2695 /* jfalse cond(r) target(offset) 2696 2697 Jumps to offset target from the current instruction, if and 2698 only if register cond converts to boolean as false. 2699 */ 2700 int cond = vPC[1].u.operand; 2701 int target = vPC[2].u.operand; 2702 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) { 2703 vPC += target; 2704 NEXT_INSTRUCTION(); 2705 } 2706 2707 vPC += OPCODE_LENGTH(op_jfalse); 2708 NEXT_INSTRUCTION(); 2709 } 2710 DEFINE_OPCODE(op_jeq_null) { 2711 /* jeq_null src(r) target(offset) 2712 2713 Jumps to offset target from the current instruction, if and 2714 only if register src is null. 2715 */ 2716 int src = vPC[1].u.operand; 2717 int target = vPC[2].u.operand; 2718 JSValue srcValue = callFrame->r(src).jsValue(); 2719 2720 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { 2721 vPC += target; 2722 NEXT_INSTRUCTION(); 2723 } 2724 2725 vPC += OPCODE_LENGTH(op_jeq_null); 2726 NEXT_INSTRUCTION(); 2727 } 2728 DEFINE_OPCODE(op_jneq_null) { 2729 /* jneq_null src(r) target(offset) 2730 2731 Jumps to offset target from the current instruction, if and 2732 only if register src is not null. 2733 */ 2734 int src = vPC[1].u.operand; 2735 int target = vPC[2].u.operand; 2736 JSValue srcValue = callFrame->r(src).jsValue(); 2737 2738 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { 2739 vPC += target; 2740 NEXT_INSTRUCTION(); 2741 } 2742 2743 vPC += OPCODE_LENGTH(op_jneq_null); 2744 NEXT_INSTRUCTION(); 2745 } 2746 DEFINE_OPCODE(op_jneq_ptr) { 2747 /* jneq_ptr src(r) ptr(jsCell) target(offset) 2748 2749 Jumps to offset target from the current instruction, if the value r is equal 2750 to ptr, using pointer equality. 2751 */ 2752 int src = vPC[1].u.operand; 2753 JSValue ptr = JSValue(vPC[2].u.jsCell); 2754 int target = vPC[3].u.operand; 2755 JSValue srcValue = callFrame->r(src).jsValue(); 2756 if (srcValue != ptr) { 2757 vPC += target; 2758 NEXT_INSTRUCTION(); 2759 } 2760 2761 vPC += OPCODE_LENGTH(op_jneq_ptr); 2762 NEXT_INSTRUCTION(); 2763 } 2764 DEFINE_OPCODE(op_loop_if_less) { 2765 /* loop_if_less src1(r) src2(r) target(offset) 2766 2767 Checks whether register src1 is less than register src2, as 2768 with the ECMAScript '<' operator, and then jumps to offset 2769 target from the current instruction, if and only if the 2770 result of the comparison is true. 2771 2772 Additionally this loop instruction may terminate JS execution is 2773 the JS timeout is reached. 2774 */ 2775 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); 2776 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); 2777 int target = vPC[3].u.operand; 2778 2779 bool result = jsLess(callFrame, src1, src2); 2780 CHECK_FOR_EXCEPTION(); 2781 2782 if (result) { 2783 vPC += target; 2784 CHECK_FOR_TIMEOUT(); 2785 NEXT_INSTRUCTION(); 2786 } 2787 2788 vPC += OPCODE_LENGTH(op_loop_if_less); 2789 NEXT_INSTRUCTION(); 2790 } 2791 DEFINE_OPCODE(op_loop_if_lesseq) { 2792 /* loop_if_lesseq src1(r) src2(r) target(offset) 2793 2794 Checks whether register src1 is less than or equal to register 2795 src2, as with the ECMAScript '<=' operator, and then jumps to 2796 offset target from the current instruction, if and only if the 2797 result of the comparison is true. 2798 2799 Additionally this loop instruction may terminate JS execution is 2800 the JS timeout is reached. 2801 */ 2802 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); 2803 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); 2804 int target = vPC[3].u.operand; 2805 2806 bool result = jsLessEq(callFrame, src1, src2); 2807 CHECK_FOR_EXCEPTION(); 2808 2809 if (result) { 2810 vPC += target; 2811 CHECK_FOR_TIMEOUT(); 2812 NEXT_INSTRUCTION(); 2813 } 2814 2815 vPC += OPCODE_LENGTH(op_loop_if_lesseq); 2816 NEXT_INSTRUCTION(); 2817 } 2818 DEFINE_OPCODE(op_jnless) { 2819 /* jnless src1(r) src2(r) target(offset) 2820 2821 Checks whether register src1 is less than register src2, as 2822 with the ECMAScript '<' operator, and then jumps to offset 2823 target from the current instruction, if and only if the 2824 result of the comparison is false. 2825 */ 2826 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); 2827 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); 2828 int target = vPC[3].u.operand; 2829 2830 bool result = jsLess(callFrame, src1, src2); 2831 CHECK_FOR_EXCEPTION(); 2832 2833 if (!result) { 2834 vPC += target; 2835 NEXT_INSTRUCTION(); 2836 } 2837 2838 vPC += OPCODE_LENGTH(op_jnless); 2839 NEXT_INSTRUCTION(); 2840 } 2841 DEFINE_OPCODE(op_jless) { 2842 /* jless src1(r) src2(r) target(offset) 2843 2844 Checks whether register src1 is less than register src2, as 2845 with the ECMAScript '<' operator, and then jumps to offset 2846 target from the current instruction, if and only if the 2847 result of the comparison is true. 2848 */ 2849 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); 2850 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); 2851 int target = vPC[3].u.operand; 2852 2853 bool result = jsLess(callFrame, src1, src2); 2854 CHECK_FOR_EXCEPTION(); 2855 2856 if (result) { 2857 vPC += target; 2858 NEXT_INSTRUCTION(); 2859 } 2860 2861 vPC += OPCODE_LENGTH(op_jless); 2862 NEXT_INSTRUCTION(); 2863 } 2864 DEFINE_OPCODE(op_jnlesseq) { 2865 /* jnlesseq src1(r) src2(r) target(offset) 2866 2867 Checks whether register src1 is less than or equal to 2868 register src2, as with the ECMAScript '<=' operator, 2869 and then jumps to offset target from the current instruction, 2870 if and only if theresult of the comparison is false. 2871 */ 2872 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); 2873 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); 2874 int target = vPC[3].u.operand; 2875 2876 bool result = jsLessEq(callFrame, src1, src2); 2877 CHECK_FOR_EXCEPTION(); 2878 2879 if (!result) { 2880 vPC += target; 2881 NEXT_INSTRUCTION(); 2882 } 2883 2884 vPC += OPCODE_LENGTH(op_jnlesseq); 2885 NEXT_INSTRUCTION(); 2886 } 2887 DEFINE_OPCODE(op_switch_imm) { 2888 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r) 2889 2890 Performs a range checked switch on the scrutinee value, using 2891 the tableIndex-th immediate switch jump table. If the scrutinee value 2892 is an immediate number in the range covered by the referenced jump 2893 table, and the value at jumpTable[scrutinee value] is non-zero, then 2894 that value is used as the jump offset, otherwise defaultOffset is used. 2895 */ 2896 int tableIndex = vPC[1].u.operand; 2897 int defaultOffset = vPC[2].u.operand; 2898 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); 2899 if (scrutinee.isInt32()) 2900 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset); 2901 else { 2902 double value; 2903 int32_t intValue; 2904 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value)) 2905 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset); 2906 else 2907 vPC += defaultOffset; 2908 } 2909 NEXT_INSTRUCTION(); 2910 } 2911 DEFINE_OPCODE(op_switch_char) { 2912 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r) 2913 2914 Performs a range checked switch on the scrutinee value, using 2915 the tableIndex-th character switch jump table. If the scrutinee value 2916 is a single character string in the range covered by the referenced jump 2917 table, and the value at jumpTable[scrutinee value] is non-zero, then 2918 that value is used as the jump offset, otherwise defaultOffset is used. 2919 */ 2920 int tableIndex = vPC[1].u.operand; 2921 int defaultOffset = vPC[2].u.operand; 2922 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); 2923 if (!scrutinee.isString()) 2924 vPC += defaultOffset; 2925 else { 2926 UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); 2927 if (value->size() != 1) 2928 vPC += defaultOffset; 2929 else 2930 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset); 2931 } 2932 NEXT_INSTRUCTION(); 2933 } 2934 DEFINE_OPCODE(op_switch_string) { 2935 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r) 2936 2937 Performs a sparse hashmap based switch on the value in the scrutinee 2938 register, using the tableIndex-th string switch jump table. If the 2939 scrutinee value is a string that exists as a key in the referenced 2940 jump table, then the value associated with the string is used as the 2941 jump offset, otherwise defaultOffset is used. 2942 */ 2943 int tableIndex = vPC[1].u.operand; 2944 int defaultOffset = vPC[2].u.operand; 2945 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); 2946 if (!scrutinee.isString()) 2947 vPC += defaultOffset; 2948 else 2949 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset); 2950 NEXT_INSTRUCTION(); 2951 } 2952 DEFINE_OPCODE(op_new_func) { 2953 /* new_func dst(r) func(f) 2954 2955 Constructs a new Function instance from function func and 2956 the current scope chain using the original Function 2957 constructor, using the rules for function declarations, and 2958 puts the result in register dst. 2959 */ 2960 int dst = vPC[1].u.operand; 2961 int func = vPC[2].u.operand; 2962 2963 callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain())); 2964 2965 vPC += OPCODE_LENGTH(op_new_func); 2966 NEXT_INSTRUCTION(); 2967 } 2968 DEFINE_OPCODE(op_new_func_exp) { 2969 /* new_func_exp dst(r) func(f) 2970 2971 Constructs a new Function instance from function func and 2972 the current scope chain using the original Function 2973 constructor, using the rules for function expressions, and 2974 puts the result in register dst. 2975 */ 2976 int dst = vPC[1].u.operand; 2977 int funcIndex = vPC[2].u.operand; 2978 2979 FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex); 2980 JSFunction* func = function->make(callFrame, callFrame->scopeChain()); 2981 2982 /* 2983 The Identifier in a FunctionExpression can be referenced from inside 2984 the FunctionExpression's FunctionBody to allow the function to call 2985 itself recursively. However, unlike in a FunctionDeclaration, the 2986 Identifier in a FunctionExpression cannot be referenced from and 2987 does not affect the scope enclosing the FunctionExpression. 2988 */ 2989 if (!function->name().isNull()) { 2990 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); 2991 func->scope().push(functionScopeObject); 2992 } 2993 2994 callFrame->r(dst) = JSValue(func); 2995 2996 vPC += OPCODE_LENGTH(op_new_func_exp); 2997 NEXT_INSTRUCTION(); 2998 } 2999 DEFINE_OPCODE(op_call_eval) { 3000 /* call_eval dst(r) func(r) argCount(n) registerOffset(n) 3001 3002 Call a function named "eval" with no explicit "this" value 3003 (which may therefore be the eval operator). If register 3004 thisVal is the global object, and register func contains 3005 that global object's original global eval function, then 3006 perform the eval operator in local scope (interpreting 3007 the argument registers as for the "call" 3008 opcode). Otherwise, act exactly as the "call" opcode would. 3009 */ 3010 3011 int dst = vPC[1].u.operand; 3012 int func = vPC[2].u.operand; 3013 int argCount = vPC[3].u.operand; 3014 int registerOffset = vPC[4].u.operand; 3015 3016 JSValue funcVal = callFrame->r(func).jsValue(); 3017 3018 Register* newCallFrame = callFrame->registers() + registerOffset; 3019 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; 3020 JSValue thisValue = argv[0].jsValue(); 3021 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject; 3022 3023 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { 3024 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); 3025 if (exceptionValue) 3026 goto vm_throw; 3027 callFrame->r(dst) = result; 3028 3029 vPC += OPCODE_LENGTH(op_call_eval); 3030 NEXT_INSTRUCTION(); 3031 } 3032 3033 // We didn't find the blessed version of eval, so process this 3034 // instruction as a normal function call. 3035 // fall through to op_call 3036 } 3037 DEFINE_OPCODE(op_call) { 3038 /* call dst(r) func(r) argCount(n) registerOffset(n) 3039 3040 Perform a function call. 3041 3042 registerOffset is the distance the callFrame pointer should move 3043 before the VM initializes the new call frame's header. 3044 3045 dst is where op_ret should store its result. 3046 */ 3047 3048 int dst = vPC[1].u.operand; 3049 int func = vPC[2].u.operand; 3050 int argCount = vPC[3].u.operand; 3051 int registerOffset = vPC[4].u.operand; 3052 3053 JSValue v = callFrame->r(func).jsValue(); 3054 3055 CallData callData; 3056 CallType callType = v.getCallData(callData); 3057 3058 if (callType == CallTypeJS) { 3059 ScopeChainNode* callDataScopeChain = callData.js.scopeChain; 3060 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); 3061 3062 CallFrame* previousCallFrame = callFrame; 3063 3064 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); 3065 if (UNLIKELY(!callFrame)) { 3066 callFrame = previousCallFrame; 3067 exceptionValue = createStackOverflowError(callFrame); 3068 goto vm_throw; 3069 } 3070 3071 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v)); 3072 vPC = newCodeBlock->instructions().begin(); 3073 3074 #if ENABLE(OPCODE_STATS) 3075 OpcodeStats::resetLastInstruction(); 3076 #endif 3077 3078 NEXT_INSTRUCTION(); 3079 } 3080 3081 if (callType == CallTypeHost) { 3082 ScopeChainNode* scopeChain = callFrame->scopeChain(); 3083 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); 3084 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0); 3085 3086 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount; 3087 ArgList args(thisRegister + 1, argCount - 1); 3088 3089 // FIXME: All host methods should be calling toThisObject, but this is not presently the case. 3090 JSValue thisValue = thisRegister->jsValue(); 3091 if (thisValue == jsNull()) 3092 thisValue = callFrame->globalThisValue(); 3093 3094 JSValue returnValue; 3095 { 3096 SamplingTool::HostCallRecord callRecord(m_sampler.get()); 3097 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args); 3098 } 3099 CHECK_FOR_EXCEPTION(); 3100 3101 callFrame->r(dst) = returnValue; 3102 3103 vPC += OPCODE_LENGTH(op_call); 3104 NEXT_INSTRUCTION(); 3105 } 3106 3107 ASSERT(callType == CallTypeNone); 3108 3109 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock()); 3110 goto vm_throw; 3111 } 3112 DEFINE_OPCODE(op_load_varargs) { 3113 int argCountDst = vPC[1].u.operand; 3114 int argsOffset = vPC[2].u.operand; 3115 3116 JSValue arguments = callFrame->r(argsOffset).jsValue(); 3117 int32_t argCount = 0; 3118 if (!arguments) { 3119 argCount = (uint32_t)(callFrame->argumentCount()) - 1; 3120 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 3121 Register* newEnd = callFrame->registers() + sizeDelta; 3122 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 3123 exceptionValue = createStackOverflowError(callFrame); 3124 goto vm_throw; 3125 } 3126 ASSERT(!callFrame->callee()->isHostFunction()); 3127 int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount(); 3128 int32_t inplaceArgs = min(argCount, expectedParams); 3129 int32_t i = 0; 3130 Register* argStore = callFrame->registers() + argsOffset; 3131 3132 // First step is to copy the "expected" parameters from their normal location relative to the callframe 3133 for (; i < inplaceArgs; i++) 3134 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams]; 3135 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this') 3136 for (; i < argCount; i++) 3137 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1]; 3138 } else if (!arguments.isUndefinedOrNull()) { 3139 if (!arguments.isObject()) { 3140 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock()); 3141 goto vm_throw; 3142 } 3143 if (asObject(arguments)->classInfo() == &Arguments::info) { 3144 Arguments* args = asArguments(arguments); 3145 argCount = args->numProvidedArguments(callFrame); 3146 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 3147 Register* newEnd = callFrame->registers() + sizeDelta; 3148 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 3149 exceptionValue = createStackOverflowError(callFrame); 3150 goto vm_throw; 3151 } 3152 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); 3153 } else if (isJSArray(&callFrame->globalData(), arguments)) { 3154 JSArray* array = asArray(arguments); 3155 argCount = array->length(); 3156 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 3157 Register* newEnd = callFrame->registers() + sizeDelta; 3158 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 3159 exceptionValue = createStackOverflowError(callFrame); 3160 goto vm_throw; 3161 } 3162 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount); 3163 } else if (asObject(arguments)->inherits(&JSArray::info)) { 3164 JSObject* argObject = asObject(arguments); 3165 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame); 3166 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize; 3167 Register* newEnd = callFrame->registers() + sizeDelta; 3168 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) { 3169 exceptionValue = createStackOverflowError(callFrame); 3170 goto vm_throw; 3171 } 3172 Register* argsBuffer = callFrame->registers() + argsOffset; 3173 for (int32_t i = 0; i < argCount; ++i) { 3174 argsBuffer[i] = asObject(arguments)->get(callFrame, i); 3175 CHECK_FOR_EXCEPTION(); 3176 } 3177 } else { 3178 if (!arguments.isObject()) { 3179 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock()); 3180 goto vm_throw; 3181 } 3182 } 3183 } 3184 CHECK_FOR_EXCEPTION(); 3185 callFrame->r(argCountDst) = Register::withInt(argCount + 1); 3186 vPC += OPCODE_LENGTH(op_load_varargs); 3187 NEXT_INSTRUCTION(); 3188 } 3189 DEFINE_OPCODE(op_call_varargs) { 3190 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n) 3191 3192 Perform a function call with a dynamic set of arguments. 3193 3194 registerOffset is the distance the callFrame pointer should move 3195 before the VM initializes the new call frame's header, excluding 3196 space for arguments. 3197 3198 dst is where op_ret should store its result. 3199 */ 3200 3201 int dst = vPC[1].u.operand; 3202 int func = vPC[2].u.operand; 3203 int argCountReg = vPC[3].u.operand; 3204 int registerOffset = vPC[4].u.operand; 3205 3206 JSValue v = callFrame->r(func).jsValue(); 3207 int argCount = callFrame->r(argCountReg).i(); 3208 registerOffset += argCount; 3209 CallData callData; 3210 CallType callType = v.getCallData(callData); 3211 3212 if (callType == CallTypeJS) { 3213 ScopeChainNode* callDataScopeChain = callData.js.scopeChain; 3214 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); 3215 3216 CallFrame* previousCallFrame = callFrame; 3217 3218 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); 3219 if (UNLIKELY(!callFrame)) { 3220 callFrame = previousCallFrame; 3221 exceptionValue = createStackOverflowError(callFrame); 3222 goto vm_throw; 3223 } 3224 3225 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v)); 3226 vPC = newCodeBlock->instructions().begin(); 3227 3228 #if ENABLE(OPCODE_STATS) 3229 OpcodeStats::resetLastInstruction(); 3230 #endif 3231 3232 NEXT_INSTRUCTION(); 3233 } 3234 3235 if (callType == CallTypeHost) { 3236 ScopeChainNode* scopeChain = callFrame->scopeChain(); 3237 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); 3238 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0); 3239 3240 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount; 3241 ArgList args(thisRegister + 1, argCount - 1); 3242 3243 // FIXME: All host methods should be calling toThisObject, but this is not presently the case. 3244 JSValue thisValue = thisRegister->jsValue(); 3245 if (thisValue == jsNull()) 3246 thisValue = callFrame->globalThisValue(); 3247 3248 JSValue returnValue; 3249 { 3250 SamplingTool::HostCallRecord callRecord(m_sampler.get()); 3251 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args); 3252 } 3253 CHECK_FOR_EXCEPTION(); 3254 3255 callFrame->r(dst) = returnValue; 3256 3257 vPC += OPCODE_LENGTH(op_call_varargs); 3258 NEXT_INSTRUCTION(); 3259 } 3260 3261 ASSERT(callType == CallTypeNone); 3262 3263 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock()); 3264 goto vm_throw; 3265 } 3266 DEFINE_OPCODE(op_tear_off_activation) { 3267 /* tear_off_activation activation(r) 3268 3269 Copy all locals and parameters to new memory allocated on 3270 the heap, and make the passed activation use this memory 3271 in the future when looking up entries in the symbol table. 3272 If there is an 'arguments' object, then it will also use 3273 this memory for storing the named parameters, but not any 3274 extra arguments. 3275 3276 This opcode should only be used immediately before op_ret. 3277 */ 3278 3279 int src = vPC[1].u.operand; 3280 ASSERT(callFrame->codeBlock()->needsFullScopeChain()); 3281 3282 asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments()); 3283 3284 vPC += OPCODE_LENGTH(op_tear_off_activation); 3285 NEXT_INSTRUCTION(); 3286 } 3287 DEFINE_OPCODE(op_tear_off_arguments) { 3288 /* tear_off_arguments 3289 3290 Copy all arguments to new memory allocated on the heap, 3291 and make the 'arguments' object use this memory in the 3292 future when looking up named parameters, but not any 3293 extra arguments. If an activation object exists for the 3294 current function context, then the tear_off_activation 3295 opcode should be used instead. 3296 3297 This opcode should only be used immediately before op_ret. 3298 */ 3299 3300 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain()); 3301 3302 if (callFrame->optionalCalleeArguments()) 3303 callFrame->optionalCalleeArguments()->copyRegisters(); 3304 3305 vPC += OPCODE_LENGTH(op_tear_off_arguments); 3306 NEXT_INSTRUCTION(); 3307 } 3308 DEFINE_OPCODE(op_ret) { 3309 /* ret result(r) 3310 3311 Return register result as the return value of the current 3312 function call, writing it into the caller's expected return 3313 value register. In addition, unwind one call frame and 3314 restore the scope chain, code block instruction pointer and 3315 register base to those of the calling function. 3316 */ 3317 3318 int result = vPC[1].u.operand; 3319 3320 if (callFrame->codeBlock()->needsFullScopeChain()) 3321 callFrame->scopeChain()->deref(); 3322 3323 JSValue returnValue = callFrame->r(result).jsValue(); 3324 3325 vPC = callFrame->returnPC(); 3326 int dst = callFrame->returnValueRegister(); 3327 callFrame = callFrame->callerFrame(); 3328 3329 if (callFrame->hasHostCallFrameFlag()) 3330 return returnValue; 3331 3332 callFrame->r(dst) = returnValue; 3333 3334 NEXT_INSTRUCTION(); 3335 } 3336 DEFINE_OPCODE(op_enter) { 3337 /* enter 3338 3339 Initializes local variables to undefined and fills constant 3340 registers with their values. If the code block requires an 3341 activation, enter_with_activation should be used instead. 3342 3343 This opcode should only be used at the beginning of a code 3344 block. 3345 */ 3346 3347 size_t i = 0; 3348 CodeBlock* codeBlock = callFrame->codeBlock(); 3349 3350 for (size_t count = codeBlock->m_numVars; i < count; ++i) 3351 callFrame->r(i) = jsUndefined(); 3352 3353 vPC += OPCODE_LENGTH(op_enter); 3354 NEXT_INSTRUCTION(); 3355 } 3356 DEFINE_OPCODE(op_enter_with_activation) { 3357 /* enter_with_activation dst(r) 3358 3359 Initializes local variables to undefined, fills constant 3360 registers with their values, creates an activation object, 3361 and places the new activation both in dst and at the top 3362 of the scope chain. If the code block does not require an 3363 activation, enter should be used instead. 3364 3365 This opcode should only be used at the beginning of a code 3366 block. 3367 */ 3368 3369 size_t i = 0; 3370 CodeBlock* codeBlock = callFrame->codeBlock(); 3371 3372 for (size_t count = codeBlock->m_numVars; i < count; ++i) 3373 callFrame->r(i) = jsUndefined(); 3374 3375 int dst = vPC[1].u.operand; 3376 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable())); 3377 callFrame->r(dst) = JSValue(activation); 3378 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation)); 3379 3380 vPC += OPCODE_LENGTH(op_enter_with_activation); 3381 NEXT_INSTRUCTION(); 3382 } 3383 DEFINE_OPCODE(op_convert_this) { 3384 /* convert_this this(r) 3385 3386 Takes the value in the 'this' register, converts it to a 3387 value that is suitable for use as the 'this' value, and 3388 stores it in the 'this' register. This opcode is emitted 3389 to avoid doing the conversion in the caller unnecessarily. 3390 3391 This opcode should only be used at the beginning of a code 3392 block. 3393 */ 3394 3395 int thisRegister = vPC[1].u.operand; 3396 JSValue thisVal = callFrame->r(thisRegister).jsValue(); 3397 if (thisVal.needsThisConversion()) 3398 callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame)); 3399 3400 vPC += OPCODE_LENGTH(op_convert_this); 3401 NEXT_INSTRUCTION(); 3402 } 3403 DEFINE_OPCODE(op_init_arguments) { 3404 /* create_arguments 3405 3406 Initialises the arguments object reference to null to ensure 3407 we can correctly detect that we need to create it later (or 3408 avoid creating it altogether). 3409 3410 This opcode should only be used at the beginning of a code 3411 block. 3412 */ 3413 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(); 3414 vPC += OPCODE_LENGTH(op_init_arguments); 3415 NEXT_INSTRUCTION(); 3416 } 3417 DEFINE_OPCODE(op_create_arguments) { 3418 /* create_arguments 3419 3420 Creates the 'arguments' object and places it in both the 3421 'arguments' call frame slot and the local 'arguments' 3422 register, if it has not already been initialised. 3423 */ 3424 3425 if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) { 3426 Arguments* arguments = new (globalData) Arguments(callFrame); 3427 callFrame->setCalleeArguments(arguments); 3428 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments); 3429 } 3430 vPC += OPCODE_LENGTH(op_create_arguments); 3431 NEXT_INSTRUCTION(); 3432 } 3433 DEFINE_OPCODE(op_construct) { 3434 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r) 3435 3436 Invoke register "func" as a constructor. For JS 3437 functions, the calling convention is exactly as for the 3438 "call" opcode, except that the "this" value is a newly 3439 created Object. For native constructors, no "this" 3440 value is passed. In either case, the argCount and registerOffset 3441 registers are interpreted as for the "call" opcode. 3442 3443 Register proto must contain the prototype property of 3444 register func. This is to enable polymorphic inline 3445 caching of this lookup. 3446 */ 3447 3448 int dst = vPC[1].u.operand; 3449 int func = vPC[2].u.operand; 3450 int argCount = vPC[3].u.operand; 3451 int registerOffset = vPC[4].u.operand; 3452 int proto = vPC[5].u.operand; 3453 int thisRegister = vPC[6].u.operand; 3454 3455 JSValue v = callFrame->r(func).jsValue(); 3456 3457 ConstructData constructData; 3458 ConstructType constructType = v.getConstructData(constructData); 3459 3460 if (constructType == ConstructTypeJS) { 3461 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain; 3462 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); 3463 3464 Structure* structure; 3465 JSValue prototype = callFrame->r(proto).jsValue(); 3466 if (prototype.isObject()) 3467 structure = asObject(prototype)->inheritorID(); 3468 else 3469 structure = callDataScopeChain->globalObject->emptyObjectStructure(); 3470 JSObject* newObject = new (globalData) JSObject(structure); 3471 3472 callFrame->r(thisRegister) = JSValue(newObject); // "this" value 3473 3474 CallFrame* previousCallFrame = callFrame; 3475 3476 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); 3477 if (UNLIKELY(!callFrame)) { 3478 callFrame = previousCallFrame; 3479 exceptionValue = createStackOverflowError(callFrame); 3480 goto vm_throw; 3481 } 3482 3483 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v)); 3484 vPC = newCodeBlock->instructions().begin(); 3485 3486 #if ENABLE(OPCODE_STATS) 3487 OpcodeStats::resetLastInstruction(); 3488 #endif 3489 3490 NEXT_INSTRUCTION(); 3491 } 3492 3493 if (constructType == ConstructTypeHost) { 3494 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1); 3495 3496 ScopeChainNode* scopeChain = callFrame->scopeChain(); 3497 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); 3498 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0); 3499 3500 JSValue returnValue; 3501 { 3502 SamplingTool::HostCallRecord callRecord(m_sampler.get()); 3503 returnValue = constructData.native.function(newCallFrame, asObject(v), args); 3504 } 3505 CHECK_FOR_EXCEPTION(); 3506 callFrame->r(dst) = JSValue(returnValue); 3507 3508 vPC += OPCODE_LENGTH(op_construct); 3509 NEXT_INSTRUCTION(); 3510 } 3511 3512 ASSERT(constructType == ConstructTypeNone); 3513 3514 exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock()); 3515 goto vm_throw; 3516 } 3517 DEFINE_OPCODE(op_construct_verify) { 3518 /* construct_verify dst(r) override(r) 3519 3520 Verifies that register dst holds an object. If not, moves 3521 the object in register override to register dst. 3522 */ 3523 3524 int dst = vPC[1].u.operand; 3525 if (LIKELY(callFrame->r(dst).jsValue().isObject())) { 3526 vPC += OPCODE_LENGTH(op_construct_verify); 3527 NEXT_INSTRUCTION(); 3528 } 3529 3530 int override = vPC[2].u.operand; 3531 callFrame->r(dst) = callFrame->r(override); 3532 3533 vPC += OPCODE_LENGTH(op_construct_verify); 3534 NEXT_INSTRUCTION(); 3535 } 3536 DEFINE_OPCODE(op_strcat) { 3537 int dst = vPC[1].u.operand; 3538 int src = vPC[2].u.operand; 3539 int count = vPC[3].u.operand; 3540 3541 callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count); 3542 CHECK_FOR_EXCEPTION(); 3543 vPC += OPCODE_LENGTH(op_strcat); 3544 3545 NEXT_INSTRUCTION(); 3546 } 3547 DEFINE_OPCODE(op_to_primitive) { 3548 int dst = vPC[1].u.operand; 3549 int src = vPC[2].u.operand; 3550 3551 callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame); 3552 vPC += OPCODE_LENGTH(op_to_primitive); 3553 3554 NEXT_INSTRUCTION(); 3555 } 3556 DEFINE_OPCODE(op_push_scope) { 3557 /* push_scope scope(r) 3558 3559 Converts register scope to object, and pushes it onto the top 3560 of the current scope chain. The contents of the register scope 3561 are replaced by the result of toObject conversion of the scope. 3562 */ 3563 int scope = vPC[1].u.operand; 3564 JSValue v = callFrame->r(scope).jsValue(); 3565 JSObject* o = v.toObject(callFrame); 3566 CHECK_FOR_EXCEPTION(); 3567 3568 callFrame->r(scope) = JSValue(o); 3569 callFrame->setScopeChain(callFrame->scopeChain()->push(o)); 3570 3571 vPC += OPCODE_LENGTH(op_push_scope); 3572 NEXT_INSTRUCTION(); 3573 } 3574 DEFINE_OPCODE(op_pop_scope) { 3575 /* pop_scope 3576 3577 Removes the top item from the current scope chain. 3578 */ 3579 callFrame->setScopeChain(callFrame->scopeChain()->pop()); 3580 3581 vPC += OPCODE_LENGTH(op_pop_scope); 3582 NEXT_INSTRUCTION(); 3583 } 3584 DEFINE_OPCODE(op_get_pnames) { 3585 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset) 3586 3587 Creates a property name list for register base and puts it 3588 in register dst, initializing i and size for iteration. If 3589 base is undefined or null, jumps to breakTarget. 3590 */ 3591 int dst = vPC[1].u.operand; 3592 int base = vPC[2].u.operand; 3593 int i = vPC[3].u.operand; 3594 int size = vPC[4].u.operand; 3595 int breakTarget = vPC[5].u.operand; 3596 3597 JSValue v = callFrame->r(base).jsValue(); 3598 if (v.isUndefinedOrNull()) { 3599 vPC += breakTarget; 3600 NEXT_INSTRUCTION(); 3601 } 3602 3603 JSObject* o = v.toObject(callFrame); 3604 Structure* structure = o->structure(); 3605 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); 3606 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame)) 3607 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o); 3608 3609 callFrame->r(dst) = jsPropertyNameIterator; 3610 callFrame->r(base) = JSValue(o); 3611 callFrame->r(i) = Register::withInt(0); 3612 callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size()); 3613 vPC += OPCODE_LENGTH(op_get_pnames); 3614 NEXT_INSTRUCTION(); 3615 } 3616 DEFINE_OPCODE(op_next_pname) { 3617 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset) 3618 3619 Copies the next name from the property name list in 3620 register iter to dst, then jumps to offset target. If there are no 3621 names left, invalidates the iterator and continues to the next 3622 instruction. 3623 */ 3624 int dst = vPC[1].u.operand; 3625 int base = vPC[2].u.operand; 3626 int i = vPC[3].u.operand; 3627 int size = vPC[4].u.operand; 3628 int iter = vPC[5].u.operand; 3629 int target = vPC[6].u.operand; 3630 3631 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator(); 3632 while (callFrame->r(i).i() != callFrame->r(size).i()) { 3633 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i()); 3634 callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1); 3635 if (key) { 3636 CHECK_FOR_TIMEOUT(); 3637 callFrame->r(dst) = key; 3638 vPC += target; 3639 NEXT_INSTRUCTION(); 3640 } 3641 } 3642 3643 vPC += OPCODE_LENGTH(op_next_pname); 3644 NEXT_INSTRUCTION(); 3645 } 3646 DEFINE_OPCODE(op_jmp_scopes) { 3647 /* jmp_scopes count(n) target(offset) 3648 3649 Removes the a number of items from the current scope chain 3650 specified by immediate number count, then jumps to offset 3651 target. 3652 */ 3653 int count = vPC[1].u.operand; 3654 int target = vPC[2].u.operand; 3655 3656 ScopeChainNode* tmp = callFrame->scopeChain(); 3657 while (count--) 3658 tmp = tmp->pop(); 3659 callFrame->setScopeChain(tmp); 3660 3661 vPC += target; 3662 NEXT_INSTRUCTION(); 3663 } 3664 #if HAVE(COMPUTED_GOTO) 3665 // Appease GCC 3666 goto *(&&skip_new_scope); 3667 #endif 3668 DEFINE_OPCODE(op_push_new_scope) { 3669 /* new_scope dst(r) property(id) value(r) 3670 3671 Constructs a new StaticScopeObject with property set to value. That scope 3672 object is then pushed onto the ScopeChain. The scope object is then stored 3673 in dst for GC. 3674 */ 3675 callFrame->setScopeChain(createExceptionScope(callFrame, vPC)); 3676 3677 vPC += OPCODE_LENGTH(op_push_new_scope); 3678 NEXT_INSTRUCTION(); 3679 } 3680 #if HAVE(COMPUTED_GOTO) 3681 skip_new_scope: 3682 #endif 3683 DEFINE_OPCODE(op_catch) { 3684 /* catch ex(r) 3685 3686 Retrieves the VM's current exception and puts it in register 3687 ex. This is only valid after an exception has been raised, 3688 and usually forms the beginning of an exception handler. 3689 */ 3690 ASSERT(exceptionValue); 3691 ASSERT(!globalData->exception); 3692 int ex = vPC[1].u.operand; 3693 callFrame->r(ex) = exceptionValue; 3694 exceptionValue = JSValue(); 3695 3696 vPC += OPCODE_LENGTH(op_catch); 3697 NEXT_INSTRUCTION(); 3698 } 3699 DEFINE_OPCODE(op_throw) { 3700 /* throw ex(r) 3701 3702 Throws register ex as an exception. This involves three 3703 steps: first, it is set as the current exception in the 3704 VM's internal state, then the stack is unwound until an 3705 exception handler or a native code boundary is found, and 3706 then control resumes at the exception handler if any or 3707 else the script returns control to the nearest native caller. 3708 */ 3709 3710 int ex = vPC[1].u.operand; 3711 exceptionValue = callFrame->r(ex).jsValue(); 3712 3713 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true); 3714 if (!handler) { 3715 *exception = exceptionValue; 3716 return jsNull(); 3717 } 3718 3719 vPC = callFrame->codeBlock()->instructions().begin() + handler->target; 3720 NEXT_INSTRUCTION(); 3721 } 3722 DEFINE_OPCODE(op_new_error) { 3723 /* new_error dst(r) type(n) message(k) 3724 3725 Constructs a new Error instance using the original 3726 constructor, using immediate number n as the type and 3727 constant message as the message string. The result is 3728 written to register dst. 3729 */ 3730 int dst = vPC[1].u.operand; 3731 int type = vPC[2].u.operand; 3732 int message = vPC[3].u.operand; 3733 3734 CodeBlock* codeBlock = callFrame->codeBlock(); 3735 callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL())); 3736 3737 vPC += OPCODE_LENGTH(op_new_error); 3738 NEXT_INSTRUCTION(); 3739 } 3740 DEFINE_OPCODE(op_end) { 3741 /* end result(r) 3742 3743 Return register result as the value of a global or eval 3744 program. Return control to the calling native code. 3745 */ 3746 3747 if (callFrame->codeBlock()->needsFullScopeChain()) { 3748 ScopeChainNode* scopeChain = callFrame->scopeChain(); 3749 ASSERT(scopeChain->refCount > 1); 3750 scopeChain->deref(); 3751 } 3752 int result = vPC[1].u.operand; 3753 return callFrame->r(result).jsValue(); 3754 } 3755 DEFINE_OPCODE(op_put_getter) { 3756 /* put_getter base(r) property(id) function(r) 3757 3758 Sets register function on register base as the getter named 3759 by identifier property. Base and function are assumed to be 3760 objects as this op should only be used for getters defined 3761 in object literal form. 3762 3763 Unlike many opcodes, this one does not write any output to 3764 the register file. 3765 */ 3766 int base = vPC[1].u.operand; 3767 int property = vPC[2].u.operand; 3768 int function = vPC[3].u.operand; 3769 3770 ASSERT(callFrame->r(base).jsValue().isObject()); 3771 JSObject* baseObj = asObject(callFrame->r(base).jsValue()); 3772 Identifier& ident = callFrame->codeBlock()->identifier(property); 3773 ASSERT(callFrame->r(function).jsValue().isObject()); 3774 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue())); 3775 3776 vPC += OPCODE_LENGTH(op_put_getter); 3777 NEXT_INSTRUCTION(); 3778 } 3779 DEFINE_OPCODE(op_put_setter) { 3780 /* put_setter base(r) property(id) function(r) 3781 3782 Sets register function on register base as the setter named 3783 by identifier property. Base and function are assumed to be 3784 objects as this op should only be used for setters defined 3785 in object literal form. 3786 3787 Unlike many opcodes, this one does not write any output to 3788 the register file. 3789 */ 3790 int base = vPC[1].u.operand; 3791 int property = vPC[2].u.operand; 3792 int function = vPC[3].u.operand; 3793 3794 ASSERT(callFrame->r(base).jsValue().isObject()); 3795 JSObject* baseObj = asObject(callFrame->r(base).jsValue()); 3796 Identifier& ident = callFrame->codeBlock()->identifier(property); 3797 ASSERT(callFrame->r(function).jsValue().isObject()); 3798 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0); 3799 3800 vPC += OPCODE_LENGTH(op_put_setter); 3801 NEXT_INSTRUCTION(); 3802 } 3803 DEFINE_OPCODE(op_method_check) { 3804 vPC++; 3805 NEXT_INSTRUCTION(); 3806 } 3807 DEFINE_OPCODE(op_jsr) { 3808 /* jsr retAddrDst(r) target(offset) 3809 3810 Places the address of the next instruction into the retAddrDst 3811 register and jumps to offset target from the current instruction. 3812 */ 3813 int retAddrDst = vPC[1].u.operand; 3814 int target = vPC[2].u.operand; 3815 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr); 3816 3817 vPC += target; 3818 NEXT_INSTRUCTION(); 3819 } 3820 DEFINE_OPCODE(op_sret) { 3821 /* sret retAddrSrc(r) 3822 3823 Jumps to the address stored in the retAddrSrc register. This 3824 differs from op_jmp because the target address is stored in a 3825 register, not as an immediate. 3826 */ 3827 int retAddrSrc = vPC[1].u.operand; 3828 vPC = callFrame->r(retAddrSrc).vPC(); 3829 NEXT_INSTRUCTION(); 3830 } 3831 DEFINE_OPCODE(op_debug) { 3832 /* debug debugHookID(n) firstLine(n) lastLine(n) 3833 3834 Notifies the debugger of the current state of execution. This opcode 3835 is only generated while the debugger is attached. 3836 */ 3837 int debugHookID = vPC[1].u.operand; 3838 int firstLine = vPC[2].u.operand; 3839 int lastLine = vPC[3].u.operand; 3840 3841 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); 3842 3843 vPC += OPCODE_LENGTH(op_debug); 3844 NEXT_INSTRUCTION(); 3845 } 3846 DEFINE_OPCODE(op_profile_will_call) { 3847 /* op_profile_will_call function(r) 3848 3849 Notifies the profiler of the beginning of a function call. This opcode 3850 is only generated if developer tools are enabled. 3851 */ 3852 int function = vPC[1].u.operand; 3853 3854 if (*enabledProfilerReference) 3855 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue()); 3856 3857 vPC += OPCODE_LENGTH(op_profile_will_call); 3858 NEXT_INSTRUCTION(); 3859 } 3860 DEFINE_OPCODE(op_profile_did_call) { 3861 /* op_profile_did_call function(r) 3862 3863 Notifies the profiler of the end of a function call. This opcode 3864 is only generated if developer tools are enabled. 3865 */ 3866 int function = vPC[1].u.operand; 3867 3868 if (*enabledProfilerReference) 3869 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue()); 3870 3871 vPC += OPCODE_LENGTH(op_profile_did_call); 3872 NEXT_INSTRUCTION(); 3873 } 3874 vm_throw: { 3875 globalData->exception = JSValue(); 3876 if (!tickCount) { 3877 // The exceptionValue is a lie! (GCC produces bad code for reasons I 3878 // cannot fathom if we don't assign to the exceptionValue before branching) 3879 exceptionValue = createInterruptedExecutionException(globalData); 3880 } 3881 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false); 3882 if (!handler) { 3883 *exception = exceptionValue; 3884 return jsNull(); 3885 } 3886 3887 vPC = callFrame->codeBlock()->instructions().begin() + handler->target; 3888 NEXT_INSTRUCTION(); 3889 } 3890 } 3891 #if !HAVE(COMPUTED_GOTO) 3892 } // iterator loop ends 3893 #endif 3894 #endif // USE(INTERPRETER) 3895 #undef NEXT_INSTRUCTION 3896 #undef DEFINE_OPCODE 3897 #undef CHECK_FOR_EXCEPTION 3898 #undef CHECK_FOR_TIMEOUT 3899 } 3900 3901 JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const 3902 { 3903 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function); 3904 if (!functionCallFrame) 3905 return jsNull(); 3906 3907 CodeBlock* codeBlock = functionCallFrame->codeBlock(); 3908 if (codeBlock->usesArguments()) { 3909 ASSERT(codeBlock->codeType() == FunctionCode); 3910 SymbolTable& symbolTable = *codeBlock->symbolTable(); 3911 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex(); 3912 if (!functionCallFrame->r(argumentsIndex).jsValue()) { 3913 Arguments* arguments = new (callFrame) Arguments(functionCallFrame); 3914 functionCallFrame->setCalleeArguments(arguments); 3915 functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments); 3916 } 3917 return functionCallFrame->r(argumentsIndex).jsValue(); 3918 } 3919 3920 Arguments* arguments = functionCallFrame->optionalCalleeArguments(); 3921 if (!arguments) { 3922 arguments = new (functionCallFrame) Arguments(functionCallFrame); 3923 arguments->copyRegisters(); 3924 callFrame->setCalleeArguments(arguments); 3925 } 3926 3927 return arguments; 3928 } 3929 3930 JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const 3931 { 3932 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function); 3933 if (!functionCallFrame) 3934 return jsNull(); 3935 3936 CallFrame* callerFrame = functionCallFrame->callerFrame(); 3937 if (callerFrame->hasHostCallFrameFlag()) 3938 return jsNull(); 3939 3940 JSValue caller = callerFrame->callee(); 3941 if (!caller) 3942 return jsNull(); 3943 3944 return caller; 3945 } 3946 3947 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const 3948 { 3949 function = JSValue(); 3950 lineNumber = -1; 3951 sourceURL = UString(); 3952 3953 CallFrame* callerFrame = callFrame->callerFrame(); 3954 if (callerFrame->hasHostCallFrameFlag()) 3955 return; 3956 3957 CodeBlock* callerCodeBlock = callerFrame->codeBlock(); 3958 if (!callerCodeBlock) 3959 return; 3960 3961 unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC()); 3962 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1); 3963 sourceID = callerCodeBlock->ownerExecutable()->sourceID(); 3964 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL(); 3965 function = callerFrame->callee(); 3966 } 3967 3968 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function) 3969 { 3970 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) { 3971 if (candidate->callee() == function) 3972 return candidate; 3973 } 3974 return 0; 3975 } 3976 3977 void Interpreter::enableSampler() 3978 { 3979 #if ENABLE(OPCODE_SAMPLING) 3980 if (!m_sampler) { 3981 m_sampler.set(new SamplingTool(this)); 3982 m_sampler->setup(); 3983 } 3984 #endif 3985 } 3986 void Interpreter::dumpSampleData(ExecState* exec) 3987 { 3988 #if ENABLE(OPCODE_SAMPLING) 3989 if (m_sampler) 3990 m_sampler->dump(exec); 3991 #else 3992 UNUSED_PARAM(exec); 3993 #endif 3994 } 3995 void Interpreter::startSampling() 3996 { 3997 #if ENABLE(SAMPLING_THREAD) 3998 if (!m_sampleEntryDepth) 3999 SamplingThread::start(); 4000 4001 m_sampleEntryDepth++; 4002 #endif 4003 } 4004 void Interpreter::stopSampling() 4005 { 4006 #if ENABLE(SAMPLING_THREAD) 4007 m_sampleEntryDepth--; 4008 if (!m_sampleEntryDepth) 4009 SamplingThread::stop(); 4010 #endif 4011 } 4012 4013 } // namespace JSC 4014