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