2 * Copyright (C) 2008, 2009 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.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
38 #include "Collector.h"
40 #include "DebuggerCallFrame.h"
41 #include "EvalCodeCache.h"
42 #include "ExceptionHelpers.h"
43 #include "GlobalEvalFunction.h"
44 #include "JSActivation.h"
46 #include "JSByteArray.h"
47 #include "JSFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "LiteralParser.h"
51 #include "JSStaticScopeObject.h"
53 #include "ObjectPrototype.h"
54 #include "Operations.h"
56 #include "RegExpObject.h"
57 #include "RegExpPrototype.h"
59 #include "SamplingTool.h"
60 #include <wtf/Threading.h>
62 #include "qscriptobject_p.h"
71 static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CodeBlock* codeBlock, void* pc)
73 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();
76 // Returns the depth of the scope chain within a given call frame.
77 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
79 if (!codeBlock->needsFullScopeChain())
81 return sc.localDepth();
84 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
86 int dst = vPC[1].u.operand;
87 int property = vPC[2].u.operand;
89 ScopeChainNode* scopeChain = callFrame->scopeChain();
90 ScopeChainIterator iter = scopeChain->begin();
91 ScopeChainIterator end = scopeChain->end();
92 Q_ASSERT(iter != end);
94 CodeBlock* codeBlock = callFrame->codeBlock();
95 Identifier& ident = codeBlock->identifier(property);
99 if (o->getPropertySlot(callFrame, ident, slot)) {
100 JSValue result = slot.getValue(callFrame, ident);
101 exceptionValue = callFrame->globalData().exception;
104 callFrame->r(dst) = JSValue(result);
107 } while (++iter != end);
108 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
112 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
114 CodeBlock* codeBlock = callFrame->codeBlock();
116 int dst = vPC[1].u.operand;
117 int property = vPC[2].u.operand;
118 int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain();
120 ScopeChainNode* scopeChain = callFrame->scopeChain();
121 ScopeChainIterator iter = scopeChain->begin();
122 ScopeChainIterator end = scopeChain->end();
123 Q_ASSERT(iter != end);
126 Q_ASSERT(iter != end);
128 Identifier& ident = codeBlock->identifier(property);
131 PropertySlot slot(o);
132 if (o->getPropertySlot(callFrame, ident, slot)) {
133 JSValue result = slot.getValue(callFrame, ident);
134 exceptionValue = callFrame->globalData().exception;
137 callFrame->r(dst) = JSValue(result);
140 } while (++iter != end);
141 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
145 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
147 int dst = vPC[1].u.operand;
148 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
149 Q_ASSERT(globalObject->isGlobalObject());
150 int property = vPC[3].u.operand;
151 Structure* structure = vPC[4].u.structure;
152 int offset = vPC[5].u.operand;
154 if (structure == globalObject->structure()) {
155 callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
159 CodeBlock* codeBlock = callFrame->codeBlock();
160 Identifier& ident = codeBlock->identifier(property);
161 PropertySlot slot(globalObject);
162 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
163 JSValue result = slot.getValue(callFrame, ident);
164 if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
165 if (vPC[4].u.structure)
166 vPC[4].u.structure->deref();
167 globalObject->structure()->ref();
168 vPC[4] = globalObject->structure();
169 vPC[5] = slot.cachedOffset();
170 callFrame->r(dst) = JSValue(result);
174 exceptionValue = callFrame->globalData().exception;
177 callFrame->r(dst) = JSValue(result);
181 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
185 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
187 int dst = vPC[1].u.operand;
188 int property = vPC[2].u.operand;
189 callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
192 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
194 int baseDst = vPC[1].u.operand;
195 int propDst = vPC[2].u.operand;
196 int property = vPC[3].u.operand;
198 ScopeChainNode* scopeChain = callFrame->scopeChain();
199 ScopeChainIterator iter = scopeChain->begin();
200 ScopeChainIterator end = scopeChain->end();
202 // FIXME: add scopeDepthIsZero optimization
204 Q_ASSERT(iter != end);
206 CodeBlock* codeBlock = callFrame->codeBlock();
207 Identifier& ident = codeBlock->identifier(property);
211 PropertySlot slot(base);
212 if (base->getPropertySlot(callFrame, ident, slot)) {
213 JSValue result = slot.getValue(callFrame, ident);
214 exceptionValue = callFrame->globalData().exception;
217 callFrame->r(propDst) = JSValue(result);
218 callFrame->r(baseDst) = JSValue(base);
222 } while (iter != end);
224 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
228 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
230 Register* r = callFrame->registers();
231 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
233 if (Q_LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
234 if (Q_UNLIKELY(!registerFile->grow(newEnd)))
237 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
238 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
239 registerOffset += omittedArgCount;
240 newEnd += omittedArgCount;
241 if (!registerFile->grow(newEnd))
245 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
246 for (size_t i = 0; i < omittedArgCount; ++i)
247 argv[i] = jsUndefined();
248 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
249 size_t numParameters = newCodeBlock->m_numParameters;
250 registerOffset += numParameters;
251 newEnd += numParameters;
253 if (!registerFile->grow(newEnd))
257 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
258 for (size_t i = 0; i < numParameters; ++i)
259 argv[i + argc] = argv[i];
262 return CallFrame::create(r);
265 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
267 if (value.isObject())
269 exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
273 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
275 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
277 exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
281 NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
284 return jsUndefined();
286 JSValue program = argv[1].jsValue();
288 if (!program.isString())
291 UString programSource = asString(program)->value(callFrame);
293 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
294 if (JSValue parsedObject = preparser.tryLiteralParse())
297 ScopeChainNode* scopeChain = callFrame->scopeChain();
298 CodeBlock* codeBlock = callFrame->codeBlock();
299 RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
301 JSValue result = jsUndefined();
303 result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
308 Interpreter::Interpreter()
309 : m_sampleEntryDepth(0)
312 #if ENABLE(OPCODE_SAMPLING)
319 void Interpreter::dumpCallFrame(CallFrame* callFrame)
321 callFrame->codeBlock()->dump(callFrame);
322 dumpRegisters(callFrame);
325 void Interpreter::dumpRegisters(CallFrame* callFrame)
327 printf("Register frame: \n\n");
328 printf("-----------------------------------------------------------------------------\n");
329 printf(" use | address | value \n");
330 printf("-----------------------------------------------------------------------------\n");
332 CodeBlock* codeBlock = callFrame->codeBlock();
333 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile();
338 if (codeBlock->codeType() == GlobalCode) {
339 it = registerFile->lastGlobal();
340 end = it + registerFile->numGlobals();
343 #if USE(JSVALUE32_64)
344 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
346 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
350 printf("-----------------------------------------------------------------------------\n");
353 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
355 #if USE(JSVALUE32_64)
356 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
358 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
360 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
364 #if USE(JSVALUE32_64)
365 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
367 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
372 printf("-----------------------------------------------------------------------------\n");
373 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
374 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
375 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
376 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
377 printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
378 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
379 printf("[Callee] | %10p | %p \n", it, (*it).object()); ++it;
380 printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
381 printf("-----------------------------------------------------------------------------\n");
383 int registerCount = 0;
385 end = it + codeBlock->m_numVars;
389 #if USE(JSVALUE32_64)
390 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
392 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
398 printf("-----------------------------------------------------------------------------\n");
400 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
404 #if USE(JSVALUE32_64)
405 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
407 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
413 printf("-----------------------------------------------------------------------------\n");
418 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
420 CodeBlock* oldCodeBlock = codeBlock;
421 ScopeChainNode* scopeChain = callFrame->scopeChain();
423 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
424 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
425 if (callFrame->callee()) {
426 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
427 debugger->functionExit(exceptionValue, codeBlock->ownerExecutable()->sourceID());
429 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
432 // If this call frame created an activation or an 'arguments' object, tear it off.
433 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
434 while (!scopeChain->object->inherits(&JSActivation::info))
435 scopeChain = scopeChain->pop();
436 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
437 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
438 if (!arguments->isTornOff())
439 arguments->copyRegisters();
442 if (oldCodeBlock->needsFullScopeChain())
445 void* returnPC = callFrame->returnPC();
446 callFrame = callFrame->callerFrame();
447 if (callFrame->hasHostCallFrameFlag())
450 codeBlock = callFrame->codeBlock();
451 bytecodeOffset = bytecodeOffsetForPC(codeBlock, returnPC);
455 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
457 // Set up the exception object
459 CodeBlock* codeBlock = callFrame->codeBlock();
460 if (exceptionValue.isObject()) {
461 JSObject* exception = asObject(exceptionValue);
462 if (exception->isNotAnObjectErrorStub()) {
463 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
464 exceptionValue = exception;
466 if (!exception->hasProperty(callFrame, Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME)) &&
467 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
468 !exception->hasProperty(callFrame, Identifier(callFrame, JSC_ERROR_FILENAME_PROPERTYNAME)) &&
469 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
470 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
471 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
476 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
477 exception->putWithAttributes(callFrame, Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME), jsNumber(callFrame, line), ReadOnly | DontDelete);
479 // We only hit this path for error messages and throw statements, which don't have a specific failure position
480 // So we just give the full range of the error/throw statement.
481 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
482 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
484 exception->putWithAttributes(callFrame, Identifier(callFrame, JSC_ERROR_LINENUMBER_PROPERTYNAME), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
485 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete);
486 exception->putWithAttributes(callFrame, Identifier(callFrame, JSC_ERROR_FILENAME_PROPERTYNAME), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete);
489 if (exception->isWatchdogException()) {
490 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
491 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
498 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
500 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
501 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
502 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset), hasHandler);
505 // Calculate an exception handler vPC, unwinding call frames as necessary.
507 HandlerInfo* handler = 0;
509 //try to find handler
510 bool hasHandler = true;
511 CallFrame *callFrameTemp = callFrame;
512 unsigned bytecodeOffsetTemp = bytecodeOffset;
513 CodeBlock *codeBlockTemp = codeBlock;
514 while (!(handler = codeBlockTemp->handlerForBytecodeOffset(bytecodeOffsetTemp))) {
515 void* returnPC = callFrameTemp->returnPC();
516 callFrameTemp = callFrameTemp->callerFrame();
517 if (callFrameTemp->hasHostCallFrameFlag()) {
521 codeBlockTemp = callFrameTemp->codeBlock();
522 bytecodeOffsetTemp = bytecodeOffsetForPC(codeBlockTemp, returnPC);
526 debugger->exceptionThrow(DebuggerCallFrame(callFrame, exceptionValue), codeBlock->ownerExecutable()->sourceID(), hasHandler);
528 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
529 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
533 // Now unwind the scope chain within the exception handler's call frame.
535 ScopeChainNode* scopeChain = callFrame->scopeChain();
536 ScopeChain sc(scopeChain);
537 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
538 Q_ASSERT(scopeDelta >= 0);
540 scopeChain = scopeChain->pop();
541 callFrame->setScopeChain(scopeChain);
546 JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
548 Q_ASSERT(!scopeChain->globalData->exception);
550 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
551 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
552 *exception = createStackOverflowError(callFrame);
557 CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain);
559 Register* oldEnd = m_registerFile.end();
560 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
561 if (!m_registerFile.grow(newEnd)) {
562 *exception = createStackOverflowError(callFrame);
566 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
568 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
569 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
570 globalObject->copyGlobalsTo(m_registerFile);
572 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
573 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
574 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
576 if (codeBlock->needsFullScopeChain())
581 SamplingTool::CallRecord callRecord(m_sampler.get());
584 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
588 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
589 lastGlobalObject->copyGlobalsTo(m_registerFile);
591 m_registerFile.shrink(oldEnd);
596 JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
598 Q_ASSERT(!scopeChain->globalData->exception);
600 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
601 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
602 *exception = createStackOverflowError(callFrame);
607 Register* oldEnd = m_registerFile.end();
608 int argc = 1 + args.size(); // implicit "this" parameter
610 if (!m_registerFile.grow(oldEnd + argc)) {
611 *exception = createStackOverflowError(callFrame);
615 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
617 CallFrame* newCallFrame = CallFrame::create(oldEnd);
619 newCallFrame->r(0) = JSValue(thisObj);
620 ArgList::const_iterator end = args.end();
621 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
622 newCallFrame->r(++dst) = *it;
624 CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain);
625 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
626 if (Q_UNLIKELY(!newCallFrame)) {
627 *exception = createStackOverflowError(callFrame);
628 m_registerFile.shrink(oldEnd);
631 // a 0 codeBlock indicates a built-in caller
632 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
636 SamplingTool::CallRecord callRecord(m_sampler.get());
639 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
643 m_registerFile.shrink(oldEnd);
647 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
649 Q_ASSERT(!scopeChain->globalData->exception);
651 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
652 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
653 *exception = createStackOverflowError(callFrame);
654 return CallFrameClosure();
658 Register* oldEnd = m_registerFile.end();
659 int argc = 1 + argCount; // implicit "this" parameter
661 if (!m_registerFile.grow(oldEnd + argc)) {
662 *exception = createStackOverflowError(callFrame);
663 return CallFrameClosure();
666 CallFrame* newCallFrame = CallFrame::create(oldEnd);
668 for (int i = 0; i < argc; ++i)
669 newCallFrame->r(++dst) = jsUndefined();
671 CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain);
672 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
673 if (Q_UNLIKELY(!newCallFrame)) {
674 *exception = createStackOverflowError(callFrame);
675 m_registerFile.shrink(oldEnd);
676 return CallFrameClosure();
678 // a 0 codeBlock indicates a built-in caller
679 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
681 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
685 JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
687 closure.resetCallFrame();
691 SamplingTool::CallRecord callRecord(m_sampler.get());
694 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
701 void Interpreter::endRepeatCall(CallFrameClosure& closure)
703 m_registerFile.shrink(closure.oldEnd);
706 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
708 return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
711 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
713 Q_ASSERT(!scopeChain->globalData->exception);
715 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
716 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
717 *exception = createStackOverflowError(callFrame);
722 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject);
724 EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain);
726 JSVariableObject* variableObject;
727 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
729 if (node->object->isVariableObject()) {
730 variableObject = static_cast<JSVariableObject*>(node->object);
735 { // Scope for BatchedTransitionOptimizer
737 BatchedTransitionOptimizer optimizer(variableObject);
739 unsigned numVariables = codeBlock->numVariables();
740 for (unsigned i = 0; i < numVariables; ++i) {
741 const Identifier& ident = codeBlock->variable(i);
742 if (!variableObject->hasProperty(callFrame, ident)) {
743 PutPropertySlot slot;
744 variableObject->put(callFrame, ident, jsUndefined(), slot);
748 int numFunctions = codeBlock->numberOfFunctionDecls();
749 for (int i = 0; i < numFunctions; ++i) {
750 FunctionExecutable* function = codeBlock->functionDecl(i);
751 PutPropertySlot slot;
752 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
757 Register* oldEnd = m_registerFile.end();
758 // with QtScript, we do not necesserly start from scratch
759 Register* newEnd = oldEnd + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
760 if (!m_registerFile.grow(newEnd)) {
761 *exception = createStackOverflowError(callFrame);
765 // with QtScript, we do not necesserly start from scratch
766 CallFrame* newCallFrame = CallFrame::create(oldEnd + globalRegisterOffset);
768 // a 0 codeBlock indicates a built-in caller
769 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
770 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
772 if (codeBlock->needsFullScopeChain())
777 SamplingTool::CallRecord callRecord(m_sampler.get());
780 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
784 m_registerFile.shrink(oldEnd);
788 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
790 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
794 switch (debugHookID) {
795 case DidEnterCallFrame:
796 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
798 case WillLeaveCallFrame:
799 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
801 case WillExecuteStatement:
802 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
804 case WillExecuteProgram:
805 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
807 case DidExecuteProgram:
808 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
810 case DidReachBreakpoint:
811 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
816 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
818 int dst = vPC[1].u.operand;
819 CodeBlock* codeBlock = callFrame->codeBlock();
820 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
821 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
822 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
823 callFrame->r(dst) = JSValue(scope);
825 return callFrame->scopeChain()->push(scope);
828 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
830 // Recursive invocation may already have specialized this instruction.
831 if (vPC[0].u.opcode != op_put_by_id)
834 if (!baseValue.isCell())
837 // Uncacheable: give up.
838 if (!slot.isCacheable()) {
839 vPC[0] = op_put_by_id_generic;
843 JSCell* baseCell = baseValue.asCell();
844 Structure* structure = baseCell->structure();
846 if (structure->isUncacheableDictionary()) {
847 vPC[0] = op_put_by_id_generic;
851 // Cache miss: record Structure to compare against next time.
852 Structure* lastStructure = vPC[4].u.structure;
853 if (structure != lastStructure) {
854 // First miss: record Structure to compare against next time.
855 if (!lastStructure) {
860 // Second miss: give up.
861 vPC[0] = op_put_by_id_generic;
865 // Cache hit: Specialize instruction and ref Structures.
867 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
868 if (baseCell != slot.base()) {
869 vPC[0] = op_put_by_id_generic;
873 // Structure transition, cache transition info
874 if (slot.type() == PutPropertySlot::NewProperty) {
875 if (structure->isDictionary()) {
876 vPC[0] = op_put_by_id_generic;
880 // put_by_id_transition checks the prototype chain for setters.
881 normalizePrototypeChain(callFrame, baseCell);
883 vPC[0] = op_put_by_id_transition;
884 vPC[4] = structure->previousID();
886 vPC[6] = structure->prototypeChain(callFrame);
887 vPC[7] = slot.cachedOffset();
888 codeBlock->refStructures(vPC);
892 vPC[0] = op_put_by_id_replace;
893 vPC[5] = slot.cachedOffset();
894 codeBlock->refStructures(vPC);
897 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
899 codeBlock->derefStructures(vPC);
900 vPC[0] = op_put_by_id;
904 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
906 // Recursive invocation may already have specialized this instruction.
907 if (vPC[0].u.opcode != op_get_by_id)
910 // FIXME: Cache property access for immediates.
911 if (!baseValue.isCell()) {
912 vPC[0] = op_get_by_id_generic;
916 JSGlobalData* globalData = &callFrame->globalData();
917 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
918 vPC[0] = op_get_array_length;
922 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
923 vPC[0] = op_get_string_length;
927 // Uncacheable: give up.
928 if (!slot.isCacheable()) {
929 vPC[0] = op_get_by_id_generic;
933 Structure* structure = baseValue.asCell()->structure();
935 if (structure->isUncacheableDictionary()) {
936 vPC[0] = op_get_by_id_generic;
941 Structure* lastStructure = vPC[4].u.structure;
942 if (structure != lastStructure) {
943 // First miss: record Structure to compare against next time.
944 if (!lastStructure) {
949 // Second miss: give up.
950 vPC[0] = op_get_by_id_generic;
954 // Cache hit: Specialize instruction and ref Structures.
956 if (slot.slotBase() == baseValue) {
957 vPC[0] = op_get_by_id_self;
958 vPC[5] = slot.cachedOffset();
960 codeBlock->refStructures(vPC);
964 if (structure->isDictionary()) {
965 vPC[0] = op_get_by_id_generic;
969 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
970 Q_ASSERT(slot.slotBase().isObject());
972 JSObject* baseObject = asObject(slot.slotBase());
973 size_t offset = slot.cachedOffset();
975 // Since we're accessing a prototype in a loop, it's a good bet that it
976 // should not be treated as a dictionary.
977 if (baseObject->structure()->isDictionary()) {
978 baseObject->flattenDictionaryObject();
979 offset = baseObject->structure()->get(propertyName);
982 Q_ASSERT(!baseObject->structure()->isUncacheableDictionary());
984 vPC[0] = op_get_by_id_proto;
985 vPC[5] = baseObject->structure();
988 codeBlock->refStructures(vPC);
992 size_t offset = slot.cachedOffset();
993 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
995 vPC[0] = op_get_by_id_generic;
999 vPC[0] = op_get_by_id_chain;
1001 vPC[5] = structure->prototypeChain(callFrame);
1004 codeBlock->refStructures(vPC);
1007 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1009 codeBlock->derefStructures(vPC);
1010 vPC[0] = op_get_by_id;
1014 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
1016 // One-time initialization of our address tables. We have to put this code
1017 // here because our labels are only in scope inside this function.
1018 if (Q_UNLIKELY(flag == InitializeAndReturn)) {
1022 JSGlobalData* globalData = &callFrame->globalData();
1023 JSValue exceptionValue;
1024 HandlerInfo* handler = 0;
1026 Instruction* vPC = callFrame->codeBlock()->instructions().begin();
1027 unsigned tickCount = globalData->timeoutChecker->ticksUntilNextCheck();
1029 #define CHECK_FOR_EXCEPTION() \
1031 if (Q_UNLIKELY(globalData->exception != JSValue())) { \
1032 exceptionValue = globalData->exception; \
1037 #if ENABLE(OPCODE_STATS)
1038 OpcodeStats::resetLastInstruction();
1041 #define CHECK_FOR_TIMEOUT() \
1042 if (!--tickCount) { \
1043 if (globalData->timeoutChecker->didTimeOut(callFrame)) { \
1044 exceptionValue = jsNull(); \
1047 tickCount = globalData->timeoutChecker->ticksUntilNextCheck(); \
1048 CHECK_FOR_EXCEPTION(); \
1051 #if ENABLE(OPCODE_SAMPLING)
1052 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1054 #define SAMPLE(codeBlock, vPC)
1057 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1058 #if ENABLE(OPCODE_STATS)
1059 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1061 #define DEFINE_OPCODE(opcode) case opcode:
1063 while (1) { // iterator loop begins
1064 interpreterLoopStart:;
1065 switch (vPC->u.opcode)
1067 DEFINE_OPCODE(op_new_object) {
1068 /* new_object dst(r)
1070 Constructs a new empty Object instance using the original
1071 constructor, and puts the result in register dst.
1073 int dst = vPC[1].u.operand;
1074 callFrame->r(dst) = JSValue(constructEmptyObject(callFrame));
1076 vPC += OPCODE_LENGTH(op_new_object);
1079 DEFINE_OPCODE(op_new_array) {
1080 /* new_array dst(r) firstArg(r) argCount(n)
1082 Constructs a new Array instance using the original
1083 constructor, and puts the result in register dst.
1084 The array will contain argCount elements with values
1085 taken from registers starting at register firstArg.
1087 int dst = vPC[1].u.operand;
1088 int firstArg = vPC[2].u.operand;
1089 int argCount = vPC[3].u.operand;
1090 ArgList args(callFrame->registers() + firstArg, argCount);
1091 callFrame->r(dst) = JSValue(constructArray(callFrame, args));
1093 vPC += OPCODE_LENGTH(op_new_array);
1096 DEFINE_OPCODE(op_new_regexp) {
1097 /* new_regexp dst(r) regExp(re)
1099 Constructs a new RegExp instance using the original
1100 constructor from regexp regExp, and puts the result in
1103 int dst = vPC[1].u.operand;
1104 int regExp = vPC[2].u.operand;
1105 callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));
1107 vPC += OPCODE_LENGTH(op_new_regexp);
1110 DEFINE_OPCODE(op_mov) {
1111 /* mov dst(r) src(r)
1113 Copies register src to register dst.
1115 int dst = vPC[1].u.operand;
1116 int src = vPC[2].u.operand;
1117 callFrame->r(dst) = callFrame->r(src);
1119 vPC += OPCODE_LENGTH(op_mov);
1122 DEFINE_OPCODE(op_eq) {
1123 /* eq dst(r) src1(r) src2(r)
1125 Checks whether register src1 and register src2 are equal,
1126 as with the ECMAScript '==' operator, and puts the result
1127 as a boolean in register dst.
1129 int dst = vPC[1].u.operand;
1130 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1131 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1132 if (src1.isInt32() && src2.isInt32())
1133 callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
1135 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
1136 CHECK_FOR_EXCEPTION();
1137 callFrame->r(dst) = result;
1140 vPC += OPCODE_LENGTH(op_eq);
1143 DEFINE_OPCODE(op_eq_null) {
1144 /* eq_null dst(r) src(r)
1146 Checks whether register src is null, as with the ECMAScript '!='
1147 operator, and puts the result as a boolean in register dst.
1149 int dst = vPC[1].u.operand;
1150 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1152 if (src.isUndefinedOrNull()) {
1153 callFrame->r(dst) = jsBoolean(true);
1154 vPC += OPCODE_LENGTH(op_eq_null);
1158 callFrame->r(dst) = jsBoolean(false);
1159 vPC += OPCODE_LENGTH(op_eq_null);
1162 DEFINE_OPCODE(op_neq) {
1163 /* neq dst(r) src1(r) src2(r)
1165 Checks whether register src1 and register src2 are not
1166 equal, as with the ECMAScript '!=' operator, and puts the
1167 result as a boolean in register dst.
1169 int dst = vPC[1].u.operand;
1170 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1171 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1172 if (src1.isInt32() && src2.isInt32())
1173 callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
1175 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
1176 CHECK_FOR_EXCEPTION();
1177 callFrame->r(dst) = result;
1180 vPC += OPCODE_LENGTH(op_neq);
1183 DEFINE_OPCODE(op_neq_null) {
1184 /* neq_null dst(r) src(r)
1186 Checks whether register src is not null, as with the ECMAScript '!='
1187 operator, and puts the result as a boolean in register dst.
1189 int dst = vPC[1].u.operand;
1190 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1192 if (src.isUndefinedOrNull()) {
1193 callFrame->r(dst) = jsBoolean(false);
1194 vPC += OPCODE_LENGTH(op_neq_null);
1198 callFrame->r(dst) = jsBoolean(!src.isCell());
1199 vPC += OPCODE_LENGTH(op_neq_null);
1202 DEFINE_OPCODE(op_stricteq) {
1203 /* stricteq dst(r) src1(r) src2(r)
1205 Checks whether register src1 and register src2 are strictly
1206 equal, as with the ECMAScript '===' operator, and puts the
1207 result as a boolean in register dst.
1209 int dst = vPC[1].u.operand;
1210 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1211 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1212 callFrame->r(dst) = jsBoolean(JSValue::strictEqual(callFrame, src1, src2));
1214 vPC += OPCODE_LENGTH(op_stricteq);
1217 DEFINE_OPCODE(op_nstricteq) {
1218 /* nstricteq dst(r) src1(r) src2(r)
1220 Checks whether register src1 and register src2 are not
1221 strictly equal, as with the ECMAScript '!==' operator, and
1222 puts the result as a boolean in register dst.
1224 int dst = vPC[1].u.operand;
1225 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1226 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1227 callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(callFrame, src1, src2));
1229 vPC += OPCODE_LENGTH(op_nstricteq);
1232 DEFINE_OPCODE(op_less) {
1233 /* less dst(r) src1(r) src2(r)
1235 Checks whether register src1 is less than register src2, as
1236 with the ECMAScript '<' operator, and puts the result as
1237 a boolean in register dst.
1239 int dst = vPC[1].u.operand;
1240 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1241 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1242 JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
1243 CHECK_FOR_EXCEPTION();
1244 callFrame->r(dst) = result;
1246 vPC += OPCODE_LENGTH(op_less);
1249 DEFINE_OPCODE(op_lesseq) {
1250 /* lesseq dst(r) src1(r) src2(r)
1252 Checks whether register src1 is less than or equal to
1253 register src2, as with the ECMAScript '<=' operator, and
1254 puts the result as a boolean in register dst.
1256 int dst = vPC[1].u.operand;
1257 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1258 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1259 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
1260 CHECK_FOR_EXCEPTION();
1261 callFrame->r(dst) = result;
1263 vPC += OPCODE_LENGTH(op_lesseq);
1266 DEFINE_OPCODE(op_pre_inc) {
1267 /* pre_inc srcDst(r)
1269 Converts register srcDst to number, adds one, and puts the result
1270 back in register srcDst.
1272 int srcDst = vPC[1].u.operand;
1273 JSValue v = callFrame->r(srcDst).jsValue();
1274 if (v.isInt32() && v.asInt32() < INT_MAX)
1275 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1277 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1);
1278 CHECK_FOR_EXCEPTION();
1279 callFrame->r(srcDst) = result;
1282 vPC += OPCODE_LENGTH(op_pre_inc);
1285 DEFINE_OPCODE(op_pre_dec) {
1286 /* pre_dec srcDst(r)
1288 Converts register srcDst to number, subtracts one, and puts the result
1289 back in register srcDst.
1291 int srcDst = vPC[1].u.operand;
1292 JSValue v = callFrame->r(srcDst).jsValue();
1293 if (v.isInt32() && v.asInt32() > INT_MIN)
1294 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1296 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1);
1297 CHECK_FOR_EXCEPTION();
1298 callFrame->r(srcDst) = result;
1301 vPC += OPCODE_LENGTH(op_pre_dec);
1304 DEFINE_OPCODE(op_post_inc) {
1305 /* post_inc dst(r) srcDst(r)
1307 Converts register srcDst to number. The number itself is
1308 written to register dst, and the number plus one is written
1309 back to register srcDst.
1311 int dst = vPC[1].u.operand;
1312 int srcDst = vPC[2].u.operand;
1313 JSValue v = callFrame->r(srcDst).jsValue();
1314 if (v.isInt32() && v.asInt32() < INT_MAX) {
1315 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1316 callFrame->r(dst) = v;
1318 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1319 CHECK_FOR_EXCEPTION();
1320 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1);
1321 callFrame->r(dst) = number;
1324 vPC += OPCODE_LENGTH(op_post_inc);
1327 DEFINE_OPCODE(op_post_dec) {
1328 /* post_dec dst(r) srcDst(r)
1330 Converts register srcDst to number. The number itself is
1331 written to register dst, and the number minus one is written
1332 back to register srcDst.
1334 int dst = vPC[1].u.operand;
1335 int srcDst = vPC[2].u.operand;
1336 JSValue v = callFrame->r(srcDst).jsValue();
1337 if (v.isInt32() && v.asInt32() > INT_MIN) {
1338 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1339 callFrame->r(dst) = v;
1341 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1342 CHECK_FOR_EXCEPTION();
1343 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1);
1344 callFrame->r(dst) = number;
1347 vPC += OPCODE_LENGTH(op_post_dec);
1350 DEFINE_OPCODE(op_to_jsnumber) {
1351 /* to_jsnumber dst(r) src(r)
1353 Converts register src to number, and puts the result
1356 int dst = vPC[1].u.operand;
1357 int src = vPC[2].u.operand;
1359 JSValue srcVal = callFrame->r(src).jsValue();
1361 if (Q_LIKELY(srcVal.isNumber()))
1362 callFrame->r(dst) = callFrame->r(src);
1364 JSValue result = srcVal.toJSNumber(callFrame);
1365 CHECK_FOR_EXCEPTION();
1366 callFrame->r(dst) = result;
1369 vPC += OPCODE_LENGTH(op_to_jsnumber);
1372 DEFINE_OPCODE(op_negate) {
1373 /* negate dst(r) src(r)
1375 Converts register src to number, negates it, and puts the
1376 result in register dst.
1378 int dst = vPC[1].u.operand;
1379 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1380 if (src.isInt32() && src.asInt32())
1381 callFrame->r(dst) = jsNumber(callFrame, -src.asInt32());
1383 JSValue result = jsNumber(callFrame, -src.toNumber(callFrame));
1384 CHECK_FOR_EXCEPTION();
1385 callFrame->r(dst) = result;
1388 vPC += OPCODE_LENGTH(op_negate);
1391 DEFINE_OPCODE(op_add) {
1392 /* add dst(r) src1(r) src2(r)
1394 Adds register src1 and register src2, and puts the result
1395 in register dst. (JS add may be string concatenation or
1396 numeric add, depending on the types of the operands.)
1398 int dst = vPC[1].u.operand;
1399 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1400 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1401 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1402 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32());
1404 JSValue result = jsAdd(callFrame, src1, src2);
1405 CHECK_FOR_EXCEPTION();
1406 callFrame->r(dst) = result;
1408 vPC += OPCODE_LENGTH(op_add);
1411 DEFINE_OPCODE(op_mul) {
1412 /* mul dst(r) src1(r) src2(r)
1414 Multiplies register src1 and register src2 (converted to
1415 numbers), and puts the product in register dst.
1417 int dst = vPC[1].u.operand;
1418 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1419 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1420 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
1421 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32());
1423 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));
1424 CHECK_FOR_EXCEPTION();
1425 callFrame->r(dst) = result;
1428 vPC += OPCODE_LENGTH(op_mul);
1431 DEFINE_OPCODE(op_div) {
1432 /* div dst(r) dividend(r) divisor(r)
1434 Divides register dividend (converted to number) by the
1435 register divisor (converted to number), and puts the
1436 quotient in register dst.
1438 int dst = vPC[1].u.operand;
1439 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1440 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1442 JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
1443 CHECK_FOR_EXCEPTION();
1444 callFrame->r(dst) = result;
1446 vPC += OPCODE_LENGTH(op_div);
1449 DEFINE_OPCODE(op_mod) {
1450 /* mod dst(r) dividend(r) divisor(r)
1452 Divides register dividend (converted to number) by
1453 register divisor (converted to number), and puts the
1454 remainder in register dst.
1456 int dst = vPC[1].u.operand;
1457 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1458 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1460 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
1461 JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32());
1463 callFrame->r(dst) = result;
1464 vPC += OPCODE_LENGTH(op_mod);
1468 // Conversion to double must happen outside the call to fmod since the
1469 // order of argument evaluation is not guaranteed.
1470 double d1 = dividend.toNumber(callFrame);
1471 double d2 = divisor.toNumber(callFrame);
1472 JSValue result = jsNumber(callFrame, fmod(d1, d2));
1473 CHECK_FOR_EXCEPTION();
1474 callFrame->r(dst) = result;
1475 vPC += OPCODE_LENGTH(op_mod);
1478 DEFINE_OPCODE(op_sub) {
1479 /* sub dst(r) src1(r) src2(r)
1481 Subtracts register src2 (converted to number) from register
1482 src1 (converted to number), and puts the difference in
1485 int dst = vPC[1].u.operand;
1486 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1487 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1488 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1489 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32());
1491 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));
1492 CHECK_FOR_EXCEPTION();
1493 callFrame->r(dst) = result;
1495 vPC += OPCODE_LENGTH(op_sub);
1498 DEFINE_OPCODE(op_lshift) {
1499 /* lshift dst(r) val(r) shift(r)
1501 Performs left shift of register val (converted to int32) by
1502 register shift (converted to uint32), and puts the result
1505 int dst = vPC[1].u.operand;
1506 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1507 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1509 if (val.isInt32() && shift.isInt32())
1510 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f));
1512 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
1513 CHECK_FOR_EXCEPTION();
1514 callFrame->r(dst) = result;
1517 vPC += OPCODE_LENGTH(op_lshift);
1520 DEFINE_OPCODE(op_rshift) {
1521 /* rshift dst(r) val(r) shift(r)
1523 Performs arithmetic right shift of register val (converted
1524 to int32) by register shift (converted to
1525 uint32), and puts the result in register dst.
1527 int dst = vPC[1].u.operand;
1528 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1529 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1531 if (val.isInt32() && shift.isInt32())
1532 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1534 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1535 CHECK_FOR_EXCEPTION();
1536 callFrame->r(dst) = result;
1539 vPC += OPCODE_LENGTH(op_rshift);
1542 DEFINE_OPCODE(op_urshift) {
1543 /* rshift dst(r) val(r) shift(r)
1545 Performs logical right shift of register val (converted
1546 to uint32) by register shift (converted to
1547 uint32), and puts the result in register dst.
1549 int dst = vPC[1].u.operand;
1550 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1551 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1552 if (val.isUInt32() && shift.isInt32())
1553 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1555 JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1556 CHECK_FOR_EXCEPTION();
1557 callFrame->r(dst) = result;
1560 vPC += OPCODE_LENGTH(op_urshift);
1563 DEFINE_OPCODE(op_bitand) {
1564 /* bitand dst(r) src1(r) src2(r)
1566 Computes bitwise AND of register src1 (converted to int32)
1567 and register src2 (converted to int32), and puts the result
1570 int dst = vPC[1].u.operand;
1571 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1572 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1573 if (src1.isInt32() && src2.isInt32())
1574 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32());
1576 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));
1577 CHECK_FOR_EXCEPTION();
1578 callFrame->r(dst) = result;
1581 vPC += OPCODE_LENGTH(op_bitand);
1584 DEFINE_OPCODE(op_bitxor) {
1585 /* bitxor dst(r) src1(r) src2(r)
1587 Computes bitwise XOR of register src1 (converted to int32)
1588 and register src2 (converted to int32), and puts the result
1591 int dst = vPC[1].u.operand;
1592 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1593 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1594 if (src1.isInt32() && src2.isInt32())
1595 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32());
1597 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
1598 CHECK_FOR_EXCEPTION();
1599 callFrame->r(dst) = result;
1602 vPC += OPCODE_LENGTH(op_bitxor);
1605 DEFINE_OPCODE(op_bitor) {
1606 /* bitor dst(r) src1(r) src2(r)
1608 Computes bitwise OR of register src1 (converted to int32)
1609 and register src2 (converted to int32), and puts the
1610 result in register dst.
1612 int dst = vPC[1].u.operand;
1613 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1614 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1615 if (src1.isInt32() && src2.isInt32())
1616 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32());
1618 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));
1619 CHECK_FOR_EXCEPTION();
1620 callFrame->r(dst) = result;
1623 vPC += OPCODE_LENGTH(op_bitor);
1626 DEFINE_OPCODE(op_bitnot) {
1627 /* bitnot dst(r) src(r)
1629 Computes bitwise NOT of register src1 (converted to int32),
1630 and puts the result in register dst.
1632 int dst = vPC[1].u.operand;
1633 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1635 callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32());
1637 JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame));
1638 CHECK_FOR_EXCEPTION();
1639 callFrame->r(dst) = result;
1641 vPC += OPCODE_LENGTH(op_bitnot);
1644 DEFINE_OPCODE(op_not) {
1645 /* not dst(r) src(r)
1647 Computes logical NOT of register src (converted to
1648 boolean), and puts the result in register dst.
1650 int dst = vPC[1].u.operand;
1651 int src = vPC[2].u.operand;
1652 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
1653 CHECK_FOR_EXCEPTION();
1654 callFrame->r(dst) = result;
1656 vPC += OPCODE_LENGTH(op_not);
1659 DEFINE_OPCODE(op_instanceof) {
1660 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1662 Tests whether register value is an instance of register
1663 constructor, and puts the boolean result in register
1664 dst. Register constructorProto must contain the "prototype"
1665 property (not the actual prototype) of the object in
1666 register constructor. This lookup is separated so that
1667 polymorphic inline caching can apply.
1669 Raises an exception if register constructor is not an
1672 int dst = vPC[1].u.operand;
1673 int value = vPC[2].u.operand;
1674 int base = vPC[3].u.operand;
1675 int baseProto = vPC[4].u.operand;
1677 JSValue baseVal = callFrame->r(base).jsValue();
1679 if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1682 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
1683 CHECK_FOR_EXCEPTION();
1684 callFrame->r(dst) = jsBoolean(result);
1686 vPC += OPCODE_LENGTH(op_instanceof);
1689 DEFINE_OPCODE(op_typeof) {
1690 /* typeof dst(r) src(r)
1692 Determines the type string for src according to ECMAScript
1693 rules, and puts the result in register dst.
1695 int dst = vPC[1].u.operand;
1696 int src = vPC[2].u.operand;
1697 callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
1699 vPC += OPCODE_LENGTH(op_typeof);
1702 DEFINE_OPCODE(op_is_undefined) {
1703 /* is_undefined dst(r) src(r)
1705 Determines whether the type string for src according to
1706 the ECMAScript rules is "undefined", and puts the result
1709 int dst = vPC[1].u.operand;
1710 int src = vPC[2].u.operand;
1711 JSValue v = callFrame->r(src).jsValue();
1712 callFrame->r(dst) = jsBoolean(v.isUndefined());
1714 vPC += OPCODE_LENGTH(op_is_undefined);
1717 DEFINE_OPCODE(op_is_boolean) {
1718 /* is_boolean dst(r) src(r)
1720 Determines whether the type string for src according to
1721 the ECMAScript rules is "boolean", and puts the result
1724 int dst = vPC[1].u.operand;
1725 int src = vPC[2].u.operand;
1726 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
1728 vPC += OPCODE_LENGTH(op_is_boolean);
1731 DEFINE_OPCODE(op_is_number) {
1732 /* is_number dst(r) src(r)
1734 Determines whether the type string for src according to
1735 the ECMAScript rules is "number", and puts the result
1738 int dst = vPC[1].u.operand;
1739 int src = vPC[2].u.operand;
1740 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
1742 vPC += OPCODE_LENGTH(op_is_number);
1745 DEFINE_OPCODE(op_is_string) {
1746 /* is_string dst(r) src(r)
1748 Determines whether the type string for src according to
1749 the ECMAScript rules is "string", and puts the result
1752 int dst = vPC[1].u.operand;
1753 int src = vPC[2].u.operand;
1754 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
1756 vPC += OPCODE_LENGTH(op_is_string);
1759 DEFINE_OPCODE(op_is_object) {
1760 /* is_object dst(r) src(r)
1762 Determines whether the type string for src according to
1763 the ECMAScript rules is "object", and puts the result
1766 int dst = vPC[1].u.operand;
1767 int src = vPC[2].u.operand;
1768 callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
1770 vPC += OPCODE_LENGTH(op_is_object);
1773 DEFINE_OPCODE(op_is_function) {
1774 /* is_function dst(r) src(r)
1776 Determines whether the type string for src according to
1777 the ECMAScript rules is "function", and puts the result
1780 int dst = vPC[1].u.operand;
1781 int src = vPC[2].u.operand;
1782 callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
1784 vPC += OPCODE_LENGTH(op_is_function);
1787 DEFINE_OPCODE(op_in) {
1788 /* in dst(r) property(r) base(r)
1790 Tests whether register base has a property named register
1791 property, and puts the boolean result in register dst.
1793 Raises an exception if register constructor is not an
1796 int dst = vPC[1].u.operand;
1797 int property = vPC[2].u.operand;
1798 int base = vPC[3].u.operand;
1800 JSValue baseVal = callFrame->r(base).jsValue();
1801 if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1804 JSObject* baseObj = asObject(baseVal);
1806 JSValue propName = callFrame->r(property).jsValue();
1809 if (propName.getUInt32(i))
1810 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
1812 Identifier property(callFrame, propName.toString(callFrame));
1813 CHECK_FOR_EXCEPTION();
1814 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
1817 vPC += OPCODE_LENGTH(op_in);
1820 DEFINE_OPCODE(op_resolve) {
1821 /* resolve dst(r) property(id)
1823 Looks up the property named by identifier property in the
1824 scope chain, and writes the resulting value to register
1825 dst. If the property is not found, raises an exception.
1827 if (Q_UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
1830 vPC += OPCODE_LENGTH(op_resolve);
1833 DEFINE_OPCODE(op_resolve_skip) {
1834 /* resolve_skip dst(r) property(id) skip(n)
1836 Looks up the property named by identifier property in the
1837 scope chain skipping the top 'skip' levels, and writes the resulting
1838 value to register dst. If the property is not found, raises an exception.
1840 if (Q_UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
1843 vPC += OPCODE_LENGTH(op_resolve_skip);
1847 DEFINE_OPCODE(op_resolve_global) {
1848 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1850 Performs a dynamic property lookup for the given property, on the provided
1851 global object. If structure matches the Structure of the global then perform
1852 a fast lookup using the case offset, otherwise fall back to a full resolve and
1853 cache the new structure and offset
1855 if (Q_UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
1858 vPC += OPCODE_LENGTH(op_resolve_global);
1862 DEFINE_OPCODE(op_get_global_var) {
1863 /* get_global_var dst(r) globalObject(c) index(n)
1865 Gets the global var at global slot index and places it in register dst.
1867 int dst = vPC[1].u.operand;
1868 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell);
1869 Q_ASSERT(scope->isGlobalObject());
1870 int index = vPC[3].u.operand;
1872 callFrame->r(dst) = scope->registerAt(index);
1873 vPC += OPCODE_LENGTH(op_get_global_var);
1876 DEFINE_OPCODE(op_put_global_var) {
1877 /* put_global_var globalObject(c) index(n) value(r)
1879 Puts value into global slot index.
1881 JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell);
1882 Q_ASSERT(scope->isGlobalObject());
1883 int index = vPC[2].u.operand;
1884 int value = vPC[3].u.operand;
1886 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
1887 vPC += OPCODE_LENGTH(op_put_global_var);
1890 DEFINE_OPCODE(op_get_scoped_var) {
1891 /* get_scoped_var dst(r) index(n) skip(n)
1893 Loads the contents of the index-th local from the scope skip nodes from
1894 the top of the scope chain, and places it in register dst
1896 int dst = vPC[1].u.operand;
1897 int index = vPC[2].u.operand;
1898 int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain();
1900 ScopeChainNode* scopeChain = callFrame->scopeChain();
1901 ScopeChainIterator iter = scopeChain->begin();
1903 ScopeChainIterator end = scopeChain->end();
1905 Q_ASSERT(iter != end);
1908 Q_ASSERT(iter != end);
1911 Q_ASSERT((*iter)->isVariableObject());
1912 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1913 callFrame->r(dst) = scope->registerAt(index);
1914 vPC += OPCODE_LENGTH(op_get_scoped_var);
1917 DEFINE_OPCODE(op_put_scoped_var) {
1918 /* put_scoped_var index(n) skip(n) value(r)
1921 int index = vPC[1].u.operand;
1922 int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain();
1923 int value = vPC[3].u.operand;
1925 ScopeChainNode* scopeChain = callFrame->scopeChain();
1926 ScopeChainIterator iter = scopeChain->begin();
1928 ScopeChainIterator end = scopeChain->end();
1930 Q_ASSERT(iter != end);
1933 Q_ASSERT(iter != end);
1936 Q_ASSERT((*iter)->isVariableObject());
1937 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1938 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
1939 vPC += OPCODE_LENGTH(op_put_scoped_var);
1942 DEFINE_OPCODE(op_resolve_base) {
1943 /* resolve_base dst(r) property(id)
1945 Searches the scope chain for an object containing
1946 identifier property, and if one is found, writes it to
1947 register dst. If none is found, the outermost scope (which
1948 will be the global object) is stored in register dst.
1950 resolveBase(callFrame, vPC);
1952 vPC += OPCODE_LENGTH(op_resolve_base);
1955 DEFINE_OPCODE(op_resolve_with_base) {
1956 /* resolve_with_base baseDst(r) propDst(r) property(id)
1958 Searches the scope chain for an object containing
1959 identifier property, and if one is found, writes it to
1960 register srcDst, and the retrieved property value to register
1961 propDst. If the property is not found, raises an exception.
1963 This is more efficient than doing resolve_base followed by
1964 resolve, or resolve_base followed by get_by_id, as it
1965 avoids duplicate hash lookups.
1967 if (Q_UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
1970 vPC += OPCODE_LENGTH(op_resolve_with_base);
1973 DEFINE_OPCODE(op_get_by_id) {
1974 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
1976 Generic property access: Gets the property named by identifier
1977 property from the value base, and puts the result in register dst.
1979 int dst = vPC[1].u.operand;
1980 int base = vPC[2].u.operand;
1981 int property = vPC[3].u.operand;
1983 CodeBlock* codeBlock = callFrame->codeBlock();
1984 Identifier& ident = codeBlock->identifier(property);
1985 JSValue baseValue = callFrame->r(base).jsValue();
1986 PropertySlot slot(baseValue);
1987 JSValue result = baseValue.get(callFrame, ident, slot);
1988 CHECK_FOR_EXCEPTION();
1990 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
1992 callFrame->r(dst) = result;
1993 vPC += OPCODE_LENGTH(op_get_by_id);
1996 DEFINE_OPCODE(op_get_by_id_self) {
1997 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
1999 Cached property access: Attempts to get a cached property from the
2000 value base. If the cache misses, op_get_by_id_self reverts to
2003 int base = vPC[2].u.operand;
2004 JSValue baseValue = callFrame->r(base).jsValue();
2006 if (Q_LIKELY(baseValue.isCell())) {
2007 JSCell* baseCell = baseValue.asCell();
2008 Structure* structure = vPC[4].u.structure;
2010 if (Q_LIKELY(baseCell->structure() == structure)) {
2011 Q_ASSERT(baseCell->isObject());
2012 JSObject* baseObject = asObject(baseCell);
2013 int dst = vPC[1].u.operand;
2014 int offset = vPC[5].u.operand;
2016 Q_ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2017 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2019 vPC += OPCODE_LENGTH(op_get_by_id_self);
2024 uncacheGetByID(callFrame->codeBlock(), vPC);
2027 DEFINE_OPCODE(op_get_by_id_proto) {
2028 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2030 Cached property access: Attempts to get a cached property from the
2031 value base's prototype. If the cache misses, op_get_by_id_proto
2032 reverts to op_get_by_id.
2034 int base = vPC[2].u.operand;
2035 JSValue baseValue = callFrame->r(base).jsValue();
2037 if (Q_LIKELY(baseValue.isCell())) {
2038 JSCell* baseCell = baseValue.asCell();
2039 Structure* structure = vPC[4].u.structure;
2041 if (Q_LIKELY(baseCell->structure() == structure)) {
2042 Q_ASSERT(structure->prototypeForLookup(callFrame).isObject());
2043 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2044 Structure* prototypeStructure = vPC[5].u.structure;
2046 if (Q_LIKELY(protoObject->structure() == prototypeStructure)) {
2047 int dst = vPC[1].u.operand;
2048 int offset = vPC[6].u.operand;
2050 Q_ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2051 Q_ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2052 callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset));
2054 vPC += OPCODE_LENGTH(op_get_by_id_proto);
2060 uncacheGetByID(callFrame->codeBlock(), vPC);
2063 DEFINE_OPCODE(op_get_by_id_chain) {
2064 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2066 Cached property access: Attempts to get a cached property from the
2067 value base's prototype chain. If the cache misses, op_get_by_id_chain
2068 reverts to op_get_by_id.
2070 int base = vPC[2].u.operand;
2071 JSValue baseValue = callFrame->r(base).jsValue();
2073 if (Q_LIKELY(baseValue.isCell())) {
2074 JSCell* baseCell = baseValue.asCell();
2075 Structure* structure = vPC[4].u.structure;
2077 if (Q_LIKELY(baseCell->structure() == structure)) {
2078 RefPtr<Structure>* it = vPC[5].u.structureChain->head();
2079 size_t count = vPC[6].u.operand;
2080 RefPtr<Structure>* end = it + count;
2083 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2085 if (Q_UNLIKELY(baseObject->structure() != (*it).get()))
2089 int dst = vPC[1].u.operand;
2090 int offset = vPC[7].u.operand;
2092 Q_ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2093 Q_ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2094 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2096 vPC += OPCODE_LENGTH(op_get_by_id_chain);
2100 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2101 baseCell = baseObject;
2106 uncacheGetByID(callFrame->codeBlock(), vPC);
2109 DEFINE_OPCODE(op_get_by_id_generic) {
2110 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2112 Generic property access: Gets the property named by identifier
2113 property from the value base, and puts the result in register dst.
2115 int dst = vPC[1].u.operand;
2116 int base = vPC[2].u.operand;
2117 int property = vPC[3].u.operand;
2119 Identifier& ident = callFrame->codeBlock()->identifier(property);
2120 JSValue baseValue = callFrame->r(base).jsValue();
2121 PropertySlot slot(baseValue);
2122 JSValue result = baseValue.get(callFrame, ident, slot);
2123 CHECK_FOR_EXCEPTION();
2125 callFrame->r(dst) = result;
2126 vPC += OPCODE_LENGTH(op_get_by_id_generic);
2129 DEFINE_OPCODE(op_get_array_length) {
2130 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2132 Cached property access: Gets the length of the array in register base,
2133 and puts the result in register dst. If register base does not hold
2134 an array, op_get_array_length reverts to op_get_by_id.
2137 int base = vPC[2].u.operand;
2138 JSValue baseValue = callFrame->r(base).jsValue();
2139 if (Q_LIKELY(isJSArray(globalData, baseValue))) {
2140 int dst = vPC[1].u.operand;
2141 callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length());
2142 vPC += OPCODE_LENGTH(op_get_array_length);
2146 uncacheGetByID(callFrame->codeBlock(), vPC);
2149 DEFINE_OPCODE(op_get_string_length) {
2150 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2152 Cached property access: Gets the length of the string in register base,
2153 and puts the result in register dst. If register base does not hold
2154 a string, op_get_string_length reverts to op_get_by_id.
2157 int base = vPC[2].u.operand;
2158 JSValue baseValue = callFrame->r(base).jsValue();
2159 if (Q_LIKELY(isJSString(globalData, baseValue))) {
2160 int dst = vPC[1].u.operand;
2161 callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length());
2162 vPC += OPCODE_LENGTH(op_get_string_length);
2166 uncacheGetByID(callFrame->codeBlock(), vPC);
2169 DEFINE_OPCODE(op_put_by_id) {
2170 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2172 Generic property access: Sets the property named by identifier
2173 property, belonging to register base, to register value.
2175 Unlike many opcodes, this one does not write any output to
2179 int base = vPC[1].u.operand;
2180 int property = vPC[2].u.operand;
2181 int value = vPC[3].u.operand;
2183 CodeBlock* codeBlock = callFrame->codeBlock();
2184 JSValue baseValue = callFrame->r(base).jsValue();
2185 Identifier& ident = codeBlock->identifier(property);
2186 PutPropertySlot slot;
2187 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2188 CHECK_FOR_EXCEPTION();
2190 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2192 vPC += OPCODE_LENGTH(op_put_by_id);
2195 DEFINE_OPCODE(op_put_by_id_transition) {
2196 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2198 Cached property access: Attempts to set a new property with a cached transition
2199 property named by identifier property, belonging to register base,
2200 to register value. If the cache misses, op_put_by_id_transition
2201 reverts to op_put_by_id_generic.
2203 Unlike many opcodes, this one does not write any output to
2206 int base = vPC[1].u.operand;
2207 JSValue baseValue = callFrame->r(base).jsValue();
2209 if (Q_LIKELY(baseValue.isCell())) {
2210 JSCell* baseCell = baseValue.asCell();
2211 Structure* oldStructure = vPC[4].u.structure;
2212 Structure* newStructure = vPC[5].u.structure;
2214 if (Q_LIKELY(baseCell->structure() == oldStructure)) {
2215 Q_ASSERT(baseCell->isObject());
2216 JSObject* baseObject = asObject(baseCell);
2218 RefPtr<Structure>* it = vPC[6].u.structureChain->head();
2220 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
2221 while (!proto.isNull()) {
2222 if (Q_UNLIKELY(asObject(proto)->structure() != (*it).get())) {
2223 uncachePutByID(callFrame->codeBlock(), vPC);
2227 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
2230 baseObject->transitionTo(newStructure);
2232 int value = vPC[3].u.operand;
2233 unsigned offset = vPC[7].u.operand;
2234 Q_ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2235 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2237 vPC += OPCODE_LENGTH(op_put_by_id_transition);
2242 uncachePutByID(callFrame->codeBlock(), vPC);
2245 DEFINE_OPCODE(op_put_by_id_replace) {
2246 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2248 Cached property access: Attempts to set a pre-existing, cached
2249 property named by identifier property, belonging to register base,
2250 to register value. If the cache misses, op_put_by_id_replace
2251 reverts to op_put_by_id.
2253 Unlike many opcodes, this one does not write any output to
2256 int base = vPC[1].u.operand;
2257 JSValue baseValue = callFrame->r(base).jsValue();
2259 if (Q_LIKELY(baseValue.isCell())) {
2260 JSCell* baseCell = baseValue.asCell();
2261 Structure* structure = vPC[4].u.structure;
2263 if (Q_LIKELY(baseCell->structure() == structure)) {
2264 Q_ASSERT(baseCell->isObject());
2265 JSObject* baseObject = asObject(baseCell);
2266 int value = vPC[3].u.operand;
2267 unsigned offset = vPC[5].u.operand;
2269 Q_ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2270 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2272 vPC += OPCODE_LENGTH(op_put_by_id_replace);
2277 uncachePutByID(callFrame->codeBlock(), vPC);
2280 DEFINE_OPCODE(op_put_by_id_generic) {
2281 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2283 Generic property access: Sets the property named by identifier
2284 property, belonging to register base, to register value.
2286 Unlike many opcodes, this one does not write any output to
2289 int base = vPC[1].u.operand;
2290 int property = vPC[2].u.operand;
2291 int value = vPC[3].u.operand;
2293 JSValue baseValue = callFrame->r(base).jsValue();
2294 Identifier& ident = callFrame->codeBlock()->identifier(property);
2295 PutPropertySlot slot;
2296 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2297 CHECK_FOR_EXCEPTION();
2299 vPC += OPCODE_LENGTH(op_put_by_id_generic);
2302 DEFINE_OPCODE(op_del_by_id) {
2303 /* del_by_id dst(r) base(r) property(id)
2305 Converts register base to Object, deletes the property
2306 named by identifier property from the object, and writes a
2307 boolean indicating success (if true) or failure (if false)
2310 int dst = vPC[1].u.operand;
2311 int base = vPC[2].u.operand;
2312 int property = vPC[3].u.operand;
2314 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
2315 Identifier& ident = callFrame->codeBlock()->identifier(property);
2316 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
2317 CHECK_FOR_EXCEPTION();
2318 callFrame->r(dst) = result;
2319 vPC += OPCODE_LENGTH(op_del_by_id);
2322 DEFINE_OPCODE(op_get_by_pname) {
2323 int dst = vPC[1].u.operand;
2324 int base = vPC[2].u.operand;
2325 int property = vPC[3].u.operand;
2326 int expected = vPC[4].u.operand;
2327 int iter = vPC[5].u.operand;
2328 int i = vPC[6].u.operand;
2330 JSValue baseValue = callFrame->r(base).jsValue();
2331 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
2332 JSValue subscript = callFrame->r(property).jsValue();
2333 JSValue expectedSubscript = callFrame->r(expected).jsValue();
2334 int index = callFrame->r(i).i() - 1;
2337 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
2338 callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset);
2339 vPC += OPCODE_LENGTH(op_get_by_pname);
2343 Identifier propertyName(callFrame, subscript.toString(callFrame));
2344 result = baseValue.get(callFrame, propertyName);
2346 CHECK_FOR_EXCEPTION();
2347 callFrame->r(dst) = result;
2348 vPC += OPCODE_LENGTH(op_get_by_pname);
2351 DEFINE_OPCODE(op_get_by_val) {
2352 /* get_by_val dst(r) base(r) property(r)
2354 Converts register base to Object, gets the property named
2355 by register property from the object, and puts the result
2356 in register dst. property is nominally converted to string
2357 but numbers are treated more efficiently.
2359 int dst = vPC[1].u.operand;
2360 int base = vPC[2].u.operand;
2361 int property = vPC[3].u.operand;
2363 JSValue baseValue = callFrame->r(base).jsValue();
2364 JSValue subscript = callFrame->r(property).jsValue();
2368 if (Q_LIKELY(subscript.isUInt32())) {
2369 uint32_t i = subscript.asUInt32();
2370 if (isJSArray(globalData, baseValue)) {
2371 JSArray* jsArray = asArray(baseValue);
2372 if (jsArray->canGetIndex(i))
2373 result = jsArray->getIndex(i);
2375 result = jsArray->JSArray::get(callFrame, i);
2376 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
2377 result = asString(baseValue)->getIndex(callFrame, i);
2378 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
2379 result = asByteArray(baseValue)->getIndex(callFrame, i);
2381 result = baseValue.get(callFrame, i);
2383 Identifier property(callFrame, subscript.toString(callFrame));
2384 result = baseValue.get(callFrame, property);
2387 CHECK_FOR_EXCEPTION();
2388 callFrame->r(dst) = result;
2389 vPC += OPCODE_LENGTH(op_get_by_val);
2392 DEFINE_OPCODE(op_put_by_val) {
2393 /* put_by_val base(r) property(r) value(r)
2395 Sets register value on register base as the property named
2396 by register property. Base is converted to object
2397 first. register property is nominally converted to string
2398 but numbers are treated more efficiently.
2400 Unlike many opcodes, this one does not write any output to
2403 int base = vPC[1].u.operand;
2404 int property = vPC[2].u.operand;
2405 int value = vPC[3].u.operand;
2407 JSValue baseValue = callFrame->r(base).jsValue();
2408 JSValue subscript = callFrame->r(property).jsValue();
2410 if (Q_LIKELY(subscript.isUInt32())) {
2411 uint32_t i = subscript.asUInt32();
2412 if (isJSArray(globalData, baseValue)) {
2413 JSArray* jsArray = asArray(baseValue);
2414 if (jsArray->canSetIndex(i))
2415 jsArray->setIndex(i, callFrame->r(value).jsValue());
2417 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
2418 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2419 JSByteArray* jsByteArray = asByteArray(baseValue);
2421 JSValue jsValue = callFrame->r(value).jsValue();
2422 if (jsValue.isInt32())
2423 jsByteArray->setIndex(i, jsValue.asInt32());
2424 else if (jsValue.getNumber(dValue))
2425 jsByteArray->setIndex(i, dValue);
2427 baseValue.put(callFrame, i, jsValue);
2429 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
2431 Identifier property(callFrame, subscript.toString(callFrame));
2432 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2433 PutPropertySlot slot;
2434 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
2438 CHECK_FOR_EXCEPTION();
2439 vPC += OPCODE_LENGTH(op_put_by_val);
2442 DEFINE_OPCODE(op_del_by_val) {
2443 /* del_by_val dst(r) base(r) property(r)
2445 Converts register base to Object, deletes the property
2446 named by register property from the object, and writes a
2447 boolean indicating success (if true) or failure (if false)
2450 int dst = vPC[1].u.operand;
2451 int base = vPC[2].u.operand;
2452 int property = vPC[3].u.operand;
2454 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
2456 JSValue subscript = callFrame->r(property).jsValue();
2459 if (subscript.getUInt32(i))
2460 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2462 CHECK_FOR_EXCEPTION();
2463 Identifier property(callFrame, subscript.toString(callFrame));
2464 CHECK_FOR_EXCEPTION();
2465 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2468 CHECK_FOR_EXCEPTION();
2469 callFrame->r(dst) = result;
2470 vPC += OPCODE_LENGTH(op_del_by_val);
2473 DEFINE_OPCODE(op_put_by_index) {
2474 /* put_by_index base(r) property(n) value(r)
2476 Sets register value on register base as the property named
2477 by the immediate number property. Base is converted to
2480 Unlike many opcodes, this one does not write any output to
2483 This opcode is mainly used to initialize array literals.
2485 int base = vPC[1].u.operand;
2486 unsigned property = vPC[2].u.operand;
2487 int value = vPC[3].u.operand;
2489 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
2491 vPC += OPCODE_LENGTH(op_put_by_index);
2494 DEFINE_OPCODE(op_loop) {
2495 /* loop target(offset)
2497 Jumps unconditionally to offset target from the current
2500 Additionally this loop instruction may terminate JS execution is
2501 the JS timeout is reached.
2503 #if ENABLE(OPCODE_STATS)
2504 OpcodeStats::resetLastInstruction();
2506 int target = vPC[1].u.operand;
2507 CHECK_FOR_TIMEOUT();
2511 DEFINE_OPCODE(op_jmp) {
2512 /* jmp target(offset)
2514 Jumps unconditionally to offset target from the current
2517 #if ENABLE(OPCODE_STATS)
2518 OpcodeStats::resetLastInstruction();
2520 int target = vPC[1].u.operand;
2525 DEFINE_OPCODE(op_loop_if_true) {
2526 /* loop_if_true cond(r) target(offset)
2528 Jumps to offset target from the current instruction, if and
2529 only if register cond converts to boolean as true.
2531 Additionally this loop instruction may terminate JS execution is
2532 the JS timeout is reached.
2534 int cond = vPC[1].u.operand;
2535 int target = vPC[2].u.operand;
2536 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2538 CHECK_FOR_TIMEOUT();
2542 vPC += OPCODE_LENGTH(op_loop_if_true);
2545 DEFINE_OPCODE(op_loop_if_false) {
2546 /* loop_if_true cond(r) target(offset)
2548 Jumps to offset target from the current instruction, if and
2549 only if register cond converts to boolean as false.
2551 Additionally this loop instruction may terminate JS execution is
2552 the JS timeout is reached.
2554 int cond = vPC[1].u.operand;
2555 int target = vPC[2].u.operand;
2556 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2558 CHECK_FOR_TIMEOUT();
2562 vPC += OPCODE_LENGTH(op_loop_if_true);
2565 DEFINE_OPCODE(op_jtrue) {
2566 /* jtrue cond(r) target(offset)
2568 Jumps to offset target from the current instruction, if and
2569 only if register cond converts to boolean as true.
2571 int cond = vPC[1].u.operand;
2572 int target = vPC[2].u.operand;
2573 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2578 vPC += OPCODE_LENGTH(op_jtrue);
2581 DEFINE_OPCODE(op_jfalse) {
2582 /* jfalse cond(r) target(offset)
2584 Jumps to offset target from the current instruction, if and
2585 only if register cond converts to boolean as false.
2587 int cond = vPC[1].u.operand;
2588 int target = vPC[2].u.operand;
2589 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2594 vPC += OPCODE_LENGTH(op_jfalse);
2597 DEFINE_OPCODE(op_jeq_null) {
2598 /* jeq_null src(r) target(offset)
2600 Jumps to offset target from the current instruction, if and
2601 only if register src is null.
2603 int src = vPC[1].u.operand;
2604 int target = vPC[2].u.operand;
2605 JSValue srcValue = callFrame->r(src).jsValue();
2607 if (srcValue.isUndefinedOrNull()) {
2612 vPC += OPCODE_LENGTH(op_jeq_null);
2615 DEFINE_OPCODE(op_jneq_null) {
2616 /* jneq_null src(r) target(offset)
2618 Jumps to offset target from the current instruction, if and
2619 only if register src is not null.
2621 int src = vPC[1].u.operand;
2622 int target = vPC[2].u.operand;
2623 JSValue srcValue = callFrame->r(src).jsValue();
2625 if (!srcValue.isUndefinedOrNull() && !srcValue.isCell()) {
2630 vPC += OPCODE_LENGTH(op_jneq_null);
2633 DEFINE_OPCODE(op_jneq_ptr) {
2634 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2636 Jumps to offset target from the current instruction, if the value r is equal
2637 to ptr, using pointer equality.
2639 int src = vPC[1].u.operand;
2640 JSValue ptr = JSValue(vPC[2].u.jsCell);
2641 int target = vPC[3].u.operand;
2642 JSValue srcValue = callFrame->r(src).jsValue();
2643 if (srcValue != ptr) {
2648 vPC += OPCODE_LENGTH(op_jneq_ptr);
2651 DEFINE_OPCODE(op_loop_if_less) {
2652 /* loop_if_less src1(r) src2(r) target(offset)
2654 Checks whether register src1 is less than register src2, as
2655 with the ECMAScript '<' operator, and then jumps to offset
2656 target from the current instruction, if and only if the
2657 result of the comparison is true.
2659 Additionally this loop instruction may terminate JS execution is
2660 the JS timeout is reached.
2662 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2663 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2664 int target = vPC[3].u.operand;
2666 bool result = jsLess(callFrame, src1, src2);
2667 CHECK_FOR_EXCEPTION();
2671 CHECK_FOR_TIMEOUT();
2675 vPC += OPCODE_LENGTH(op_loop_if_less);
2678 DEFINE_OPCODE(op_loop_if_lesseq) {
2679 /* loop_if_lesseq src1(r) src2(r) target(offset)
2681 Checks whether register src1 is less than or equal to register
2682 src2, as with the ECMAScript '<=' operator, and then jumps to
2683 offset target from the current instruction, if and only if the
2684 result of the comparison is true.
2686 Additionally this loop instruction may terminate JS execution is
2687 the JS timeout is reached.
2689 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2690 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2691 int target = vPC[3].u.operand;
2693 bool result = jsLessEq(callFrame, src1, src2);
2694 CHECK_FOR_EXCEPTION();
2698 CHECK_FOR_TIMEOUT();
2702 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
2705 DEFINE_OPCODE(op_jnless) {
2706 /* jnless src1(r) src2(r) target(offset)
2708 Checks whether register src1 is less than register src2, as
2709 with the ECMAScript '<' operator, and then jumps to offset
2710 target from the current instruction, if and only if the
2711 result of the comparison is false.
2713 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2714 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2715 int target = vPC[3].u.operand;
2717 bool result = jsLess(callFrame, src1, src2);
2718 CHECK_FOR_EXCEPTION();
2725 vPC += OPCODE_LENGTH(op_jnless);
2728 DEFINE_OPCODE(op_jless) {
2729 /* jless 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 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2737 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2738 int target = vPC[3].u.operand;
2740 bool result = jsLess(callFrame, src1, src2);
2741 CHECK_FOR_EXCEPTION();
2748 vPC += OPCODE_LENGTH(op_jless);
2751 DEFINE_OPCODE(op_jnlesseq) {
2752 /* jnlesseq src1(r) src2(r) target(offset)
2754 Checks whether register src1 is less than or equal to
2755 register src2, as with the ECMAScript '<=' operator,
2756 and then jumps to offset target from the current instruction,
2757 if and only if theresult of the comparison is false.
2759 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
2760 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
2761 int target = vPC[3].u.operand;
2763 bool result = jsLessEq(callFrame, src1, src2);
2764 CHECK_FOR_EXCEPTION();
2771 vPC += OPCODE_LENGTH(op_jnlesseq);
2774 DEFINE_OPCODE(op_switch_imm) {
2775 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2777 Performs a range checked switch on the scrutinee value, using
2778 the tableIndex-th immediate switch jump table. If the scrutinee value
2779 is an immediate number in the range covered by the referenced jump
2780 table, and the value at jumpTable[scrutinee value] is non-zero, then
2781 that value is used as the jump offset, otherwise defaultOffset is used.
2783 int tableIndex = vPC[1].u.operand;
2784 int defaultOffset = vPC[2].u.operand;
2785 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2786 if (scrutinee.isInt32())
2787 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
2791 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
2792 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
2794 vPC += defaultOffset;
2798 DEFINE_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[1].u.operand;
2808 int defaultOffset = vPC[2].u.operand;
2809 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2810 if (!scrutinee.isString())
2811 vPC += defaultOffset;
2813 UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
2814 if (value->size() != 1)
2815 vPC += defaultOffset;
2817 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);
2821 DEFINE_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[1].u.operand;
2831 int defaultOffset = vPC[2].u.operand;
2832 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
2833 if (!scrutinee.isString())
2834 vPC += defaultOffset;
2836 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset);
2839 DEFINE_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[1].u.operand;
2848 int func = vPC[2].u.operand;
2850 callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
2852 vPC += OPCODE_LENGTH(op_new_func);
2855 DEFINE_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[1].u.operand;
2864 int funcIndex = vPC[2].u.operand;
2866 FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex);
2867 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
2870 The Identifier in a FunctionExpression can be referenced from inside
2871 the FunctionExpression's FunctionBody to allow the function to call
2872 itself recursively. However, unlike in a FunctionDeclaration, the
2873 Identifier in a FunctionExpression cannot be referenced from and
2874 does not affect the scope enclosing the FunctionExpression.
2876 if (!function->name().isNull()) {
2877 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
2878 func->scope().push(functionScopeObject);
2881 callFrame->r(dst) = JSValue(func);
2883 vPC += OPCODE_LENGTH(op_new_func_exp);
2886 DEFINE_OPCODE(op_call_eval) {
2887 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
2889 Call a function named "eval" with no explicit "this" value
2890 (which may therefore be the eval operator). If register
2891 thisVal is the global object, and register func contains
2892 that global object's original global eval function, then
2893 perform the eval operator in local scope (interpreting
2894 the argument registers as for the "call"
2895 opcode). Otherwise, act exactly as the "call" opcode would.
2898 int dst = vPC[1].u.operand;
2899 int func = vPC[2].u.operand;
2900 int argCount = vPC[3].u.operand;
2901 int registerOffset = vPC[4].u.operand;
2903 JSValue funcVal = callFrame->r(func).jsValue();
2905 Register* newCallFrame = callFrame->registers() + registerOffset;
2906 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
2907 JSValue thisValue = argv[0].jsValue();
2908 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
2910 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
2911 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
2914 callFrame->r(dst) = result;
2916 vPC += OPCODE_LENGTH(op_call_eval);
2920 // We didn't find the blessed version of eval, so process this
2921 // instruction as a normal function call.
2922 // fall through to op_call
2924 DEFINE_OPCODE(op_call) {
2925 /* call dst(r) func(r) argCount(n) registerOffset(n)
2927 Perform a function call.
2929 registerOffset is the distance the callFrame pointer should move
2930 before the VM initializes the new call frame's header.
2932 dst is where op_ret should store its result.
2935 int dst = vPC[1].u.operand;
2936 int func = vPC[2].u.operand;
2937 int argCount = vPC[3].u.operand;
2938 int registerOffset = vPC[4].u.operand;
2940 JSValue v = callFrame->r(func).jsValue();
2943 CallType callType = v.getCallData(callData);
2945 if (callType == CallTypeJS) {
2946 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2947 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
2949 CallFrame* previousCallFrame = callFrame;
2951 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
2952 if (Q_UNLIKELY(!callFrame)) {
2953 callFrame = previousCallFrame;
2954 exceptionValue = createStackOverflowError(callFrame);
2958 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
2959 vPC = newCodeBlock->instructions().begin();
2961 #if ENABLE(OPCODE_STATS)
2962 OpcodeStats::resetLastInstruction();
2968 if (callType == CallTypeHost) {
2969 ScopeChainNode* scopeChain = callFrame->scopeChain();
2970 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
2971 // we need the returnValue to be 0 as it is used as flags
2972 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, 0, argCount, asObject(v));
2973 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
2974 ArgList args(thisRegister + 1, argCount - 1);
2976 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
2977 JSValue thisValue = thisRegister->jsValue();
2978 if (thisValue == jsNull())
2979 thisValue = callFrame->globalThisValue();
2981 JSValue returnValue;
2983 SamplingTool::HostCallRecord callRecord(m_sampler.get());
2984 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
2986 CHECK_FOR_EXCEPTION();
2988 callFrame->r(dst) = returnValue;
2990 vPC += OPCODE_LENGTH(op_call);
2994 Q_ASSERT(callType == CallTypeNone);
2996 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
2999 DEFINE_OPCODE(op_load_varargs) {
3000 int argCountDst = vPC[1].u.operand;
3001 int argsOffset = vPC[2].u.operand;
3003 JSValue arguments = callFrame->r(argsOffset).jsValue();
3004 int32_t argCount = 0;
3006 argCount = (uint32_t)(callFrame->argumentCount()) - 1;
3007 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3008 Register* newEnd = callFrame->registers() + sizeDelta;
3009 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3010 exceptionValue = createStackOverflowError(callFrame);
3013 Q_ASSERT(!asFunction(callFrame->callee())->isHostFunction());
3014 int32_t expectedParams = static_cast<JSFunction*>(callFrame->callee())->jsExecutable()->parameterCount();
3015 int32_t inplaceArgs = std::min(argCount, expectedParams);
3017 Register* argStore = callFrame->registers() + argsOffset;
3019 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3020 for (; i < inplaceArgs; i++)
3021 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
3022 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3023 for (; i < argCount; i++)
3024 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
3025 } else if (!arguments.isUndefinedOrNull()) {
3026 if (!arguments.isObject()) {
3027 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3030 if (asObject(arguments)->classInfo() == &Arguments::info) {
3031 Arguments* args = asArguments(arguments);
3032 argCount = args->numProvidedArguments(callFrame);
3033 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3034 Register* newEnd = callFrame->registers() + sizeDelta;
3035 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3036 exceptionValue = createStackOverflowError(callFrame);
3039 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3040 } else if (isJSArray(&callFrame->globalData(), arguments)) {
3041 JSArray* array = asArray(arguments);
3042 argCount = array->length();
3043 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3044 Register* newEnd = callFrame->registers() + sizeDelta;
3045 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3046 exceptionValue = createStackOverflowError(callFrame);
3049 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3050 } else if (asObject(arguments)->inherits(&JSArray::info)) {
3051 JSObject* argObject = asObject(arguments);
3052 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
3053 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3054 Register* newEnd = callFrame->registers() + sizeDelta;
3055 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3056 exceptionValue = createStackOverflowError(callFrame);
3059 Register* argsBuffer = callFrame->registers() + argsOffset;
3060 for (int32_t i = 0; i < argCount; ++i) {
3061 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
3062 CHECK_FOR_EXCEPTION();
3065 if (!arguments.isObject()) {
3066 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3071 CHECK_FOR_EXCEPTION();
3072 callFrame->r(argCountDst) = Register::withInt(argCount + 1);
3073 vPC += OPCODE_LENGTH(op_load_varargs);
3076 DEFINE_OPCODE(op_call_varargs) {
3077 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3079 Perform a function call with a dynamic set of arguments.
3081 registerOffset is the distance the callFrame pointer should move
3082 before the VM initializes the new call frame's header, excluding
3083 space for arguments.
3085 dst is where op_ret should store its result.
3088 int dst = vPC[1].u.operand;
3089 int func = vPC[2].u.operand;
3090 int argCountReg = vPC[3].u.operand;
3091 int registerOffset = vPC[4].u.operand;
3093 JSValue v = callFrame->r(func).jsValue();
3094 int argCount = callFrame->r(argCountReg).i();
3095 registerOffset += argCount;
3097 CallType callType = v.getCallData(callData);
3099 if (callType == CallTypeJS) {
3100 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3101 CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
3103 CallFrame* previousCallFrame = callFrame;
3105 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3106 if (Q_UNLIKELY(!callFrame)) {
3107 callFrame = previousCallFrame;
3108 exceptionValue = createStackOverflowError(callFrame);
3112 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3113 vPC = newCodeBlock->instructions().begin();
3115 #if ENABLE(OPCODE_STATS)
3116 OpcodeStats::resetLastInstruction();
3122 if (callType == CallTypeHost) {
3123 ScopeChainNode* scopeChain = callFrame->scopeChain();
3124 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3125 // we need the returnValue to be 0 as it is used as flags
3126 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, 0, argCount, asObject(v));
3128 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3129 ArgList args(thisRegister + 1, argCount - 1);
3131 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3132 JSValue thisValue = thisRegister->jsValue();
3133 if (thisValue == jsNull())
3134 thisValue = callFrame->globalThisValue();
3136 JSValue returnValue;
3138 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3139 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3141 CHECK_FOR_EXCEPTION();
3143 callFrame->r(dst) = returnValue;
3145 vPC += OPCODE_LENGTH(op_call_varargs);
3149 Q_ASSERT(callType == CallTypeNone);
3151 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3154 DEFINE_OPCODE(op_tear_off_activation) {
3155 /* tear_off_activation activation(r)
3157 Copy all locals and parameters to new memory allocated on
3158 the heap, and make the passed activation use this memory
3159 in the future when looking up entries in the symbol table.
3160 If there is an 'arguments' object, then it will also use
3161 this memory for storing the named parameters, but not any
3164 This opcode should only be used immediately before op_ret.
3167 int src = vPC[1].u.operand;
3168 Q_ASSERT(callFrame->codeBlock()->needsFullScopeChain());
3170 asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments());
3172 vPC += OPCODE_LENGTH(op_tear_off_activation);
3175 DEFINE_OPCODE(op_tear_off_arguments) {
3176 /* tear_off_arguments
3178 Copy all arguments to new memory allocated on the heap,
3179 and make the 'arguments' object use this memory in the
3180 future when looking up named parameters, but not any
3181 extra arguments. If an activation object exists for the
3182 current function context, then the tear_off_activation
3183 opcode should be used instead.
3185 This opcode should only be used immediately before op_ret.
3188 Q_ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
3190 if (callFrame->optionalCalleeArguments())
3191 callFrame->optionalCalleeArguments()->copyRegisters();
3193 vPC += OPCODE_LENGTH(op_tear_off_arguments);
3196 DEFINE_OPCODE(op_ret) {
3199 Return register result as the return value of the current
3200 function call, writing it into the caller's expected return
3201 value register. In addition, unwind one call frame and
3202 restore the scope chain, code block instruction pointer and
3203 register base to those of the calling function.
3206 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
3207 intptr_t sourceId = callFrame->codeBlock()->source()->asID();
3209 int result = vPC[1].u.operand;
3211 if (callFrame->codeBlock()->needsFullScopeChain())
3212 callFrame->scopeChain()->deref();
3214 JSValue returnValue = callFrame->r(result).jsValue();
3216 debugger->functionExit(returnValue, sourceId);
3218 vPC = callFrame->returnPC();
3219 int dst = callFrame->returnValueRegister();
3220 callFrame = callFrame->callerFrame();
3222 if (callFrame->hasHostCallFrameFlag())
3225 callFrame->r(dst) = returnValue;
3229 DEFINE_OPCODE(op_enter) {
3232 Initializes local variables to undefined and fills constant
3233 registers with their values. If the code block requires an
3234 activation, enter_with_activation should be used instead.
3236 This opcode should only be used at the beginning of a code
3241 CodeBlock* codeBlock = callFrame->codeBlock();
3243 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3244 callFrame->r(i) = jsUndefined();
3246 vPC += OPCODE_LENGTH(op_enter);
3249 DEFINE_OPCODE(op_enter_with_activation) {
3250 /* enter_with_activation dst(r)
3252 Initializes local variables to undefined, fills constant
3253 registers with their values, creates an activation object,
3254 and places the new activation both in dst and at the top
3255 of the scope chain. If the code block does not require an
3256 activation, enter should be used instead.
3258 This opcode should only be used at the beginning of a code
3263 CodeBlock* codeBlock = callFrame->codeBlock();
3265 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3266 callFrame->r(i) = jsUndefined();
3268 int dst = vPC[1].u.operand;
3269 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
3270 callFrame->r(dst) = JSValue(activation);
3271 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
3273 vPC += OPCODE_LENGTH(op_enter_with_activation);
3276 DEFINE_OPCODE(op_convert_this) {
3277 /* convert_this this(r)
3279 Takes the value in the 'this' register, converts it to a
3280 value that is suitable for use as the 'this' value, and
3281 stores it in the 'this' register. This opcode is emitted
3282 to avoid doing the conversion in the caller unnecessarily.
3284 This opcode should only be used at the beginning of a code
3288 int thisRegister = vPC[1].u.operand;
3289 JSValue thisVal = callFrame->r(thisRegister).jsValue();
3290 if (thisVal.needsThisConversion())
3291 callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
3293 vPC += OPCODE_LENGTH(op_convert_this);
3296 DEFINE_OPCODE(op_init_arguments) {
3299 Initialises the arguments object reference to null to ensure
3300 we can correctly detect that we need to create it later (or
3301 avoid creating it altogether).
3303 This opcode should only be used at the beginning of a code
3306 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue();
3307 vPC += OPCODE_LENGTH(op_init_arguments);
3310 DEFINE_OPCODE(op_create_arguments) {
3313 Creates the 'arguments' object and places it in both the
3314 'arguments' call frame slot and the local 'arguments'
3315 register, if it has not already been initialised.
3318 if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) {
3319 Arguments* arguments = new (globalData) Arguments(callFrame);
3320 callFrame->setCalleeArguments(arguments);
3321 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3323 vPC += OPCODE_LENGTH(op_create_arguments);
3326 DEFINE_OPCODE(op_construct) {
3327 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3329 Invoke register "func" as a constructor. For JS
3330 functions, the calling convention is exactly as for the
3331 "call" opcode, except that the "this" value is a newly
3332 created Object. For native constructors, no "this"
3333 value is passed. In either case, the argCount and registerOffset
3334 registers are interpreted as for the "call" opcode.
3336 Register proto must contain the prototype property of
3337 register func. This is to enable polymorphic inline
3338 caching of this lookup.
3341 int dst = vPC[1].u.operand;
3342 int func = vPC[2].u.operand;
3343 int argCount = vPC[3].u.operand;
3344 int registerOffset = vPC[4].u.operand;
3345 int proto = vPC[5].u.operand;
3346 int thisRegister = vPC[6].u.operand;
3348 JSValue v = callFrame->r(func).jsValue();
3350 ConstructData constructData;
3351 ConstructType constructType = v.getConstructData(constructData);
3353 if (constructType == ConstructTypeJS) {
3354 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3355 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain);
3357 Structure* structure;
3358 JSValue prototype = callFrame->r(proto).jsValue();
3359 if (prototype.isObject())
3360 structure = asObject(prototype)->inheritorID();
3362 structure = callDataScopeChain->globalObject->emptyObjectStructure();
3363 // ### world-class hack
3364 QT_PREPEND_NAMESPACE(QScriptObject)* newObject = new (globalData) QT_PREPEND_NAMESPACE(QScriptObject)(structure);
3366 callFrame->r(thisRegister) = JSValue(newObject); // "this" value
3368 CallFrame* previousCallFrame = callFrame;
3370 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3371 if (Q_UNLIKELY(!callFrame)) {
3372 callFrame = previousCallFrame;
3373 exceptionValue = createStackOverflowError(callFrame);
3377 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3378 vPC = newCodeBlock->instructions().begin();
3380 #if ENABLE(OPCODE_STATS)
3381 OpcodeStats::resetLastInstruction();
3387 if (constructType == ConstructTypeHost) {
3388 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
3390 ScopeChainNode* scopeChain = callFrame->scopeChain();
3391 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3392 // we need the returnValue to be 0 as it is used as flags
3393 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, 0, argCount, asObject(v));
3395 JSValue returnValue;
3397 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3398 returnValue = constructData.native.function(newCallFrame, asObject(v), args);
3400 CHECK_FOR_EXCEPTION();
3401 callFrame->r(dst) = JSValue(returnValue);
3403 vPC += OPCODE_LENGTH(op_construct);
3407 Q_ASSERT(constructType == ConstructTypeNone);
3409 exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3412 DEFINE_OPCODE(op_construct_verify) {
3413 /* construct_verify dst(r) override(r)
3415 Verifies that register dst holds an object. If not, moves
3416 the object in register override to register dst.
3419 int dst = vPC[1].u.operand;
3420 if (Q_LIKELY(callFrame->r(dst).jsValue().isObject())) {
3421 vPC += OPCODE_LENGTH(op_construct_verify);
3425 int override = vPC[2].u.operand;
3426 callFrame->r(dst) = callFrame->r(override);
3428 vPC += OPCODE_LENGTH(op_construct_verify);
3431 DEFINE_OPCODE(op_strcat) {
3432 int dst = vPC[1].u.operand;
3433 int src = vPC[2].u.operand;
3434 int count = vPC[3].u.operand;
3436 callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count);
3437 CHECK_FOR_EXCEPTION();
3438 vPC += OPCODE_LENGTH(op_strcat);
3442 DEFINE_OPCODE(op_to_primitive) {
3443 int dst = vPC[1].u.operand;
3444 int src = vPC[2].u.operand;
3446 callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
3447 vPC += OPCODE_LENGTH(op_to_primitive);
3451 DEFINE_OPCODE(op_push_scope) {
3452 /* push_scope scope(r)
3454 Converts register scope to object, and pushes it onto the top
3455 of the current scope chain. The contents of the register scope
3456 are replaced by the result of toObject conversion of the scope.
3458 int scope = vPC[1].u.operand;
3459 JSValue v = callFrame->r(scope).jsValue();
3460 JSObject* o = v.toObject(callFrame);
3461 CHECK_FOR_EXCEPTION();
3463 callFrame->r(scope) = JSValue(o);
3464 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3466 vPC += OPCODE_LENGTH(op_push_scope);
3469 DEFINE_OPCODE(op_pop_scope) {
3472 Removes the top item from the current scope chain.
3474 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3476 vPC += OPCODE_LENGTH(op_pop_scope);
3479 DEFINE_OPCODE(op_get_pnames) {
3480 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
3482 Creates a property name list for register base and puts it
3483 in register dst, initializing i and size for iteration. If
3484 base is undefined or null, jumps to breakTarget.
3486 int dst = vPC[1].u.operand;
3487 int base = vPC[2].u.operand;
3488 int i = vPC[3].u.operand;
3489 int size = vPC[4].u.operand;
3490 int breakTarget = vPC[5].u.operand;
3492 JSValue v = callFrame->r(base).jsValue();
3493 if (v.isUndefinedOrNull()) {
3498 JSObject* o = v.toObject(callFrame);
3499 Structure* structure = o->structure();
3500 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
3501 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
3502 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
3504 callFrame->r(dst) = jsPropertyNameIterator;
3505 callFrame->r(base) = JSValue(o);
3506 callFrame->r(i) = Register::withInt(0);
3507 callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size());
3508 vPC += OPCODE_LENGTH(op_get_pnames);
3511 DEFINE_OPCODE(op_next_pname) {
3512 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
3514 Copies the next name from the property name list in
3515 register iter to dst, then jumps to offset target. If there are no
3516 names left, invalidates the iterator and continues to the next
3519 int dst = vPC[1].u.operand;
3520 int base = vPC[2].u.operand;
3521 int i = vPC[3].u.operand;
3522 int size = vPC[4].u.operand;
3523 int iter = vPC[5].u.operand;
3524 int target = vPC[6].u.operand;
3526 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3527 while (callFrame->r(i).i() != callFrame->r(size).i()) {
3528 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
3529 callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1);
3531 CHECK_FOR_TIMEOUT();
3532 callFrame->r(dst) = key;
3538 vPC += OPCODE_LENGTH(op_next_pname);
3541 DEFINE_OPCODE(op_jmp_scopes) {
3542 /* jmp_scopes count(n) target(offset)
3544 Removes the a number of items from the current scope chain
3545 specified by immediate number count, then jumps to offset
3548 int count = vPC[1].u.operand;
3549 int target = vPC[2].u.operand;
3551 ScopeChainNode* tmp = callFrame->scopeChain();
3554 callFrame->setScopeChain(tmp);
3559 DEFINE_OPCODE(op_push_new_scope) {
3560 /* new_scope dst(r) property(id) value(r)
3562 Constructs a new StaticScopeObject with property set to value. That scope
3563 object is then pushed onto the ScopeChain. The scope object is then stored
3566 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3568 vPC += OPCODE_LENGTH(op_push_new_scope);
3571 DEFINE_OPCODE(op_catch) {
3574 Retrieves the VM's current exception and puts it in register
3575 ex. This is only valid after an exception has been raised,
3576 and usually forms the beginning of an exception handler.
3578 Q_ASSERT(exceptionValue);
3579 Q_ASSERT(!globalData->exception);
3581 CodeBlock* codeBlock = callFrame->codeBlock();
3582 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
3584 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
3585 debugger->exceptionCatch(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID());
3588 int ex = vPC[1].u.operand;
3589 callFrame->r(ex) = exceptionValue;
3590 exceptionValue = JSValue();
3592 vPC += OPCODE_LENGTH(op_catch);
3595 DEFINE_OPCODE(op_throw) {
3598 Throws register ex as an exception. This involves three
3599 steps: first, it is set as the current exception in the
3600 VM's internal state, then the stack is unwound until an
3601 exception handler or a native code boundary is found, and
3602 then control resumes at the exception handler if any or
3603 else the script returns control to the nearest native caller.
3606 int ex = vPC[1].u.operand;
3607 exceptionValue = callFrame->r(ex).jsValue();
3609 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);
3611 *exception = exceptionValue;
3615 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3618 DEFINE_OPCODE(op_new_error) {
3619 /* new_error dst(r) type(n) message(k)
3621 Constructs a new Error instance using the original
3622 constructor, using immediate number n as the type and
3623 constant message as the message string. The result is
3624 written to register dst.
3626 int dst = vPC[1].u.operand;
3627 int type = vPC[2].u.operand;
3628 int message = vPC[3].u.operand;
3630 CodeBlock* codeBlock = callFrame->codeBlock();
3631 callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()));
3633 vPC += OPCODE_LENGTH(op_new_error);
3636 DEFINE_OPCODE(op_end) {
3639 Return register result as the value of a global or eval
3640 program. Return control to the calling native code.
3643 if (callFrame->codeBlock()->needsFullScopeChain()) {
3644 ScopeChainNode* scopeChain = callFrame->scopeChain();
3645 Q_ASSERT(scopeChain->refCount > 1);
3646 scopeChain->deref();
3648 int result = vPC[1].u.operand;
3649 return callFrame->r(result).jsValue();
3651 DEFINE_OPCODE(op_put_getter) {
3652 /* put_getter base(r) property(id) function(r)
3654 Sets register function on register base as the getter named
3655 by identifier property. Base and function are assumed to be
3656 objects as this op should only be used for getters defined
3657 in object literal form.
3659 Unlike many opcodes, this one does not write any output to
3662 int base = vPC[1].u.operand;
3663 int property = vPC[2].u.operand;
3664 int function = vPC[3].u.operand;
3666 Q_ASSERT(callFrame->r(base).jsValue().isObject());
3667 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3668 Identifier& ident = callFrame->codeBlock()->identifier(property);
3669 Q_ASSERT(callFrame->r(function).jsValue().isObject());
3670 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
3672 vPC += OPCODE_LENGTH(op_put_getter);
3675 DEFINE_OPCODE(op_put_setter) {
3676 /* put_setter base(r) property(id) function(r)
3678 Sets register function on register base as the setter named
3679 by identifier property. Base and function are assumed to be
3680 objects as this op should only be used for setters defined
3681 in object literal form.
3683 Unlike many opcodes, this one does not write any output to
3686 int base = vPC[1].u.operand;
3687 int property = vPC[2].u.operand;
3688 int function = vPC[3].u.operand;
3690 Q_ASSERT(callFrame->r(base).jsValue().isObject());
3691 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3692 Identifier& ident = callFrame->codeBlock()->identifier(property);
3693 Q_ASSERT(callFrame->r(function).jsValue().isObject());
3694 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
3696 vPC += OPCODE_LENGTH(op_put_setter);
3699 DEFINE_OPCODE(op_method_check) {
3703 DEFINE_OPCODE(op_jsr) {
3704 /* jsr retAddrDst(r) target(offset)
3706 Places the address of the next instruction into the retAddrDst
3707 register and jumps to offset target from the current instruction.
3709 int retAddrDst = vPC[1].u.operand;
3710 int target = vPC[2].u.operand;
3711 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
3716 DEFINE_OPCODE(op_sret) {
3717 /* sret retAddrSrc(r)
3719 Jumps to the address stored in the retAddrSrc register. This
3720 differs from op_jmp because the target address is stored in a
3721 register, not as an immediate.
3723 int retAddrSrc = vPC[1].u.operand;
3724 vPC = callFrame->r(retAddrSrc).vPC();
3727 DEFINE_OPCODE(op_debug) {
3728 /* debug debugHookID(n) firstLine(n) lastLine(n)
3730 Notifies the debugger of the current state of execution. This opcode
3731 is only generated while the debugger is attached.
3733 int debugHookID = vPC[1].u.operand;
3734 int firstLine = vPC[2].u.operand;
3735 int lastLine = vPC[3].u.operand;
3737 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3739 vPC += OPCODE_LENGTH(op_debug);
3743 globalData->exception = JSValue();
3745 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3746 // cannot fathom if we don't assign to the exceptionValue before branching)
3747 exceptionValue = createInterruptedExecutionException(globalData);
3749 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);
3751 *exception = exceptionValue;
3755 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3759 } // iterator loop ends
3760 #undef NEXT_INSTRUCTION
3761 #undef DEFINE_OPCODE
3762 #undef CHECK_FOR_EXCEPTION
3763 #undef CHECK_FOR_TIMEOUT
3766 JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3768 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3769 if (!functionCallFrame)
3772 CodeBlock* codeBlock = functionCallFrame->codeBlock();
3773 if (codeBlock->usesArguments()) {
3774 Q_ASSERT(codeBlock->codeType() == FunctionCode);
3775 SymbolTable& symbolTable = *codeBlock->symbolTable();
3776 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
3777 if (!functionCallFrame->r(argumentsIndex).jsValue()) {
3778 Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
3779 functionCallFrame->setCalleeArguments(arguments);
3780 functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3782 return functionCallFrame->r(argumentsIndex).jsValue();
3785 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
3787 arguments = new (functionCallFrame) Arguments(functionCallFrame);
3788 arguments->copyRegisters();
3789 callFrame->setCalleeArguments(arguments);
3795 JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
3797 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3798 if (!functionCallFrame)
3801 CallFrame* callerFrame = functionCallFrame->callerFrame();
3802 if (callerFrame->hasHostCallFrameFlag())
3805 JSValue caller = callerFrame->callee();
3812 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
3814 function = JSValue();
3816 sourceURL = UString();
3818 CallFrame* callerFrame = callFrame->callerFrame();
3819 if (callerFrame->hasHostCallFrameFlag())
3822 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
3823 if (!callerCodeBlock)
3826 unsigned bytecodeOffset = bytecodeOffsetForPC(callerCodeBlock, callFrame->returnPC());
3827 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);
3828 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
3829 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
3830 function = callerFrame->callee();
3833 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
3835 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
3836 if (candidate->callee() == function)
3842 void Interpreter::enableSampler()
3844 #if ENABLE(OPCODE_SAMPLING)
3846 m_sampler.set(new SamplingTool(this));
3851 void Interpreter::dumpSampleData(ExecState* exec)
3853 #if ENABLE(OPCODE_SAMPLING)
3855 m_sampler->dump(exec);
3860 void Interpreter::startSampling()
3862 #if ENABLE(SAMPLING_THREAD)
3863 if (!m_sampleEntryDepth)
3864 SamplingThread::start();
3866 m_sampleEntryDepth++;
3869 void Interpreter::stopSampling()
3871 #if ENABLE(SAMPLING_THREAD)
3872 m_sampleEntryDepth--;
3873 if (!m_sampleEntryDepth)
3874 SamplingThread::stop();