2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
33 #include "BatchedTransitionOptimizer.h"
34 #include "CodeBlock.h"
35 #include "DebuggerCallFrame.h"
36 #include "ExceptionHelpers.h"
37 #include "ExecState.h"
38 #include "GlobalEvalFunction.h"
39 #include "JSActivation.h"
41 #include "JSFunction.h"
42 #include "JSNotAnObject.h"
43 #include "JSPropertyNameIterator.h"
44 #include "JSStaticScopeObject.h"
46 #include "ObjectPrototype.h"
49 #include "RegExpObject.h"
50 #include "RegExpPrototype.h"
52 #include "collector.h"
54 #include "operations.h"
55 #include "SamplingTool.h"
59 #include <mach/mach.h>
78 // Preferred number of milliseconds between each timeout check
79 static const int preferredScriptCheckTimeInterval = 1000;
81 #if HAVE(COMPUTED_GOTO)
82 static void* op_throw_end_indirect;
83 static void* op_call_indirect;
86 // Returns the depth of the scope chain within a given call frame.
87 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89 if (!codeBlock->needsFullScopeChain)
92 ScopeChainIterator iter = sc.begin();
93 ScopeChainIterator end = sc.end();
94 while (!(*iter)->isActivationObject()) {
103 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
104 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
105 static bool fastIsNumber(JSValue* value, double& arg)
107 if (JSImmediate::isNumber(value))
108 arg = JSImmediate::getTruncatedInt32(value);
109 else if (Heap::isNumber(static_cast<JSCell*>(value)))
110 arg = static_cast<JSNumberCell*>(value)->value();
116 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
117 static bool fastToInt32(JSValue* value, int32_t& arg)
119 if (JSImmediate::isNumber(value))
120 arg = JSImmediate::getTruncatedInt32(value);
121 else if (Heap::isNumber(static_cast<JSCell*>(value)))
122 arg = static_cast<JSNumberCell*>(value)->toInt32();
128 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
130 if (JSImmediate::isNumber(value)) {
131 if (JSImmediate::getTruncatedUInt32(value, arg))
134 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
136 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
137 arg = static_cast<JSNumberCell*>(value)->toUInt32();
143 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
145 if (JSImmediate::areBothImmediateNumbers(v1, v2))
146 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
150 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
155 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
156 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
158 if (wasNotString1 | wasNotString2)
161 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
164 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
166 if (JSImmediate::areBothImmediateNumbers(v1, v2))
167 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
171 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
176 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
177 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
179 if (wasNotString1 | wasNotString2)
182 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
185 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
187 // exception for the Date exception in defaultValue()
188 JSValue* p1 = v1->toPrimitive(exec);
189 JSValue* p2 = v2->toPrimitive(exec);
191 if (p1->isString() || p2->isString()) {
192 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
194 return throwOutOfMemoryError(exec);
195 return jsString(exec, value.release());
198 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
201 // Fast-path choices here are based on frequency data from SunSpider:
202 // <times> Add case: <t1> <t2>
203 // ---------------------------
204 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
205 // 247412 Add case: 5 5
206 // 20900 Add case: 5 6
207 // 13962 Add case: 5 3
208 // 4000 Add case: 3 5
210 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
214 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
215 return jsNumber(exec, left + right);
217 if (v1->isString() && v2->isString()) {
218 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
220 return throwOutOfMemoryError(exec);
221 return jsString(exec, value.release());
224 // All other cases are pretty uncommon
225 return jsAddSlowCase(exec, v1, v2);
228 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
230 if (v->isUndefined())
231 return jsNontrivialString(exec, "undefined");
233 return jsNontrivialString(exec, "boolean");
235 return jsNontrivialString(exec, "number");
237 return jsNontrivialString(exec, "string");
239 // Return "undefined" for objects that should be treated
240 // as null when doing comparisons.
241 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
242 return jsNontrivialString(exec, "undefined");
244 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
245 return jsNontrivialString(exec, "function");
247 return jsNontrivialString(exec, "object");
250 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
252 int dst = (vPC + 1)->u.operand;
253 int property = (vPC + 2)->u.operand;
255 ScopeChainIterator iter = scopeChain->begin();
256 ScopeChainIterator end = scopeChain->end();
259 Identifier& ident = codeBlock->identifiers[property];
262 PropertySlot slot(o);
263 if (o->getPropertySlot(exec, ident, slot)) {
264 JSValue* result = slot.getValue(exec, ident);
265 exceptionValue = exec->exception();
271 } while (++iter != end);
272 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
276 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
278 int dst = (vPC + 1)->u.operand;
279 int property = (vPC + 2)->u.operand;
280 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
282 ScopeChainIterator iter = scopeChain->begin();
283 ScopeChainIterator end = scopeChain->end();
289 Identifier& ident = codeBlock->identifiers[property];
292 PropertySlot slot(o);
293 if (o->getPropertySlot(exec, ident, slot)) {
294 JSValue* result = slot.getValue(exec, ident);
295 exceptionValue = exec->exception();
301 } while (++iter != end);
302 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
306 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
308 ScopeChainIterator iter = scopeChain->begin();
309 ScopeChainIterator next = iter;
311 ScopeChainIterator end = scopeChain->end();
318 if (next == end || base->getPropertySlot(exec, property, slot))
325 ASSERT_NOT_REACHED();
329 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
331 int dst = (vPC + 1)->u.operand;
332 int property = (vPC + 2)->u.operand;
333 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
336 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
338 int baseDst = (vPC + 1)->u.operand;
339 int propDst = (vPC + 2)->u.operand;
340 int property = (vPC + 3)->u.operand;
342 ScopeChainIterator iter = scopeChain->begin();
343 ScopeChainIterator end = scopeChain->end();
345 // FIXME: add scopeDepthIsZero optimization
349 Identifier& ident = codeBlock->identifiers[property];
353 PropertySlot slot(base);
354 if (base->getPropertySlot(exec, ident, slot)) {
355 JSValue* result = slot.getValue(exec, ident);
356 exceptionValue = exec->exception();
364 } while (iter != end);
366 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
370 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
372 int baseDst = (vPC + 1)->u.operand;
373 int funcDst = (vPC + 2)->u.operand;
374 int property = (vPC + 3)->u.operand;
376 ScopeChainIterator iter = scopeChain->begin();
377 ScopeChainIterator end = scopeChain->end();
379 // FIXME: add scopeDepthIsZero optimization
383 Identifier& ident = codeBlock->identifiers[property];
387 PropertySlot slot(base);
388 if (base->getPropertySlot(exec, ident, slot)) {
389 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
390 // However, section 10.2.3 says that in the case where the value provided
391 // by the caller is null, the global object should be used. It also says
392 // that the section does not apply to internal functions, but for simplicity
393 // of implementation we use the global object anyway here. This guarantees
394 // that in host objects you always get a valid object for this.
395 // We also handle wrapper substitution for the global object at the same time.
396 JSObject* thisObj = base->toThisObject(exec);
397 JSValue* result = slot.getValue(exec, ident);
398 exceptionValue = exec->exception();
402 r[baseDst] = thisObj;
407 } while (iter != end);
409 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
413 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
415 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
416 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
417 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
418 callFrame[RegisterFile::CallerRegisters] = r;
419 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
420 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
421 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
422 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
423 callFrame[RegisterFile::Callee] = function;
424 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
427 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
429 size_t registerOffset = argv + newCodeBlock->numLocals;
430 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
432 if (argc == newCodeBlock->numParameters) { // correct number of arguments
433 if (!registerFile->grow(size)) {
434 exceptionValue = createStackOverflowError(exec);
438 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
439 if (!registerFile->grow(size)) {
440 exceptionValue = createStackOverflowError(exec);
445 int omittedArgCount = newCodeBlock->numParameters - argc;
446 Register* endOfParams = r - newCodeBlock->numVars;
447 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
448 (*it) = jsUndefined();
449 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
450 int shift = argc + RegisterFile::CallFrameHeaderSize;
451 registerOffset += shift;
454 if (!registerFile->grow(size)) {
455 exceptionValue = createStackOverflowError(exec);
460 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
461 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
462 for ( ; it != end; ++it)
466 // initialize local variable slots
467 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
468 (*it) = jsUndefined();
470 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
471 r[i] = newCodeBlock->constantRegisters[i];
476 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
478 if (newCodeBlock->needsFullScopeChain) {
479 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
480 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
482 return callDataScopeChain->copy()->push(activation);
485 return callDataScopeChain;
488 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
490 if (value->isObject())
492 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
496 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
499 return jsUndefined();
501 JSValue* program = r[argv + 1].jsValue(exec);
503 if (!program->isString())
506 Profiler** profiler = Profiler::enabledProfilerReference();
508 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
510 UString programSource = static_cast<JSString*>(program)->value();
512 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
516 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
519 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
527 , m_ctiArrayLengthTrampoline(0)
528 , m_ctiStringLengthTrampoline(0)
529 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
533 , m_timeAtLastCheckTimeout(0)
535 , m_timeoutCheckCount(0)
536 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
538 privateExecute(InitializeAndReturn);
540 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
541 void* storage = fastMalloc(sizeof(CollectorBlock));
543 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
544 m_jsArrayVptr = jsArray->vptr();
545 static_cast<JSCell*>(jsArray)->~JSCell();
547 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
548 m_jsStringVptr = jsString->vptr();
549 static_cast<JSCell*>(jsString)->~JSCell();
551 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
552 m_jsFunctionVptr = jsFunction->vptr();
553 static_cast<JSCell*>(jsFunction)->~JSCell();
561 if (m_ctiArrayLengthTrampoline)
562 fastFree(m_ctiArrayLengthTrampoline);
563 if (m_ctiStringLengthTrampoline)
564 fastFree(m_ctiStringLengthTrampoline);
570 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
572 ScopeChain sc(scopeChain);
573 JSGlobalObject* globalObject = sc.globalObject();
574 codeBlock->dump(globalObject->globalExec());
575 dumpRegisters(codeBlock, registerFile, r);
578 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
580 printf("Register frame: \n\n");
581 printf("----------------------------------------------------\n");
582 printf(" use | address | value \n");
583 printf("----------------------------------------------------\n");
588 if (codeBlock->codeType == GlobalCode) {
589 it = registerFile->lastGlobal();
590 end = it + registerFile->numGlobals();
592 printf("[global var] | %10p | %10p \n", it, (*it).v());
595 printf("----------------------------------------------------\n");
598 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
599 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
600 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
601 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
602 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
603 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
604 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
605 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
606 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
607 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
608 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
609 printf("----------------------------------------------------\n");
611 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
612 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
615 printf("[param] | %10p | %10p \n", it, (*it).v());
619 printf("----------------------------------------------------\n");
621 if (codeBlock->codeType != GlobalCode) {
622 end = it + codeBlock->numVars;
625 printf("[var] | %10p | %10p \n", it, (*it).v());
628 printf("----------------------------------------------------\n");
632 end = it + codeBlock->numTemporaries;
635 printf("[temp] | %10p | %10p \n", it, (*it).v());
643 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
645 bool Machine::isOpcode(Opcode opcode)
647 #if HAVE(COMPUTED_GOTO)
648 return opcode != HashTraits<Opcode>::emptyValue()
649 && !HashTraits<Opcode>::isDeletedValue(opcode)
650 && m_opcodeIDTable.contains(opcode);
652 return opcode >= 0 && opcode <= op_end;
658 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
660 CodeBlock* oldCodeBlock = codeBlock;
661 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
663 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
664 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
665 if (callFrame[RegisterFile::Callee].jsValue(exec))
666 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
668 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
671 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
672 if (callFrame[RegisterFile::Callee].jsValue(exec))
673 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
675 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
678 if (oldCodeBlock->needsFullScopeChain)
681 // If this call frame created an activation, tear it off.
682 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
683 ASSERT(activation->isActivationObject());
684 activation->copyRegisters();
687 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
691 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
692 r = callFrame[RegisterFile::CallerRegisters].r();
693 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
694 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
699 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
701 // Set up the exception object
703 if (exceptionValue->isObject()) {
704 JSObject* exception = static_cast<JSObject*>(exceptionValue);
705 if (exception->isNotAnObjectErrorStub()) {
706 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
707 exceptionValue = exception;
709 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
710 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
711 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
712 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
713 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
714 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
719 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
720 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
722 // We only hit this path for error messages and throw statements, which don't have a specific failure position
723 // So we just give the full range of the error/throw statement.
724 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
725 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
727 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
728 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
729 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
732 if (exception->isWatchdogException()) {
733 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
734 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
741 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
742 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
743 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
746 // Calculate an exception handler vPC, unwinding call frames as necessary.
749 Instruction* handlerVPC;
751 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
752 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
756 // Now unwind the scope chain within the exception handler's call frame.
758 ScopeChain sc(scopeChain);
759 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
760 ASSERT(scopeDelta >= 0);
763 setScopeChain(exec, scopeChain, sc.node());
768 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
770 if (m_reentryDepth >= MaxReentryDepth) {
771 *exception = createStackOverflowError(exec);
775 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
777 size_t oldSize = m_registerFile.size();
778 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
779 if (!m_registerFile.grow(newSize)) {
780 *exception = createStackOverflowError(exec);
784 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
785 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
786 globalObject->copyGlobalsTo(m_registerFile);
788 Register* callFrame = m_registerFile.base() + oldSize;
790 // a 0 codeBlock indicates a built-in caller
791 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
793 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
794 r[codeBlock->thisRegister] = thisObj;
796 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
797 r[i] = codeBlock->constantRegisters[i];
799 if (codeBlock->needsFullScopeChain)
800 scopeChain = scopeChain->copy();
802 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
804 Profiler** profiler = Profiler::enabledProfilerReference();
806 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
810 if (!codeBlock->ctiCode)
811 CTI::compile(this, exec, codeBlock);
812 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
814 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
818 MACHINE_SAMPLING_privateExecuteReturned();
821 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
823 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
824 lastGlobalObject->copyGlobalsTo(m_registerFile);
826 m_registerFile.shrink(oldSize);
830 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
832 if (m_reentryDepth >= MaxReentryDepth) {
833 *exception = createStackOverflowError(exec);
837 int argv = RegisterFile::CallFrameHeaderSize;
838 int argc = args.size() + 1; // implicit "this" parameter
840 size_t oldSize = m_registerFile.size();
841 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
842 *exception = createStackOverflowError(exec);
846 Register* callFrame = m_registerFile.base() + oldSize;
848 // put args in place, including "this"
849 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
852 ArgList::const_iterator end = args.end();
853 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
856 // a 0 codeBlock indicates a built-in caller
857 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
859 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
860 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
862 m_registerFile.shrink(oldSize);
866 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
868 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
870 Profiler** profiler = Profiler::enabledProfilerReference();
872 (*profiler)->willExecute(exec, function);
876 if (!newCodeBlock->ctiCode)
877 CTI::compile(this, exec, newCodeBlock);
878 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
880 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
884 MACHINE_SAMPLING_privateExecuteReturned();
886 m_registerFile.shrink(oldSize);
890 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
892 if (m_reentryDepth >= MaxReentryDepth) {
893 *exception = createStackOverflowError(exec);
897 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
899 JSVariableObject* variableObject;
900 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
902 if (node->object->isVariableObject()) {
903 variableObject = static_cast<JSVariableObject*>(node->object);
908 { // Scope for BatchedTransitionOptimizer
910 BatchedTransitionOptimizer optimizer(variableObject);
912 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
913 Node::VarStack::const_iterator varStackEnd = varStack.end();
914 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
915 const Identifier& ident = (*it).first;
916 if (!variableObject->hasProperty(exec, ident)) {
917 PutPropertySlot slot;
918 variableObject->put(exec, ident, jsUndefined(), slot);
922 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
923 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
924 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
925 PutPropertySlot slot;
926 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
931 size_t oldSize = m_registerFile.size();
932 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
933 if (!m_registerFile.grow(newSize)) {
934 *exception = createStackOverflowError(exec);
938 Register* callFrame = m_registerFile.base() + registerOffset;
940 // a 0 codeBlock indicates a built-in caller
941 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
943 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
944 r[codeBlock->thisRegister] = thisObj;
946 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
947 r[i] = codeBlock->constantRegisters[i];
949 if (codeBlock->needsFullScopeChain)
950 scopeChain = scopeChain->copy();
952 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
954 Profiler** profiler = Profiler::enabledProfilerReference();
956 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
960 if (!codeBlock->ctiCode)
961 CTI::compile(this, exec, codeBlock);
962 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
964 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
968 MACHINE_SAMPLING_privateExecuteReturned();
971 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
973 m_registerFile.shrink(oldSize);
977 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
979 scopeChain = newScopeChain;
980 exec->m_scopeChain = newScopeChain;
983 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
985 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
989 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
991 switch (debugHookID) {
992 case DidEnterCallFrame:
993 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
995 case WillLeaveCallFrame:
996 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
998 case WillExecuteStatement:
999 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1001 case WillExecuteProgram:
1002 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1004 case DidExecuteProgram:
1005 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1007 case DidReachBreakpoint:
1008 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1013 void Machine::resetTimeoutCheck()
1015 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1016 m_timeAtLastCheckTimeout = 0;
1017 m_timeExecuting = 0;
1020 // Returns the time the current thread has spent executing, in milliseconds.
1021 static inline unsigned getCPUTime()
1023 #if PLATFORM(DARWIN)
1024 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1025 thread_basic_info_data_t info;
1027 // Get thread information
1028 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1030 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1031 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1034 #elif HAVE(SYS_TIME_H)
1035 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1037 gettimeofday(&tv, 0);
1038 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1040 QDateTime t = QDateTime::currentDateTime();
1041 return t.toTime_t() * 1000 + t.time().msec();
1042 #elif PLATFORM(WIN_OS)
1045 unsigned long long fileTimeAsLong;
1046 } userTime, kernelTime;
1048 // GetThreadTimes won't accept NULL arguments so we pass these even though
1049 // they're not used.
1050 FILETIME creationTime, exitTime;
1052 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1054 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1056 #error Platform does not have getCurrentTime function
1060 // We have to return a JSValue here, gcc seems to produce worse code if
1061 // we attempt to return a bool
1062 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1064 unsigned currentTime = getCPUTime();
1066 if (!m_timeAtLastCheckTimeout) {
1067 // Suspicious amount of looping in a script -- start timing it
1068 m_timeAtLastCheckTimeout = currentTime;
1072 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1077 m_timeExecuting += timeDiff;
1078 m_timeAtLastCheckTimeout = currentTime;
1080 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1081 // preferredScriptCheckTimeInterval
1082 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1083 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1084 // preferred script check time interval.
1085 if (m_ticksUntilNextTimeoutCheck == 0)
1086 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1088 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1089 if (globalObject->shouldInterruptScript())
1090 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1092 resetTimeoutCheck();
1098 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1100 int dst = (++vPC)->u.operand;
1101 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1102 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1103 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1105 return scopeChain->push(scope);
1108 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1110 JSValue* prototype = structureID->prototypeForLookup(exec);
1111 if (JSImmediate::isImmediate(prototype))
1113 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1114 structureID->setCachedPrototypeChain(chain.release());
1115 return structureID->cachedPrototypeChain();
1118 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1120 // Recursive invocation may already have specialized this instruction.
1121 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1124 if (JSImmediate::isImmediate(baseValue))
1127 // Uncacheable: give up.
1128 if (!slot.isCacheable()) {
1129 vPC[0] = getOpcode(op_put_by_id_generic);
1133 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1134 StructureID* structureID = baseCell->structureID();
1136 if (structureID->isDictionary()) {
1137 vPC[0] = getOpcode(op_put_by_id_generic);
1141 // Cache miss: record StructureID to compare against next time.
1142 StructureID* lastStructureID = vPC[4].u.structureID;
1143 if (structureID != lastStructureID) {
1144 // First miss: record StructureID to compare against next time.
1145 if (!lastStructureID) {
1146 vPC[4] = structureID;
1150 // Second miss: give up.
1151 vPC[0] = getOpcode(op_put_by_id_generic);
1155 // Cache hit: Specialize instruction and ref StructureIDs.
1157 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1158 if (baseCell != slot.base()) {
1159 vPC[0] = getOpcode(op_put_by_id_generic);
1163 // StructureID transition, cache transition info
1164 if (slot.type() == PutPropertySlot::NewProperty) {
1165 vPC[0] = getOpcode(op_put_by_id_transition);
1166 vPC[4] = structureID->previousID();
1167 vPC[5] = structureID;
1168 StructureIDChain* chain = structureID->cachedPrototypeChain();
1170 chain = cachePrototypeChain(exec, structureID);
1172 // This happens if someone has manually inserted null into the prototype chain
1173 vPC[0] = getOpcode(op_put_by_id_generic);
1178 vPC[7] = slot.cachedOffset();
1179 codeBlock->refStructureIDs(vPC);
1183 vPC[0] = getOpcode(op_put_by_id_replace);
1184 vPC[5] = slot.cachedOffset();
1185 codeBlock->refStructureIDs(vPC);
1188 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1190 codeBlock->derefStructureIDs(vPC);
1191 vPC[0] = getOpcode(op_put_by_id);
1195 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1197 // Recursive invocation may already have specialized this instruction.
1198 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1201 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1202 vPC[0] = getOpcode(op_get_array_length);
1206 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1207 vPC[0] = getOpcode(op_get_string_length);
1211 // Uncacheable: give up.
1212 if (!slot.isCacheable()) {
1213 vPC[0] = getOpcode(op_get_by_id_generic);
1217 // FIXME: Cache property access for immediates.
1218 if (JSImmediate::isImmediate(baseValue)) {
1219 vPC[0] = getOpcode(op_get_by_id_generic);
1223 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1225 if (structureID->isDictionary()) {
1226 vPC[0] = getOpcode(op_get_by_id_generic);
1231 StructureID* lastStructureID = vPC[4].u.structureID;
1232 if (structureID != lastStructureID) {
1233 // First miss: record StructureID to compare against next time.
1234 if (!lastStructureID) {
1235 vPC[4] = structureID;
1239 // Second miss: give up.
1240 vPC[0] = getOpcode(op_get_by_id_generic);
1244 // Cache hit: Specialize instruction and ref StructureIDs.
1246 if (slot.slotBase() == baseValue) {
1247 vPC[0] = getOpcode(op_get_by_id_self);
1248 vPC[5] = slot.cachedOffset();
1250 codeBlock->refStructureIDs(vPC);
1254 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1255 ASSERT(slot.slotBase()->isObject());
1257 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1259 // Heavy access to a prototype is a good indication that it's not being
1260 // used as a dictionary.
1261 if (baseObject->structureID()->isDictionary()) {
1262 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1263 baseObject->setStructureID(transition.release());
1264 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1267 vPC[0] = getOpcode(op_get_by_id_proto);
1268 vPC[5] = baseObject->structureID();
1269 vPC[6] = slot.cachedOffset();
1271 codeBlock->refStructureIDs(vPC);
1276 JSObject* o = static_cast<JSObject*>(baseValue);
1277 while (slot.slotBase() != o) {
1278 JSValue* v = o->structureID()->prototypeForLookup(exec);
1280 // If we didn't find base in baseValue's prototype chain, then baseValue
1281 // must be a proxy for another object.
1283 vPC[0] = getOpcode(op_get_by_id_generic);
1287 o = static_cast<JSObject*>(v);
1289 // Heavy access to a prototype is a good indication that it's not being
1290 // used as a dictionary.
1291 if (o->structureID()->isDictionary()) {
1292 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1293 o->setStructureID(transition.release());
1294 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1300 StructureIDChain* chain = structureID->cachedPrototypeChain();
1302 chain = cachePrototypeChain(exec, structureID);
1305 vPC[0] = getOpcode(op_get_by_id_chain);
1306 vPC[4] = structureID;
1309 vPC[7] = slot.cachedOffset();
1310 codeBlock->refStructureIDs(vPC);
1313 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1315 codeBlock->derefStructureIDs(vPC);
1316 vPC[0] = getOpcode(op_get_by_id);
1320 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1322 // One-time initialization of our address tables. We have to put this code
1323 // here because our labels are only in scope inside this function.
1324 if (flag == InitializeAndReturn) {
1325 #if HAVE(COMPUTED_GOTO)
1326 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1327 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1330 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1331 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1332 #undef ADD_OPCODE_ID
1333 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1334 op_throw_end_indirect = &&op_throw_end;
1335 op_call_indirect = &&op_call;
1336 #endif // HAVE(COMPUTED_GOTO)
1341 // Currently with CTI enabled we never interpret functions
1342 ASSERT_NOT_REACHED();
1345 JSValue* exceptionValue = 0;
1346 Instruction* handlerVPC = 0;
1348 Register* registerBase = registerFile->base();
1349 Instruction* vPC = codeBlock->instructions.begin();
1350 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1351 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1353 #define VM_CHECK_EXCEPTION() \
1355 if (UNLIKELY(exec->hadException())) { \
1356 exceptionValue = exec->exception(); \
1361 #if DUMP_OPCODE_STATS
1362 OpcodeStats::resetLastInstruction();
1365 #define CHECK_FOR_TIMEOUT() \
1366 if (!--tickCount) { \
1367 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1369 tickCount = m_ticksUntilNextTimeoutCheck; \
1372 #if HAVE(COMPUTED_GOTO)
1373 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1374 #if DUMP_OPCODE_STATS
1375 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1377 #define BEGIN_OPCODE(opcode) opcode:
1381 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1382 #if DUMP_OPCODE_STATS
1383 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1385 #define BEGIN_OPCODE(opcode) case opcode:
1387 while (1) // iterator loop begins
1388 switch (vPC->u.opcode)
1391 BEGIN_OPCODE(op_new_object) {
1392 /* new_object dst(r)
1394 Constructs a new empty Object instance using the original
1395 constructor, and puts the result in register dst.
1397 int dst = (++vPC)->u.operand;
1398 r[dst] = constructEmptyObject(exec);
1403 BEGIN_OPCODE(op_new_array) {
1404 /* new_array dst(r) firstArg(r) argCount(n)
1406 Constructs a new Array instance using the original
1407 constructor, and puts the result in register dst.
1408 The array will contain argCount elements with values
1409 taken from registers starting at register firstArg.
1411 int dst = (++vPC)->u.operand;
1412 int firstArg = (++vPC)->u.operand;
1413 int argCount = (++vPC)->u.operand;
1414 ArgList args(r + firstArg, argCount);
1415 r[dst] = constructArray(exec, args);
1420 BEGIN_OPCODE(op_new_regexp) {
1421 /* new_regexp dst(r) regExp(re)
1423 Constructs a new RegExp instance using the original
1424 constructor from regexp regExp, and puts the result in
1427 int dst = (++vPC)->u.operand;
1428 int regExp = (++vPC)->u.operand;
1429 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1434 BEGIN_OPCODE(op_mov) {
1435 /* mov dst(r) src(r)
1437 Copies register src to register dst.
1439 int dst = (++vPC)->u.operand;
1440 int src = (++vPC)->u.operand;
1446 BEGIN_OPCODE(op_eq) {
1447 /* eq dst(r) src1(r) src2(r)
1449 Checks whether register src1 and register src2 are equal,
1450 as with the ECMAScript '==' operator, and puts the result
1451 as a boolean in register dst.
1453 int dst = (++vPC)->u.operand;
1454 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1455 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1456 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1457 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1459 JSValue* result = jsBoolean(equal(exec, src1, src2));
1460 VM_CHECK_EXCEPTION();
1467 BEGIN_OPCODE(op_eq_null) {
1468 /* neq dst(r) src(r)
1470 Checks whether register src is null, as with the ECMAScript '!='
1471 operator, and puts the result as a boolean in register dst.
1473 int dst = (++vPC)->u.operand;
1474 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1476 if (src->isUndefinedOrNull()) {
1477 r[dst] = jsBoolean(true);
1482 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1486 BEGIN_OPCODE(op_neq) {
1487 /* neq dst(r) src1(r) src2(r)
1489 Checks whether register src1 and register src2 are not
1490 equal, as with the ECMAScript '!=' operator, and puts the
1491 result as a boolean in register dst.
1493 int dst = (++vPC)->u.operand;
1494 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1495 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1496 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1497 r[dst] = jsBoolean(src1 != src2);
1499 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1500 VM_CHECK_EXCEPTION();
1507 BEGIN_OPCODE(op_neq_null) {
1508 /* neq dst(r) src(r)
1510 Checks whether register src is not null, as with the ECMAScript '!='
1511 operator, and puts the result as a boolean in register dst.
1513 int dst = (++vPC)->u.operand;
1514 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1516 if (src->isUndefinedOrNull()) {
1517 r[dst] = jsBoolean(false);
1522 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1526 BEGIN_OPCODE(op_stricteq) {
1527 /* stricteq dst(r) src1(r) src2(r)
1529 Checks whether register src1 and register src2 are strictly
1530 equal, as with the ECMAScript '===' operator, and puts the
1531 result as a boolean in register dst.
1533 int dst = (++vPC)->u.operand;
1534 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1535 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1536 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1537 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1539 r[dst] = jsBoolean(strictEqual(src1, src2));
1544 BEGIN_OPCODE(op_nstricteq) {
1545 /* nstricteq dst(r) src1(r) src2(r)
1547 Checks whether register src1 and register src2 are not
1548 strictly equal, as with the ECMAScript '!==' operator, and
1549 puts the result as a boolean in register dst.
1551 int dst = (++vPC)->u.operand;
1552 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1553 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1554 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1555 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1557 r[dst] = jsBoolean(!strictEqual(src1, src2));
1562 BEGIN_OPCODE(op_less) {
1563 /* less dst(r) src1(r) src2(r)
1565 Checks whether register src1 is less than register src2, as
1566 with the ECMAScript '<' operator, and puts the result as
1567 a boolean in register dst.
1569 int dst = (++vPC)->u.operand;
1570 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1571 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1572 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1573 VM_CHECK_EXCEPTION();
1579 BEGIN_OPCODE(op_lesseq) {
1580 /* lesseq dst(r) src1(r) src2(r)
1582 Checks whether register src1 is less than or equal to
1583 register src2, as with the ECMAScript '<=' operator, and
1584 puts the result as a boolean in register dst.
1586 int dst = (++vPC)->u.operand;
1587 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1588 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1589 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1590 VM_CHECK_EXCEPTION();
1596 BEGIN_OPCODE(op_pre_inc) {
1597 /* pre_inc srcDst(r)
1599 Converts register srcDst to number, adds one, and puts the result
1600 back in register srcDst.
1602 int srcDst = (++vPC)->u.operand;
1603 JSValue* v = r[srcDst].jsValue(exec);
1604 if (JSImmediate::canDoFastAdditiveOperations(v))
1605 r[srcDst] = JSImmediate::incImmediateNumber(v);
1607 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1608 VM_CHECK_EXCEPTION();
1615 BEGIN_OPCODE(op_pre_dec) {
1616 /* pre_dec srcDst(r)
1618 Converts register srcDst to number, subtracts one, and puts the result
1619 back in register srcDst.
1621 int srcDst = (++vPC)->u.operand;
1622 JSValue* v = r[srcDst].jsValue(exec);
1623 if (JSImmediate::canDoFastAdditiveOperations(v))
1624 r[srcDst] = JSImmediate::decImmediateNumber(v);
1626 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1627 VM_CHECK_EXCEPTION();
1634 BEGIN_OPCODE(op_post_inc) {
1635 /* post_inc dst(r) srcDst(r)
1637 Converts register srcDst to number. The number itself is
1638 written to register dst, and the number plus one is written
1639 back to register srcDst.
1641 int dst = (++vPC)->u.operand;
1642 int srcDst = (++vPC)->u.operand;
1643 JSValue* v = r[srcDst].jsValue(exec);
1644 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1646 r[srcDst] = JSImmediate::incImmediateNumber(v);
1648 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1649 VM_CHECK_EXCEPTION();
1651 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1657 BEGIN_OPCODE(op_post_dec) {
1658 /* post_dec dst(r) srcDst(r)
1660 Converts register srcDst to number. The number itself is
1661 written to register dst, and the number minus one is written
1662 back to register srcDst.
1664 int dst = (++vPC)->u.operand;
1665 int srcDst = (++vPC)->u.operand;
1666 JSValue* v = r[srcDst].jsValue(exec);
1667 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1669 r[srcDst] = JSImmediate::decImmediateNumber(v);
1671 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1672 VM_CHECK_EXCEPTION();
1674 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1680 BEGIN_OPCODE(op_to_jsnumber) {
1681 /* to_jsnumber dst(r) src(r)
1683 Converts register src to number, and puts the result
1686 int dst = (++vPC)->u.operand;
1687 int src = (++vPC)->u.operand;
1688 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1689 VM_CHECK_EXCEPTION();
1696 BEGIN_OPCODE(op_negate) {
1697 /* negate dst(r) src(r)
1699 Converts register src to number, negates it, and puts the
1700 result in register dst.
1702 int dst = (++vPC)->u.operand;
1703 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1705 if (fastIsNumber(src, v))
1706 r[dst] = jsNumber(exec, -v);
1708 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1709 VM_CHECK_EXCEPTION();
1716 BEGIN_OPCODE(op_add) {
1717 /* add dst(r) src1(r) src2(r)
1719 Adds register src1 and register src2, and puts the result
1720 in register dst. (JS add may be string concatenation or
1721 numeric add, depending on the types of the operands.)
1723 int dst = (++vPC)->u.operand;
1724 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1725 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1726 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1727 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1729 JSValue* result = jsAdd(exec, src1, src2);
1730 VM_CHECK_EXCEPTION();
1736 BEGIN_OPCODE(op_mul) {
1737 /* mul dst(r) src1(r) src2(r)
1739 Multiplies register src1 and register src2 (converted to
1740 numbers), and puts the product in register dst.
1742 int dst = (++vPC)->u.operand;
1743 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1744 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1747 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1748 r[dst] = jsNumber(exec, left * right);
1750 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1751 VM_CHECK_EXCEPTION();
1758 BEGIN_OPCODE(op_div) {
1759 /* div dst(r) dividend(r) divisor(r)
1761 Divides register dividend (converted to number) by the
1762 register divisor (converted to number), and puts the
1763 quotient in register dst.
1765 int dst = (++vPC)->u.operand;
1766 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1767 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1770 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1771 r[dst] = jsNumber(exec, left / right);
1773 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1774 VM_CHECK_EXCEPTION();
1780 BEGIN_OPCODE(op_mod) {
1781 /* mod dst(r) dividend(r) divisor(r)
1783 Divides register dividend (converted to number) by
1784 register divisor (converted to number), and puts the
1785 remainder in register dst.
1787 int dst = (++vPC)->u.operand;
1788 int dividend = (++vPC)->u.operand;
1789 int divisor = (++vPC)->u.operand;
1791 JSValue* dividendValue = r[dividend].jsValue(exec);
1792 JSValue* divisorValue = r[divisor].jsValue(exec);
1794 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1795 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1800 double d = dividendValue->toNumber(exec);
1801 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1802 VM_CHECK_EXCEPTION();
1807 BEGIN_OPCODE(op_sub) {
1808 /* sub dst(r) src1(r) src2(r)
1810 Subtracts register src2 (converted to number) from register
1811 src1 (converted to number), and puts the difference in
1814 int dst = (++vPC)->u.operand;
1815 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1816 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1819 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1820 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1821 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1822 r[dst] = jsNumber(exec, left - right);
1824 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1825 VM_CHECK_EXCEPTION();
1831 BEGIN_OPCODE(op_lshift) {
1832 /* lshift dst(r) val(r) shift(r)
1834 Performs left shift of register val (converted to int32) by
1835 register shift (converted to uint32), and puts the result
1838 int dst = (++vPC)->u.operand;
1839 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1840 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1843 if (JSImmediate::areBothImmediateNumbers(val, shift))
1844 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1845 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1846 r[dst] = jsNumber(exec, left << (right & 0x1f));
1848 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1849 VM_CHECK_EXCEPTION();
1856 BEGIN_OPCODE(op_rshift) {
1857 /* rshift dst(r) val(r) shift(r)
1859 Performs arithmetic right shift of register val (converted
1860 to int32) by register shift (converted to
1861 uint32), and puts the result in register dst.
1863 int dst = (++vPC)->u.operand;
1864 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1865 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1868 if (JSImmediate::areBothImmediateNumbers(val, shift))
1869 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1870 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1871 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1873 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1874 VM_CHECK_EXCEPTION();
1881 BEGIN_OPCODE(op_urshift) {
1882 /* rshift dst(r) val(r) shift(r)
1884 Performs logical right shift of register val (converted
1885 to uint32) by register shift (converted to
1886 uint32), and puts the result in register dst.
1888 int dst = (++vPC)->u.operand;
1889 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1890 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1891 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1892 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1894 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1895 VM_CHECK_EXCEPTION();
1902 BEGIN_OPCODE(op_bitand) {
1903 /* bitand dst(r) src1(r) src2(r)
1905 Computes bitwise AND of register src1 (converted to int32)
1906 and register src2 (converted to int32), and puts the result
1909 int dst = (++vPC)->u.operand;
1910 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1911 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1914 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1915 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1916 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1917 r[dst] = jsNumber(exec, left & right);
1919 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1920 VM_CHECK_EXCEPTION();
1927 BEGIN_OPCODE(op_bitxor) {
1928 /* bitxor dst(r) src1(r) src2(r)
1930 Computes bitwise XOR of register src1 (converted to int32)
1931 and register src2 (converted to int32), and puts the result
1934 int dst = (++vPC)->u.operand;
1935 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1936 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1939 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1940 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1941 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1942 r[dst] = jsNumber(exec, left ^ right);
1944 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1945 VM_CHECK_EXCEPTION();
1952 BEGIN_OPCODE(op_bitor) {
1953 /* bitor dst(r) src1(r) src2(r)
1955 Computes bitwise OR of register src1 (converted to int32)
1956 and register src2 (converted to int32), and puts the
1957 result in register dst.
1959 int dst = (++vPC)->u.operand;
1960 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1961 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1964 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1965 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1966 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1967 r[dst] = jsNumber(exec, left | right);
1969 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1970 VM_CHECK_EXCEPTION();
1977 BEGIN_OPCODE(op_bitnot) {
1978 /* bitnot dst(r) src(r)
1980 Computes bitwise NOT of register src1 (converted to int32),
1981 and puts the result in register dst.
1983 int dst = (++vPC)->u.operand;
1984 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1986 if (fastToInt32(src, value))
1987 r[dst] = jsNumber(exec, ~value);
1989 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
1990 VM_CHECK_EXCEPTION();
1996 BEGIN_OPCODE(op_not) {
1997 /* not dst(r) src(r)
1999 Computes logical NOT of register src (converted to
2000 boolean), and puts the result in register dst.
2002 int dst = (++vPC)->u.operand;
2003 int src = (++vPC)->u.operand;
2004 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2005 VM_CHECK_EXCEPTION();
2011 BEGIN_OPCODE(op_instanceof) {
2012 /* instanceof dst(r) value(r) constructor(r)
2014 Tests whether register value is an instance of register
2015 constructor, and puts the boolean result in register dst.
2017 Raises an exception if register constructor is not an
2020 int dst = (++vPC)->u.operand;
2021 int value = (++vPC)->u.operand;
2022 int base = (++vPC)->u.operand;
2024 JSValue* baseVal = r[base].jsValue(exec);
2026 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2029 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2030 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
2035 BEGIN_OPCODE(op_typeof) {
2036 /* typeof dst(r) src(r)
2038 Determines the type string for src according to ECMAScript
2039 rules, and puts the result in register dst.
2041 int dst = (++vPC)->u.operand;
2042 int src = (++vPC)->u.operand;
2043 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2048 BEGIN_OPCODE(op_in) {
2049 /* in dst(r) property(r) base(r)
2051 Tests whether register base has a property named register
2052 property, and puts the boolean result in register dst.
2054 Raises an exception if register constructor is not an
2057 int dst = (++vPC)->u.operand;
2058 int property = (++vPC)->u.operand;
2059 int base = (++vPC)->u.operand;
2061 JSValue* baseVal = r[base].jsValue(exec);
2062 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2065 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2067 JSValue* propName = r[property].jsValue(exec);
2070 if (propName->getUInt32(i))
2071 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2073 Identifier property(exec, propName->toString(exec));
2074 VM_CHECK_EXCEPTION();
2075 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2081 BEGIN_OPCODE(op_resolve) {
2082 /* resolve dst(r) property(id)
2084 Looks up the property named by identifier property in the
2085 scope chain, and writes the resulting value to register
2086 dst. If the property is not found, raises an exception.
2088 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2094 BEGIN_OPCODE(op_resolve_skip) {
2095 /* resolve_skip dst(r) property(id) skip(n)
2097 Looks up the property named by identifier property in the
2098 scope chain skipping the top 'skip' levels, and writes the resulting
2099 value to register dst. If the property is not found, raises an exception.
2101 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2108 BEGIN_OPCODE(op_get_global_var) {
2109 /* get_global_var dst(r) index(n)
2111 Gets the global var at global slot index and places it in register dst.
2113 int dst = (++vPC)->u.operand;
2114 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2115 ASSERT(scope->isGlobalObject());
2116 int index = (++vPC)->u.operand;
2118 r[dst] = scope->registerAt(index);
2122 BEGIN_OPCODE(op_put_global_var) {
2123 /* put_global_var globalObject(c) index(n) value(r)
2125 Puts value into global slot index.
2127 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2128 ASSERT(scope->isGlobalObject());
2129 int index = (++vPC)->u.operand;
2130 int value = (++vPC)->u.operand;
2132 scope->registerAt(index) = r[value].jsValue(exec);
2136 BEGIN_OPCODE(op_get_scoped_var) {
2137 /* get_scoped_var dst(r) index(n) skip(n)
2139 Loads the contents of the index-th local from the scope skip nodes from
2140 the top of the scope chain, and places it in register dst
2142 int dst = (++vPC)->u.operand;
2143 int index = (++vPC)->u.operand;
2144 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2146 ScopeChainIterator iter = scopeChain->begin();
2147 ScopeChainIterator end = scopeChain->end();
2148 ASSERT(iter != end);
2151 ASSERT(iter != end);
2154 ASSERT((*iter)->isVariableObject());
2155 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2156 r[dst] = scope->registerAt(index);
2160 BEGIN_OPCODE(op_put_scoped_var) {
2161 /* put_scoped_var index(n) skip(n) value(r)
2164 int index = (++vPC)->u.operand;
2165 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2166 int value = (++vPC)->u.operand;
2168 ScopeChainIterator iter = scopeChain->begin();
2169 ScopeChainIterator end = scopeChain->end();
2170 ASSERT(iter != end);
2173 ASSERT(iter != end);
2176 ASSERT((*iter)->isVariableObject());
2177 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2178 scope->registerAt(index) = r[value].jsValue(exec);
2182 BEGIN_OPCODE(op_resolve_base) {
2183 /* resolve_base dst(r) property(id)
2185 Searches the scope chain for an object containing
2186 identifier property, and if one is found, writes it to
2187 register dst. If none is found, the outermost scope (which
2188 will be the global object) is stored in register dst.
2190 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2195 BEGIN_OPCODE(op_resolve_with_base) {
2196 /* resolve_with_base baseDst(r) propDst(r) property(id)
2198 Searches the scope chain for an object containing
2199 identifier property, and if one is found, writes it to
2200 register srcDst, and the retrieved property value to register
2201 propDst. If the property is not found, raises an exception.
2203 This is more efficient than doing resolve_base followed by
2204 resolve, or resolve_base followed by get_by_id, as it
2205 avoids duplicate hash lookups.
2207 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2213 BEGIN_OPCODE(op_resolve_func) {
2214 /* resolve_func baseDst(r) funcDst(r) property(id)
2216 Searches the scope chain for an object containing
2217 identifier property, and if one is found, writes the
2218 appropriate object to use as "this" when calling its
2219 properties to register baseDst; and the retrieved property
2220 value to register propDst. If the property is not found,
2221 raises an exception.
2223 This differs from resolve_with_base, because the
2224 global this value will be substituted for activations or
2225 the global object, which is the right behavior for function
2226 calls but not for other property lookup.
2228 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2234 BEGIN_OPCODE(op_get_by_id) {
2235 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2237 Generic property access: Gets the property named by identifier
2238 property from the value base, and puts the result in register dst.
2240 int dst = vPC[1].u.operand;
2241 int base = vPC[2].u.operand;
2242 int property = vPC[3].u.operand;
2244 Identifier& ident = codeBlock->identifiers[property];
2245 JSValue* baseValue = r[base].jsValue(exec);
2246 PropertySlot slot(baseValue);
2247 JSValue* result = baseValue->get(exec, ident, slot);
2248 VM_CHECK_EXCEPTION();
2250 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2256 BEGIN_OPCODE(op_get_by_id_self) {
2257 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2259 Cached property access: Attempts to get a cached property from the
2260 value base. If the cache misses, op_get_by_id_self reverts to
2263 int base = vPC[2].u.operand;
2264 JSValue* baseValue = r[base].jsValue(exec);
2266 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2267 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2268 StructureID* structureID = vPC[4].u.structureID;
2270 if (LIKELY(baseCell->structureID() == structureID)) {
2271 ASSERT(baseCell->isObject());
2272 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2273 int dst = vPC[1].u.operand;
2274 int offset = vPC[5].u.operand;
2276 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2277 r[dst] = baseObject->getDirectOffset(offset);
2284 uncacheGetByID(codeBlock, vPC);
2287 BEGIN_OPCODE(op_get_by_id_proto) {
2288 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2290 Cached property access: Attempts to get a cached property from the
2291 value base's prototype. If the cache misses, op_get_by_id_proto
2292 reverts to op_get_by_id.
2294 int base = vPC[2].u.operand;
2295 JSValue* baseValue = r[base].jsValue(exec);
2297 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2298 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2299 StructureID* structureID = vPC[4].u.structureID;
2301 if (LIKELY(baseCell->structureID() == structureID)) {
2302 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2303 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2304 StructureID* protoStructureID = vPC[5].u.structureID;
2306 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2307 int dst = vPC[1].u.operand;
2308 int offset = vPC[6].u.operand;
2310 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2311 r[dst] = protoObject->getDirectOffset(offset);
2319 uncacheGetByID(codeBlock, vPC);
2322 BEGIN_OPCODE(op_get_by_id_chain) {
2323 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2325 Cached property access: Attempts to get a cached property from the
2326 value base's prototype chain. If the cache misses, op_get_by_id_chain
2327 reverts to op_get_by_id.
2329 int base = vPC[2].u.operand;
2330 JSValue* baseValue = r[base].jsValue(exec);
2332 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2333 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2334 StructureID* structureID = vPC[4].u.structureID;
2336 if (LIKELY(baseCell->structureID() == structureID)) {
2337 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2338 size_t count = vPC[6].u.operand;
2339 RefPtr<StructureID>* end = it + count;
2342 ASSERT(baseCell->isObject());
2343 JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototypeForLookup(exec));
2344 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2348 int dst = vPC[1].u.operand;
2349 int offset = vPC[7].u.operand;
2351 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2352 r[dst] = baseObject->getDirectOffset(offset);
2361 uncacheGetByID(codeBlock, vPC);
2364 BEGIN_OPCODE(op_get_by_id_generic) {
2365 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2367 Generic property access: Gets the property named by identifier
2368 property from the value base, and puts the result in register dst.
2370 int dst = vPC[1].u.operand;
2371 int base = vPC[2].u.operand;
2372 int property = vPC[3].u.operand;
2374 Identifier& ident = codeBlock->identifiers[property];
2376 JSValue* baseValue = r[base].jsValue(exec);
2377 PropertySlot slot(baseValue);
2378 JSValue* result = baseValue->get(exec, ident, slot);
2379 VM_CHECK_EXCEPTION();
2385 BEGIN_OPCODE(op_get_array_length) {
2386 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2388 Cached property access: Gets the length of the array in register base,
2389 and puts the result in register dst. If register base does not hold
2390 an array, op_get_array_length reverts to op_get_by_id.
2393 int base = vPC[2].u.operand;
2394 JSValue* baseValue = r[base].jsValue(exec);
2395 if (LIKELY(isJSArray(baseValue))) {
2396 int dst = vPC[1].u.operand;
2397 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2402 uncacheGetByID(codeBlock, vPC);
2405 BEGIN_OPCODE(op_get_string_length) {
2406 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2408 Cached property access: Gets the length of the string in register base,
2409 and puts the result in register dst. If register base does not hold
2410 a string, op_get_string_length reverts to op_get_by_id.
2413 int base = vPC[2].u.operand;
2414 JSValue* baseValue = r[base].jsValue(exec);
2415 if (LIKELY(isJSString(baseValue))) {
2416 int dst = vPC[1].u.operand;
2417 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2422 uncacheGetByID(codeBlock, vPC);
2425 BEGIN_OPCODE(op_put_by_id) {
2426 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2428 Generic property access: Sets the property named by identifier
2429 property, belonging to register base, to register value.
2431 Unlike many opcodes, this one does not write any output to
2435 int base = vPC[1].u.operand;
2436 int property = vPC[2].u.operand;
2437 int value = vPC[3].u.operand;
2439 JSValue* baseValue = r[base].jsValue(exec);
2441 PutPropertySlot slot;
2442 Identifier& ident = codeBlock->identifiers[property];
2443 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2444 VM_CHECK_EXCEPTION();
2446 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2451 BEGIN_OPCODE(op_put_by_id_transition) {
2452 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2454 Cached property access: Attempts to set a new property with a cached transition
2455 property named by identifier property, belonging to register base,
2456 to register value. If the cache misses, op_put_by_id_transition
2457 reverts to op_put_by_id_generic.
2459 Unlike many opcodes, this one does not write any output to
2462 int base = vPC[1].u.operand;
2463 JSValue* baseValue = r[base].jsValue(exec);
2465 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2466 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2467 StructureID* oldStructureID = vPC[4].u.structureID;
2468 StructureID* newStructureID = vPC[5].u.structureID;
2470 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2471 ASSERT(baseCell->isObject());
2472 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2474 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2476 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2477 while (!proto->isNull()) {
2478 if (UNLIKELY(proto->structureID() != (*it).get())) {
2479 uncachePutByID(codeBlock, vPC);
2483 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2486 baseObject->transitionTo(newStructureID);
2487 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2488 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2490 int value = vPC[3].u.operand;
2491 unsigned offset = vPC[7].u.operand;
2492 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2493 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2500 uncachePutByID(codeBlock, vPC);
2503 BEGIN_OPCODE(op_put_by_id_replace) {
2504 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2506 Cached property access: Attempts to set a pre-existing, cached
2507 property named by identifier property, belonging to register base,
2508 to register value. If the cache misses, op_put_by_id_replace
2509 reverts to op_put_by_id.
2511 Unlike many opcodes, this one does not write any output to
2514 int base = vPC[1].u.operand;
2515 JSValue* baseValue = r[base].jsValue(exec);
2517 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2518 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2519 StructureID* structureID = vPC[4].u.structureID;
2521 if (LIKELY(baseCell->structureID() == structureID)) {
2522 ASSERT(baseCell->isObject());
2523 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2524 int value = vPC[3].u.operand;
2525 unsigned offset = vPC[5].u.operand;
2527 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2528 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2535 uncachePutByID(codeBlock, vPC);
2538 BEGIN_OPCODE(op_put_by_id_generic) {
2539 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2541 Generic property access: Sets the property named by identifier
2542 property, belonging to register base, to register value.
2544 Unlike many opcodes, this one does not write any output to
2547 int base = vPC[1].u.operand;
2548 int property = vPC[2].u.operand;
2549 int value = vPC[3].u.operand;
2551 JSValue* baseValue = r[base].jsValue(exec);
2553 PutPropertySlot slot;
2554 Identifier& ident = codeBlock->identifiers[property];
2555 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2556 VM_CHECK_EXCEPTION();
2561 BEGIN_OPCODE(op_del_by_id) {
2562 /* del_by_id dst(r) base(r) property(id)
2564 Converts register base to Object, deletes the property
2565 named by identifier property from the object, and writes a
2566 boolean indicating success (if true) or failure (if false)
2569 int dst = (++vPC)->u.operand;
2570 int base = (++vPC)->u.operand;
2571 int property = (++vPC)->u.operand;
2573 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2575 Identifier& ident = codeBlock->identifiers[property];
2576 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2577 VM_CHECK_EXCEPTION();
2582 BEGIN_OPCODE(op_get_by_val) {
2583 /* get_by_val dst(r) base(r) property(r)
2585 Converts register base to Object, gets the property named
2586 by register property from the object, and puts the result
2587 in register dst. property is nominally converted to string
2588 but numbers are treated more efficiently.
2590 int dst = (++vPC)->u.operand;
2591 int base = (++vPC)->u.operand;
2592 int property = (++vPC)->u.operand;
2594 JSValue* baseValue = r[base].jsValue(exec);
2595 JSValue* subscript = r[property].jsValue(exec);
2600 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2601 if (LIKELY(isUInt32)) {
2602 if (isJSArray(baseValue)) {
2603 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2604 if (jsArray->canGetIndex(i))
2605 result = jsArray->getIndex(i);
2607 result = jsArray->JSArray::get(exec, i);
2608 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2609 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2611 result = baseValue->get(exec, i);
2613 Identifier property(exec, subscript->toString(exec));
2614 result = baseValue->get(exec, property);
2617 VM_CHECK_EXCEPTION();
2622 BEGIN_OPCODE(op_put_by_val) {
2623 /* put_by_val base(r) property(r) value(r)
2625 Sets register value on register base as the property named
2626 by register property. Base is converted to object
2627 first. register property is nominally converted to string
2628 but numbers are treated more efficiently.
2630 Unlike many opcodes, this one does not write any output to
2633 int base = (++vPC)->u.operand;
2634 int property = (++vPC)->u.operand;
2635 int value = (++vPC)->u.operand;
2637 JSValue* baseValue = r[base].jsValue(exec);
2638 JSValue* subscript = r[property].jsValue(exec);
2642 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2643 if (LIKELY(isUInt32)) {
2644 if (isJSArray(baseValue)) {
2645 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2646 if (jsArray->canSetIndex(i))
2647 jsArray->setIndex(i, r[value].jsValue(exec));
2649 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2651 baseValue->put(exec, i, r[value].jsValue(exec));
2653 Identifier property(exec, subscript->toString(exec));
2654 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2655 PutPropertySlot slot;
2656 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2660 VM_CHECK_EXCEPTION();
2664 BEGIN_OPCODE(op_del_by_val) {
2665 /* del_by_val dst(r) base(r) property(r)
2667 Converts register base to Object, deletes the property
2668 named by register property from the object, and writes a
2669 boolean indicating success (if true) or failure (if false)
2672 int dst = (++vPC)->u.operand;
2673 int base = (++vPC)->u.operand;
2674 int property = (++vPC)->u.operand;
2676 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2678 JSValue* subscript = r[property].jsValue(exec);
2681 if (subscript->getUInt32(i))
2682 result = jsBoolean(baseObj->deleteProperty(exec, i));
2684 VM_CHECK_EXCEPTION();
2685 Identifier property(exec, subscript->toString(exec));
2686 VM_CHECK_EXCEPTION();
2687 result = jsBoolean(baseObj->deleteProperty(exec, property));
2690 VM_CHECK_EXCEPTION();
2695 BEGIN_OPCODE(op_put_by_index) {
2696 /* put_by_index base(r) property(n) value(r)
2698 Sets register value on register base as the property named
2699 by the immediate number property. Base is converted to
2702 Unlike many opcodes, this one does not write any output to
2705 This opcode is mainly used to initialize array literals.
2707 int base = (++vPC)->u.operand;
2708 unsigned property = (++vPC)->u.operand;
2709 int value = (++vPC)->u.operand;
2711 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2716 BEGIN_OPCODE(op_loop) {
2717 /* loop target(offset)
2719 Jumps unconditionally to offset target from the current
2722 Additionally this loop instruction may terminate JS execution is
2723 the JS timeout is reached.
2725 #if DUMP_OPCODE_STATS
2726 OpcodeStats::resetLastInstruction();
2728 int target = (++vPC)->u.operand;
2729 CHECK_FOR_TIMEOUT();
2733 BEGIN_OPCODE(op_jmp) {
2734 /* jmp target(offset)
2736 Jumps unconditionally to offset target from the current
2739 #if DUMP_OPCODE_STATS
2740 OpcodeStats::resetLastInstruction();
2742 int target = (++vPC)->u.operand;
2747 BEGIN_OPCODE(op_loop_if_true) {
2748 /* loop_if_true cond(r) target(offset)
2750 Jumps to offset target from the current instruction, if and
2751 only if register cond converts to boolean as true.
2753 Additionally this loop instruction may terminate JS execution is
2754 the JS timeout is reached.
2756 int cond = (++vPC)->u.operand;
2757 int target = (++vPC)->u.operand;
2758 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2760 CHECK_FOR_TIMEOUT();
2767 BEGIN_OPCODE(op_jtrue) {
2768 /* jtrue cond(r) target(offset)
2770 Jumps to offset target from the current instruction, if and
2771 only if register cond converts to boolean as true.
2773 int cond = (++vPC)->u.operand;
2774 int target = (++vPC)->u.operand;
2775 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2783 BEGIN_OPCODE(op_jfalse) {
2784 /* jfalse cond(r) target(offset)
2786 Jumps to offset target from the current instruction, if and
2787 only if register cond converts to boolean as false.
2789 int cond = (++vPC)->u.operand;
2790 int target = (++vPC)->u.operand;
2791 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2799 BEGIN_OPCODE(op_loop_if_less) {
2800 /* loop_if_less src1(r) src2(r) target(offset)
2802 Checks whether register src1 is less than register src2, as
2803 with the ECMAScript '<' operator, and then jumps to offset
2804 target from the current instruction, if and only if the
2805 result of the comparison is true.
2807 Additionally this loop instruction may terminate JS execution is
2808 the JS timeout is reached.
2810 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2811 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2812 int target = (++vPC)->u.operand;
2814 bool result = jsLess(exec, src1, src2);
2815 VM_CHECK_EXCEPTION();
2819 CHECK_FOR_TIMEOUT();
2826 BEGIN_OPCODE(op_jnless) {
2827 /* jnless src1(r) src2(r) target(offset)
2829 Checks whether register src1 is less than register src2, as
2830 with the ECMAScript '<' operator, and then jumps to offset
2831 target from the current instruction, if and only if the
2832 result of the comparison is false.
2834 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2835 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2836 int target = (++vPC)->u.operand;
2838 bool result = jsLess(exec, src1, src2);
2839 VM_CHECK_EXCEPTION();
2849 BEGIN_OPCODE(op_switch_imm) {
2850 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2852 Performs a range checked switch on the scrutinee value, using
2853 the tableIndex-th immediate switch jump table. If the scrutinee value
2854 is an immediate number in the range covered by the referenced jump
2855 table, and the value at jumpTable[scrutinee value] is non-zero, then
2856 that value is used as the jump offset, otherwise defaultOffset is used.
2858 int tableIndex = (++vPC)->u.operand;
2859 int defaultOffset = (++vPC)->u.operand;
2860 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2861 if (!JSImmediate::isNumber(scrutinee))
2862 vPC += defaultOffset;
2864 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2865 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2869 BEGIN_OPCODE(op_switch_char) {
2870 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2872 Performs a range checked switch on the scrutinee value, using
2873 the tableIndex-th character switch jump table. If the scrutinee value
2874 is a single character string in the range covered by the referenced jump
2875 table, and the value at jumpTable[scrutinee value] is non-zero, then
2876 that value is used as the jump offset, otherwise defaultOffset is used.
2878 int tableIndex = (++vPC)->u.operand;
2879 int defaultOffset = (++vPC)->u.operand;
2880 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2881 if (!scrutinee->isString())
2882 vPC += defaultOffset;
2884 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2885 if (value->size() != 1)
2886 vPC += defaultOffset;
2888 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2892 BEGIN_OPCODE(op_switch_string) {
2893 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2895 Performs a sparse hashmap based switch on the value in the scrutinee
2896 register, using the tableIndex-th string switch jump table. If the
2897 scrutinee value is a string that exists as a key in the referenced
2898 jump table, then the value associated with the string is used as the
2899 jump offset, otherwise defaultOffset is used.
2901 int tableIndex = (++vPC)->u.operand;
2902 int defaultOffset = (++vPC)->u.operand;
2903 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2904 if (!scrutinee->isString())
2905 vPC += defaultOffset;
2907 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
2910 BEGIN_OPCODE(op_new_func) {
2911 /* new_func dst(r) func(f)
2913 Constructs a new Function instance from function func and
2914 the current scope chain using the original Function
2915 constructor, using the rules for function declarations, and
2916 puts the result in register dst.
2918 int dst = (++vPC)->u.operand;
2919 int func = (++vPC)->u.operand;
2921 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2926 BEGIN_OPCODE(op_new_func_exp) {
2927 /* new_func_exp dst(r) func(f)
2929 Constructs a new Function instance from function func and
2930 the current scope chain using the original Function
2931 constructor, using the rules for function expressions, and
2932 puts the result in register dst.
2934 int dst = (++vPC)->u.operand;
2935 int func = (++vPC)->u.operand;
2937 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2942 BEGIN_OPCODE(op_call_eval) {
2943 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2945 Call a function named "eval" with no explicit "this" value
2946 (which may therefore be the eval operator). If register
2947 thisVal is the global object, and register func contains
2948 that global object's original global eval function, then
2949 perform the eval operator in local scope (interpreting
2950 the argument registers as for the "call"
2951 opcode). Otherwise, act exactly as the "call" opcode would.
2954 int dst = (++vPC)->u.operand;
2955 int func = (++vPC)->u.operand;
2956 int thisVal = (++vPC)->u.operand;
2957 int firstArg = (++vPC)->u.operand;
2958 int argCount = (++vPC)->u.operand;
2960 JSValue* funcVal = r[func].jsValue(exec);
2961 JSValue* baseVal = r[thisVal].jsValue(exec);
2963 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2964 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2965 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2975 // We didn't find the blessed version of eval, so reset vPC and process
2976 // this instruction as a normal function call, supplying the proper 'this'
2979 r[thisVal] = baseVal->toThisObject(exec);
2981 #if HAVE(COMPUTED_GOTO)
2982 // Hack around gcc performance quirk by performing an indirect goto
2983 // in order to set the vPC -- attempting to do so directly results in a
2984 // significant regression.
2985 goto *op_call_indirect; // indirect goto -> op_call
2987 // fall through to op_call
2989 BEGIN_OPCODE(op_call) {
2990 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2992 Perform a function call. Specifically, call register func
2993 with a "this" value of register thisVal, and put the result
2996 The arguments start at register firstArg and go up to
2997 argCount, but the "this" value is considered an implicit
2998 first argument, so the argCount should be one greater than
2999 the number of explicit arguments passed, and the register
3000 after firstArg should contain the actual first
3001 argument. This opcode will copy from the thisVal register
3002 to the firstArg register, unless the register index of
3003 thisVal is the special missing this object marker, which is
3004 2^31-1; in that case, the global object will be used as the
3007 If func is a native code function, then this opcode calls
3008 it and returns the value immediately.
3010 But if it is a JS function, then the current scope chain
3011 and code block is set to the function's, and we slide the
3012 register window so that the arguments would form the first
3013 few local registers of the called function's register
3014 window. In addition, a call frame header is written
3015 immediately before the arguments; see the call frame
3016 documentation for an explanation of how many registers a
3017 call frame takes and what they contain. That many registers
3018 before the firstArg register will be overwritten by the
3019 call. In addition, any registers higher than firstArg +
3020 argCount may be overwritten. Once this setup is complete,
3021 execution continues from the called function's first
3022 argument, and does not return until a "ret" opcode is
3026 int dst = (++vPC)->u.operand;
3027 int func = (++vPC)->u.operand;
3028 int thisVal = (++vPC)->u.operand;
3029 int firstArg = (++vPC)->u.operand;
3030 int argCount = (++vPC)->u.operand;
3032 JSValue* v = r[func].jsValue(exec);
3035 CallType callType = v->getCallData(callData);
3037 if (*enabledProfilerReference)
3038 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3040 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3041 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
3042 exec->m_callFrame = callFrame;
3044 if (callType == CallTypeJS) {
3046 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3047 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3048 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3050 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3052 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3053 if (UNLIKELY(exceptionValue != 0))
3056 codeBlock = newCodeBlock;
3057 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3058 vPC = codeBlock->instructions.begin();
3060 #if DUMP_OPCODE_STATS
3061 OpcodeStats::resetLastInstruction();
3067 if (callType == CallTypeHost) {
3068 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3069 ArgList args(r + firstArg + 1, argCount - 1);
3071 MACHINE_SAMPLING_callingHostFunction();
3073 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3074 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3075 VM_CHECK_EXCEPTION();
3077 r[dst] = returnValue;
3079 if (*enabledProfilerReference)
3080 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3086 ASSERT(callType == CallTypeNone);
3088 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3089 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3092 BEGIN_OPCODE(op_ret) {
3095 Return register result as the return value of the current
3096 function call, writing it into the caller's expected return
3097 value register. In addition, unwind one call frame and
3098 restore the scope chain, code block instruction pointer and
3099 register base to those of the calling function.
3102 int result = (++vPC)->u.operand;
3104 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3105 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3106 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3107 ASSERT(activation->isActivationObject());
3108 activation->copyRegisters();
3111 if (*enabledProfilerReference)
3112 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3114 if (codeBlock->needsFullScopeChain)
3115 scopeChain->deref();
3117 JSValue* returnValue = r[result].jsValue(exec);
3118 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
3119 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
3120 returnValue = thisObject;
3123 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3127 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3128 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3129 r = callFrame[RegisterFile::CallerRegisters].r();
3130 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3131 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3132 r[dst] = returnValue;
3136 BEGIN_OPCODE(op_construct) {
3137 /* construct dst(r) constr(r) firstArg(r) argCount(n)
3139 Invoke register "constr" as a constructor. For JS
3140 functions, the calling convention is exactly as for the
3141 "call" opcode, except that the "this" value is a newly
3142 created Object. For native constructors, a null "this"
3143 value is passed. In either case, the firstArg and argCount
3144 registers are interpreted as for the "call" opcode.
3147 int dst = (++vPC)->u.operand;
3148 int constr = (++vPC)->u.operand;
3149 int firstArg = (++vPC)->u.operand;
3150 int argCount = (++vPC)->u.operand;
3152 JSValue* constrVal = r[constr].jsValue(exec);
3154 ConstructData constructData;
3155 ConstructType constructType = constrVal->getConstructData(constructData);
3157 // Removing this line of code causes a measurable regression on squirrelfish.
3158 JSObject* constructor = static_cast<JSObject*>(constrVal);
3160 if (constructType == ConstructTypeJS) {
3161 if (*enabledProfilerReference)
3162 (*enabledProfilerReference)->willExecute(exec, constructor);
3164 JSObject* prototype;
3165 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
3167 prototype = static_cast<JSObject*>(p);
3169 prototype = scopeChain->globalObject()->objectPrototype();
3170 JSObject* newObject = new (exec) JSObject(prototype);
3172 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3173 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3174 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3176 r[firstArg] = newObject; // "this" value
3178 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3179 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
3180 exec->m_callFrame = callFrame;
3182 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3186 codeBlock = newCodeBlock;
3187 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3188 vPC = codeBlock->instructions.begin();
3193 if (constructType == ConstructTypeHost) {
3194 if (*enabledProfilerReference)
3195 (*enabledProfilerReference)->willExecute(exec, constructor);
3197 ArgList args(r + firstArg + 1, argCount - 1);
3199 MACHINE_SAMPLING_callingHostFunction();
3201 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3203 VM_CHECK_EXCEPTION();
3204 r[dst] = returnValue;
3206 if (*enabledProfilerReference)
3207 (*enabledProfilerReference)->didExecute(exec, constructor);
3213 ASSERT(constructType == ConstructTypeNone);
3215 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3218 BEGIN_OPCODE(op_push_scope) {
3219 /* push_scope scope(r)
3221 Converts register scope to object, and pushes it onto the top
3222 of the current scope chain.
3224 int scope = (++vPC)->u.operand;
3225 JSValue* v = r[scope].jsValue(exec);
3226 JSObject* o = v->toObject(exec);
3227 VM_CHECK_EXCEPTION();
3229 setScopeChain(exec, scopeChain, scopeChain->push(o));
3234 BEGIN_OPCODE(op_pop_scope) {
3237 Removes the top item from the current scope chain.
3239 setScopeChain(exec, scopeChain, scopeChain->pop());
3244 BEGIN_OPCODE(op_get_pnames) {
3245 /* get_pnames dst(r) base(r)
3247 Creates a property name list for register base and puts it
3248 in register dst. This is not a true JavaScript value, just
3249 a synthetic value used to keep the iteration state in a
3252 int dst = (++vPC)->u.operand;
3253 int base = (++vPC)->u.operand;
3255 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3259 BEGIN_OPCODE(op_next_pname) {
3260 /* next_pname dst(r) iter(r) target(offset)
3262 Tries to copies the next name from property name list in
3263 register iter. If there are names left, then copies one to
3264 register dst, and jumps to offset target. If there are none
3265 left, invalidates the iterator and continues to the next
3268 int dst = (++vPC)->u.operand;
3269 int iter = (++vPC)->u.operand;
3270 int target = (++vPC)->u.operand;
3272 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3273 if (JSValue* temp = it->next(exec)) {
3274 CHECK_FOR_TIMEOUT();
3284 BEGIN_OPCODE(op_jmp_scopes) {
3285 /* jmp_scopes count(n) target(offset)
3287 Removes the a number of items from the current scope chain
3288 specified by immediate number count, then jumps to offset
3291 int count = (++vPC)->u.operand;
3292 int target = (++vPC)->u.operand;
3294 ScopeChainNode* tmp = scopeChain;
3297 setScopeChain(exec, scopeChain, tmp);
3302 #if HAVE(COMPUTED_GOTO)
3304 goto *(&&skip_new_scope);
3306 BEGIN_OPCODE(op_push_new_scope) {
3307 /* new_scope dst(r) property(id) value(r)
3309 Constructs a new StaticScopeObject with property set to value. That scope
3310 object is then pushed onto the ScopeChain. The scope object is then stored
3313 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
3317 #if HAVE(COMPUTED_GOTO)
3320 BEGIN_OPCODE(op_catch) {
3323 Retrieves the VMs current exception and puts it in register
3324 ex. This is only valid after an exception has been raised,
3325 and usually forms the beginning of an exception handler.
3327 ASSERT(exceptionValue);
3328 ASSERT(!exec->hadException());
3329 int ex = (++vPC)->u.operand;
3330 r[ex] = exceptionValue;
3336 BEGIN_OPCODE(op_throw) {
3339 Throws register ex as an exception. This involves three
3340 steps: first, it is set as the current exception in the
3341 VM's internal state, then the stack is unwound until an
3342 exception handler or a native code boundary is found, and
3343 then control resumes at the exception handler if any or
3344 else the script returns control to the nearest native caller.
3347 int ex = (++vPC)->u.operand;
3348 exceptionValue = r[ex].jsValue(exec);
3350 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
3352 *exception = exceptionValue;
3356 #if HAVE(COMPUTED_GOTO)
3357 // Hack around gcc performance quirk by performing an indirect goto
3358 // in order to set the vPC -- attempting to do so directly results in a
3359 // significant regression.
3360 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3368 BEGIN_OPCODE(op_unexpected_load) {
3369 /* unexpected_load load dst(r) src(k)
3371 Copies constant src to register dst.
3373 int dst = (++vPC)->u.operand;
3374 int src = (++vPC)->u.operand;
3375 r[dst] = codeBlock->unexpectedConstants[src];
3380 BEGIN_OPCODE(op_new_error) {
3381 /* new_error dst(r) type(n) message(k)
3383 Constructs a new Error instance using the original
3384 constructor, using immediate number n as the type and
3385 constant message as the message string. The result is
3386 written to register dst.
3388 int dst = (++vPC)->u.operand;
3389 int type = (++vPC)->u.operand;
3390 int message = (++vPC)->u.operand;
3392 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
3397 BEGIN_OPCODE(op_end) {
3400 Return register result as the value of a global or eval
3401 program. Return control to the calling native code.
3404 if (codeBlock->needsFullScopeChain) {
3405 ASSERT(scopeChain->refCount > 1);
3406 scopeChain->deref();
3408 int result = (++vPC)->u.operand;
3409 return r[result].jsValue(exec);
3411 BEGIN_OPCODE(op_put_getter) {
3412 /* put_getter base(r) property(id) function(r)
3414 Sets register function on register base as the getter named
3415 by identifier property. Base and function are assumed to be
3416 objects as this op should only be used for getters defined
3417 in object literal form.
3419 Unlike many opcodes, this one does not write any output to
3422 int base = (++vPC)->u.operand;
3423 int property = (++vPC)->u.operand;
3424 int function = (++vPC)->u.operand;
3426 ASSERT(r[base].jsValue(exec)->isObject());
3427 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3428 Identifier& ident = codeBlock->identifiers[property];
3429 ASSERT(r[function].jsValue(exec)->isObject());
3430 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3435 BEGIN_OPCODE(op_put_setter) {
3436 /* put_setter base(r) property(id) function(r)
3438 Sets register function on register base as the setter named
3439 by identifier property. Base and functi