2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "BatchedTransitionOptimizer.h"
34 #include "CodeBlock.h"
35 #include "DebuggerCallFrame.h"
36 #include "ExceptionHelpers.h"
37 #include "ExecState.h"
38 #include "GlobalEvalFunction.h"
39 #include "JSActivation.h"
41 #include "JSFunction.h"
42 #include "JSNotAnObject.h"
43 #include "JSPropertyNameIterator.h"
44 #include "JSStaticScopeObject.h"
46 #include "ObjectPrototype.h"
49 #include "RegExpObject.h"
50 #include "RegExpPrototype.h"
52 #include "collector.h"
54 #include "operations.h"
55 #include "SamplingTool.h"
59 #include <mach/mach.h>
78 // Preferred number of milliseconds between each timeout check
79 static const int preferredScriptCheckTimeInterval = 1000;
81 #if HAVE(COMPUTED_GOTO)
82 static void* op_throw_end_indirect;
83 static void* op_call_indirect;
86 // Returns the depth of the scope chain within a given call frame.
87 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89 if (!codeBlock->needsFullScopeChain)
92 ScopeChainIterator iter = sc.begin();
93 ScopeChainIterator end = sc.end();
94 while (!(*iter)->isActivationObject()) {
103 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
104 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
105 static bool fastIsNumber(JSValue* value, double& arg)
107 if (JSImmediate::isNumber(value))
108 arg = JSImmediate::getTruncatedInt32(value);
109 else if (Heap::isNumber(static_cast<JSCell*>(value)))
110 arg = static_cast<JSNumberCell*>(value)->value();
116 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
117 static bool fastToInt32(JSValue* value, int32_t& arg)
119 if (JSImmediate::isNumber(value))
120 arg = JSImmediate::getTruncatedInt32(value);
121 else if (Heap::isNumber(static_cast<JSCell*>(value)))
122 arg = static_cast<JSNumberCell*>(value)->toInt32();
128 static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
130 if (JSImmediate::isNumber(value)) {
131 if (JSImmediate::getTruncatedUInt32(value, arg))
134 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
136 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
137 arg = static_cast<JSNumberCell*>(value)->toUInt32();
143 static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
145 if (JSImmediate::areBothImmediateNumbers(v1, v2))
146 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
150 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
155 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
156 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
158 if (wasNotString1 | wasNotString2)
161 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
164 static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
166 if (JSImmediate::areBothImmediateNumbers(v1, v2))
167 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
171 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
176 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
177 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
179 if (wasNotString1 | wasNotString2)
182 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
185 static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
187 // exception for the Date exception in defaultValue()
188 JSValue* p1 = v1->toPrimitive(exec);
189 JSValue* p2 = v2->toPrimitive(exec);
191 if (p1->isString() || p2->isString()) {
192 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
194 return throwOutOfMemoryError(exec);
195 return jsString(exec, value.release());
198 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
201 // Fast-path choices here are based on frequency data from SunSpider:
202 // <times> Add case: <t1> <t2>
203 // ---------------------------
204 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
205 // 247412 Add case: 5 5
206 // 20900 Add case: 5 6
207 // 13962 Add case: 5 3
208 // 4000 Add case: 3 5
210 static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
214 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
215 return jsNumber(exec, left + right);
217 if (v1->isString() && v2->isString()) {
218 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
220 return throwOutOfMemoryError(exec);
221 return jsString(exec, value.release());
224 // All other cases are pretty uncommon
225 return jsAddSlowCase(exec, v1, v2);
228 static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
230 if (v->isUndefined())
231 return jsNontrivialString(exec, "undefined");
233 return jsNontrivialString(exec, "boolean");
235 return jsNontrivialString(exec, "number");
237 return jsNontrivialString(exec, "string");
239 // Return "undefined" for objects that should be treated
240 // as null when doing comparisons.
241 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
242 return jsNontrivialString(exec, "undefined");
244 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
245 return jsNontrivialString(exec, "function");
247 return jsNontrivialString(exec, "object");
250 static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
252 int dst = (vPC + 1)->u.operand;
253 int property = (vPC + 2)->u.operand;
255 ScopeChainIterator iter = scopeChain->begin();
256 ScopeChainIterator end = scopeChain->end();
259 Identifier& ident = codeBlock->identifiers[property];
262 PropertySlot slot(o);
263 if (o->getPropertySlot(exec, ident, slot)) {
264 JSValue* result = slot.getValue(exec, ident);
265 exceptionValue = exec->exception();
271 } while (++iter != end);
272 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
276 static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
278 int dst = (vPC + 1)->u.operand;
279 int property = (vPC + 2)->u.operand;
280 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
282 ScopeChainIterator iter = scopeChain->begin();
283 ScopeChainIterator end = scopeChain->end();
289 Identifier& ident = codeBlock->identifiers[property];
292 PropertySlot slot(o);
293 if (o->getPropertySlot(exec, ident, slot)) {
294 JSValue* result = slot.getValue(exec, ident);
295 exceptionValue = exec->exception();
301 } while (++iter != end);
302 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
306 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
308 ScopeChainIterator iter = scopeChain->begin();
309 ScopeChainIterator next = iter;
311 ScopeChainIterator end = scopeChain->end();
318 if (next == end || base->getPropertySlot(exec, property, slot))
325 ASSERT_NOT_REACHED();
329 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
331 int dst = (vPC + 1)->u.operand;
332 int property = (vPC + 2)->u.operand;
333 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
336 static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
338 int baseDst = (vPC + 1)->u.operand;
339 int propDst = (vPC + 2)->u.operand;
340 int property = (vPC + 3)->u.operand;
342 ScopeChainIterator iter = scopeChain->begin();
343 ScopeChainIterator end = scopeChain->end();
345 // FIXME: add scopeDepthIsZero optimization
349 Identifier& ident = codeBlock->identifiers[property];
353 PropertySlot slot(base);
354 if (base->getPropertySlot(exec, ident, slot)) {
355 JSValue* result = slot.getValue(exec, ident);
356 exceptionValue = exec->exception();
364 } while (iter != end);
366 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
370 static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
372 int baseDst = (vPC + 1)->u.operand;
373 int funcDst = (vPC + 2)->u.operand;
374 int property = (vPC + 3)->u.operand;
376 ScopeChainIterator iter = scopeChain->begin();
377 ScopeChainIterator end = scopeChain->end();
379 // FIXME: add scopeDepthIsZero optimization
383 Identifier& ident = codeBlock->identifiers[property];
387 PropertySlot slot(base);
388 if (base->getPropertySlot(exec, ident, slot)) {
389 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
390 // However, section 10.2.3 says that in the case where the value provided
391 // by the caller is null, the global object should be used. It also says
392 // that the section does not apply to internal functions, but for simplicity
393 // of implementation we use the global object anyway here. This guarantees
394 // that in host objects you always get a valid object for this.
395 // We also handle wrapper substitution for the global object at the same time.
396 JSObject* thisObj = base->toThisObject(exec);
397 JSValue* result = slot.getValue(exec, ident);
398 exceptionValue = exec->exception();
402 r[baseDst] = thisObj;
407 } while (iter != end);
409 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
413 ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
415 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
416 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
417 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
418 callFrame[RegisterFile::CallerRegisters] = r;
419 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
420 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
421 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
422 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
423 callFrame[RegisterFile::Callee] = function;
424 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
427 ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
429 size_t registerOffset = argv + newCodeBlock->numLocals;
430 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
432 if (argc == newCodeBlock->numParameters) { // correct number of arguments
433 if (!registerFile->grow(size)) {
434 exceptionValue = createStackOverflowError(exec);
438 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
439 if (!registerFile->grow(size)) {
440 exceptionValue = createStackOverflowError(exec);
445 int omittedArgCount = newCodeBlock->numParameters - argc;
446 Register* endOfParams = r - newCodeBlock->numVars;
447 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
448 (*it) = jsUndefined();
449 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
450 int shift = argc + RegisterFile::CallFrameHeaderSize;
451 registerOffset += shift;
454 if (!registerFile->grow(size)) {
455 exceptionValue = createStackOverflowError(exec);
460 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
461 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
462 for ( ; it != end; ++it)
466 // initialize local variable slots
467 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
468 (*it) = jsUndefined();
470 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
471 r[i] = newCodeBlock->constantRegisters[i];
476 ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
478 if (newCodeBlock->needsFullScopeChain) {
479 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
480 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
482 return callDataScopeChain->copy()->push(activation);
485 return callDataScopeChain;
488 static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
490 if (value->isObject())
492 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
496 NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
499 return jsUndefined();
501 JSValue* program = r[argv + 1].jsValue(exec);
503 if (!program->isString())
506 Profiler** profiler = Profiler::enabledProfilerReference();
508 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
510 UString programSource = static_cast<JSString*>(program)->value();
512 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
516 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
519 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
527 , m_ctiArrayLengthTrampoline(0)
528 , m_ctiStringLengthTrampoline(0)
529 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
533 , m_timeAtLastCheckTimeout(0)
535 , m_timeoutCheckCount(0)
536 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
538 privateExecute(InitializeAndReturn);
540 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
541 void* storage = fastMalloc(sizeof(CollectorBlock));
543 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
544 m_jsArrayVptr = jsArray->vptr();
545 static_cast<JSCell*>(jsArray)->~JSCell();
547 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
548 m_jsStringVptr = jsString->vptr();
549 static_cast<JSCell*>(jsString)->~JSCell();
551 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
552 m_jsFunctionVptr = jsFunction->vptr();
553 static_cast<JSCell*>(jsFunction)->~JSCell();
561 if (m_ctiArrayLengthTrampoline)
562 fastFree(m_ctiArrayLengthTrampoline);
563 if (m_ctiStringLengthTrampoline)
564 fastFree(m_ctiStringLengthTrampoline);
570 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
572 ScopeChain sc(scopeChain);
573 JSGlobalObject* globalObject = sc.globalObject();
574 codeBlock->dump(globalObject->globalExec());
575 dumpRegisters(codeBlock, registerFile, r);
578 void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
580 printf("Register frame: \n\n");
581 printf("----------------------------------------------------\n");
582 printf(" use | address | value \n");
583 printf("----------------------------------------------------\n");
588 if (codeBlock->codeType == GlobalCode) {
589 it = registerFile->lastGlobal();
590 end = it + registerFile->numGlobals();
592 printf("[global var] | %10p | %10p \n", it, (*it).v());
595 printf("----------------------------------------------------\n");
598 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
599 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
600 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
601 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
602 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
603 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
604 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
605 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
606 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
607 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
608 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
609 printf("----------------------------------------------------\n");
611 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
612 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
615 printf("[param] | %10p | %10p \n", it, (*it).v());
619 printf("----------------------------------------------------\n");
621 if (codeBlock->codeType != GlobalCode) {
622 end = it + codeBlock->numVars;
625 printf("[var] | %10p | %10p \n", it, (*it).v());
628 printf("----------------------------------------------------\n");
632 end = it + codeBlock->numTemporaries;
635 printf("[temp] | %10p | %10p \n", it, (*it).v());
643 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
645 bool Machine::isOpcode(Opcode opcode)
647 #if HAVE(COMPUTED_GOTO)
648 return opcode != HashTraits<Opcode>::emptyValue()
649 && !HashTraits<Opcode>::isDeletedValue(opcode)
650 && m_opcodeIDTable.contains(opcode);
652 return opcode >= 0 && opcode <= op_end;
658 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
660 CodeBlock* oldCodeBlock = codeBlock;
661 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
663 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
664 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
665 if (callFrame[RegisterFile::Callee].jsValue(exec))
666 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
668 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
671 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
672 if (callFrame[RegisterFile::Callee].jsValue(exec))
673 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
675 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
678 if (oldCodeBlock->needsFullScopeChain)
681 // If this call frame created an activation, tear it off.
682 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
683 ASSERT(activation->isActivationObject());
684 activation->copyRegisters();
687 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
691 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
692 r = callFrame[RegisterFile::CallerRegisters].r();
693 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
694 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
699 NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
701 // Set up the exception object
703 if (exceptionValue->isObject()) {
704 JSObject* exception = static_cast<JSObject*>(exceptionValue);
705 if (exception->isNotAnObjectErrorStub()) {
706 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
707 exceptionValue = exception;
709 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
710 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
711 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
712 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
713 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
714 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
719 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
720 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
722 // We only hit this path for error messages and throw statements, which don't have a specific failure position
723 // So we just give the full range of the error/throw statement.
724 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
725 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
727 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
728 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
729 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
732 if (exception->isWatchdogException()) {
733 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
734 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
741 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
742 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
743 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
746 // Calculate an exception handler vPC, unwinding call frames as necessary.
749 Instruction* handlerVPC;
751 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
752 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
756 // Now unwind the scope chain within the exception handler's call frame.
758 ScopeChain sc(scopeChain);
759 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
760 ASSERT(scopeDelta >= 0);
763 setScopeChain(exec, scopeChain, sc.node());
768 JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
770 if (m_reentryDepth >= MaxReentryDepth) {
771 *exception = createStackOverflowError(exec);
775 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
777 size_t oldSize = m_registerFile.size();
778 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
779 if (!m_registerFile.grow(newSize)) {
780 *exception = createStackOverflowError(exec);
784 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
785 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
786 globalObject->copyGlobalsTo(m_registerFile);
788 Register* callFrame = m_registerFile.base() + oldSize;
790 // a 0 codeBlock indicates a built-in caller
791 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
793 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
794 r[codeBlock->thisRegister] = thisObj;
796 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
797 r[i] = codeBlock->constantRegisters[i];
799 if (codeBlock->needsFullScopeChain)
800 scopeChain = scopeChain->copy();
802 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
804 Profiler** profiler = Profiler::enabledProfilerReference();
806 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
810 if (!codeBlock->ctiCode)
811 CTI::compile(this, exec, codeBlock);
812 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
814 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
818 MACHINE_SAMPLING_privateExecuteReturned();
821 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
823 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
824 lastGlobalObject->copyGlobalsTo(m_registerFile);
826 m_registerFile.shrink(oldSize);
830 JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
832 if (m_reentryDepth >= MaxReentryDepth) {
833 *exception = createStackOverflowError(exec);
837 int argv = RegisterFile::CallFrameHeaderSize;
838 int argc = args.size() + 1; // implicit "this" parameter
840 size_t oldSize = m_registerFile.size();
841 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
842 *exception = createStackOverflowError(exec);
846 Register* callFrame = m_registerFile.base() + oldSize;
848 // put args in place, including "this"
849 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
852 ArgList::const_iterator end = args.end();
853 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
856 // a 0 codeBlock indicates a built-in caller
857 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
859 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
860 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
862 m_registerFile.shrink(oldSize);
866 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
868 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
870 Profiler** profiler = Profiler::enabledProfilerReference();
872 (*profiler)->willExecute(exec, function);
876 if (!newCodeBlock->ctiCode)
877 CTI::compile(this, exec, newCodeBlock);
878 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
880 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
884 MACHINE_SAMPLING_privateExecuteReturned();
886 m_registerFile.shrink(oldSize);
890 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
892 if (m_reentryDepth >= MaxReentryDepth) {
893 *exception = createStackOverflowError(exec);
897 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
899 JSVariableObject* variableObject;
900 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
902 if (node->object->isVariableObject()) {
903 variableObject = static_cast<JSVariableObject*>(node->object);
908 { // Scope for BatchedTransitionOptimizer
910 BatchedTransitionOptimizer optimizer(variableObject);
912 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
913 Node::VarStack::const_iterator varStackEnd = varStack.end();
914 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
915 const Identifier& ident = (*it).first;
916 if (!variableObject->hasProperty(exec, ident)) {
917 PutPropertySlot slot;
918 variableObject->put(exec, ident, jsUndefined(), slot);
922 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
923 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
924 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
925 PutPropertySlot slot;
926 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
931 size_t oldSize = m_registerFile.size();
932 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
933 if (!m_registerFile.grow(newSize)) {
934 *exception = createStackOverflowError(exec);
938 Register* callFrame = m_registerFile.base() + registerOffset;
940 // a 0 codeBlock indicates a built-in caller
941 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
943 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
944 r[codeBlock->thisRegister] = thisObj;
946 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
947 r[i] = codeBlock->constantRegisters[i];
949 if (codeBlock->needsFullScopeChain)
950 scopeChain = scopeChain->copy();
952 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
954 Profiler** profiler = Profiler::enabledProfilerReference();
956 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
960 if (!codeBlock->ctiCode)
961 CTI::compile(this, exec, codeBlock);
962 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
964 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
968 MACHINE_SAMPLING_privateExecuteReturned();
971 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
973 m_registerFile.shrink(oldSize);
977 ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
979 scopeChain = newScopeChain;
980 exec->m_scopeChain = newScopeChain;
983 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
985 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
989 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
991 switch (debugHookID) {
992 case DidEnterCallFrame:
993 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
995 case WillLeaveCallFrame:
996 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
998 case WillExecuteStatement:
999 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1001 case WillExecuteProgram:
1002 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1004 case DidExecuteProgram:
1005 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1007 case DidReachBreakpoint:
1008 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1013 void Machine::resetTimeoutCheck()
1015 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1016 m_timeAtLastCheckTimeout = 0;
1017 m_timeExecuting = 0;
1020 // Returns the time the current thread has spent executing, in milliseconds.
1021 static inline unsigned getCPUTime()
1023 #if PLATFORM(DARWIN)
1024 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1025 thread_basic_info_data_t info;
1027 // Get thread information
1028 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1030 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1031 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1034 #elif HAVE(SYS_TIME_H)
1035 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1037 gettimeofday(&tv, 0);
1038 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1040 QDateTime t = QDateTime::currentDateTime();
1041 return t.toTime_t() * 1000 + t.time().msec();
1042 #elif PLATFORM(WIN_OS)
1045 unsigned long long fileTimeAsLong;
1046 } userTime, kernelTime;
1048 // GetThreadTimes won't accept NULL arguments so we pass these even though
1049 // they're not used.
1050 FILETIME creationTime, exitTime;
1052 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1054 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1056 #error Platform does not have getCurrentTime function
1060 // We have to return a JSValue here, gcc seems to produce worse code if
1061 // we attempt to return a bool
1062 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1064 unsigned currentTime = getCPUTime();
1066 if (!m_timeAtLastCheckTimeout) {
1067 // Suspicious amount of looping in a script -- start timing it
1068 m_timeAtLastCheckTimeout = currentTime;
1072 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1077 m_timeExecuting += timeDiff;
1078 m_timeAtLastCheckTimeout = currentTime;
1080 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1081 // preferredScriptCheckTimeInterval
1082 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1083 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1084 // preferred script check time interval.
1085 if (m_ticksUntilNextTimeoutCheck == 0)
1086 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1088 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1089 if (globalObject->shouldInterruptScript())
1090 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1092 resetTimeoutCheck();
1098 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1100 int dst = (++vPC)->u.operand;
1101 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1102 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1103 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1105 return scopeChain->push(scope);
1108 static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1110 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(structureID->prototypeForLookup(exec))->structureID());
1111 structureID->setCachedPrototypeChain(chain.release());
1112 return structureID->cachedPrototypeChain();
1115 NEVER_INLINE void Machine::tryCachePutByID(CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1117 // Recursive invocation may already have specialized this instruction.
1118 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1121 if (JSImmediate::isImmediate(baseValue))
1124 // Uncacheable: give up.
1125 if (!slot.isCacheable()) {
1126 vPC[0] = getOpcode(op_put_by_id_generic);
1130 // FIXME: Cache new property transitions, too.
1131 if (slot.type() == PutPropertySlot::NewProperty) {
1132 vPC[0] = getOpcode(op_put_by_id_generic);
1136 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1137 StructureID* structureID = baseCell->structureID();
1139 if (structureID->isDictionary()) {
1140 vPC[0] = getOpcode(op_put_by_id_generic);
1144 // Cache miss: record StructureID to compare against next time.
1145 StructureID* lastStructureID = vPC[4].u.structureID;
1146 if (structureID != lastStructureID) {
1147 // First miss: record StructureID to compare against next time.
1148 if (!lastStructureID) {
1149 vPC[4] = structureID;
1153 // Second miss: give up.
1154 vPC[0] = getOpcode(op_put_by_id_generic);
1158 // Cache hit: Specialize instruction and ref StructureIDs.
1160 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1161 if (baseCell != slot.base()) {
1162 vPC[0] = getOpcode(op_put_by_id_generic);
1165 vPC[0] = getOpcode(op_put_by_id_replace);
1166 vPC[5] = slot.cachedOffset();
1167 codeBlock->refStructureIDs(vPC);
1170 NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1172 codeBlock->derefStructureIDs(vPC);
1173 vPC[0] = getOpcode(op_put_by_id);
1177 NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1179 // Recursive invocation may already have specialized this instruction.
1180 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1183 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1184 vPC[0] = getOpcode(op_get_array_length);
1188 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1189 vPC[0] = getOpcode(op_get_string_length);
1193 // Uncacheable: give up.
1194 if (!slot.isCacheable()) {
1195 vPC[0] = getOpcode(op_get_by_id_generic);
1199 // FIXME: Cache property access for immediates.
1200 if (JSImmediate::isImmediate(baseValue)) {
1201 vPC[0] = getOpcode(op_get_by_id_generic);
1205 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1207 if (structureID->isDictionary()) {
1208 vPC[0] = getOpcode(op_get_by_id_generic);
1213 StructureID* lastStructureID = vPC[4].u.structureID;
1214 if (structureID != lastStructureID) {
1215 // First miss: record StructureID to compare against next time.
1216 if (!lastStructureID) {
1217 vPC[4] = structureID;
1221 // Second miss: give up.
1222 vPC[0] = getOpcode(op_get_by_id_generic);
1226 // Cache hit: Specialize instruction and ref StructureIDs.
1228 if (slot.slotBase() == baseValue) {
1229 vPC[0] = getOpcode(op_get_by_id_self);
1230 vPC[5] = slot.cachedOffset();
1232 codeBlock->refStructureIDs(vPC);
1236 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1237 ASSERT(slot.slotBase()->isObject());
1239 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1241 // Heavy access to a prototype is a good indication that it's not being
1242 // used as a dictionary.
1243 if (baseObject->structureID()->isDictionary()) {
1244 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1245 baseObject->setStructureID(transition.release());
1246 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1249 vPC[0] = getOpcode(op_get_by_id_proto);
1250 vPC[5] = baseObject->structureID();
1251 vPC[6] = slot.cachedOffset();
1253 codeBlock->refStructureIDs(vPC);
1258 JSObject* o = static_cast<JSObject*>(baseValue);
1259 while (slot.slotBase() != o) {
1260 JSValue* v = o->structureID()->prototypeForLookup(exec);
1262 // If we didn't find base in baseValue's prototype chain, then baseValue
1263 // must be a proxy for another object.
1265 vPC[0] = getOpcode(op_get_by_id_generic);
1269 o = static_cast<JSObject*>(v);
1271 // Heavy access to a prototype is a good indication that it's not being
1272 // used as a dictionary.
1273 if (o->structureID()->isDictionary()) {
1274 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1275 o->setStructureID(transition.release());
1276 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1282 StructureIDChain* chain = structureID->cachedPrototypeChain();
1284 chain = cachePrototypeChain(exec, structureID);
1286 vPC[0] = getOpcode(op_get_by_id_chain);
1287 vPC[4] = structureID;
1290 vPC[7] = slot.cachedOffset();
1291 codeBlock->refStructureIDs(vPC);
1294 NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1296 codeBlock->derefStructureIDs(vPC);
1297 vPC[0] = getOpcode(op_get_by_id);
1301 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1303 // One-time initialization of our address tables. We have to put this code
1304 // here because our labels are only in scope inside this function.
1305 if (flag == InitializeAndReturn) {
1306 #if HAVE(COMPUTED_GOTO)
1307 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1308 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1311 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1312 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1313 #undef ADD_OPCODE_ID
1314 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1315 op_throw_end_indirect = &&op_throw_end;
1316 op_call_indirect = &&op_call;
1317 #endif // HAVE(COMPUTED_GOTO)
1322 // Currently with CTI enabled we never interpret functions
1323 ASSERT_NOT_REACHED();
1326 JSValue* exceptionValue = 0;
1327 Instruction* handlerVPC = 0;
1329 Register* registerBase = registerFile->base();
1330 Instruction* vPC = codeBlock->instructions.begin();
1331 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1332 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1334 #define VM_CHECK_EXCEPTION() \
1336 if (UNLIKELY(exec->hadException())) { \
1337 exceptionValue = exec->exception(); \
1342 #if DUMP_OPCODE_STATS
1343 OpcodeStats::resetLastInstruction();
1346 #define CHECK_FOR_TIMEOUT() \
1347 if (!--tickCount) { \
1348 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1350 tickCount = m_ticksUntilNextTimeoutCheck; \
1353 #if HAVE(COMPUTED_GOTO)
1354 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1355 #if DUMP_OPCODE_STATS
1356 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1358 #define BEGIN_OPCODE(opcode) opcode:
1362 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1363 #if DUMP_OPCODE_STATS
1364 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1366 #define BEGIN_OPCODE(opcode) case opcode:
1368 while (1) // iterator loop begins
1369 switch (vPC->u.opcode)
1372 BEGIN_OPCODE(op_new_object) {
1373 /* new_object dst(r)
1375 Constructs a new empty Object instance using the original
1376 constructor, and puts the result in register dst.
1378 int dst = (++vPC)->u.operand;
1379 r[dst] = constructEmptyObject(exec);
1384 BEGIN_OPCODE(op_new_array) {
1385 /* new_array dst(r) firstArg(r) argCount(n)
1387 Constructs a new Array instance using the original
1388 constructor, and puts the result in register dst.
1389 The array will contain argCount elements with values
1390 taken from registers starting at register firstArg.
1392 int dst = (++vPC)->u.operand;
1393 int firstArg = (++vPC)->u.operand;
1394 int argCount = (++vPC)->u.operand;
1395 ArgList args(r + firstArg, argCount);
1396 r[dst] = constructArray(exec, args);
1401 BEGIN_OPCODE(op_new_regexp) {
1402 /* new_regexp dst(r) regExp(re)
1404 Constructs a new RegExp instance using the original
1405 constructor from regexp regExp, and puts the result in
1408 int dst = (++vPC)->u.operand;
1409 int regExp = (++vPC)->u.operand;
1410 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1415 BEGIN_OPCODE(op_mov) {
1416 /* mov dst(r) src(r)
1418 Copies register src to register dst.
1420 int dst = (++vPC)->u.operand;
1421 int src = (++vPC)->u.operand;
1427 BEGIN_OPCODE(op_eq) {
1428 /* eq dst(r) src1(r) src2(r)
1430 Checks whether register src1 and register src2 are equal,
1431 as with the ECMAScript '==' operator, and puts the result
1432 as a boolean in register dst.
1434 int dst = (++vPC)->u.operand;
1435 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1436 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1437 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1438 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1440 JSValue* result = jsBoolean(equal(exec, src1, src2));
1441 VM_CHECK_EXCEPTION();
1448 BEGIN_OPCODE(op_eq_null) {
1449 /* neq dst(r) src(r)
1451 Checks whether register src is null, as with the ECMAScript '!='
1452 operator, and puts the result as a boolean in register dst.
1454 int dst = (++vPC)->u.operand;
1455 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1457 if (src->isUndefinedOrNull()) {
1458 r[dst] = jsBoolean(true);
1463 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1467 BEGIN_OPCODE(op_neq) {
1468 /* neq dst(r) src1(r) src2(r)
1470 Checks whether register src1 and register src2 are not
1471 equal, as with the ECMAScript '!=' operator, and puts the
1472 result as a boolean in register dst.
1474 int dst = (++vPC)->u.operand;
1475 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1476 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1477 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1478 r[dst] = jsBoolean(src1 != src2);
1480 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1481 VM_CHECK_EXCEPTION();
1488 BEGIN_OPCODE(op_neq_null) {
1489 /* neq dst(r) src(r)
1491 Checks whether register src is not null, as with the ECMAScript '!='
1492 operator, and puts the result as a boolean in register dst.
1494 int dst = (++vPC)->u.operand;
1495 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1497 if (src->isUndefinedOrNull()) {
1498 r[dst] = jsBoolean(false);
1503 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1507 BEGIN_OPCODE(op_stricteq) {
1508 /* stricteq dst(r) src1(r) src2(r)
1510 Checks whether register src1 and register src2 are strictly
1511 equal, as with the ECMAScript '===' operator, and puts the
1512 result as a boolean in register dst.
1514 int dst = (++vPC)->u.operand;
1515 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1516 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1517 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1518 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1520 r[dst] = jsBoolean(strictEqual(src1, src2));
1525 BEGIN_OPCODE(op_nstricteq) {
1526 /* nstricteq dst(r) src1(r) src2(r)
1528 Checks whether register src1 and register src2 are not
1529 strictly equal, as with the ECMAScript '!==' operator, and
1530 puts the result as a boolean in register dst.
1532 int dst = (++vPC)->u.operand;
1533 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1534 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1535 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1536 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1538 r[dst] = jsBoolean(!strictEqual(src1, src2));
1543 BEGIN_OPCODE(op_less) {
1544 /* less dst(r) src1(r) src2(r)
1546 Checks whether register src1 is less than register src2, as
1547 with the ECMAScript '<' operator, and puts the result as
1548 a boolean in register dst.
1550 int dst = (++vPC)->u.operand;
1551 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1552 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1553 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1554 VM_CHECK_EXCEPTION();
1560 BEGIN_OPCODE(op_lesseq) {
1561 /* lesseq dst(r) src1(r) src2(r)
1563 Checks whether register src1 is less than or equal to
1564 register src2, as with the ECMAScript '<=' operator, and
1565 puts the result as a boolean in register dst.
1567 int dst = (++vPC)->u.operand;
1568 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1569 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1570 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1571 VM_CHECK_EXCEPTION();
1577 BEGIN_OPCODE(op_pre_inc) {
1578 /* pre_inc srcDst(r)
1580 Converts register srcDst to number, adds one, and puts the result
1581 back in register srcDst.
1583 int srcDst = (++vPC)->u.operand;
1584 JSValue* v = r[srcDst].jsValue(exec);
1585 if (JSImmediate::canDoFastAdditiveOperations(v))
1586 r[srcDst] = JSImmediate::incImmediateNumber(v);
1588 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1589 VM_CHECK_EXCEPTION();
1596 BEGIN_OPCODE(op_pre_dec) {
1597 /* pre_dec srcDst(r)
1599 Converts register srcDst to number, subtracts one, and puts the result
1600 back in register srcDst.
1602 int srcDst = (++vPC)->u.operand;
1603 JSValue* v = r[srcDst].jsValue(exec);
1604 if (JSImmediate::canDoFastAdditiveOperations(v))
1605 r[srcDst] = JSImmediate::decImmediateNumber(v);
1607 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1608 VM_CHECK_EXCEPTION();
1615 BEGIN_OPCODE(op_post_inc) {
1616 /* post_inc dst(r) srcDst(r)
1618 Converts register srcDst to number. The number itself is
1619 written to register dst, and the number plus one is written
1620 back to register srcDst.
1622 int dst = (++vPC)->u.operand;
1623 int srcDst = (++vPC)->u.operand;
1624 JSValue* v = r[srcDst].jsValue(exec);
1625 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1627 r[srcDst] = JSImmediate::incImmediateNumber(v);
1629 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1630 VM_CHECK_EXCEPTION();
1632 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1638 BEGIN_OPCODE(op_post_dec) {
1639 /* post_dec dst(r) srcDst(r)
1641 Converts register srcDst to number. The number itself is
1642 written to register dst, and the number minus one is written
1643 back to register srcDst.
1645 int dst = (++vPC)->u.operand;
1646 int srcDst = (++vPC)->u.operand;
1647 JSValue* v = r[srcDst].jsValue(exec);
1648 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1650 r[srcDst] = JSImmediate::decImmediateNumber(v);
1652 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1653 VM_CHECK_EXCEPTION();
1655 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1661 BEGIN_OPCODE(op_to_jsnumber) {
1662 /* to_jsnumber dst(r) src(r)
1664 Converts register src to number, and puts the result
1667 int dst = (++vPC)->u.operand;
1668 int src = (++vPC)->u.operand;
1669 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1670 VM_CHECK_EXCEPTION();
1677 BEGIN_OPCODE(op_negate) {
1678 /* negate dst(r) src(r)
1680 Converts register src to number, negates it, and puts the
1681 result in register dst.
1683 int dst = (++vPC)->u.operand;
1684 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1686 if (fastIsNumber(src, v))
1687 r[dst] = jsNumber(exec, -v);
1689 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1690 VM_CHECK_EXCEPTION();
1697 BEGIN_OPCODE(op_add) {
1698 /* add dst(r) src1(r) src2(r)
1700 Adds register src1 and register src2, and puts the result
1701 in register dst. (JS add may be string concatenation or
1702 numeric add, depending on the types of the operands.)
1704 int dst = (++vPC)->u.operand;
1705 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1706 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1707 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1708 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1710 JSValue* result = jsAdd(exec, src1, src2);
1711 VM_CHECK_EXCEPTION();
1717 BEGIN_OPCODE(op_mul) {
1718 /* mul dst(r) src1(r) src2(r)
1720 Multiplies register src1 and register src2 (converted to
1721 numbers), and puts the product in register dst.
1723 int dst = (++vPC)->u.operand;
1724 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1725 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1728 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1729 r[dst] = jsNumber(exec, left * right);
1731 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1732 VM_CHECK_EXCEPTION();
1739 BEGIN_OPCODE(op_div) {
1740 /* div dst(r) dividend(r) divisor(r)
1742 Divides register dividend (converted to number) by the
1743 register divisor (converted to number), and puts the
1744 quotient in register dst.
1746 int dst = (++vPC)->u.operand;
1747 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1748 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1751 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1752 r[dst] = jsNumber(exec, left / right);
1754 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1755 VM_CHECK_EXCEPTION();
1761 BEGIN_OPCODE(op_mod) {
1762 /* mod dst(r) dividend(r) divisor(r)
1764 Divides register dividend (converted to number) by
1765 register divisor (converted to number), and puts the
1766 remainder in register dst.
1768 int dst = (++vPC)->u.operand;
1769 int dividend = (++vPC)->u.operand;
1770 int divisor = (++vPC)->u.operand;
1772 JSValue* dividendValue = r[dividend].jsValue(exec);
1773 JSValue* divisorValue = r[divisor].jsValue(exec);
1775 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1776 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1781 double d = dividendValue->toNumber(exec);
1782 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1783 VM_CHECK_EXCEPTION();
1788 BEGIN_OPCODE(op_sub) {
1789 /* sub dst(r) src1(r) src2(r)
1791 Subtracts register src2 (converted to number) from register
1792 src1 (converted to number), and puts the difference in
1795 int dst = (++vPC)->u.operand;
1796 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1797 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1800 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1801 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1802 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1803 r[dst] = jsNumber(exec, left - right);
1805 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1806 VM_CHECK_EXCEPTION();
1812 BEGIN_OPCODE(op_lshift) {
1813 /* lshift dst(r) val(r) shift(r)
1815 Performs left shift of register val (converted to int32) by
1816 register shift (converted to uint32), and puts the result
1819 int dst = (++vPC)->u.operand;
1820 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1821 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1824 if (JSImmediate::areBothImmediateNumbers(val, shift))
1825 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1826 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1827 r[dst] = jsNumber(exec, left << (right & 0x1f));
1829 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1830 VM_CHECK_EXCEPTION();
1837 BEGIN_OPCODE(op_rshift) {
1838 /* rshift dst(r) val(r) shift(r)
1840 Performs arithmetic right shift of register val (converted
1841 to int32) by register shift (converted to
1842 uint32), and puts the result in register dst.
1844 int dst = (++vPC)->u.operand;
1845 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1846 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1849 if (JSImmediate::areBothImmediateNumbers(val, shift))
1850 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1851 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1852 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1854 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1855 VM_CHECK_EXCEPTION();
1862 BEGIN_OPCODE(op_urshift) {
1863 /* rshift dst(r) val(r) shift(r)
1865 Performs logical right shift of register val (converted
1866 to uint32) by register shift (converted to
1867 uint32), and puts the result in register dst.
1869 int dst = (++vPC)->u.operand;
1870 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1871 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1872 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1873 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1875 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1876 VM_CHECK_EXCEPTION();
1883 BEGIN_OPCODE(op_bitand) {
1884 /* bitand dst(r) src1(r) src2(r)
1886 Computes bitwise AND of register src1 (converted to int32)
1887 and register src2 (converted to int32), and puts the result
1890 int dst = (++vPC)->u.operand;
1891 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1892 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1895 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1896 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1897 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1898 r[dst] = jsNumber(exec, left & right);
1900 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1901 VM_CHECK_EXCEPTION();
1908 BEGIN_OPCODE(op_bitxor) {
1909 /* bitxor dst(r) src1(r) src2(r)
1911 Computes bitwise XOR of register src1 (converted to int32)
1912 and register src2 (converted to int32), and puts the result
1915 int dst = (++vPC)->u.operand;
1916 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1917 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1920 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1921 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1922 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1923 r[dst] = jsNumber(exec, left ^ right);
1925 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1926 VM_CHECK_EXCEPTION();
1933 BEGIN_OPCODE(op_bitor) {
1934 /* bitor dst(r) src1(r) src2(r)
1936 Computes bitwise OR of register src1 (converted to int32)
1937 and register src2 (converted to int32), and puts the
1938 result in register dst.
1940 int dst = (++vPC)->u.operand;
1941 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1942 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1945 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1946 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1947 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1948 r[dst] = jsNumber(exec, left | right);
1950 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1951 VM_CHECK_EXCEPTION();
1958 BEGIN_OPCODE(op_bitnot) {
1959 /* bitnot dst(r) src(r)
1961 Computes bitwise NOT of register src1 (converted to int32),
1962 and puts the result in register dst.
1964 int dst = (++vPC)->u.operand;
1965 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1967 if (fastToInt32(src, value))
1968 r[dst] = jsNumber(exec, ~value);
1970 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
1971 VM_CHECK_EXCEPTION();
1977 BEGIN_OPCODE(op_not) {
1978 /* not dst(r) src(r)
1980 Computes logical NOT of register src (converted to
1981 boolean), and puts the result in register dst.
1983 int dst = (++vPC)->u.operand;
1984 int src = (++vPC)->u.operand;
1985 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
1986 VM_CHECK_EXCEPTION();
1992 BEGIN_OPCODE(op_instanceof) {
1993 /* instanceof dst(r) value(r) constructor(r)
1995 Tests whether register value is an instance of register
1996 constructor, and puts the boolean result in register dst.
1998 Raises an exception if register constructor is not an
2001 int dst = (++vPC)->u.operand;
2002 int value = (++vPC)->u.operand;
2003 int base = (++vPC)->u.operand;
2005 JSValue* baseVal = r[base].jsValue(exec);
2007 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2010 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2011 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
2016 BEGIN_OPCODE(op_typeof) {
2017 /* typeof dst(r) src(r)
2019 Determines the type string for src according to ECMAScript
2020 rules, and puts the result in register dst.
2022 int dst = (++vPC)->u.operand;
2023 int src = (++vPC)->u.operand;
2024 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2029 BEGIN_OPCODE(op_in) {
2030 /* in dst(r) property(r) base(r)
2032 Tests whether register base has a property named register
2033 property, and puts the boolean result in register dst.
2035 Raises an exception if register constructor is not an
2038 int dst = (++vPC)->u.operand;
2039 int property = (++vPC)->u.operand;
2040 int base = (++vPC)->u.operand;
2042 JSValue* baseVal = r[base].jsValue(exec);
2043 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2046 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2048 JSValue* propName = r[property].jsValue(exec);
2051 if (propName->getUInt32(i))
2052 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2054 Identifier property(exec, propName->toString(exec));
2055 VM_CHECK_EXCEPTION();
2056 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2062 BEGIN_OPCODE(op_resolve) {
2063 /* resolve dst(r) property(id)
2065 Looks up the property named by identifier property in the
2066 scope chain, and writes the resulting value to register
2067 dst. If the property is not found, raises an exception.
2069 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2075 BEGIN_OPCODE(op_resolve_skip) {
2076 /* resolve_skip dst(r) property(id) skip(n)
2078 Looks up the property named by identifier property in the
2079 scope chain skipping the top 'skip' levels, and writes the resulting
2080 value to register dst. If the property is not found, raises an exception.
2082 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2089 BEGIN_OPCODE(op_get_global_var) {
2090 /* get_global_var dst(r) index(n)
2092 Gets the global var at global slot index and places it in register dst.
2094 int dst = (++vPC)->u.operand;
2095 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2096 ASSERT(scope->isGlobalObject());
2097 int index = (++vPC)->u.operand;
2099 r[dst] = scope->registerAt(index);
2103 BEGIN_OPCODE(op_put_global_var) {
2104 /* put_global_var globalObject(c) index(n) value(r)
2106 Puts value into global slot index.
2108 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2109 ASSERT(scope->isGlobalObject());
2110 int index = (++vPC)->u.operand;
2111 int value = (++vPC)->u.operand;
2113 scope->registerAt(index) = r[value].jsValue(exec);
2117 BEGIN_OPCODE(op_get_scoped_var) {
2118 /* get_scoped_var dst(r) index(n) skip(n)
2120 Loads the contents of the index-th local from the scope skip nodes from
2121 the top of the scope chain, and places it in register dst
2123 int dst = (++vPC)->u.operand;
2124 int index = (++vPC)->u.operand;
2125 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2127 ScopeChainIterator iter = scopeChain->begin();
2128 ScopeChainIterator end = scopeChain->end();
2129 ASSERT(iter != end);
2132 ASSERT(iter != end);
2135 ASSERT((*iter)->isVariableObject());
2136 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2137 r[dst] = scope->registerAt(index);
2141 BEGIN_OPCODE(op_put_scoped_var) {
2142 /* put_scoped_var index(n) skip(n) value(r)
2145 int index = (++vPC)->u.operand;
2146 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2147 int value = (++vPC)->u.operand;
2149 ScopeChainIterator iter = scopeChain->begin();
2150 ScopeChainIterator end = scopeChain->end();
2151 ASSERT(iter != end);
2154 ASSERT(iter != end);
2157 ASSERT((*iter)->isVariableObject());
2158 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2159 scope->registerAt(index) = r[value].jsValue(exec);
2163 BEGIN_OPCODE(op_resolve_base) {
2164 /* resolve_base dst(r) property(id)
2166 Searches the scope chain for an object containing
2167 identifier property, and if one is found, writes it to
2168 register dst. If none is found, the outermost scope (which
2169 will be the global object) is stored in register dst.
2171 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2176 BEGIN_OPCODE(op_resolve_with_base) {
2177 /* resolve_with_base baseDst(r) propDst(r) property(id)
2179 Searches the scope chain for an object containing
2180 identifier property, and if one is found, writes it to
2181 register srcDst, and the retrieved property value to register
2182 propDst. If the property is not found, raises an exception.
2184 This is more efficient than doing resolve_base followed by
2185 resolve, or resolve_base followed by get_by_id, as it
2186 avoids duplicate hash lookups.
2188 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2194 BEGIN_OPCODE(op_resolve_func) {
2195 /* resolve_func baseDst(r) funcDst(r) property(id)
2197 Searches the scope chain for an object containing
2198 identifier property, and if one is found, writes the
2199 appropriate object to use as "this" when calling its
2200 properties to register baseDst; and the retrieved property
2201 value to register propDst. If the property is not found,
2202 raises an exception.
2204 This differs from resolve_with_base, because the
2205 global this value will be substituted for activations or
2206 the global object, which is the right behavior for function
2207 calls but not for other property lookup.
2209 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2215 BEGIN_OPCODE(op_get_by_id) {
2216 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2218 Generic property access: Gets the property named by identifier
2219 property from the value base, and puts the result in register dst.
2221 int dst = vPC[1].u.operand;
2222 int base = vPC[2].u.operand;
2223 int property = vPC[3].u.operand;
2225 Identifier& ident = codeBlock->identifiers[property];
2226 JSValue* baseValue = r[base].jsValue(exec);
2227 PropertySlot slot(baseValue);
2228 JSValue* result = baseValue->get(exec, ident, slot);
2229 VM_CHECK_EXCEPTION();
2231 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2237 BEGIN_OPCODE(op_get_by_id_self) {
2238 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2240 Cached property access: Attempts to get a cached property from the
2241 value base. If the cache misses, op_get_by_id_self reverts to
2244 int base = vPC[2].u.operand;
2245 JSValue* baseValue = r[base].jsValue(exec);
2247 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2248 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2249 StructureID* structureID = vPC[4].u.structureID;
2251 if (LIKELY(baseCell->structureID() == structureID)) {
2252 ASSERT(baseCell->isObject());
2253 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2254 int dst = vPC[1].u.operand;
2255 int offset = vPC[5].u.operand;
2257 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2258 r[dst] = baseObject->getDirectOffset(offset);
2265 uncacheGetByID(codeBlock, vPC);
2268 BEGIN_OPCODE(op_get_by_id_proto) {
2269 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2271 Cached property access: Attempts to get a cached property from the
2272 value base's prototype. If the cache misses, op_get_by_id_proto
2273 reverts to op_get_by_id.
2275 int base = vPC[2].u.operand;
2276 JSValue* baseValue = r[base].jsValue(exec);
2278 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2279 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2280 StructureID* structureID = vPC[4].u.structureID;
2282 if (LIKELY(baseCell->structureID() == structureID)) {
2283 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2284 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2285 StructureID* protoStructureID = vPC[5].u.structureID;
2287 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2288 int dst = vPC[1].u.operand;
2289 int offset = vPC[6].u.operand;
2291 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2292 r[dst] = protoObject->getDirectOffset(offset);
2300 uncacheGetByID(codeBlock, vPC);
2303 BEGIN_OPCODE(op_get_by_id_chain) {
2304 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2306 Cached property access: Attempts to get a cached property from the
2307 value base's prototype chain. If the cache misses, op_get_by_id_chain
2308 reverts to op_get_by_id.
2310 int base = vPC[2].u.operand;
2311 JSValue* baseValue = r[base].jsValue(exec);
2313 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2314 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2315 StructureID* structureID = vPC[4].u.structureID;
2317 if (LIKELY(baseCell->structureID() == structureID)) {
2318 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2319 size_t count = vPC[6].u.operand;
2320 RefPtr<StructureID>* end = it + count;
2323 ASSERT(baseCell->isObject());
2324 JSObject* baseObject = static_cast<JSObject*>(baseCell->structureID()->prototypeForLookup(exec));
2325 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2329 int dst = vPC[1].u.operand;
2330 int offset = vPC[7].u.operand;
2332 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2333 r[dst] = baseObject->getDirectOffset(offset);
2342 uncacheGetByID(codeBlock, vPC);
2345 BEGIN_OPCODE(op_get_by_id_generic) {
2346 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2348 Generic property access: Gets the property named by identifier
2349 property from the value base, and puts the result in register dst.
2351 int dst = vPC[1].u.operand;
2352 int base = vPC[2].u.operand;
2353 int property = vPC[3].u.operand;
2355 Identifier& ident = codeBlock->identifiers[property];
2357 JSValue* baseValue = r[base].jsValue(exec);
2358 PropertySlot slot(baseValue);
2359 JSValue* result = baseValue->get(exec, ident, slot);
2360 VM_CHECK_EXCEPTION();
2366 BEGIN_OPCODE(op_get_array_length) {
2367 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2369 Cached property access: Gets the length of the array in register base,
2370 and puts the result in register dst. If register base does not hold
2371 an array, op_get_array_length reverts to op_get_by_id.
2374 int base = vPC[2].u.operand;
2375 JSValue* baseValue = r[base].jsValue(exec);
2376 if (LIKELY(isJSArray(baseValue))) {
2377 int dst = vPC[1].u.operand;
2378 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2383 uncacheGetByID(codeBlock, vPC);
2386 BEGIN_OPCODE(op_get_string_length) {
2387 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2389 Cached property access: Gets the length of the string in register base,
2390 and puts the result in register dst. If register base does not hold
2391 a string, op_get_string_length reverts to op_get_by_id.
2394 int base = vPC[2].u.operand;
2395 JSValue* baseValue = r[base].jsValue(exec);
2396 if (LIKELY(isJSString(baseValue))) {
2397 int dst = vPC[1].u.operand;
2398 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2403 uncacheGetByID(codeBlock, vPC);
2406 BEGIN_OPCODE(op_put_by_id) {
2407 /* put_by_id base(r) property(id) value(r) nop(n) nop(n)
2409 Generic property access: Sets the property named by identifier
2410 property, belonging to register base, to register value.
2412 Unlike many opcodes, this one does not write any output to
2416 int base = vPC[1].u.operand;
2417 int property = vPC[2].u.operand;
2418 int value = vPC[3].u.operand;
2420 JSValue* baseValue = r[base].jsValue(exec);
2422 PutPropertySlot slot;
2423 Identifier& ident = codeBlock->identifiers[property];
2424 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2425 VM_CHECK_EXCEPTION();
2427 tryCachePutByID(codeBlock, vPC, baseValue, slot);
2432 BEGIN_OPCODE(op_put_by_id_replace) {
2433 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n)
2435 Cached property access: Attempts to set a pre-existing, cached
2436 property named by identifier property, belonging to register base,
2437 to register value. If the cache misses, op_put_by_id_replace
2438 reverts to op_put_by_id.
2440 Unlike many opcodes, this one does not write any output to
2443 int base = vPC[1].u.operand;
2444 JSValue* baseValue = r[base].jsValue(exec);
2446 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2447 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2448 StructureID* structureID = vPC[4].u.structureID;
2450 if (LIKELY(baseCell->structureID() == structureID)) {
2451 ASSERT(baseCell->isObject());
2452 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2453 int value = vPC[3].u.operand;
2454 unsigned offset = vPC[5].u.operand;
2456 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2457 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2464 uncachePutByID(codeBlock, vPC);
2467 BEGIN_OPCODE(op_put_by_id_generic) {
2468 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n)
2470 Generic property access: Sets the property named by identifier
2471 property, belonging to register base, to register value.
2473 Unlike many opcodes, this one does not write any output to
2476 int base = vPC[1].u.operand;
2477 int property = vPC[2].u.operand;
2478 int value = vPC[3].u.operand;
2480 JSValue* baseValue = r[base].jsValue(exec);
2482 PutPropertySlot slot;
2483 Identifier& ident = codeBlock->identifiers[property];
2484 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2485 VM_CHECK_EXCEPTION();
2490 BEGIN_OPCODE(op_del_by_id) {
2491 /* del_by_id dst(r) base(r) property(id)
2493 Converts register base to Object, deletes the property
2494 named by identifier property from the object, and writes a
2495 boolean indicating success (if true) or failure (if false)
2498 int dst = (++vPC)->u.operand;
2499 int base = (++vPC)->u.operand;
2500 int property = (++vPC)->u.operand;
2502 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2504 Identifier& ident = codeBlock->identifiers[property];
2505 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2506 VM_CHECK_EXCEPTION();
2511 BEGIN_OPCODE(op_get_by_val) {
2512 /* get_by_val dst(r) base(r) property(r)
2514 Converts register base to Object, gets the property named
2515 by register property from the object, and puts the result
2516 in register dst. property is nominally converted to string
2517 but numbers are treated more efficiently.
2519 int dst = (++vPC)->u.operand;
2520 int base = (++vPC)->u.operand;
2521 int property = (++vPC)->u.operand;
2523 JSValue* baseValue = r[base].jsValue(exec);
2524 JSValue* subscript = r[property].jsValue(exec);
2529 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2530 if (LIKELY(isUInt32)) {
2531 if (isJSArray(baseValue)) {
2532 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2533 if (jsArray->canGetIndex(i))
2534 result = jsArray->getIndex(i);
2536 result = jsArray->JSArray::get(exec, i);
2537 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2538 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2540 result = baseValue->get(exec, i);
2542 Identifier property(exec, subscript->toString(exec));
2543 result = baseValue->get(exec, property);
2546 VM_CHECK_EXCEPTION();
2551 BEGIN_OPCODE(op_put_by_val) {
2552 /* put_by_val base(r) property(r) value(r)
2554 Sets register value on register base as the property named
2555 by register property. Base is converted to object
2556 first. register property is nominally converted to string
2557 but numbers are treated more efficiently.
2559 Unlike many opcodes, this one does not write any output to
2562 int base = (++vPC)->u.operand;
2563 int property = (++vPC)->u.operand;
2564 int value = (++vPC)->u.operand;
2566 JSValue* baseValue = r[base].jsValue(exec);
2567 JSValue* subscript = r[property].jsValue(exec);
2571 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2572 if (LIKELY(isUInt32)) {
2573 if (isJSArray(baseValue)) {
2574 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2575 if (jsArray->canSetIndex(i))
2576 jsArray->setIndex(i, r[value].jsValue(exec));
2578 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2580 baseValue->put(exec, i, r[value].jsValue(exec));
2582 Identifier property(exec, subscript->toString(exec));
2583 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2584 PutPropertySlot slot;
2585 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2589 VM_CHECK_EXCEPTION();
2593 BEGIN_OPCODE(op_del_by_val) {
2594 /* del_by_val dst(r) base(r) property(r)
2596 Converts register base to Object, deletes the property
2597 named by register property from the object, and writes a
2598 boolean indicating success (if true) or failure (if false)
2601 int dst = (++vPC)->u.operand;
2602 int base = (++vPC)->u.operand;
2603 int property = (++vPC)->u.operand;
2605 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2607 JSValue* subscript = r[property].jsValue(exec);
2610 if (subscript->getUInt32(i))
2611 result = jsBoolean(baseObj->deleteProperty(exec, i));
2613 VM_CHECK_EXCEPTION();
2614 Identifier property(exec, subscript->toString(exec));
2615 VM_CHECK_EXCEPTION();
2616 result = jsBoolean(baseObj->deleteProperty(exec, property));
2619 VM_CHECK_EXCEPTION();
2624 BEGIN_OPCODE(op_put_by_index) {
2625 /* put_by_index base(r) property(n) value(r)
2627 Sets register value on register base as the property named
2628 by the immediate number property. Base is converted to
2631 Unlike many opcodes, this one does not write any output to
2634 This opcode is mainly used to initialize array literals.
2636 int base = (++vPC)->u.operand;
2637 unsigned property = (++vPC)->u.operand;
2638 int value = (++vPC)->u.operand;
2640 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2645 BEGIN_OPCODE(op_loop) {
2646 /* loop target(offset)
2648 Jumps unconditionally to offset target from the current
2651 Additionally this loop instruction may terminate JS execution is
2652 the JS timeout is reached.
2654 #if DUMP_OPCODE_STATS
2655 OpcodeStats::resetLastInstruction();
2657 int target = (++vPC)->u.operand;
2658 CHECK_FOR_TIMEOUT();
2662 BEGIN_OPCODE(op_jmp) {
2663 /* jmp target(offset)
2665 Jumps unconditionally to offset target from the current
2668 #if DUMP_OPCODE_STATS
2669 OpcodeStats::resetLastInstruction();
2671 int target = (++vPC)->u.operand;
2676 BEGIN_OPCODE(op_loop_if_true) {
2677 /* loop_if_true cond(r) target(offset)
2679 Jumps to offset target from the current instruction, if and
2680 only if register cond converts to boolean as true.
2682 Additionally this loop instruction may terminate JS execution is
2683 the JS timeout is reached.
2685 int cond = (++vPC)->u.operand;
2686 int target = (++vPC)->u.operand;
2687 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2689 CHECK_FOR_TIMEOUT();
2696 BEGIN_OPCODE(op_jtrue) {
2697 /* jtrue cond(r) target(offset)
2699 Jumps to offset target from the current instruction, if and
2700 only if register cond converts to boolean as true.
2702 int cond = (++vPC)->u.operand;
2703 int target = (++vPC)->u.operand;
2704 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2712 BEGIN_OPCODE(op_jfalse) {
2713 /* jfalse cond(r) target(offset)
2715 Jumps to offset target from the current instruction, if and
2716 only if register cond converts to boolean as false.
2718 int cond = (++vPC)->u.operand;
2719 int target = (++vPC)->u.operand;
2720 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2728 BEGIN_OPCODE(op_loop_if_less) {
2729 /* loop_if_less src1(r) src2(r) target(offset)
2731 Checks whether register src1 is less than register src2, as
2732 with the ECMAScript '<' operator, and then jumps to offset
2733 target from the current instruction, if and only if the
2734 result of the comparison is true.
2736 Additionally this loop instruction may terminate JS execution is
2737 the JS timeout is reached.
2739 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2740 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2741 int target = (++vPC)->u.operand;
2743 bool result = jsLess(exec, src1, src2);
2744 VM_CHECK_EXCEPTION();
2748 CHECK_FOR_TIMEOUT();
2755 BEGIN_OPCODE(op_jnless) {
2756 /* jnless src1(r) src2(r) target(offset)
2758 Checks whether register src1 is less than register src2, as
2759 with the ECMAScript '<' operator, and then jumps to offset
2760 target from the current instruction, if and only if the
2761 result of the comparison is false.
2763 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2764 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2765 int target = (++vPC)->u.operand;
2767 bool result = jsLess(exec, src1, src2);
2768 VM_CHECK_EXCEPTION();
2778 BEGIN_OPCODE(op_switch_imm) {
2779 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2781 Performs a range checked switch on the scrutinee value, using
2782 the tableIndex-th immediate switch jump table. If the scrutinee value
2783 is an immediate number in the range covered by the referenced jump
2784 table, and the value at jumpTable[scrutinee value] is non-zero, then
2785 that value is used as the jump offset, otherwise defaultOffset is used.
2787 int tableIndex = (++vPC)->u.operand;
2788 int defaultOffset = (++vPC)->u.operand;
2789 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2790 if (!JSImmediate::isNumber(scrutinee))
2791 vPC += defaultOffset;
2793 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2794 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2798 BEGIN_OPCODE(op_switch_char) {
2799 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2801 Performs a range checked switch on the scrutinee value, using
2802 the tableIndex-th character switch jump table. If the scrutinee value
2803 is a single character string in the range covered by the referenced jump
2804 table, and the value at jumpTable[scrutinee value] is non-zero, then
2805 that value is used as the jump offset, otherwise defaultOffset is used.
2807 int tableIndex = (++vPC)->u.operand;
2808 int defaultOffset = (++vPC)->u.operand;
2809 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2810 if (!scrutinee->isString())
2811 vPC += defaultOffset;
2813 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2814 if (value->size() != 1)
2815 vPC += defaultOffset;
2817 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2821 BEGIN_OPCODE(op_switch_string) {
2822 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2824 Performs a sparse hashmap based switch on the value in the scrutinee
2825 register, using the tableIndex-th string switch jump table. If the
2826 scrutinee value is a string that exists as a key in the referenced
2827 jump table, then the value associated with the string is used as the
2828 jump offset, otherwise defaultOffset is used.
2830 int tableIndex = (++vPC)->u.operand;
2831 int defaultOffset = (++vPC)->u.operand;
2832 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2833 if (!scrutinee->isString())
2834 vPC += defaultOffset;
2836 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
2839 BEGIN_OPCODE(op_new_func) {
2840 /* new_func dst(r) func(f)
2842 Constructs a new Function instance from function func and
2843 the current scope chain using the original Function
2844 constructor, using the rules for function declarations, and
2845 puts the result in register dst.
2847 int dst = (++vPC)->u.operand;
2848 int func = (++vPC)->u.operand;
2850 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2855 BEGIN_OPCODE(op_new_func_exp) {
2856 /* new_func_exp dst(r) func(f)
2858 Constructs a new Function instance from function func and
2859 the current scope chain using the original Function
2860 constructor, using the rules for function expressions, and
2861 puts the result in register dst.
2863 int dst = (++vPC)->u.operand;
2864 int func = (++vPC)->u.operand;
2866 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2871 BEGIN_OPCODE(op_call_eval) {
2872 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2874 Call a function named "eval" with no explicit "this" value
2875 (which may therefore be the eval operator). If register
2876 thisVal is the global object, and register func contains
2877 that global object's original global eval function, then
2878 perform the eval operator in local scope (interpreting
2879 the argument registers as for the "call"
2880 opcode). Otherwise, act exactly as the "call" opcode would.
2883 int dst = (++vPC)->u.operand;
2884 int func = (++vPC)->u.operand;
2885 int thisVal = (++vPC)->u.operand;
2886 int firstArg = (++vPC)->u.operand;
2887 int argCount = (++vPC)->u.operand;
2889 JSValue* funcVal = r[func].jsValue(exec);
2890 JSValue* baseVal = r[thisVal].jsValue(exec);
2892 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2893 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2894 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2904 // We didn't find the blessed version of eval, so reset vPC and process
2905 // this instruction as a normal function call, supplying the proper 'this'
2908 r[thisVal] = baseVal->toThisObject(exec);
2910 #if HAVE(COMPUTED_GOTO)
2911 // Hack around gcc performance quirk by performing an indirect goto
2912 // in order to set the vPC -- attempting to do so directly results in a
2913 // significant regression.
2914 goto *op_call_indirect; // indirect goto -> op_call
2916 // fall through to op_call
2918 BEGIN_OPCODE(op_call) {
2919 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2921 Perform a function call. Specifically, call register func
2922 with a "this" value of register thisVal, and put the result
2925 The arguments start at register firstArg and go up to
2926 argCount, but the "this" value is considered an implicit
2927 first argument, so the argCount should be one greater than
2928 the number of explicit arguments passed, and the register
2929 after firstArg should contain the actual first
2930 argument. This opcode will copy from the thisVal register
2931 to the firstArg register, unless the register index of
2932 thisVal is the special missing this object marker, which is
2933 2^31-1; in that case, the global object will be used as the
2936 If func is a native code function, then this opcode calls
2937 it and returns the value immediately.
2939 But if it is a JS function, then the current scope chain
2940 and code block is set to the function's, and we slide the
2941 register window so that the arguments would form the first
2942 few local registers of the called function's register
2943 window. In addition, a call frame header is written
2944 immediately before the arguments; see the call frame
2945 documentation for an explanation of how many registers a
2946 call frame takes and what they contain. That many registers
2947 before the firstArg register will be overwritten by the
2948 call. In addition, any registers higher than firstArg +
2949 argCount may be overwritten. Once this setup is complete,
2950 execution continues from the called function's first
2951 argument, and does not return until a "ret" opcode is
2955 int dst = (++vPC)->u.operand;
2956 int func = (++vPC)->u.operand;
2957 int thisVal = (++vPC)->u.operand;
2958 int firstArg = (++vPC)->u.operand;
2959 int argCount = (++vPC)->u.operand;
2961 JSValue* v = r[func].jsValue(exec);
2964 CallType callType = v->getCallData(callData);
2966 if (*enabledProfilerReference)
2967 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2969 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2970 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
2971 exec->m_callFrame = callFrame;
2973 if (callType == CallTypeJS) {
2975 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2976 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
2977 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2979 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2981 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2982 if (UNLIKELY(exceptionValue != 0))
2985 codeBlock = newCodeBlock;
2986 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2987 vPC = codeBlock->instructions.begin();
2989 #if DUMP_OPCODE_STATS
2990 OpcodeStats::resetLastInstruction();
2996 if (callType == CallTypeHost) {
2997 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2998 ArgList args(r + firstArg + 1, argCount - 1);
3000 MACHINE_SAMPLING_callingHostFunction();
3002 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3003 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3004 VM_CHECK_EXCEPTION();
3006 r[dst] = returnValue;
3008 if (*enabledProfilerReference)
3009 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3015 ASSERT(callType == CallTypeNone);
3017 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3018 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3021 BEGIN_OPCODE(op_ret) {
3024 Return register result as the return value of the current
3025 function call, writing it into the caller's expected return
3026 value register. In addition, unwind one call frame and
3027 restore the scope chain, code block instruction pointer and
3028 register base to those of the calling function.
3031 int result = (++vPC)->u.operand;
3033 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3034 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3035 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3036 ASSERT(activation->isActivationObject());
3037 activation->copyRegisters();
3040 if (*enabledProfilerReference)
3041 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3043 if (codeBlock->needsFullScopeChain)
3044 scopeChain->deref();
3046 JSValue* returnValue = r[result].jsValue(exec);
3047 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
3048 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
3049 returnValue = thisObject;
3052 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3056 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3057 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3058 r = callFrame[RegisterFile::CallerRegisters].r();
3059 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3060 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3061 r[dst] = returnValue;
3065 BEGIN_OPCODE(op_construct) {
3066 /* construct dst(r) constr(r) firstArg(r) argCount(n)
3068 Invoke register "constr" as a constructor. For JS
3069 functions, the calling convention is exactly as for the
3070 "call" opcode, except that the "this" value is a newly
3071 created Object. For native constructors, a null "this"
3072 value is passed. In either case, the firstArg and argCount
3073 registers are interpreted as for the "call" opcode.
3076 int dst = (++vPC)->u.operand;
3077 int constr = (++vPC)->u.operand;
3078 int firstArg = (++vPC)->u.operand;
3079 int argCount = (++vPC)->u.operand;
3081 JSValue* constrVal = r[constr].jsValue(exec);
3083 ConstructData constructData;
3084 ConstructType constructType = constrVal->getConstructData(constructData);
3086 // Removing this line of code causes a measurable regression on squirrelfish.
3087 JSObject* constructor = static_cast<JSObject*>(constrVal);
3089 if (constructType == ConstructTypeJS) {
3090 if (*enabledProfilerReference)
3091 (*enabledProfilerReference)->willExecute(exec, constructor);
3093 JSObject* prototype;
3094 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
3096 prototype = static_cast<JSObject*>(p);
3098 prototype = scopeChain->globalObject()->objectPrototype();
3099 JSObject* newObject = new (exec) JSObject(prototype);
3101 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3102 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3103 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3105 r[firstArg] = newObject; // "this" value
3107 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3108 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
3109 exec->m_callFrame = callFrame;
3111 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3115 codeBlock = newCodeBlock;
3116 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3117 vPC = codeBlock->instructions.begin();
3122 if (constructType == ConstructTypeHost) {
3123 if (*enabledProfilerReference)
3124 (*enabledProfilerReference)->willExecute(exec, constructor);
3126 ArgList args(r + firstArg + 1, argCount - 1);
3128 MACHINE_SAMPLING_callingHostFunction();
3130 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3132 VM_CHECK_EXCEPTION();
3133 r[dst] = returnValue;
3135 if (*enabledProfilerReference)
3136 (*enabledProfilerReference)->didExecute(exec, constructor);
3142 ASSERT(constructType == ConstructTypeNone);
3144 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3147 BEGIN_OPCODE(op_push_scope) {
3148 /* push_scope scope(r)
3150 Converts register scope to object, and pushes it onto the top
3151 of the current scope chain.
3153 int scope = (++vPC)->u.operand;
3154 JSValue* v = r[scope].jsValue(exec);
3155 JSObject* o = v->toObject(exec);
3156 VM_CHECK_EXCEPTION();
3158 setScopeChain(exec, scopeChain, scopeChain->push(o));
3163 BEGIN_OPCODE(op_pop_scope) {
3166 Removes the top item from the current scope chain.
3168 setScopeChain(exec, scopeChain, scopeChain->pop());
3173 BEGIN_OPCODE(op_get_pnames) {
3174 /* get_pnames dst(r) base(r)
3176 Creates a property name list for register base and puts it
3177 in register dst. This is not a true JavaScript value, just
3178 a synthetic value used to keep the iteration state in a
3181 int dst = (++vPC)->u.operand;
3182 int base = (++vPC)->u.operand;
3184 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3188 BEGIN_OPCODE(op_next_pname) {
3189 /* next_pname dst(r) iter(r) target(offset)
3191 Tries to copies the next name from property name list in
3192 register iter. If there are names left, then copies one to
3193 register dst, and jumps to offset target. If there are none
3194 left, invalidates the iterator and continues to the next
3197 int dst = (++vPC)->u.operand;
3198 int iter = (++vPC)->u.operand;
3199 int target = (++vPC)->u.operand;
3201 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3202 if (JSValue* temp = it->next(exec)) {
3203 CHECK_FOR_TIMEOUT();
3213 BEGIN_OPCODE(op_jmp_scopes) {
3214 /* jmp_scopes count(n) target(offset)
3216 Removes the a number of items from the current scope chain
3217 specified by immediate number count, then jumps to offset
3220 int count = (++vPC)->u.operand;
3221 int target = (++vPC)->u.operand;
3223 ScopeChainNode* tmp = scopeChain;
3226 setScopeChain(exec, scopeChain, tmp);
3231 #if HAVE(COMPUTED_GOTO)
3233 goto *(&&skip_new_scope);
3235 BEGIN_OPCODE(op_push_new_scope) {
3236 /* new_scope dst(r) property(id) value(r)
3238 Constructs a new StaticScopeObject with property set to value. That scope
3239 object is then pushed onto the ScopeChain. The scope object is then stored
3242 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
3246 #if HAVE(COMPUTED_GOTO)
3249 BEGIN_OPCODE(op_catch) {
3252 Retrieves the VMs current exception and puts it in register
3253 ex. This is only valid after an exception has been raised,
3254 and usually forms the beginning of an exception handler.
3256 ASSERT(exceptionValue);
3257 ASSERT(!exec->hadException());
3258 int ex = (++vPC)->u.operand;
3259 r[ex] = exceptionValue;
3265 BEGIN_OPCODE(op_throw) {
3268 Throws register ex as an exception. This involves three
3269 steps: first, it is set as the current exception in the
3270 VM's internal state, then the stack is unwound until an
3271 exception handler or a native code boundary is found, and
3272 then control resumes at the exception handler if any or
3273 else the script returns control to the nearest native caller.
3276 int ex = (++vPC)->u.operand;
3277 exceptionValue = r[ex].jsValue(exec);
3279 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
3281 *exception = exceptionValue;
3285 #if HAVE(COMPUTED_GOTO)
3286 // Hack around gcc performance quirk by performing an indirect goto
3287 // in order to set the vPC -- attempting to do so directly results in a
3288 // significant regression.
3289 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3297 BEGIN_OPCODE(op_unexpected_load) {
3298 /* unexpected_load load dst(r) src(k)
3300 Copies constant src to register dst.
3302 int dst = (++vPC)->u.operand;
3303 int src = (++vPC)->u.operand;
3304 r[dst] = codeBlock->unexpectedConstants[src];
3309 BEGIN_OPCODE(op_new_error) {
3310 /* new_error dst(r) type(n) message(k)
3312 Constructs a new Error instance using the original
3313 constructor, using immediate number n as the type and
3314 constant message as the message string. The result is
3315 written to register dst.
3317 int dst = (++vPC)->u.operand;
3318 int type = (++vPC)->u.operand;
3319 int message = (++vPC)->u.operand;
3321 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
3326 BEGIN_OPCODE(op_end) {
3329 Return register result as the value of a global or eval
3330 program. Return control to the calling native code.
3333 if (codeBlock->needsFullScopeChain) {
3334 ASSERT(scopeChain->refCount > 1);
3335 scopeChain->deref();
3337 int result = (++vPC)->u.operand;
3338 return r[result].jsValue(exec);
3340 BEGIN_OPCODE(op_put_getter) {
3341 /* put_getter base(r) property(id) function(r)
3343 Sets register function on register base as the getter named
3344 by identifier property. Base and function are assumed to be
3345 objects as this op should only be used for getters defined
3346 in object literal form.
3348 Unlike many opcodes, this one does not write any output to
3351 int base = (++vPC)->u.operand;
3352 int property = (++vPC)->u.operand;
3353 int function = (++vPC)->u.operand;
3355 ASSERT(r[base].jsValue(exec)->isObject());
3356 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3357 Identifier& ident = codeBlock->identifiers[property];
3358 ASSERT(r[function].jsValue(exec)->isObject());
3359 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3364 BEGIN_OPCODE(op_put_setter) {
3365 /* put_setter base(r) property(id) function(r)
3367 Sets register function on register base as the setter named
3368 by identifier property. Base and function are assumed to be
3369 objects as this op should only be used for setters defined
3370 in object literal form.
3372 Unlike many opcodes, this one does not write any output to
3375 int base = (++vPC)->u.operand;
3376 int property = (++vPC)->u.operand;
3377 int function = (++vPC)->u.operand;
3379 ASSERT(r[base].jsValue(exec)->isObject());
3380 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3381 Identifier& ident = codeBlock->identifiers[property];
3382 ASSERT(r[function].jsValue(exec)->isObject());
3383 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3388 BEGIN_OPCODE(op_jsr) {
3389 /* jsr retAddrDst(r) target(offset)
3391 Places the address of the next instruction into the retAddrDst
3392 register and jumps to offset target from the current instruction.
3394 int retAddrDst = (++vPC)->u.operand;
3395 int target = (++vPC)->u.operand;
3396 r[retAddrDst] = vPC + 1;
3401 BEGIN_OPCODE(op_sret) {
3402 /* sret retAddrSrc(r)
3404 Jumps to the address stored in the retAddrSrc register. This
3405 differs from op_jmp because the target address is stored in a
3406 register, not as an immediate.
3408 int retAddrSrc = (++vPC)->u.operand;
3409 vPC = r[retAddrSrc].vPC();
3412 BEGIN_OPCODE(op_debug) {
3413 /* debug debugHookID(n) firstLine(n) lastLine(n)
3415 Notifies the debugger of the current state of execution. This opcode
3416 is only generated while the debugger is attached.
3418 int debugHookID = (++vPC)->u.operand;
3419 int firstLine = (++vPC)->u.operand;
3420 int lastLine = (++vPC)->u.operand;
3422 debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3428 exec->clearException();
3430 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3431 // cannot fathom if we don't assign to the exceptionValue before branching)
3432 exceptionValue = createInterruptedExecutionException(exec);
3434 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
3436 *exception = exceptionValue;
3445 #undef VM_CHECK_EXCEPTION
3446 #undef CHECK_FOR_TIMEOUT
3449 JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
3451 Register* callFrame = this->callFrame(exec, function);
3455 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
3457 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
3458 activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
3459 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
3462 return activation->get(exec, exec->propertyNames().arguments);
3465 JSValue* Machine::retrieveCaller(ExecState* exec, InternalFunction* function) const
3467 Register* callFrame = this->callFrame(exec, function);
3471 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3472 if (!callerCodeBlock)
3475 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3476 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
3482 void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const
3486 sourceURL = UString();
3488 Register* callFrame = exec->m_callFrame;
3492 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3493 if (!callerCodeBlock)
3496 Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3497 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
3498 sourceId = callerCodeBlock->ownerNode->sourceId();
3499 sourceURL = callerCodeBlock->ownerNode->sourceURL();
3501 JSValue* callee = callFrame[RegisterFile::Callee].getJSValue();
3502 if (callee->toThisObject(exec)->inherits(&InternalFunction::info))
3503 function = retrieveCaller(exec, static_cast<InternalFunction*>(callee));
3506 Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
3508 Register* callFrame = exec->m_callFrame;
3511 while (!callFrame) {
3512 exec = exec->m_prev;
3515 callFrame = exec->m_callFrame;
3518 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
3521 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3522 if (!callerCodeBlock) {
3527 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3531 void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
3533 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
3534 ASSERT(function->inherits(&JSFunction::info));
3536 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
3537 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
3542 NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress)
3544 ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline);
3547 NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
3549 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
3551 if (JSImmediate::isImmediate(baseValue))
3554 // Uncacheable: give up.
3555 if (!slot.isCacheable()) {
3556 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3560 // FIXME: Cache new property transitions, too.
3561 if (slot.type() == PutPropertySlot::NewProperty) {
3562 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3566 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3567 StructureID* structureID = baseCell->structureID();
3569 if (structureID->isDictionary()) {
3570 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3574 // In the interpreter the last structure is trapped here; in CTI we use the
3575 // *_second method to achieve a similar (but not quite the same) effect.
3577 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3578 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3580 // Cache hit: Specialize instruction and ref StructureIDs.
3582 // If baseCell != base, then baseCell must be a proxy for another object.
3583 if (baseCell != slot.base()) {
3584 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3587 vPC[0] = getOpcode(op_put_by_id_replace);
3588 vPC[4] = structureID;
3589 vPC[5] = slot.cachedOffset();
3590 codeBlock->refStructureIDs(vPC);
3592 ctiRepatchCallByReturnAddress(returnAddress, CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset()));
3595 void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3597 if (!m_ctiArrayLengthTrampoline)
3598 m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock);
3600 return m_ctiArrayLengthTrampoline;
3603 void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3605 if (!m_ctiStringLengthTrampoline)
3606 m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock);
3608 return m_ctiStringLengthTrampoline;
3611 NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
3613 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
3615 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
3616 ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock));
3619 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
3620 ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock));
3624 // Uncacheable: give up.
3625 if (!slot.isCacheable()) {
3626 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3630 // FIXME: Cache property access for immediates.
3631 if (JSImmediate::isImmediate(baseValue)) {
3632 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3636 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3637 StructureID* structureID = baseCell->structureID();
3639 if (structureID->isDictionary()) {
3640 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3644 // In the interpreter the last structure is trapped here; in CTI we use the
3645 // *_second method to achieve a similar (but not quite the same) effect.
3647 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3648 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3650 // Cache hit: Specialize instruction and ref StructureIDs.
3652 if (slot.slotBase() == baseValue) {
3653 // set this up, so derefStructureIDs can do it's job.
3654 vPC[0] = getOpcode(op_get_by_id_self);
3655 vPC[4] = structureID;
3656 vPC[5] = slot.cachedOffset();
3657 codeBlock->refStructureIDs(vPC);
3659 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset()));
3663 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
3664 ASSERT(slot.slotBase()->isObject());
3666 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
3668 // Heavy access to a prototype is a good indication that it's not being
3669 // used as a dictionary.
3670 if (slotBaseObject->structureID()->isDictionary()) {
3671 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
3672 slotBaseObject->setStructureID(transition.release());
3673 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
3676 vPC[0] = getOpcode(op_get_by_id_proto);
3677 vPC[4] = structureID;
3678 vPC[5] = slotBaseObject->structureID();
3679 vPC[6] = slot.cachedOffset();
3680 codeBlock->refStructureIDs(vPC);
3682 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset()));
3687 JSObject* o = static_cast<JSObject*>(baseValue);
3688 while (slot.slotBase() != o) {
3689 JSValue* v = o->structureID()->prototypeForLookup(exec);
3691 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
3692 // must be a proxy for another object.
3695 vPC[0] = getOpcode(op_get_by_id_generic);
3699 o = static_cast<JSObject*>(v);
3701 // Heavy access to a prototype is a good indication that it's not being
3702 // used as a dictionary.
3703 if (o->structureID()->isDictionary()) {
3704 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
3705 o->setStructureID(transition.release());
3706 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
3712 StructureIDChain* chain = structureID->cachedPrototypeChain();
3714 chain = cachePrototypeChain(exec, structureID);
3716 vPC[0] = getOpcode(op_get_by_id_chain);
3717 vPC[4] = structureID;
3720 vPC[7] = slot.cachedOffset();
3721 codeBlock->refStructureIDs(vPC);
3723 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdChain(this, exec, codeBlock, structureID, chain, count, slot.cachedOffset()));
3727 #define JSVALUE_VM_CHECK_EXCEPTION_ARG(exception) \
3729 if (UNLIKELY(exception != 0)) { \
3730 exec->setException(exception); \
3731 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
3732 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
3736 #define VM_CHECK_EXCEPTION_v() \
3738 if (UNLIKELY(exec->hadException())) { \
3739 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
3740 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
3744 #define VM_CHECK_EXCEPTION(type) \
3746 if (UNLIKELY(exec->hadException())) { \
3747 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
3748 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
3752 #define VM_CHECK_EXCEPTION_AT_END() \
3754 if (UNLIKELY(exec->hadException())) { \
3755 /*printf("VM_CHECK_EXCEPTION_AT_END()\n");*/ \
3756 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
3757 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
3761 void Machine::cti_op_end(CTI_ARGS)
3763 ASSERT(ARG_scopeChain->refCount > 1);
3764 ARG_scopeChain->deref();
3767 JSValue* Machine::cti_op_add(CTI_ARGS)
3769 JSValue* src1 = ARG_src1;
3770 JSValue* src2 = ARG_src2;
3772 ExecState* exec = ARG_exec;
3773 JSValue* result = jsAdd(exec, src1, src2);
3774 VM_CHECK_EXCEPTION_AT_END();
3778 JSValue* Machine::cti_op_pre_inc(CTI_ARGS)
3780 JSValue* v = ARG_src1;
3782 ExecState* exec = ARG_exec;
3783 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
3784 VM_CHECK_EXCEPTION_AT_END();
3788 void Machine::cti_timeout_check(CTI_ARGS)
3790 ExecState* exec = ARG_exec;
3792 if (exec->machine()->checkTimeout(exec->dynamicGlobalObject()))
3793 exec->setException(createInterruptedExecutionException(exec));
3795 VM_CHECK_EXCEPTION_AT_END();
3799 int Machine::cti_op_loop_if_less(CTI_ARGS)
3801 JSValue* src1 = ARG_src1;
3802 JSValue* src2 = ARG_src2;
3803 ExecState* exec = ARG_exec;
3805 bool result = jsLess(exec, src1, src2);
3806 VM_CHECK_EXCEPTION_AT_END();
3810 JSValue* Machine::cti_op_new_object(CTI_ARGS)
3812 return constructEmptyObject(ARG_exec);;
3815 void Machine::cti_op_put_by_id(CTI_ARGS)
3817 ExecState* exec = ARG_exec;
3818 Identifier& ident = *ARG_id2;
3820 PutPropertySlot slot;
3821 ARG_src1->put(exec, ident, ARG_src3, slot);
3823 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_second);
3825 VM_CHECK_EXCEPTION_AT_END();
3828 void Machine::cti_op_put_by_id_second(CTI_ARGS)
3830 ExecState* exec = ARG_exec;
3831 Identifier& ident = *ARG_id2;
3833 JSValue* baseValue = ARG_src1;
3834 PutPropertySlot slot;
3835 baseValue->put(exec, ident, ARG_src3, slot);
3837 exec->machine()->tryCTICachePutByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, slot);
3839 VM_CHECK_EXCEPTION_AT_END();
3842 void Machine::cti_op_put_by_id_generic(CTI_ARGS)
3844 ExecState* exec = ARG_exec;
3845 Identifier& ident = *ARG_id2;
3847 PutPropertySlot slot;
3848 ARG_src1->put(exec, ident, ARG_src3, slot);
3850 VM_CHECK_EXCEPTION_AT_END();
3853 void Machine::cti_op_put_by_id_fail(CTI_ARGS)
3855 ExecState* exec = ARG_exec;
3856 Identifier& ident = *ARG_id2;
3858 PutPropertySlot slot;
3859 ARG_src1->put(exec, ident, ARG_src3, slot);
3861 // should probably uncachePutByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
3862 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_generic);
3864 VM_CHECK_EXCEPTION_AT_END();
3867 JSValue* Machine::cti_op_get_by_id(CTI_ARGS)
3869 ExecState* exec = ARG_exec;
3870 Identifier& ident = *ARG_id2;
3872 JSValue* baseValue = ARG_src1;
3873 PropertySlot slot(baseValue);
3874 JSValue* result = baseValue->get(exec, ident, slot);
3876 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_second);
3878 VM_CHECK_EXCEPTION_AT_END();
3882 JSValue* Machine::cti_op_get_by_id_second(CTI_ARGS)
3884 ExecState* exec = ARG_exec;
3885 Identifier& ident = *ARG_id2;
3887 JSValue* baseValue = ARG_src1;
3888 PropertySlot slot(baseValue);
3889 JSValue* result = baseValue->get(exec, ident, slot);
3891 exec->machine()->tryCTICacheGetByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, ident, slot);
3893 VM_CHECK_EXCEPTION_AT_END();
3897 JSValue* Machine::cti_op_get_by_id_generic(CTI_ARGS)
3899 ExecState* exec = ARG_exec;
3900 Identifier& ident = *ARG_id2;
3902 JSValue* baseValue = ARG_src1;
3903 PropertySlot slot(baseValue);
3904 JSValue* result = baseValue->get(exec, ident, slot);
3906 VM_CHECK_EXCEPTION_AT_END();
3910 JSValue* Machine::cti_op_get_by_id_fail(CTI_ARGS)
3912 ExecState* exec = ARG_exec;
3913 Identifier& ident = *ARG_id2;
3915 JSValue* baseValue = ARG_src1;
3916 PropertySlot slot(baseValue);
3917 JSValue* result = baseValue->get(exec, ident, slot);
3919 // should probably uncacheGetByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
3920 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_generic);
3922 VM_CHECK_EXCEPTION_AT_END();
3926 JSValue* Machine::cti_op_instanceof(CTI_ARGS)
3928 ExecState* exec = ARG_exec;
3929 JSValue* baseVal = ARG_src2;
3931 if (!baseVal->isObject()) {
3932 CodeBlock* codeBlock = ARG_codeBlock;
3933 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
3934 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
3935 exec->setException(createInvalidParamError(exec, "instanceof", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock));
3936 VM_CHECK_EXCEPTION(JSValue*);
3939 JSObject* baseObj = static_cast<JSObject*>(baseVal);
3940 JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, ARG_src1) : false);
3941 VM_CHECK_EXCEPTION_AT_END();
3945 JSValue* Machine::cti_op_del_by_id(CTI_ARGS)
3947 ExecState* exec = ARG_exec;
3948 Identifier& ident = *ARG_id2;
3950 JSObject* baseObj = ARG_src1->toObject(exec);
3952 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
3953 VM_CHECK_EXCEPTION_AT_END();
3957 JSValue* Machine::cti_op_mul(CTI_ARGS)
3959 ExecState* exec = ARG_exec;
3960 JSValue* src1 = ARG_src1;
3961 JSValue* src2 = ARG_src2;
3965 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
3966 return jsNumber(exec, left * right);
3968 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
3969 VM_CHECK_EXCEPTION_AT_END();
3974 JSValue* Machine::cti_op_new_func(CTI_ARGS)
3976 return ARG_func1->makeFunction(ARG_exec, ARG_scopeChain);
3979 void* Machine::cti_op_call_JSFunction(CTI_ARGS)
3981 ExecState* exec = ARG_exec;
3982 RegisterFile* registerFile = ARG_registerFile;
3983 Register* r = ARG_r;
3984 CodeBlock* codeBlock = ARG_codeBlock;
3985 ScopeChainNode* scopeChain = ARG_scopeChain;
3987 Machine* machine = exec->machine();
3988 JSValue* exceptionValue = 0;
3989 Register* registerBase = registerFile->base();
3991 JSValue* funcVal = ARG_src1;
3992 JSValue* thisValue = ARG_src2;
3993 int firstArg = ARG_int3;
3994 int argCount = ARG_int4;
4000 funcVal->getCallData(callData);
4002 ASSERT(callType == CallTypeJS);
4004 if (*ARG_profilerReference)
4005 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
4007 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
4008 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
4009 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
4011 r[firstArg] = thisValue;
4013 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4014 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
4015 exec->m_callFrame = callFrame;
4017 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
4018 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
4020 codeBlock = newCodeBlock;
4021 machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
4023 if (!codeBlock->ctiCode)
4024 CTI::compile(machine, exec, codeBlock);
4026 ARG_setScopeChain(scopeChain);
4027 ARG_setCodeBlock(codeBlock);
4029 return codeBlock->ctiCode;
4032 JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
4034 ExecState* exec = ARG_exec;
4035 Register* r = ARG_r;
4037 JSValue* funcVal = ARG_src1;
4038 JSValue* thisValue = ARG_src2;
4039 int firstArg = ARG_int3;
4040 int argCount = ARG_int4;
4043 CallType callType = funcVal->getCallData(callData);
4045 ASSERT(callType != CallTypeJS);
4047 if (callType == CallTypeHost) {
4048 CodeBlock* codeBlock = ARG_codeBlock;
4049 ScopeChainNode* scopeChain = ARG_scopeChain;
4050 Machine* machine = exec->machine();
4052 Register* oldCallFrame = exec->m_callFrame;
4053 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4054 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
4055 exec->m_callFrame = callFrame;
4057 if (*ARG_profilerReference)
4058 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
4060 ArgList argList(r + firstArg + 1, argCount - 1);
4062 CTI_MACHINE_SAMPLING_callingHostFunction();
4064 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), thisValue, argList);
4065 exec->m_callFrame = oldCallFrame;
4066 VM_CHECK_EXCEPTION(JSValue*);
4068 if (*ARG_profilerReference)
4069 (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(funcVal));
4075 ASSERT(callType == CallTypeNone);
4077 exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr5, ARG_codeBlock));
4078 VM_CHECK_EXCEPTION_AT_END();
4082 JSValue* Machine::cti_op_ret(CTI_ARGS)
4084 ExecState* exec = ARG_exec;
4085 Register* r = ARG_r;
4086 CodeBlock* codeBlock = ARG_codeBlock;
4087 ScopeChainNode* scopeChain = ARG_scopeChain;
4089 Machine* machine = exec->machine();