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 jsIsObjectType(JSValue* v)
252 if (JSImmediate::isImmediate(v))
255 JSType type = static_cast<JSCell*>(v)->structureID()->type();
256 if (type == NumberType || type == StringType)
258 if (type == ObjectType) {
259 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
262 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
268 static bool jsIsFunctionType(JSValue* v)
272 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
278 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
280 int dst = (vPC + 1)->u.operand;
281 int property = (vPC + 2)->u.operand;
283 ScopeChainIterator iter = scopeChain->begin();
284 ScopeChainIterator end = scopeChain->end();
287 Identifier& ident = codeBlock->identifiers[property];
290 PropertySlot slot(o);
291 if (o->getPropertySlot(exec, ident, slot)) {
292 JSValue* result = slot.getValue(exec, ident);
293 exceptionValue = exec->exception();
299 } while (++iter != end);
300 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
304 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
306 int dst = (vPC + 1)->u.operand;
307 int property = (vPC + 2)->u.operand;
308 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
310 ScopeChainIterator iter = scopeChain->begin();
311 ScopeChainIterator end = scopeChain->end();
317 Identifier& ident = codeBlock->identifiers[property];
320 PropertySlot slot(o);
321 if (o->getPropertySlot(exec, ident, slot)) {
322 JSValue* result = slot.getValue(exec, ident);
323 exceptionValue = exec->exception();
329 } while (++iter != end);
330 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
334 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
336 ScopeChainIterator iter = scopeChain->begin();
337 ScopeChainIterator next = iter;
339 ScopeChainIterator end = scopeChain->end();
346 if (next == end || base->getPropertySlot(exec, property, slot))
353 ASSERT_NOT_REACHED();
357 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
359 int dst = (vPC + 1)->u.operand;
360 int property = (vPC + 2)->u.operand;
361 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
364 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
366 int baseDst = (vPC + 1)->u.operand;
367 int propDst = (vPC + 2)->u.operand;
368 int property = (vPC + 3)->u.operand;
370 ScopeChainIterator iter = scopeChain->begin();
371 ScopeChainIterator end = scopeChain->end();
373 // FIXME: add scopeDepthIsZero optimization
377 Identifier& ident = codeBlock->identifiers[property];
381 PropertySlot slot(base);
382 if (base->getPropertySlot(exec, ident, slot)) {
383 JSValue* result = slot.getValue(exec, ident);
384 exceptionValue = exec->exception();
392 } while (iter != end);
394 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
398 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
400 int baseDst = (vPC + 1)->u.operand;
401 int funcDst = (vPC + 2)->u.operand;
402 int property = (vPC + 3)->u.operand;
404 ScopeChainIterator iter = scopeChain->begin();
405 ScopeChainIterator end = scopeChain->end();
407 // FIXME: add scopeDepthIsZero optimization
411 Identifier& ident = codeBlock->identifiers[property];
415 PropertySlot slot(base);
416 if (base->getPropertySlot(exec, ident, slot)) {
417 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
418 // However, section 10.2.3 says that in the case where the value provided
419 // by the caller is null, the global object should be used. It also says
420 // that the section does not apply to internal functions, but for simplicity
421 // of implementation we use the global object anyway here. This guarantees
422 // that in host objects you always get a valid object for this.
423 // We also handle wrapper substitution for the global object at the same time.
424 JSObject* thisObj = base->toThisObject(exec);
425 JSValue* result = slot.getValue(exec, ident);
426 exceptionValue = exec->exception();
430 r[baseDst] = thisObj;
435 } while (iter != end);
437 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
441 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
443 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
444 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
445 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
446 callFrame[RegisterFile::CallerRegisters] = r;
447 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
448 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
449 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
450 callFrame[RegisterFile::Callee] = function;
451 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
454 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
456 size_t registerOffset = argv + newCodeBlock->numLocals;
457 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
459 if (argc == newCodeBlock->numParameters) { // correct number of arguments
460 if (!registerFile->grow(size)) {
461 exceptionValue = createStackOverflowError(exec);
465 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
466 if (!registerFile->grow(size)) {
467 exceptionValue = createStackOverflowError(exec);
472 int omittedArgCount = newCodeBlock->numParameters - argc;
473 Register* endOfParams = r - newCodeBlock->numVars;
474 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
475 (*it) = jsUndefined();
476 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
477 int shift = argc + RegisterFile::CallFrameHeaderSize;
478 registerOffset += shift;
481 if (!registerFile->grow(size)) {
482 exceptionValue = createStackOverflowError(exec);
487 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
488 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
489 for ( ; it != end; ++it)
493 // initialize local variable slots
494 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
495 (*it) = jsUndefined();
497 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
498 r[i] = newCodeBlock->constantRegisters[i];
503 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
505 if (newCodeBlock->needsFullScopeChain) {
506 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
507 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
509 return callDataScopeChain->copy()->push(activation);
512 return callDataScopeChain;
515 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
517 if (value->isObject())
519 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
523 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
526 return jsUndefined();
528 JSValue* program = r[argv + 1].jsValue(exec);
530 if (!program->isString())
533 Profiler** profiler = Profiler::enabledProfilerReference();
535 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
537 UString programSource = static_cast<JSString*>(program)->value();
539 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
543 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
546 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
554 , m_ctiArrayLengthTrampoline(0)
555 , m_ctiStringLengthTrampoline(0)
556 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
560 , m_timeAtLastCheckTimeout(0)
562 , m_timeoutCheckCount(0)
563 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
565 privateExecute(InitializeAndReturn);
567 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
568 void* storage = fastMalloc(sizeof(CollectorBlock));
570 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
571 m_jsArrayVptr = jsArray->vptr();
572 static_cast<JSCell*>(jsArray)->~JSCell();
574 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
575 m_jsStringVptr = jsString->vptr();
576 static_cast<JSCell*>(jsString)->~JSCell();
578 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
579 m_jsFunctionVptr = jsFunction->vptr();
580 static_cast<JSCell*>(jsFunction)->~JSCell();
588 if (m_ctiArrayLengthTrampoline)
589 fastFree(m_ctiArrayLengthTrampoline);
590 if (m_ctiStringLengthTrampoline)
591 fastFree(m_ctiStringLengthTrampoline);
597 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
599 ScopeChain sc(scopeChain);
600 JSGlobalObject* globalObject = sc.globalObject();
601 codeBlock->dump(globalObject->globalExec());
602 dumpRegisters(codeBlock, registerFile, r);
605 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
607 printf("Register frame: \n\n");
608 printf("----------------------------------------------------\n");
609 printf(" use | address | value \n");
610 printf("----------------------------------------------------\n");
615 if (codeBlock->codeType == GlobalCode) {
616 it = registerFile->lastGlobal();
617 end = it + registerFile->numGlobals();
619 printf("[global var] | %10p | %10p \n", it, (*it).v());
622 printf("----------------------------------------------------\n");
625 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
626 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
627 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
628 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
629 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
630 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
631 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
632 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
633 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
634 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
635 printf("----------------------------------------------------\n");
637 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
638 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
641 printf("[param] | %10p | %10p \n", it, (*it).v());
645 printf("----------------------------------------------------\n");
647 if (codeBlock->codeType != GlobalCode) {
648 end = it + codeBlock->numVars;
651 printf("[var] | %10p | %10p \n", it, (*it).v());
654 printf("----------------------------------------------------\n");
658 end = it + codeBlock->numTemporaries;
661 printf("[temp] | %10p | %10p \n", it, (*it).v());
669 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
671 bool Machine::isOpcode(Opcode opcode)
673 #if HAVE(COMPUTED_GOTO)
674 return opcode != HashTraits<Opcode>::emptyValue()
675 && !HashTraits<Opcode>::isDeletedValue(opcode)
676 && m_opcodeIDTable.contains(opcode);
678 return opcode >= 0 && opcode <= op_end;
684 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
686 CodeBlock* oldCodeBlock = codeBlock;
687 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
689 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
690 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
691 if (callFrame[RegisterFile::Callee].jsValue(exec))
692 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
694 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
697 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
698 if (callFrame[RegisterFile::Callee].jsValue(exec))
699 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
701 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
704 if (oldCodeBlock->needsFullScopeChain)
707 // If this call frame created an activation, tear it off.
708 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
709 ASSERT(activation->isActivationObject());
710 activation->copyRegisters();
713 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
717 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
718 r = callFrame[RegisterFile::CallerRegisters].r();
719 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
720 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
725 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
727 // Set up the exception object
729 if (exceptionValue->isObject()) {
730 JSObject* exception = static_cast<JSObject*>(exceptionValue);
731 if (exception->isNotAnObjectErrorStub()) {
732 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
733 exceptionValue = exception;
735 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
736 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
737 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
738 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
739 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
740 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
745 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
746 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
748 // We only hit this path for error messages and throw statements, which don't have a specific failure position
749 // So we just give the full range of the error/throw statement.
750 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
751 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
753 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
754 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
755 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
758 if (exception->isWatchdogException()) {
759 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
760 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
767 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
768 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
769 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
772 // Calculate an exception handler vPC, unwinding call frames as necessary.
775 Instruction* handlerVPC;
777 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
778 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
782 // Now unwind the scope chain within the exception handler's call frame.
784 ScopeChain sc(scopeChain);
785 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
786 ASSERT(scopeDelta >= 0);
789 setScopeChain(exec, scopeChain, sc.node());
794 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
796 if (m_reentryDepth >= MaxReentryDepth) {
797 *exception = createStackOverflowError(exec);
801 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
803 size_t oldSize = m_registerFile.size();
804 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
805 if (!m_registerFile.grow(newSize)) {
806 *exception = createStackOverflowError(exec);
810 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
811 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
812 globalObject->copyGlobalsTo(m_registerFile);
814 Register* callFrame = m_registerFile.base() + oldSize;
816 // a 0 codeBlock indicates a built-in caller
817 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
819 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
820 r[codeBlock->thisRegister] = thisObj;
822 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
823 r[i] = codeBlock->constantRegisters[i];
825 if (codeBlock->needsFullScopeChain)
826 scopeChain = scopeChain->copy();
828 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
830 Profiler** profiler = Profiler::enabledProfilerReference();
832 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
836 if (!codeBlock->ctiCode)
837 CTI::compile(this, exec, codeBlock);
838 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
840 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
844 MACHINE_SAMPLING_privateExecuteReturned();
847 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
849 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
850 lastGlobalObject->copyGlobalsTo(m_registerFile);
852 m_registerFile.shrink(oldSize);
856 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
858 if (m_reentryDepth >= MaxReentryDepth) {
859 *exception = createStackOverflowError(exec);
863 int argv = RegisterFile::CallFrameHeaderSize;
864 int argc = args.size() + 1; // implicit "this" parameter
866 size_t oldSize = m_registerFile.size();
867 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
868 *exception = createStackOverflowError(exec);
872 Register* callFrame = m_registerFile.base() + oldSize;
874 // put args in place, including "this"
875 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
878 ArgList::const_iterator end = args.end();
879 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
882 // a 0 codeBlock indicates a built-in caller
883 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
885 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
886 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
888 m_registerFile.shrink(oldSize);
892 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
894 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
896 Profiler** profiler = Profiler::enabledProfilerReference();
898 (*profiler)->willExecute(exec, function);
902 if (!newCodeBlock->ctiCode)
903 CTI::compile(this, exec, newCodeBlock);
904 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
906 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
910 MACHINE_SAMPLING_privateExecuteReturned();
912 m_registerFile.shrink(oldSize);
916 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
918 if (m_reentryDepth >= MaxReentryDepth) {
919 *exception = createStackOverflowError(exec);
923 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
925 JSVariableObject* variableObject;
926 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
928 if (node->object->isVariableObject()) {
929 variableObject = static_cast<JSVariableObject*>(node->object);
934 { // Scope for BatchedTransitionOptimizer
936 BatchedTransitionOptimizer optimizer(variableObject);
938 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
939 Node::VarStack::const_iterator varStackEnd = varStack.end();
940 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
941 const Identifier& ident = (*it).first;
942 if (!variableObject->hasProperty(exec, ident)) {
943 PutPropertySlot slot;
944 variableObject->put(exec, ident, jsUndefined(), slot);
948 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
949 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
950 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
951 PutPropertySlot slot;
952 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
957 size_t oldSize = m_registerFile.size();
958 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
959 if (!m_registerFile.grow(newSize)) {
960 *exception = createStackOverflowError(exec);
964 Register* callFrame = m_registerFile.base() + registerOffset;
966 // a 0 codeBlock indicates a built-in caller
967 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
969 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
970 r[codeBlock->thisRegister] = thisObj;
972 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
973 r[i] = codeBlock->constantRegisters[i];
975 if (codeBlock->needsFullScopeChain)
976 scopeChain = scopeChain->copy();
978 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
980 Profiler** profiler = Profiler::enabledProfilerReference();
982 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
986 if (!codeBlock->ctiCode)
987 CTI::compile(this, exec, codeBlock);
988 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
990 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
994 MACHINE_SAMPLING_privateExecuteReturned();
997 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
999 m_registerFile.shrink(oldSize);
1003 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1005 scopeChain = newScopeChain;
1006 exec->m_scopeChain = newScopeChain;
1009 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1011 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1015 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1017 switch (debugHookID) {
1018 case DidEnterCallFrame:
1019 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1021 case WillLeaveCallFrame:
1022 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1024 case WillExecuteStatement:
1025 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1027 case WillExecuteProgram:
1028 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1030 case DidExecuteProgram:
1031 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1033 case DidReachBreakpoint:
1034 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1039 void Machine::resetTimeoutCheck()
1041 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1042 m_timeAtLastCheckTimeout = 0;
1043 m_timeExecuting = 0;
1046 // Returns the time the current thread has spent executing, in milliseconds.
1047 static inline unsigned getCPUTime()
1049 #if PLATFORM(DARWIN)
1050 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1051 thread_basic_info_data_t info;
1053 // Get thread information
1054 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1056 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1057 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1060 #elif HAVE(SYS_TIME_H)
1061 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1063 gettimeofday(&tv, 0);
1064 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1066 QDateTime t = QDateTime::currentDateTime();
1067 return t.toTime_t() * 1000 + t.time().msec();
1068 #elif PLATFORM(WIN_OS)
1071 unsigned long long fileTimeAsLong;
1072 } userTime, kernelTime;
1074 // GetThreadTimes won't accept NULL arguments so we pass these even though
1075 // they're not used.
1076 FILETIME creationTime, exitTime;
1078 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1080 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1082 #error Platform does not have getCurrentTime function
1086 // We have to return a JSValue here, gcc seems to produce worse code if
1087 // we attempt to return a bool
1088 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1090 unsigned currentTime = getCPUTime();
1092 if (!m_timeAtLastCheckTimeout) {
1093 // Suspicious amount of looping in a script -- start timing it
1094 m_timeAtLastCheckTimeout = currentTime;
1098 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1103 m_timeExecuting += timeDiff;
1104 m_timeAtLastCheckTimeout = currentTime;
1106 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1107 // preferredScriptCheckTimeInterval
1108 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1109 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1110 // preferred script check time interval.
1111 if (m_ticksUntilNextTimeoutCheck == 0)
1112 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1114 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1115 if (globalObject->shouldInterruptScript())
1116 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1118 resetTimeoutCheck();
1124 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1126 int dst = (++vPC)->u.operand;
1127 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1128 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1129 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1131 return scopeChain->push(scope);
1134 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1136 JSValue* prototype = structureID->prototypeForLookup(exec);
1137 if (JSImmediate::isImmediate(prototype))
1139 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1140 structureID->setCachedPrototypeChain(chain.release());
1141 return structureID->cachedPrototypeChain();
1144 NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1146 // Recursive invocation may already have specialized this instruction.
1147 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1150 if (JSImmediate::isImmediate(baseValue))
1153 // Uncacheable: give up.
1154 if (!slot.isCacheable()) {
1155 vPC[0] = getOpcode(op_put_by_id_generic);
1159 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1160 StructureID* structureID = baseCell->structureID();
1162 if (structureID->isDictionary()) {
1163 vPC[0] = getOpcode(op_put_by_id_generic);
1167 // Cache miss: record StructureID to compare against next time.
1168 StructureID* lastStructureID = vPC[4].u.structureID;
1169 if (structureID != lastStructureID) {
1170 // First miss: record StructureID to compare against next time.
1171 if (!lastStructureID) {
1172 vPC[4] = structureID;
1176 // Second miss: give up.
1177 vPC[0] = getOpcode(op_put_by_id_generic);
1181 // Cache hit: Specialize instruction and ref StructureIDs.
1183 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1184 if (baseCell != slot.base()) {
1185 vPC[0] = getOpcode(op_put_by_id_generic);
1189 // StructureID transition, cache transition info
1190 if (slot.type() == PutPropertySlot::NewProperty) {
1191 vPC[0] = getOpcode(op_put_by_id_transition);
1192 vPC[4] = structureID->previousID();
1193 vPC[5] = structureID;
1194 StructureIDChain* chain = structureID->cachedPrototypeChain();
1196 chain = cachePrototypeChain(exec, structureID);
1198 // This happens if someone has manually inserted null into the prototype chain
1199 vPC[0] = getOpcode(op_put_by_id_generic);
1204 vPC[7] = slot.cachedOffset();
1205 codeBlock->refStructureIDs(vPC);
1209 vPC[0] = getOpcode(op_put_by_id_replace);
1210 vPC[5] = slot.cachedOffset();
1211 codeBlock->refStructureIDs(vPC);
1214 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1216 codeBlock->derefStructureIDs(vPC);
1217 vPC[0] = getOpcode(op_put_by_id);
1221 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1223 // Recursive invocation may already have specialized this instruction.
1224 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1227 // FIXME: Cache property access for immediates.
1228 if (JSImmediate::isImmediate(baseValue)) {
1229 vPC[0] = getOpcode(op_get_by_id_generic);
1233 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1234 vPC[0] = getOpcode(op_get_array_length);
1238 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1239 vPC[0] = getOpcode(op_get_string_length);
1243 // Uncacheable: give up.
1244 if (!slot.isCacheable()) {
1245 vPC[0] = getOpcode(op_get_by_id_generic);
1249 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1251 if (structureID->isDictionary()) {
1252 vPC[0] = getOpcode(op_get_by_id_generic);
1257 StructureID* lastStructureID = vPC[4].u.structureID;
1258 if (structureID != lastStructureID) {
1259 // First miss: record StructureID to compare against next time.
1260 if (!lastStructureID) {
1261 vPC[4] = structureID;
1265 // Second miss: give up.
1266 vPC[0] = getOpcode(op_get_by_id_generic);
1270 // Cache hit: Specialize instruction and ref StructureIDs.
1272 if (slot.slotBase() == baseValue) {
1273 vPC[0] = getOpcode(op_get_by_id_self);
1274 vPC[5] = slot.cachedOffset();
1276 codeBlock->refStructureIDs(vPC);
1280 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1281 ASSERT(slot.slotBase()->isObject());
1283 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1285 // Heavy access to a prototype is a good indication that it's not being
1286 // used as a dictionary.
1287 if (baseObject->structureID()->isDictionary()) {
1288 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1289 baseObject->setStructureID(transition.release());
1290 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1293 vPC[0] = getOpcode(op_get_by_id_proto);
1294 vPC[5] = baseObject->structureID();
1295 vPC[6] = slot.cachedOffset();
1297 codeBlock->refStructureIDs(vPC);
1302 JSObject* o = static_cast<JSObject*>(baseValue);
1303 while (slot.slotBase() != o) {
1304 JSValue* v = o->structureID()->prototypeForLookup(exec);
1306 // If we didn't find base in baseValue's prototype chain, then baseValue
1307 // must be a proxy for another object.
1309 vPC[0] = getOpcode(op_get_by_id_generic);
1313 o = static_cast<JSObject*>(v);
1315 // Heavy access to a prototype is a good indication that it's not being
1316 // used as a dictionary.
1317 if (o->structureID()->isDictionary()) {
1318 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1319 o->setStructureID(transition.release());
1320 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1326 StructureIDChain* chain = structureID->cachedPrototypeChain();
1328 chain = cachePrototypeChain(exec, structureID);
1331 vPC[0] = getOpcode(op_get_by_id_chain);
1332 vPC[4] = structureID;
1335 vPC[7] = slot.cachedOffset();
1336 codeBlock->refStructureIDs(vPC);
1339 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1341 codeBlock->derefStructureIDs(vPC);
1342 vPC[0] = getOpcode(op_get_by_id);
1346 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1348 // One-time initialization of our address tables. We have to put this code
1349 // here because our labels are only in scope inside this function.
1350 if (flag == InitializeAndReturn) {
1351 #if HAVE(COMPUTED_GOTO)
1352 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1353 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1356 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1357 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1358 #undef ADD_OPCODE_ID
1359 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1360 op_throw_end_indirect = &&op_throw_end;
1361 op_call_indirect = &&op_call;
1362 #endif // HAVE(COMPUTED_GOTO)
1367 // Currently with CTI enabled we never interpret functions
1368 ASSERT_NOT_REACHED();
1371 JSValue* exceptionValue = 0;
1372 Instruction* handlerVPC = 0;
1374 Register* registerBase = registerFile->base();
1375 Instruction* vPC = codeBlock->instructions.begin();
1376 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1377 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1379 #define VM_CHECK_EXCEPTION() \
1381 if (UNLIKELY(exec->hadException())) { \
1382 exceptionValue = exec->exception(); \
1387 #if DUMP_OPCODE_STATS
1388 OpcodeStats::resetLastInstruction();
1391 #define CHECK_FOR_TIMEOUT() \
1392 if (!--tickCount) { \
1393 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1395 tickCount = m_ticksUntilNextTimeoutCheck; \
1398 #if HAVE(COMPUTED_GOTO)
1399 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1400 #if DUMP_OPCODE_STATS
1401 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1403 #define BEGIN_OPCODE(opcode) opcode:
1407 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1408 #if DUMP_OPCODE_STATS
1409 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1411 #define BEGIN_OPCODE(opcode) case opcode:
1413 while (1) // iterator loop begins
1414 switch (vPC->u.opcode)
1417 BEGIN_OPCODE(op_new_object) {
1418 /* new_object dst(r)
1420 Constructs a new empty Object instance using the original
1421 constructor, and puts the result in register dst.
1423 int dst = (++vPC)->u.operand;
1424 r[dst] = constructEmptyObject(exec);
1429 BEGIN_OPCODE(op_new_array) {
1430 /* new_array dst(r) firstArg(r) argCount(n)
1432 Constructs a new Array instance using the original
1433 constructor, and puts the result in register dst.
1434 The array will contain argCount elements with values
1435 taken from registers starting at register firstArg.
1437 int dst = (++vPC)->u.operand;
1438 int firstArg = (++vPC)->u.operand;
1439 int argCount = (++vPC)->u.operand;
1440 ArgList args(r + firstArg, argCount);
1441 r[dst] = constructArray(exec, args);
1446 BEGIN_OPCODE(op_new_regexp) {
1447 /* new_regexp dst(r) regExp(re)
1449 Constructs a new RegExp instance using the original
1450 constructor from regexp regExp, and puts the result in
1453 int dst = (++vPC)->u.operand;
1454 int regExp = (++vPC)->u.operand;
1455 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1460 BEGIN_OPCODE(op_mov) {
1461 /* mov dst(r) src(r)
1463 Copies register src to register dst.
1465 int dst = (++vPC)->u.operand;
1466 int src = (++vPC)->u.operand;
1472 BEGIN_OPCODE(op_eq) {
1473 /* eq dst(r) src1(r) src2(r)
1475 Checks whether register src1 and register src2 are equal,
1476 as with the ECMAScript '==' operator, and puts the result
1477 as a boolean in register dst.
1479 int dst = (++vPC)->u.operand;
1480 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1481 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1482 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1483 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1485 JSValue* result = jsBoolean(equal(exec, src1, src2));
1486 VM_CHECK_EXCEPTION();
1493 BEGIN_OPCODE(op_eq_null) {
1494 /* neq dst(r) src(r)
1496 Checks whether register src is null, as with the ECMAScript '!='
1497 operator, and puts the result as a boolean in register dst.
1499 int dst = (++vPC)->u.operand;
1500 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1502 if (src->isUndefinedOrNull()) {
1503 r[dst] = jsBoolean(true);
1508 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1512 BEGIN_OPCODE(op_neq) {
1513 /* neq dst(r) src1(r) src2(r)
1515 Checks whether register src1 and register src2 are not
1516 equal, as with the ECMAScript '!=' operator, and puts the
1517 result as a boolean in register dst.
1519 int dst = (++vPC)->u.operand;
1520 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1521 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1522 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1523 r[dst] = jsBoolean(src1 != src2);
1525 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1526 VM_CHECK_EXCEPTION();
1533 BEGIN_OPCODE(op_neq_null) {
1534 /* neq dst(r) src(r)
1536 Checks whether register src is not null, as with the ECMAScript '!='
1537 operator, and puts the result as a boolean in register dst.
1539 int dst = (++vPC)->u.operand;
1540 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1542 if (src->isUndefinedOrNull()) {
1543 r[dst] = jsBoolean(false);
1548 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1552 BEGIN_OPCODE(op_stricteq) {
1553 /* stricteq dst(r) src1(r) src2(r)
1555 Checks whether register src1 and register src2 are strictly
1556 equal, as with the ECMAScript '===' operator, and puts the
1557 result as a boolean in register dst.
1559 int dst = (++vPC)->u.operand;
1560 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1561 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1562 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1563 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1565 r[dst] = jsBoolean(strictEqual(src1, src2));
1570 BEGIN_OPCODE(op_nstricteq) {
1571 /* nstricteq dst(r) src1(r) src2(r)
1573 Checks whether register src1 and register src2 are not
1574 strictly equal, as with the ECMAScript '!==' operator, and
1575 puts the result as a boolean in register dst.
1577 int dst = (++vPC)->u.operand;
1578 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1579 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1580 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1581 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1583 r[dst] = jsBoolean(!strictEqual(src1, src2));
1588 BEGIN_OPCODE(op_less) {
1589 /* less dst(r) src1(r) src2(r)
1591 Checks whether register src1 is less than register src2, as
1592 with the ECMAScript '<' operator, and puts the result as
1593 a boolean in register dst.
1595 int dst = (++vPC)->u.operand;
1596 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1597 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1598 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1599 VM_CHECK_EXCEPTION();
1605 BEGIN_OPCODE(op_lesseq) {
1606 /* lesseq dst(r) src1(r) src2(r)
1608 Checks whether register src1 is less than or equal to
1609 register src2, as with the ECMAScript '<=' operator, and
1610 puts the result as a boolean in register dst.
1612 int dst = (++vPC)->u.operand;
1613 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1614 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1615 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1616 VM_CHECK_EXCEPTION();
1622 BEGIN_OPCODE(op_pre_inc) {
1623 /* pre_inc srcDst(r)
1625 Converts register srcDst to number, adds one, and puts the result
1626 back in register srcDst.
1628 int srcDst = (++vPC)->u.operand;
1629 JSValue* v = r[srcDst].jsValue(exec);
1630 if (JSImmediate::canDoFastAdditiveOperations(v))
1631 r[srcDst] = JSImmediate::incImmediateNumber(v);
1633 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1634 VM_CHECK_EXCEPTION();
1641 BEGIN_OPCODE(op_pre_dec) {
1642 /* pre_dec srcDst(r)
1644 Converts register srcDst to number, subtracts one, and puts the result
1645 back in register srcDst.
1647 int srcDst = (++vPC)->u.operand;
1648 JSValue* v = r[srcDst].jsValue(exec);
1649 if (JSImmediate::canDoFastAdditiveOperations(v))
1650 r[srcDst] = JSImmediate::decImmediateNumber(v);
1652 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1653 VM_CHECK_EXCEPTION();
1660 BEGIN_OPCODE(op_post_inc) {
1661 /* post_inc dst(r) srcDst(r)
1663 Converts register srcDst to number. The number itself is
1664 written to register dst, and the number plus one is written
1665 back to register srcDst.
1667 int dst = (++vPC)->u.operand;
1668 int srcDst = (++vPC)->u.operand;
1669 JSValue* v = r[srcDst].jsValue(exec);
1670 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1672 r[srcDst] = JSImmediate::incImmediateNumber(v);
1674 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1675 VM_CHECK_EXCEPTION();
1677 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1683 BEGIN_OPCODE(op_post_dec) {
1684 /* post_dec dst(r) srcDst(r)
1686 Converts register srcDst to number. The number itself is
1687 written to register dst, and the number minus one is written
1688 back to register srcDst.
1690 int dst = (++vPC)->u.operand;
1691 int srcDst = (++vPC)->u.operand;
1692 JSValue* v = r[srcDst].jsValue(exec);
1693 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1695 r[srcDst] = JSImmediate::decImmediateNumber(v);
1697 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1698 VM_CHECK_EXCEPTION();
1700 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1706 BEGIN_OPCODE(op_to_jsnumber) {
1707 /* to_jsnumber dst(r) src(r)
1709 Converts register src to number, and puts the result
1712 int dst = (++vPC)->u.operand;
1713 int src = (++vPC)->u.operand;
1714 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1715 VM_CHECK_EXCEPTION();
1722 BEGIN_OPCODE(op_negate) {
1723 /* negate dst(r) src(r)
1725 Converts register src to number, negates it, and puts the
1726 result in register dst.
1728 int dst = (++vPC)->u.operand;
1729 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1731 if (fastIsNumber(src, v))
1732 r[dst] = jsNumber(exec, -v);
1734 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1735 VM_CHECK_EXCEPTION();
1742 BEGIN_OPCODE(op_add) {
1743 /* add dst(r) src1(r) src2(r)
1745 Adds register src1 and register src2, and puts the result
1746 in register dst. (JS add may be string concatenation or
1747 numeric add, depending on the types of the operands.)
1749 int dst = (++vPC)->u.operand;
1750 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1751 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1752 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1753 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1755 JSValue* result = jsAdd(exec, src1, src2);
1756 VM_CHECK_EXCEPTION();
1762 BEGIN_OPCODE(op_mul) {
1763 /* mul dst(r) src1(r) src2(r)
1765 Multiplies register src1 and register src2 (converted to
1766 numbers), and puts the product in register dst.
1768 int dst = (++vPC)->u.operand;
1769 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1770 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1773 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1774 r[dst] = jsNumber(exec, left * right);
1776 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1777 VM_CHECK_EXCEPTION();
1784 BEGIN_OPCODE(op_div) {
1785 /* div dst(r) dividend(r) divisor(r)
1787 Divides register dividend (converted to number) by the
1788 register divisor (converted to number), and puts the
1789 quotient in register dst.
1791 int dst = (++vPC)->u.operand;
1792 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1793 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1796 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1797 r[dst] = jsNumber(exec, left / right);
1799 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1800 VM_CHECK_EXCEPTION();
1806 BEGIN_OPCODE(op_mod) {
1807 /* mod dst(r) dividend(r) divisor(r)
1809 Divides register dividend (converted to number) by
1810 register divisor (converted to number), and puts the
1811 remainder in register dst.
1813 int dst = (++vPC)->u.operand;
1814 int dividend = (++vPC)->u.operand;
1815 int divisor = (++vPC)->u.operand;
1817 JSValue* dividendValue = r[dividend].jsValue(exec);
1818 JSValue* divisorValue = r[divisor].jsValue(exec);
1820 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1821 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1826 double d = dividendValue->toNumber(exec);
1827 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1828 VM_CHECK_EXCEPTION();
1833 BEGIN_OPCODE(op_sub) {
1834 /* sub dst(r) src1(r) src2(r)
1836 Subtracts register src2 (converted to number) from register
1837 src1 (converted to number), and puts the difference in
1840 int dst = (++vPC)->u.operand;
1841 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1842 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1845 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1846 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1847 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1848 r[dst] = jsNumber(exec, left - right);
1850 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1851 VM_CHECK_EXCEPTION();
1857 BEGIN_OPCODE(op_lshift) {
1858 /* lshift dst(r) val(r) shift(r)
1860 Performs left shift of register val (converted to int32) by
1861 register shift (converted to uint32), and puts the result
1864 int dst = (++vPC)->u.operand;
1865 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1866 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1869 if (JSImmediate::areBothImmediateNumbers(val, shift))
1870 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1871 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1872 r[dst] = jsNumber(exec, left << (right & 0x1f));
1874 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1875 VM_CHECK_EXCEPTION();
1882 BEGIN_OPCODE(op_rshift) {
1883 /* rshift dst(r) val(r) shift(r)
1885 Performs arithmetic right shift of register val (converted
1886 to int32) by register shift (converted to
1887 uint32), and puts the result in register dst.
1889 int dst = (++vPC)->u.operand;
1890 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1891 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1894 if (JSImmediate::areBothImmediateNumbers(val, shift))
1895 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1896 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1897 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1899 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1900 VM_CHECK_EXCEPTION();
1907 BEGIN_OPCODE(op_urshift) {
1908 /* rshift dst(r) val(r) shift(r)
1910 Performs logical right shift of register val (converted
1911 to uint32) by register shift (converted to
1912 uint32), and puts the result in register dst.
1914 int dst = (++vPC)->u.operand;
1915 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1916 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1917 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1918 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1920 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1921 VM_CHECK_EXCEPTION();
1928 BEGIN_OPCODE(op_bitand) {
1929 /* bitand dst(r) src1(r) src2(r)
1931 Computes bitwise AND of register src1 (converted to int32)
1932 and register src2 (converted to int32), and puts the result
1935 int dst = (++vPC)->u.operand;
1936 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1937 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1940 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1941 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1942 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1943 r[dst] = jsNumber(exec, left & right);
1945 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1946 VM_CHECK_EXCEPTION();
1953 BEGIN_OPCODE(op_bitxor) {
1954 /* bitxor dst(r) src1(r) src2(r)
1956 Computes bitwise XOR of register src1 (converted to int32)
1957 and register src2 (converted to int32), and puts the result
1960 int dst = (++vPC)->u.operand;
1961 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1962 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1965 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1966 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1967 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1968 r[dst] = jsNumber(exec, left ^ right);
1970 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1971 VM_CHECK_EXCEPTION();
1978 BEGIN_OPCODE(op_bitor) {
1979 /* bitor dst(r) src1(r) src2(r)
1981 Computes bitwise OR of register src1 (converted to int32)
1982 and register src2 (converted to int32), and puts the
1983 result in register dst.
1985 int dst = (++vPC)->u.operand;
1986 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1987 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1990 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1991 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1992 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1993 r[dst] = jsNumber(exec, left | right);
1995 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1996 VM_CHECK_EXCEPTION();
2003 BEGIN_OPCODE(op_bitnot) {
2004 /* bitnot dst(r) src(r)
2006 Computes bitwise NOT of register src1 (converted to int32),
2007 and puts the result in register dst.
2009 int dst = (++vPC)->u.operand;
2010 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2012 if (fastToInt32(src, value))
2013 r[dst] = jsNumber(exec, ~value);
2015 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2016 VM_CHECK_EXCEPTION();
2022 BEGIN_OPCODE(op_not) {
2023 /* not dst(r) src(r)
2025 Computes logical NOT of register src (converted to
2026 boolean), and puts the result in register dst.
2028 int dst = (++vPC)->u.operand;
2029 int src = (++vPC)->u.operand;
2030 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2031 VM_CHECK_EXCEPTION();
2037 BEGIN_OPCODE(op_instanceof) {
2038 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2040 Tests whether register value is an instance of register
2041 constructor, and puts the boolean result in register
2042 dst. Register constructorProto must contain the "prototype"
2043 property (not the actual prototype) of the object in
2044 register constructor. This lookup is separated so that
2045 polymorphic inline caching can apply.
2047 Raises an exception if register constructor is not an
2050 int dst = (++vPC)->u.operand;
2051 int value = (++vPC)->u.operand;
2052 int base = (++vPC)->u.operand;
2053 int baseProto = (++vPC)->u.operand;
2055 JSValue* baseVal = r[base].jsValue(exec);
2057 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2060 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2061 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2066 BEGIN_OPCODE(op_typeof) {
2067 /* typeof dst(r) src(r)
2069 Determines the type string for src according to ECMAScript
2070 rules, and puts the result in register dst.
2072 int dst = (++vPC)->u.operand;
2073 int src = (++vPC)->u.operand;
2074 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2079 BEGIN_OPCODE(op_is_undefined) {
2080 /* is_undefined dst(r) src(r)
2082 Determines whether the type string for src according to
2083 the ECMAScript rules is "undefined", and puts the result
2086 int dst = (++vPC)->u.operand;
2087 int src = (++vPC)->u.operand;
2088 JSValue* v = r[src].jsValue(exec);
2089 r[dst] = jsBoolean(v->isUndefined() || (v->isObject() && static_cast<JSObject*>(v)->masqueradeAsUndefined()));
2094 BEGIN_OPCODE(op_is_boolean) {
2095 /* is_boolean dst(r) src(r)
2097 Determines whether the type string for src according to
2098 the ECMAScript rules is "boolean", and puts the result
2101 int dst = (++vPC)->u.operand;
2102 int src = (++vPC)->u.operand;
2103 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2108 BEGIN_OPCODE(op_is_number) {
2109 /* is_number dst(r) src(r)
2111 Determines whether the type string for src according to
2112 the ECMAScript rules is "number", and puts the result
2115 int dst = (++vPC)->u.operand;
2116 int src = (++vPC)->u.operand;
2117 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2122 BEGIN_OPCODE(op_is_string) {
2123 /* is_string dst(r) src(r)
2125 Determines whether the type string for src according to
2126 the ECMAScript rules is "string", and puts the result
2129 int dst = (++vPC)->u.operand;
2130 int src = (++vPC)->u.operand;
2131 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2136 BEGIN_OPCODE(op_is_object) {
2137 /* is_object dst(r) src(r)
2139 Determines whether the type string for src according to
2140 the ECMAScript rules is "object", and puts the result
2143 int dst = (++vPC)->u.operand;
2144 int src = (++vPC)->u.operand;
2145 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2150 BEGIN_OPCODE(op_is_function) {
2151 /* is_function dst(r) src(r)
2153 Determines whether the type string for src according to
2154 the ECMAScript rules is "function", and puts the result
2157 int dst = (++vPC)->u.operand;
2158 int src = (++vPC)->u.operand;
2159 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2164 BEGIN_OPCODE(op_in) {
2165 /* in dst(r) property(r) base(r)
2167 Tests whether register base has a property named register
2168 property, and puts the boolean result in register dst.
2170 Raises an exception if register constructor is not an
2173 int dst = (++vPC)->u.operand;
2174 int property = (++vPC)->u.operand;
2175 int base = (++vPC)->u.operand;
2177 JSValue* baseVal = r[base].jsValue(exec);
2178 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2181 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2183 JSValue* propName = r[property].jsValue(exec);
2186 if (propName->getUInt32(i))
2187 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2189 Identifier property(exec, propName->toString(exec));
2190 VM_CHECK_EXCEPTION();
2191 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2197 BEGIN_OPCODE(op_resolve) {
2198 /* resolve dst(r) property(id)
2200 Looks up the property named by identifier property in the
2201 scope chain, and writes the resulting value to register
2202 dst. If the property is not found, raises an exception.
2204 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2210 BEGIN_OPCODE(op_resolve_skip) {
2211 /* resolve_skip dst(r) property(id) skip(n)
2213 Looks up the property named by identifier property in the
2214 scope chain skipping the top 'skip' levels, and writes the resulting
2215 value to register dst. If the property is not found, raises an exception.
2217 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2224 BEGIN_OPCODE(op_get_global_var) {
2225 /* get_global_var dst(r) index(n)
2227 Gets the global var at global slot index and places it in register dst.
2229 int dst = (++vPC)->u.operand;
2230 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2231 ASSERT(scope->isGlobalObject());
2232 int index = (++vPC)->u.operand;
2234 r[dst] = scope->registerAt(index);
2238 BEGIN_OPCODE(op_put_global_var) {
2239 /* put_global_var globalObject(c) index(n) value(r)
2241 Puts value into global slot index.
2243 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2244 ASSERT(scope->isGlobalObject());
2245 int index = (++vPC)->u.operand;
2246 int value = (++vPC)->u.operand;
2248 scope->registerAt(index) = r[value].jsValue(exec);
2252 BEGIN_OPCODE(op_get_scoped_var) {
2253 /* get_scoped_var dst(r) index(n) skip(n)
2255 Loads the contents of the index-th local from the scope skip nodes from
2256 the top of the scope chain, and places it in register dst
2258 int dst = (++vPC)->u.operand;
2259 int index = (++vPC)->u.operand;
2260 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2262 ScopeChainIterator iter = scopeChain->begin();
2263 ScopeChainIterator end = scopeChain->end();
2264 ASSERT(iter != end);
2267 ASSERT(iter != end);
2270 ASSERT((*iter)->isVariableObject());
2271 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2272 r[dst] = scope->registerAt(index);
2276 BEGIN_OPCODE(op_put_scoped_var) {
2277 /* put_scoped_var index(n) skip(n) value(r)
2280 int index = (++vPC)->u.operand;
2281 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2282 int value = (++vPC)->u.operand;
2284 ScopeChainIterator iter = scopeChain->begin();
2285 ScopeChainIterator end = scopeChain->end();
2286 ASSERT(iter != end);
2289 ASSERT(iter != end);
2292 ASSERT((*iter)->isVariableObject());
2293 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2294 scope->registerAt(index) = r[value].jsValue(exec);
2298 BEGIN_OPCODE(op_resolve_base) {
2299 /* resolve_base dst(r) property(id)
2301 Searches the scope chain for an object containing
2302 identifier property, and if one is found, writes it to
2303 register dst. If none is found, the outermost scope (which
2304 will be the global object) is stored in register dst.
2306 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2311 BEGIN_OPCODE(op_resolve_with_base) {
2312 /* resolve_with_base baseDst(r) propDst(r) property(id)
2314 Searches the scope chain for an object containing
2315 identifier property, and if one is found, writes it to
2316 register srcDst, and the retrieved property value to register
2317 propDst. If the property is not found, raises an exception.
2319 This is more efficient than doing resolve_base followed by
2320 resolve, or resolve_base followed by get_by_id, as it
2321 avoids duplicate hash lookups.
2323 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2329 BEGIN_OPCODE(op_resolve_func) {
2330 /* resolve_func baseDst(r) funcDst(r) property(id)
2332 Searches the scope chain for an object containing
2333 identifier property, and if one is found, writes the
2334 appropriate object to use as "this" when calling its
2335 properties to register baseDst; and the retrieved property
2336 value to register propDst. If the property is not found,
2337 raises an exception.
2339 This differs from resolve_with_base, because the
2340 global this value will be substituted for activations or
2341 the global object, which is the right behavior for function
2342 calls but not for other property lookup.
2344 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2350 BEGIN_OPCODE(op_get_by_id) {
2351 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2353 Generic property access: Gets the property named by identifier
2354 property from the value base, and puts the result in register dst.
2356 int dst = vPC[1].u.operand;
2357 int base = vPC[2].u.operand;
2358 int property = vPC[3].u.operand;
2360 Identifier& ident = codeBlock->identifiers[property];
2361 JSValue* baseValue = r[base].jsValue(exec);
2362 PropertySlot slot(baseValue);
2363 JSValue* result = baseValue->get(exec, ident, slot);
2364 VM_CHECK_EXCEPTION();
2366 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2372 BEGIN_OPCODE(op_get_by_id_self) {
2373 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2375 Cached property access: Attempts to get a cached property from the
2376 value base. If the cache misses, op_get_by_id_self reverts to
2379 int base = vPC[2].u.operand;
2380 JSValue* baseValue = r[base].jsValue(exec);
2382 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2383 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2384 StructureID* structureID = vPC[4].u.structureID;
2386 if (LIKELY(baseCell->structureID() == structureID)) {
2387 ASSERT(baseCell->isObject());
2388 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2389 int dst = vPC[1].u.operand;
2390 int offset = vPC[5].u.operand;
2392 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2393 r[dst] = baseObject->getDirectOffset(offset);
2400 uncacheGetByID(codeBlock, vPC);
2403 BEGIN_OPCODE(op_get_by_id_proto) {
2404 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2406 Cached property access: Attempts to get a cached property from the
2407 value base's prototype. If the cache misses, op_get_by_id_proto
2408 reverts to op_get_by_id.
2410 int base = vPC[2].u.operand;
2411 JSValue* baseValue = r[base].jsValue(exec);
2413 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2414 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2415 StructureID* structureID = vPC[4].u.structureID;
2417 if (LIKELY(baseCell->structureID() == structureID)) {
2418 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2419 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2420 StructureID* protoStructureID = vPC[5].u.structureID;
2422 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2423 int dst = vPC[1].u.operand;
2424 int offset = vPC[6].u.operand;
2426 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2427 r[dst] = protoObject->getDirectOffset(offset);
2435 uncacheGetByID(codeBlock, vPC);
2438 BEGIN_OPCODE(op_get_by_id_chain) {
2439 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2441 Cached property access: Attempts to get a cached property from the
2442 value base's prototype chain. If the cache misses, op_get_by_id_chain
2443 reverts to op_get_by_id.
2445 int base = vPC[2].u.operand;
2446 JSValue* baseValue = r[base].jsValue(exec);
2448 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2449 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2450 StructureID* structureID = vPC[4].u.structureID;
2452 if (LIKELY(baseCell->structureID() == structureID)) {
2453 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2454 size_t count = vPC[6].u.operand;
2455 RefPtr<StructureID>* end = it + count;
2457 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2459 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2460 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2464 int dst = vPC[1].u.operand;
2465 int offset = vPC[7].u.operand;
2467 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2468 r[dst] = baseObject->getDirectOffset(offset);
2477 uncacheGetByID(codeBlock, vPC);
2480 BEGIN_OPCODE(op_get_by_id_generic) {
2481 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2483 Generic property access: Gets the property named by identifier
2484 property from the value base, and puts the result in register dst.
2486 int dst = vPC[1].u.operand;
2487 int base = vPC[2].u.operand;
2488 int property = vPC[3].u.operand;
2490 Identifier& ident = codeBlock->identifiers[property];
2492 JSValue* baseValue = r[base].jsValue(exec);
2493 PropertySlot slot(baseValue);
2494 JSValue* result = baseValue->get(exec, ident, slot);
2495 VM_CHECK_EXCEPTION();
2501 BEGIN_OPCODE(op_get_array_length) {
2502 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2504 Cached property access: Gets the length of the array in register base,
2505 and puts the result in register dst. If register base does not hold
2506 an array, op_get_array_length reverts to op_get_by_id.
2509 int base = vPC[2].u.operand;
2510 JSValue* baseValue = r[base].jsValue(exec);
2511 if (LIKELY(isJSArray(baseValue))) {
2512 int dst = vPC[1].u.operand;
2513 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2518 uncacheGetByID(codeBlock, vPC);
2521 BEGIN_OPCODE(op_get_string_length) {
2522 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2524 Cached property access: Gets the length of the string in register base,
2525 and puts the result in register dst. If register base does not hold
2526 a string, op_get_string_length reverts to op_get_by_id.
2529 int base = vPC[2].u.operand;
2530 JSValue* baseValue = r[base].jsValue(exec);
2531 if (LIKELY(isJSString(baseValue))) {
2532 int dst = vPC[1].u.operand;
2533 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2538 uncacheGetByID(codeBlock, vPC);
2541 BEGIN_OPCODE(op_put_by_id) {
2542 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2544 Generic property access: Sets the property named by identifier
2545 property, belonging to register base, to register value.
2547 Unlike many opcodes, this one does not write any output to
2551 int base = vPC[1].u.operand;
2552 int property = vPC[2].u.operand;
2553 int value = vPC[3].u.operand;
2555 JSValue* baseValue = r[base].jsValue(exec);
2557 PutPropertySlot slot;
2558 Identifier& ident = codeBlock->identifiers[property];
2559 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2560 VM_CHECK_EXCEPTION();
2562 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2567 BEGIN_OPCODE(op_put_by_id_transition) {
2568 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2570 Cached property access: Attempts to set a new property with a cached transition
2571 property named by identifier property, belonging to register base,
2572 to register value. If the cache misses, op_put_by_id_transition
2573 reverts to op_put_by_id_generic.
2575 Unlike many opcodes, this one does not write any output to
2578 int base = vPC[1].u.operand;
2579 JSValue* baseValue = r[base].jsValue(exec);
2581 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2582 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2583 StructureID* oldStructureID = vPC[4].u.structureID;
2584 StructureID* newStructureID = vPC[5].u.structureID;
2586 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2587 ASSERT(baseCell->isObject());
2588 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2590 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2592 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2593 while (!proto->isNull()) {
2594 if (UNLIKELY(proto->structureID() != (*it).get())) {
2595 uncachePutByID(codeBlock, vPC);
2599 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2602 baseObject->transitionTo(newStructureID);
2603 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2604 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2606 int value = vPC[3].u.operand;
2607 unsigned offset = vPC[7].u.operand;
2608 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2609 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2616 uncachePutByID(codeBlock, vPC);
2619 BEGIN_OPCODE(op_put_by_id_replace) {
2620 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2622 Cached property access: Attempts to set a pre-existing, cached
2623 property named by identifier property, belonging to register base,
2624 to register value. If the cache misses, op_put_by_id_replace
2625 reverts to op_put_by_id.
2627 Unlike many opcodes, this one does not write any output to
2630 int base = vPC[1].u.operand;
2631 JSValue* baseValue = r[base].jsValue(exec);
2633 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2634 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2635 StructureID* structureID = vPC[4].u.structureID;
2637 if (LIKELY(baseCell->structureID() == structureID)) {
2638 ASSERT(baseCell->isObject());
2639 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2640 int value = vPC[3].u.operand;
2641 unsigned offset = vPC[5].u.operand;
2643 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2644 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2651 uncachePutByID(codeBlock, vPC);
2654 BEGIN_OPCODE(op_put_by_id_generic) {
2655 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2657 Generic property access: Sets the property named by identifier
2658 property, belonging to register base, to register value.
2660 Unlike many opcodes, this one does not write any output to
2663 int base = vPC[1].u.operand;
2664 int property = vPC[2].u.operand;
2665 int value = vPC[3].u.operand;
2667 JSValue* baseValue = r[base].jsValue(exec);
2669 PutPropertySlot slot;
2670 Identifier& ident = codeBlock->identifiers[property];
2671 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2672 VM_CHECK_EXCEPTION();
2677 BEGIN_OPCODE(op_del_by_id) {
2678 /* del_by_id dst(r) base(r) property(id)
2680 Converts register base to Object, deletes the property
2681 named by identifier property from the object, and writes a
2682 boolean indicating success (if true) or failure (if false)
2685 int dst = (++vPC)->u.operand;
2686 int base = (++vPC)->u.operand;
2687 int property = (++vPC)->u.operand;
2689 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2691 Identifier& ident = codeBlock->identifiers[property];
2692 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2693 VM_CHECK_EXCEPTION();
2698 BEGIN_OPCODE(op_get_by_val) {
2699 /* get_by_val dst(r) base(r) property(r)
2701 Converts register base to Object, gets the property named
2702 by register property from the object, and puts the result
2703 in register dst. property is nominally converted to string
2704 but numbers are treated more efficiently.
2706 int dst = (++vPC)->u.operand;
2707 int base = (++vPC)->u.operand;
2708 int property = (++vPC)->u.operand;
2710 JSValue* baseValue = r[base].jsValue(exec);
2711 JSValue* subscript = r[property].jsValue(exec);
2716 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2717 if (LIKELY(isUInt32)) {
2718 if (isJSArray(baseValue)) {
2719 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2720 if (jsArray->canGetIndex(i))
2721 result = jsArray->getIndex(i);
2723 result = jsArray->JSArray::get(exec, i);
2724 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2725 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2727 result = baseValue->get(exec, i);
2729 Identifier property(exec, subscript->toString(exec));
2730 result = baseValue->get(exec, property);
2733 VM_CHECK_EXCEPTION();
2738 BEGIN_OPCODE(op_put_by_val) {
2739 /* put_by_val base(r) property(r) value(r)
2741 Sets register value on register base as the property named
2742 by register property. Base is converted to object
2743 first. register property is nominally converted to string
2744 but numbers are treated more efficiently.
2746 Unlike many opcodes, this one does not write any output to
2749 int base = (++vPC)->u.operand;
2750 int property = (++vPC)->u.operand;
2751 int value = (++vPC)->u.operand;
2753 JSValue* baseValue = r[base].jsValue(exec);
2754 JSValue* subscript = r[property].jsValue(exec);
2758 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2759 if (LIKELY(isUInt32)) {
2760 if (isJSArray(baseValue)) {
2761 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2762 if (jsArray->canSetIndex(i))
2763 jsArray->setIndex(i, r[value].jsValue(exec));
2765 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2767 baseValue->put(exec, i, r[value].jsValue(exec));
2769 Identifier property(exec, subscript->toString(exec));
2770 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2771 PutPropertySlot slot;
2772 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2776 VM_CHECK_EXCEPTION();
2780 BEGIN_OPCODE(op_del_by_val) {
2781 /* del_by_val dst(r) base(r) property(r)
2783 Converts register base to Object, deletes the property
2784 named by register property from the object, and writes a
2785 boolean indicating success (if true) or failure (if false)
2788 int dst = (++vPC)->u.operand;
2789 int base = (++vPC)->u.operand;
2790 int property = (++vPC)->u.operand;
2792 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2794 JSValue* subscript = r[property].jsValue(exec);
2797 if (subscript->getUInt32(i))
2798 result = jsBoolean(baseObj->deleteProperty(exec, i));
2800 VM_CHECK_EXCEPTION();
2801 Identifier property(exec, subscript->toString(exec));
2802 VM_CHECK_EXCEPTION();
2803 result = jsBoolean(baseObj->deleteProperty(exec, property));
2806 VM_CHECK_EXCEPTION();
2811 BEGIN_OPCODE(op_put_by_index) {
2812 /* put_by_index base(r) property(n) value(r)
2814 Sets register value on register base as the property named
2815 by the immediate number property. Base is converted to
2818 Unlike many opcodes, this one does not write any output to
2821 This opcode is mainly used to initialize array literals.
2823 int base = (++vPC)->u.operand;
2824 unsigned property = (++vPC)->u.operand;
2825 int value = (++vPC)->u.operand;
2827 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2832 BEGIN_OPCODE(op_loop) {
2833 /* loop target(offset)
2835 Jumps unconditionally to offset target from the current
2838 Additionally this loop instruction may terminate JS execution is
2839 the JS timeout is reached.
2841 #if DUMP_OPCODE_STATS
2842 OpcodeStats::resetLastInstruction();
2844 int target = (++vPC)->u.operand;
2845 CHECK_FOR_TIMEOUT();
2849 BEGIN_OPCODE(op_jmp) {
2850 /* jmp target(offset)
2852 Jumps unconditionally to offset target from the current
2855 #if DUMP_OPCODE_STATS
2856 OpcodeStats::resetLastInstruction();
2858 int target = (++vPC)->u.operand;
2863 BEGIN_OPCODE(op_loop_if_true) {
2864 /* loop_if_true cond(r) target(offset)
2866 Jumps to offset target from the current instruction, if and
2867 only if register cond converts to boolean as true.
2869 Additionally this loop instruction may terminate JS execution is
2870 the JS timeout is reached.
2872 int cond = (++vPC)->u.operand;
2873 int target = (++vPC)->u.operand;
2874 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2876 CHECK_FOR_TIMEOUT();
2883 BEGIN_OPCODE(op_jtrue) {
2884 /* jtrue cond(r) target(offset)
2886 Jumps to offset target from the current instruction, if and
2887 only if register cond converts to boolean as true.
2889 int cond = (++vPC)->u.operand;
2890 int target = (++vPC)->u.operand;
2891 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2899 BEGIN_OPCODE(op_jfalse) {
2900 /* jfalse cond(r) target(offset)
2902 Jumps to offset target from the current instruction, if and
2903 only if register cond converts to boolean as false.
2905 int cond = (++vPC)->u.operand;
2906 int target = (++vPC)->u.operand;
2907 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2915 BEGIN_OPCODE(op_loop_if_less) {
2916 /* loop_if_less src1(r) src2(r) target(offset)
2918 Checks whether register src1 is less than register src2, as
2919 with the ECMAScript '<' operator, and then jumps to offset
2920 target from the current instruction, if and only if the
2921 result of the comparison is true.
2923 Additionally this loop instruction may terminate JS execution is
2924 the JS timeout is reached.
2926 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2927 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2928 int target = (++vPC)->u.operand;
2930 bool result = jsLess(exec, src1, src2);
2931 VM_CHECK_EXCEPTION();
2935 CHECK_FOR_TIMEOUT();
2942 BEGIN_OPCODE(op_loop_if_lesseq) {
2943 /* loop_if_lesseq src1(r) src2(r) target(offset)
2945 Checks whether register src1 is less than or equal to register
2946 src2, as with the ECMAScript '<=' operator, and then jumps to
2947 offset target from the current instruction, if and only if the
2948 result of the comparison is true.
2950 Additionally this loop instruction may terminate JS execution is
2951 the JS timeout is reached.
2953 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2954 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2955 int target = (++vPC)->u.operand;
2957 bool result = jsLessEq(exec, src1, src2);
2958 VM_CHECK_EXCEPTION();
2962 CHECK_FOR_TIMEOUT();
2969 BEGIN_OPCODE(op_jnless) {
2970 /* jnless src1(r) src2(r) target(offset)
2972 Checks whether register src1 is less than register src2, as
2973 with the ECMAScript '<' operator, and then jumps to offset
2974 target from the current instruction, if and only if the
2975 result of the comparison is false.
2977 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2978 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2979 int target = (++vPC)->u.operand;
2981 bool result = jsLess(exec, src1, src2);
2982 VM_CHECK_EXCEPTION();
2992 BEGIN_OPCODE(op_switch_imm) {
2993 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2995 Performs a range checked switch on the scrutinee value, using
2996 the tableIndex-th immediate switch jump table. If the scrutinee value
2997 is an immediate number in the range covered by the referenced jump
2998 table, and the value at jumpTable[scrutinee value] is non-zero, then
2999 that value is used as the jump offset, otherwise defaultOffset is used.
3001 int tableIndex = (++vPC)->u.operand;
3002 int defaultOffset = (++vPC)->u.operand;
3003 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3004 if (!JSImmediate::isNumber(scrutinee))
3005 vPC += defaultOffset;
3007 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3008 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3012 BEGIN_OPCODE(op_switch_char) {
3013 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3015 Performs a range checked switch on the scrutinee value, using
3016 the tableIndex-th character switch jump table. If the scrutinee value
3017 is a single character string in the range covered by the referenced jump
3018 table, and the value at jumpTable[scrutinee value] is non-zero, then
3019 that value is used as the jump offset, otherwise defaultOffset is used.
3021 int tableIndex = (++vPC)->u.operand;
3022 int defaultOffset = (++vPC)->u.operand;
3023 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3024 if (!scrutinee->isString())
3025 vPC += defaultOffset;
3027 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3028 if (value->size() != 1)
3029 vPC += defaultOffset;
3031 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3035 BEGIN_OPCODE(op_switch_string) {
3036 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3038 Performs a sparse hashmap based switch on the value in the scrutinee
3039 register, using the tableIndex-th string switch jump table. If the
3040 scrutinee value is a string that exists as a key in the referenced
3041 jump table, then the value associated with the string is used as the
3042 jump offset, otherwise defaultOffset is used.
3044 int tableIndex = (++vPC)->u.operand;
3045 int defaultOffset = (++vPC)->u.operand;
3046 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3047 if (!scrutinee->isString())
3048 vPC += defaultOffset;
3050 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3053 BEGIN_OPCODE(op_new_func) {
3054 /* new_func dst(r) func(f)
3056 Constructs a new Function instance from function func and
3057 the current scope chain using the original Function
3058 constructor, using the rules for function declarations, and
3059 puts the result in register dst.
3061 int dst = (++vPC)->u.operand;
3062 int func = (++vPC)->u.operand;
3064 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3069 BEGIN_OPCODE(op_new_func_exp) {
3070 /* new_func_exp dst(r) func(f)
3072 Constructs a new Function instance from function func and
3073 the current scope chain using the original Function
3074 constructor, using the rules for function expressions, and
3075 puts the result in register dst.
3077 int dst = (++vPC)->u.operand;
3078 int func = (++vPC)->u.operand;
3080 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3085 BEGIN_OPCODE(op_call_eval) {
3086 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3088 Call a function named "eval" with no explicit "this" value
3089 (which may therefore be the eval operator). If register
3090 thisVal is the global object, and register func contains
3091 that global object's original global eval function, then
3092 perform the eval operator in local scope (interpreting
3093 the argument registers as for the "call"
3094 opcode). Otherwise, act exactly as the "call" opcode would.
3097 int dst = (++vPC)->u.operand;
3098 int func = (++vPC)->u.operand;
3099 int thisVal = (++vPC)->u.operand;
3100 int firstArg = (++vPC)->u.operand;
3101 int argCount = (++vPC)->u.operand;
3103 JSValue* funcVal = r[func].jsValue(exec);
3104 JSValue* baseVal = r[thisVal].jsValue(exec);
3106 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3107 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3108 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3118 // We didn't find the blessed version of eval, so reset vPC and process
3119 // this instruction as a normal function call, supplying the proper 'this'
3122 r[thisVal] = baseVal->toThisObject(exec);
3124 #if HAVE(COMPUTED_GOTO)
3125 // Hack around gcc performance quirk by performing an indirect goto
3126 // in order to set the vPC -- attempting to do so directly results in a
3127 // significant regression.
3128 goto *op_call_indirect; // indirect goto -> op_call
3130 // fall through to op_call
3132 BEGIN_OPCODE(op_call) {
3133 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3135 Perform a function call. Specifically, call register func
3136 with a "this" value of register thisVal, and put the result
3139 The arguments start at register firstArg and go up to
3140 argCount, but the "this" value is considered an implicit
3141 first argument, so the argCount should be one greater than
3142 the number of explicit arguments passed, and the register
3143 after firstArg should contain the actual first
3144 argument. This opcode will copy from the thisVal register
3145 to the firstArg register, unless the register index of
3146 thisVal is the special missing this object marker, which is
3147 2^31-1; in that case, the global object will be used as the
3150 If func is a native code function, then this opcode calls
3151 it and returns the value immediately.
3153 But if it is a JS function, then the current scope chain
3154 and code block is set to the function's, and we slide the
3155 register window so that the arguments would form the first
3156 few local registers of the called function's register
3157 window. In addition, a call frame header is written
3158 immediately before the arguments; see the call frame
3159 documentation for an explanation of how many registers a
3160 call frame takes and what they contain. That many registers
3161 before the firstArg register will be overwritten by the
3162 call. In addition, any registers higher than firstArg +
3163 argCount may be overwritten. Once this setup is complete,
3164 execution continues from the called function's first
3165 argument, and does not return until a "ret" opcode is
3169 int dst = (++vPC)->u.operand;
3170 int func = (++vPC)->u.operand;
3171 int thisVal = (++vPC)->u.operand;
3172 int firstArg = (++vPC)->u.operand;
3173 int argCount = (++vPC)->u.operand;
3175 JSValue* v = r[func].jsValue(exec);
3178 CallType callType = v->getCallData(callData);
3180 if (*enabledProfilerReference)
3181 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3183 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3184 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
3185 exec->m_callFrame = callFrame;
3187 if (callType == CallTypeJS) {
3189 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3190 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3191 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3193 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3195 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3196 if (UNLIKELY(exceptionValue != 0))
3199 codeBlock = newCodeBlock;
3200 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3201 vPC = codeBlock->instructions.begin();
3203 #if DUMP_OPCODE_STATS
3204 OpcodeStats::resetLastInstruction();
3210 if (callType == CallTypeHost) {
3211 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3212 ArgList args(r + firstArg + 1, argCount - 1);
3214 MACHINE_SAMPLING_callingHostFunction();
3216 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3217 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3218 VM_CHECK_EXCEPTION();
3220 r[dst] = returnValue;
3222 if (*enabledProfilerReference)
3223 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3229 ASSERT(callType == CallTypeNone);
3231 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3232 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3235 BEGIN_OPCODE(op_ret) {
3238 Return register result as the return value of the current
3239 function call, writing it into the caller's expected return
3240 value register. In addition, unwind one call frame and
3241 restore the scope chain, code block instruction pointer and
3242 register base to those of the calling function.
3245 int result = (++vPC)->u.operand;
3247 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3248 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3249 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3250 ASSERT(activation->isActivationObject());
3251 activation->copyRegisters();
3254 if (*enabledProfilerReference)
3255 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3257 if (codeBlock->needsFullScopeChain)
3258 scopeChain->deref();
3260 JSValue* returnValue = r[result].jsValue(exec);
3262 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3266 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3267 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3268 r = callFrame[RegisterFile::CallerRegisters].r();
3269 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3270 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3271 r[dst] = returnValue;
3275 BEGIN_OPCODE(op_construct) {
3276 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
3278 Invoke register "constr" as a constructor. For JS
3279 functions, the calling convention is exactly as for the
3280 "call" opcode, except that the "this" value is a newly
3281 created Object. For native constructors, a null "this"
3282 value is passed. In either case, the firstArg and argCount
3283 registers are interpreted as for the "call" opcode.
3285 Register constrProto must contain the prototype property of
3286 register constsr. This is to enable polymorphic inline
3287 caching of this lookup.
3290 int dst = (++vPC)->u.operand;
3291 int constr = (++vPC)->u.operand;
3292 int constrProto = (++vPC)->u.operand;
3293 int firstArg = (++vPC)->u.operand;
3294 int argCount = (++vPC)->u.operand;
3296 JSValue* constrVal = r[constr].jsValue(exec);
3298 ConstructData constructData;
3299 ConstructType constructType = constrVal->getConstructData(constructData);
3301 // Removing this line of code causes a measurable regression on squirrelfish.
3302 JSObject* constructor = static_cast<JSObject*>(constrVal);
3304 if (constructType == ConstructTypeJS) {
3305 if (*enabledProfilerReference)
3306 (*enabledProfilerReference)->willExecute(exec, constructor);
3308 JSObject* prototype;
3309 JSValue* p = r[constrProto].jsValue(exec);
3311 prototype = static_cast<JSObject*>(p);
3313 prototype = scopeChain->globalObject()->objectPrototype();
3314 JSObject* newObject = new (exec) JSObject(prototype);
3316 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3317 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3318 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3320 r[firstArg] = newObject; // "this" value
3322 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3323 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
3324 exec->m_callFrame = callFrame;
3326 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3330 codeBlock = newCodeBlock;
3331 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3332 vPC = codeBlock->instructions.begin();
3337 if (constructType == ConstructTypeHost) {
3338 if (*enabledProfilerReference)
3339 (*enabledProfilerReference)->willExecute(exec, constructor);
3341 ArgList args(r + firstArg + 1, argCount - 1);
3343 MACHINE_SAMPLING_callingHostFunction();
3345 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3347 VM_CHECK_EXCEPTION();
3348 r[dst] = returnValue;
3350 if (*enabledProfilerReference)
3351 (*enabledProfilerReference)->didExecute(exec, constructor);
3357 ASSERT(constructType == ConstructTypeNone);
3359 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3362 BEGIN_OPCODE(op_construct_verify) {
3363 /* construct_verify dst(r) override(r)
3365 Verifies that register dst holds an object. If not, moves
3366 the object in register override to register dst.
3369 int dst = vPC[1].u.operand;;
3370 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3375 int override = vPC[2].u.operand;
3376 r[dst] = r[override];
3381 BEGIN_OPCODE(op_push_scope) {
3382 /* push_scope scope(r)
3384 Converts register scope to object, and pushes it onto the top
3385 of the current scope chain.
3387 int scope = (++vPC)->u.operand;
3388 JSValue* v = r[scope].jsValue(exec);
3389 JSObject* o = v->toObject(exec);
3390 VM_CHECK_EXCEPTION();
3392 setScopeChain(exec, scopeChain, scopeChain->push(o));
3397 BEGIN_OPCODE(op_pop_scope) {
3400 Removes the top item from the current scope chain.
3402 setScopeChain(exec, scopeChain, scopeChain->pop());
3407 BEGIN_OPCODE(op_get_pnames) {
3408 /* get_pnames dst(r) base(r)
3410 Creates a property name list for register base and puts it
3411 in register dst. This is not a true JavaScript value, just
3412 a synthetic value used to keep the iteration state in a
3415 int dst = (++vPC)->u.operand;
3416 int base = (++vPC)->u.operand;
3418 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3422 BEGIN_OPCODE(op_next_pname) {
3423 /* next_pname dst(r) iter(r) target(offset)
3425 Tries to copies the next name from property name list in
3426 register iter. If there are names left, then copies one to
3427 register dst, and jumps to offset target. If there are none
3428 left, invalidates the iterator and continues to the next
3431 int dst = (++vPC)->u.operand;
3432 int iter = (++vPC)->u.operand;
3433 int target = (++vPC)->u.operand;
3435 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3436 if (JSValue* temp = it->next(exec)) {
3437 CHECK_FOR_TIMEOUT();