2 * Copyright (C) 2008, 2009, 2010 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"
40 #include "DebuggerCallFrame.h"
41 #include "ErrorInstance.h"
42 #include "EvalCodeCache.h"
43 #include "ExceptionHelpers.h"
44 #include "GetterSetter.h"
45 #include "JSActivation.h"
47 #include "JSByteArray.h"
48 #include "JSFunction.h"
49 #include "JSNotAnObject.h"
50 #include "JSPropertyNameIterator.h"
51 #include "LiteralParser.h"
52 #include "JSStaticScopeObject.h"
54 #include "ObjectPrototype.h"
55 #include "Operations.h"
58 #include "RegExpObject.h"
59 #include "RegExpPrototype.h"
61 #include "SamplingTool.h"
62 #include "StrictEvalActivation.h"
63 #include "UStringConcatenate.h"
66 #include <wtf/Threading.h>
72 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__))
78 // Returns the depth of the scope chain within a given call frame.
79 static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
81 if (!codeBlock->needsFullScopeChain())
83 return sc->localDepth();
86 #if ENABLE(INTERPRETER)
87 static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)
89 return jsString(exec, strings, count);
92 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
94 int dst = vPC[1].u.operand;
95 int property = vPC[2].u.operand;
97 ScopeChainNode* scopeChain = callFrame->scopeChain();
98 ScopeChainIterator iter = scopeChain->begin();
99 ScopeChainIterator end = scopeChain->end();
102 CodeBlock* codeBlock = callFrame->codeBlock();
103 Identifier& ident = codeBlock->identifier(property);
105 JSObject* o = iter->get();
106 PropertySlot slot(o);
107 if (o->getPropertySlot(callFrame, ident, slot)) {
108 JSValue result = slot.getValue(callFrame, ident);
109 exceptionValue = callFrame->globalData().exception;
112 callFrame->uncheckedR(dst) = JSValue(result);
115 } while (++iter != end);
116 exceptionValue = createUndefinedVariableError(callFrame, ident);
120 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
122 CodeBlock* codeBlock = callFrame->codeBlock();
124 int dst = vPC[1].u.operand;
125 int property = vPC[2].u.operand;
126 int skip = vPC[3].u.operand;
128 ScopeChainNode* scopeChain = callFrame->scopeChain();
129 ScopeChainIterator iter = scopeChain->begin();
130 ScopeChainIterator end = scopeChain->end();
132 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
133 ASSERT(skip || !checkTopLevel);
134 if (checkTopLevel && skip--) {
135 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
142 Identifier& ident = codeBlock->identifier(property);
144 JSObject* o = iter->get();
145 PropertySlot slot(o);
146 if (o->getPropertySlot(callFrame, ident, slot)) {
147 JSValue result = slot.getValue(callFrame, ident);
148 exceptionValue = callFrame->globalData().exception;
152 callFrame->uncheckedR(dst) = JSValue(result);
155 } while (++iter != end);
156 exceptionValue = createUndefinedVariableError(callFrame, ident);
160 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
162 int dst = vPC[1].u.operand;
163 CodeBlock* codeBlock = callFrame->codeBlock();
164 JSGlobalObject* globalObject = codeBlock->globalObject();
165 ASSERT(globalObject->isGlobalObject());
166 int property = vPC[2].u.operand;
167 Structure* structure = vPC[3].u.structure.get();
168 int offset = vPC[4].u.operand;
170 if (structure == globalObject->structure()) {
171 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
175 Identifier& ident = codeBlock->identifier(property);
176 PropertySlot slot(globalObject);
177 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
178 JSValue result = slot.getValue(callFrame, ident);
179 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
180 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
181 vPC[4] = slot.cachedOffset();
182 callFrame->uncheckedR(dst) = JSValue(result);
186 exceptionValue = callFrame->globalData().exception;
189 callFrame->uncheckedR(dst) = JSValue(result);
193 exceptionValue = createUndefinedVariableError(callFrame, ident);
197 NEVER_INLINE bool Interpreter::resolveGlobalDynamic(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
199 int dst = vPC[1].u.operand;
200 CodeBlock* codeBlock = callFrame->codeBlock();
201 JSGlobalObject* globalObject = codeBlock->globalObject();
202 ASSERT(globalObject->isGlobalObject());
203 int property = vPC[2].u.operand;
204 Structure* structure = vPC[3].u.structure.get();
205 int offset = vPC[4].u.operand;
206 int skip = vPC[5].u.operand;
208 ScopeChainNode* scopeChain = callFrame->scopeChain();
209 ScopeChainIterator iter = scopeChain->begin();
210 ScopeChainIterator end = scopeChain->end();
212 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
213 ASSERT(skip || !checkTopLevel);
214 if (checkTopLevel && skip--) {
215 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
219 JSObject* o = iter->get();
220 if (o->hasCustomProperties()) {
221 Identifier& ident = codeBlock->identifier(property);
223 PropertySlot slot(o);
224 if (o->getPropertySlot(callFrame, ident, slot)) {
225 JSValue result = slot.getValue(callFrame, ident);
226 exceptionValue = callFrame->globalData().exception;
230 callFrame->uncheckedR(dst) = JSValue(result);
238 exceptionValue = createUndefinedVariableError(callFrame, ident);
244 if (structure == globalObject->structure()) {
245 callFrame->uncheckedR(dst) = JSValue(globalObject->getDirectOffset(offset));
246 ASSERT(callFrame->uncheckedR(dst).jsValue());
250 Identifier& ident = codeBlock->identifier(property);
251 PropertySlot slot(globalObject);
252 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
253 JSValue result = slot.getValue(callFrame, ident);
254 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
255 vPC[3].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
256 vPC[4] = slot.cachedOffset();
258 callFrame->uncheckedR(dst) = JSValue(result);
262 exceptionValue = callFrame->globalData().exception;
266 callFrame->uncheckedR(dst) = JSValue(result);
270 exceptionValue = createUndefinedVariableError(callFrame, ident);
274 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
276 int dst = vPC[1].u.operand;
277 int property = vPC[2].u.operand;
278 bool isStrictPut = vPC[3].u.operand;
279 Identifier ident = callFrame->codeBlock()->identifier(property);
280 JSValue result = JSC::resolveBase(callFrame, ident, callFrame->scopeChain(), isStrictPut);
282 callFrame->uncheckedR(dst) = result;
283 ASSERT(callFrame->uncheckedR(dst).jsValue());
285 callFrame->globalData().exception = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
288 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
290 int baseDst = vPC[1].u.operand;
291 int propDst = vPC[2].u.operand;
292 int property = vPC[3].u.operand;
294 ScopeChainNode* scopeChain = callFrame->scopeChain();
295 ScopeChainIterator iter = scopeChain->begin();
296 ScopeChainIterator end = scopeChain->end();
298 // FIXME: add scopeDepthIsZero optimization
302 CodeBlock* codeBlock = callFrame->codeBlock();
303 Identifier& ident = codeBlock->identifier(property);
307 PropertySlot slot(base);
308 if (base->getPropertySlot(callFrame, ident, slot)) {
309 JSValue result = slot.getValue(callFrame, ident);
310 exceptionValue = callFrame->globalData().exception;
313 callFrame->uncheckedR(propDst) = JSValue(result);
314 callFrame->uncheckedR(baseDst) = JSValue(base);
318 } while (iter != end);
320 exceptionValue = createUndefinedVariableError(callFrame, ident);
324 #endif // ENABLE(INTERPRETER)
326 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
328 Register* r = callFrame->registers();
329 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
331 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
332 if (UNLIKELY(!registerFile->grow(newEnd)))
335 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
336 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
337 registerOffset += omittedArgCount;
338 newEnd += omittedArgCount;
339 if (!registerFile->grow(newEnd))
343 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
344 for (size_t i = 0; i < omittedArgCount; ++i)
345 argv[i] = jsUndefined();
346 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
347 size_t numParameters = newCodeBlock->m_numParameters;
348 registerOffset += numParameters;
349 newEnd += numParameters;
351 if (!registerFile->grow(newEnd))
355 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
356 for (size_t i = 0; i < numParameters; ++i)
357 argv[i + argc] = argv[i];
360 return CallFrame::create(r);
363 #if ENABLE(INTERPRETER)
364 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
366 if (value.isObject())
368 exceptionData = createInvalidParamError(callFrame, "in" , value);
372 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, JSValue value, JSValue& exceptionData)
374 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
376 exceptionData = createInvalidParamError(callFrame, "instanceof" , value);
381 NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset)
384 return jsUndefined();
386 JSValue program = argv[1].jsValue();
388 if (!program.isString())
391 UString programSource = asString(program)->value(callFrame);
392 if (callFrame->hadException())
395 CodeBlock* codeBlock = callFrame->codeBlock();
396 if (!codeBlock->isStrictMode()) {
397 // FIXME: We can use the preparser in strict mode, we just need additional logic
398 // to prevent duplicates.
399 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
400 if (JSValue parsedObject = preparser.tryLiteralParse())
404 ScopeChainNode* scopeChain = callFrame->scopeChain();
405 JSValue exceptionValue;
406 EvalExecutable* eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
408 ASSERT(!eval == exceptionValue);
410 return throwError(callFrame, exceptionValue);
412 return callFrame->globalData().interpreter->execute(eval, callFrame, callFrame->uncheckedR(codeBlock->thisRegister()).jsValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain);
415 Interpreter::Interpreter(JSGlobalData& globalData)
416 : m_sampleEntryDepth(0)
418 , m_registerFile(globalData)
420 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
421 privateExecute(InitializeAndReturn, 0, 0);
423 for (int i = 0; i < numOpcodeIDs; ++i)
424 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
425 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
427 #if ENABLE(OPCODE_SAMPLING)
434 void Interpreter::dumpCallFrame(CallFrame* callFrame)
436 callFrame->codeBlock()->dump(callFrame);
437 dumpRegisters(callFrame);
440 void Interpreter::dumpRegisters(CallFrame* callFrame)
442 printf("Register frame: \n\n");
443 printf("-----------------------------------------------------------------------------\n");
444 printf(" use | address | value \n");
445 printf("-----------------------------------------------------------------------------\n");
447 CodeBlock* codeBlock = callFrame->codeBlock();
448 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData().interpreter->registerFile();
453 if (codeBlock->codeType() == GlobalCode) {
454 it = registerFile->lastGlobal();
455 end = it + registerFile->numGlobals();
458 #if USE(JSVALUE32_64)
459 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
461 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
465 printf("-----------------------------------------------------------------------------\n");
468 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
470 #if USE(JSVALUE32_64)
471 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
473 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
475 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
479 #if USE(JSVALUE32_64)
480 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
482 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
487 printf("-----------------------------------------------------------------------------\n");
488 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
489 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
490 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
491 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
492 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
493 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
494 printf("-----------------------------------------------------------------------------\n");
496 int registerCount = 0;
498 end = it + codeBlock->m_numVars;
502 #if USE(JSVALUE32_64)
503 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
505 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
511 printf("-----------------------------------------------------------------------------\n");
513 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
517 #if USE(JSVALUE32_64)
518 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
520 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
526 printf("-----------------------------------------------------------------------------\n");
531 bool Interpreter::isOpcode(Opcode opcode)
533 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
534 return opcode != HashTraits<Opcode>::emptyValue()
535 && !HashTraits<Opcode>::isDeletedValue(opcode)
536 && m_opcodeIDTable.contains(opcode);
538 return opcode >= 0 && opcode <= op_end;
542 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
544 CodeBlock* oldCodeBlock = codeBlock;
545 ScopeChainNode* scopeChain = callFrame->scopeChain();
547 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
548 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
549 if (callFrame->callee())
550 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
552 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine());
555 // If this call frame created an activation or an 'arguments' object, tear it off.
556 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
557 if (!callFrame->uncheckedR(oldCodeBlock->activationRegister()).jsValue()) {
558 oldCodeBlock->createActivation(callFrame);
559 scopeChain = callFrame->scopeChain();
561 while (!scopeChain->object->inherits(&JSActivation::s_info))
562 scopeChain = scopeChain->pop();
564 callFrame->setScopeChain(scopeChain);
565 JSActivation* activation = asActivation(scopeChain->object.get());
566 activation->copyRegisters(*scopeChain->globalData);
567 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue()) {
568 if (!oldCodeBlock->isStrictMode())
569 asArguments(arguments)->setActivation(callFrame->globalData(), activation);
571 } else if (oldCodeBlock->usesArguments() && !oldCodeBlock->isStrictMode()) {
572 if (JSValue arguments = callFrame->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock->argumentsRegister())).jsValue())
573 asArguments(arguments)->copyRegisters(callFrame->globalData());
576 CallFrame* callerFrame = callFrame->callerFrame();
577 if (callerFrame->hasHostCallFrameFlag())
580 codeBlock = callerFrame->codeBlock();
581 #if ENABLE(JIT) && ENABLE(INTERPRETER)
582 if (callerFrame->globalData().canUseJIT())
583 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
585 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC());
587 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC());
589 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC());
592 callFrame = callerFrame;
596 static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
598 exception->clearAppendSourceToMessage();
600 if (!callFrame->codeBlock()->hasExpressionInfo())
607 CodeBlock* codeBlock = callFrame->codeBlock();
608 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset);
610 int expressionStart = divotPoint - startOffset;
611 int expressionStop = divotPoint + endOffset;
613 if (!expressionStop || expressionStart > codeBlock->source()->length())
616 JSGlobalData* globalData = &callFrame->globalData();
617 JSValue jsMessage = exception->getDirect(*globalData, globalData->propertyNames->message);
618 if (!jsMessage || !jsMessage.isString())
621 UString message = asString(jsMessage)->value(callFrame);
623 if (expressionStart < expressionStop)
624 message = makeUString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
626 // No range information, so give a few characters of context
627 const UChar* data = codeBlock->source()->data();
628 int dataLength = codeBlock->source()->length();
629 int start = expressionStart;
630 int stop = expressionStart;
631 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
632 // then strip whitespace.
633 while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
635 while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
637 while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
639 while (stop > expressionStart && isStrWhiteSpace(data[stop - 1]))
641 message = makeUString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
644 exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
647 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
649 CodeBlock* codeBlock = callFrame->codeBlock();
650 bool isInterrupt = false;
652 // Set up the exception object
653 if (exceptionValue.isObject()) {
654 JSObject* exception = asObject(exceptionValue);
656 if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
657 appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
659 // Using hasExpressionInfo to imply we are interested in rich exception info.
660 if (codeBlock->hasExpressionInfo() && !hasErrorInfo(callFrame, exception)) {
661 ASSERT(codeBlock->hasLineInfo());
663 // FIXME: should only really be adding these properties to VM generated exceptions,
664 // but the inspector currently requires these for all thrown objects.
665 addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
668 ComplType exceptionType = exception->exceptionType();
669 isInterrupt = exceptionType == Interrupted || exceptionType == Terminated;
672 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
673 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
674 bool hasHandler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
675 debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), hasHandler);
678 // Calculate an exception handler vPC, unwinding call frames as necessary.
679 HandlerInfo* handler = 0;
680 while (isInterrupt || !(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
681 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
682 if (Profiler* profiler = *Profiler::enabledProfilerReference())
683 profiler->exceptionUnwind(callFrame);
688 if (Profiler* profiler = *Profiler::enabledProfilerReference())
689 profiler->exceptionUnwind(callFrame);
691 // Shrink the JS stack, in case stack overflow made it huge.
692 Register* highWaterMark = 0;
693 for (CallFrame* callerFrame = callFrame; callerFrame; callerFrame = callerFrame->callerFrame()->removeHostCallFrameFlag()) {
694 CodeBlock* codeBlock = callerFrame->codeBlock();
697 Register* callerHighWaterMark = callerFrame->registers() + codeBlock->m_numCalleeRegisters;
698 highWaterMark = max(highWaterMark, callerHighWaterMark);
700 m_registerFile.shrink(highWaterMark);
702 // Unwind the scope chain within the exception handler's call frame.
703 ScopeChainNode* scopeChain = callFrame->scopeChain();
705 if (!codeBlock->needsFullScopeChain() || codeBlock->codeType() != FunctionCode
706 || callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
707 scopeDelta = depth(codeBlock, scopeChain) - handler->scopeDepth;
708 ASSERT(scopeDelta >= 0);
710 scopeChain = scopeChain->pop();
711 callFrame->setScopeChain(scopeChain);
716 static inline JSValue checkedReturn(JSValue returnValue)
722 static inline JSObject* checkedReturn(JSObject* returnValue)
728 JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
730 ASSERT(!scopeChain->globalData->exception);
732 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
733 return checkedReturn(throwStackOverflowError(callFrame));
735 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
737 JSObject* error = program->compile(callFrame, scopeChain);
739 return checkedReturn(throwError(callFrame, error));
740 CodeBlock* codeBlock = &program->generatedBytecode();
742 Register* oldEnd = m_registerFile.end();
743 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
744 if (!m_registerFile.grow(newEnd))
745 return checkedReturn(throwStackOverflowError(callFrame));
747 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
748 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
749 globalObject->copyGlobalsTo(m_registerFile);
751 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
752 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
753 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), codeBlock->m_numParameters, 0);
754 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
756 Profiler** profiler = Profiler::enabledProfilerReference();
758 (*profiler)->willExecute(callFrame, program->sourceURL(), program->lineNo());
762 SamplingTool::CallRecord callRecord(m_sampler.get());
766 if (callFrame->globalData().canUseJIT())
767 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
770 result = privateExecute(Normal, &m_registerFile, newCallFrame);
776 (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo());
778 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
779 lastGlobalObject->copyGlobalsTo(m_registerFile);
781 m_registerFile.shrink(oldEnd);
783 return checkedReturn(result);
786 JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
788 ASSERT(!callFrame->hadException());
790 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
791 return checkedReturn(throwStackOverflowError(callFrame));
793 Register* oldEnd = m_registerFile.end();
794 int argCount = 1 + args.size(); // implicit "this" parameter
795 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
797 if (!m_registerFile.grow(oldEnd + registerOffset))
798 return checkedReturn(throwStackOverflowError(callFrame));
800 CallFrame* newCallFrame = CallFrame::create(oldEnd);
802 newCallFrame->uncheckedR(0) = thisValue;
803 ArgList::const_iterator end = args.end();
804 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
805 newCallFrame->uncheckedR(++dst) = *it;
807 if (callType == CallTypeJS) {
808 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
810 DynamicGlobalObjectScope globalObjectScope(*callDataScopeChain->globalData, callDataScopeChain->globalObject.get());
812 JSObject* compileError = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
813 if (UNLIKELY(!!compileError)) {
814 m_registerFile.shrink(oldEnd);
815 return checkedReturn(throwError(callFrame, compileError));
818 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
819 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
820 if (UNLIKELY(!newCallFrame)) {
821 m_registerFile.shrink(oldEnd);
822 return checkedReturn(throwStackOverflowError(callFrame));
825 newCallFrame->init(newCodeBlock, 0, callDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
827 Profiler** profiler = Profiler::enabledProfilerReference();
829 (*profiler)->willExecute(callFrame, function);
833 SamplingTool::CallRecord callRecord(m_sampler.get());
837 if (callFrame->globalData().canUseJIT())
838 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScopeChain->globalData);
841 result = privateExecute(Normal, &m_registerFile, newCallFrame);
846 (*profiler)->didExecute(callFrame, function);
848 m_registerFile.shrink(oldEnd);
849 return checkedReturn(result);
852 ASSERT(callType == CallTypeHost);
853 ScopeChainNode* scopeChain = callFrame->scopeChain();
854 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
855 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, function);
857 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
859 Profiler** profiler = Profiler::enabledProfilerReference();
861 (*profiler)->willExecute(callFrame, function);
865 SamplingTool::HostCallRecord callRecord(m_sampler.get());
866 result = JSValue::decode(callData.native.function(newCallFrame));
870 (*profiler)->didExecute(callFrame, function);
872 m_registerFile.shrink(oldEnd);
873 return checkedReturn(result);
876 JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
878 ASSERT(!callFrame->hadException());
880 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
881 return checkedReturn(throwStackOverflowError(callFrame));
883 Register* oldEnd = m_registerFile.end();
884 int argCount = 1 + args.size(); // implicit "this" parameter
885 size_t registerOffset = argCount + RegisterFile::CallFrameHeaderSize;
887 if (!m_registerFile.grow(oldEnd + registerOffset))
888 return checkedReturn(throwStackOverflowError(callFrame));
890 CallFrame* newCallFrame = CallFrame::create(oldEnd);
892 ArgList::const_iterator end = args.end();
893 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
894 newCallFrame->uncheckedR(++dst) = *it;
896 if (constructType == ConstructTypeJS) {
897 ScopeChainNode* constructDataScopeChain = constructData.js.scopeChain;
899 DynamicGlobalObjectScope globalObjectScope(*constructDataScopeChain->globalData, constructDataScopeChain->globalObject.get());
901 JSObject* compileError = constructData.js.functionExecutable->compileForConstruct(callFrame, constructDataScopeChain);
902 if (UNLIKELY(!!compileError)) {
903 m_registerFile.shrink(oldEnd);
904 return checkedReturn(throwError(callFrame, compileError));
907 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
908 newCallFrame = slideRegisterWindowForCall(newCodeBlock, &m_registerFile, newCallFrame, registerOffset, argCount);
909 if (UNLIKELY(!newCallFrame)) {
910 m_registerFile.shrink(oldEnd);
911 return checkedReturn(throwStackOverflowError(callFrame));
914 newCallFrame->init(newCodeBlock, 0, constructDataScopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
916 Profiler** profiler = Profiler::enabledProfilerReference();
918 (*profiler)->willExecute(callFrame, constructor);
922 SamplingTool::CallRecord callRecord(m_sampler.get());
926 if (callFrame->globalData().canUseJIT())
927 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScopeChain->globalData);
930 result = privateExecute(Normal, &m_registerFile, newCallFrame);
935 (*profiler)->didExecute(callFrame, constructor);
937 m_registerFile.shrink(oldEnd);
938 if (callFrame->hadException())
940 ASSERT(result.isObject());
941 return checkedReturn(asObject(result));
944 ASSERT(constructType == ConstructTypeHost);
945 ScopeChainNode* scopeChain = callFrame->scopeChain();
946 newCallFrame = CallFrame::create(newCallFrame->registers() + registerOffset);
947 newCallFrame->init(0, 0, scopeChain, callFrame->addHostCallFrameFlag(), argCount, constructor);
949 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
951 Profiler** profiler = Profiler::enabledProfilerReference();
953 (*profiler)->willExecute(callFrame, constructor);
957 SamplingTool::HostCallRecord callRecord(m_sampler.get());
958 result = JSValue::decode(constructData.native.function(newCallFrame));
962 (*profiler)->didExecute(callFrame, constructor);
964 m_registerFile.shrink(oldEnd);
965 if (callFrame->hadException())
967 ASSERT(result.isObject());
968 return checkedReturn(asObject(result));
971 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain)
973 ASSERT(!scopeChain->globalData->exception);
975 if (m_reentryDepth >= MaxSmallThreadReentryDepth) {
976 if (m_reentryDepth >= callFrame->globalData().maxReentryDepth) {
977 throwStackOverflowError(callFrame);
978 return CallFrameClosure();
982 Register* oldEnd = m_registerFile.end();
983 int argc = 1 + argCount; // implicit "this" parameter
985 if (!m_registerFile.grow(oldEnd + argc)) {
986 throwStackOverflowError(callFrame);
987 return CallFrameClosure();
990 CallFrame* newCallFrame = CallFrame::create(oldEnd);
991 // We initialise |this| unnecessarily here for the sake of code clarity
993 for (int i = 0; i < argc; ++i)
994 newCallFrame->uncheckedR(dst++) = jsUndefined();
996 JSObject* error = FunctionExecutable->compileForCall(callFrame, scopeChain);
998 throwError(callFrame, error);
999 m_registerFile.shrink(oldEnd);
1000 return CallFrameClosure();
1002 CodeBlock* codeBlock = &FunctionExecutable->generatedBytecodeForCall();
1004 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
1005 if (UNLIKELY(!newCallFrame)) {
1006 throwStackOverflowError(callFrame);
1007 m_registerFile.shrink(oldEnd);
1008 return CallFrameClosure();
1010 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), argc, function);
1011 CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
1015 JSValue Interpreter::execute(CallFrameClosure& closure)
1017 closure.resetCallFrame();
1018 Profiler** profiler = Profiler::enabledProfilerReference();
1020 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
1024 SamplingTool::CallRecord callRecord(m_sampler.get());
1028 #if ENABLE(INTERPRETER)
1029 if (closure.newCallFrame->globalData().canUseJIT())
1031 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData);
1032 #if ENABLE(INTERPRETER)
1036 #if ENABLE(INTERPRETER)
1037 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);
1043 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
1044 return checkedReturn(result);
1047 void Interpreter::endRepeatCall(CallFrameClosure& closure)
1049 m_registerFile.shrink(closure.oldEnd);
1052 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain)
1054 JSObject* compileError = eval->compile(callFrame, scopeChain);
1055 if (UNLIKELY(!!compileError))
1056 return checkedReturn(throwError(callFrame, compileError));
1057 return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->generatedBytecode().m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain);
1060 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain)
1062 ASSERT(!scopeChain->globalData->exception);
1064 DynamicGlobalObjectScope globalObjectScope(*scopeChain->globalData, scopeChain->globalObject.get());
1066 if (m_reentryDepth >= MaxSmallThreadReentryDepth && m_reentryDepth >= callFrame->globalData().maxReentryDepth)
1067 return checkedReturn(throwStackOverflowError(callFrame));
1069 JSObject* compileError = eval->compile(callFrame, scopeChain);
1070 if (UNLIKELY(!!compileError))
1071 return checkedReturn(throwError(callFrame, compileError));
1072 EvalCodeBlock* codeBlock = &eval->generatedBytecode();
1074 JSObject* variableObject;
1075 for (ScopeChainNode* node = scopeChain; ; node = node->next.get()) {
1077 if (node->object->isVariableObject()) {
1078 variableObject = static_cast<JSVariableObject*>(node->object.get());
1083 unsigned numVariables = codeBlock->numVariables();
1084 int numFunctions = codeBlock->numberOfFunctionDecls();
1085 bool pushedScope = false;
1086 if (numVariables || numFunctions) {
1087 if (codeBlock->isStrictMode()) {
1088 variableObject = new (callFrame) StrictEvalActivation(callFrame);
1089 scopeChain = scopeChain->push(variableObject);
1092 // Scope for BatchedTransitionOptimizer
1093 BatchedTransitionOptimizer optimizer(callFrame->globalData(), variableObject);
1095 for (unsigned i = 0; i < numVariables; ++i) {
1096 const Identifier& ident = codeBlock->variable(i);
1097 if (!variableObject->hasProperty(callFrame, ident)) {
1098 PutPropertySlot slot;
1099 variableObject->put(callFrame, ident, jsUndefined(), slot);
1103 for (int i = 0; i < numFunctions; ++i) {
1104 FunctionExecutable* function = codeBlock->functionDecl(i);
1105 PutPropertySlot slot;
1106 variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot);
1110 Register* oldEnd = m_registerFile.end();
1111 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
1112 if (!m_registerFile.grow(newEnd)) {
1115 return checkedReturn(throwStackOverflowError(callFrame));
1118 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
1120 ASSERT(codeBlock->m_numParameters == 1); // 1 parameter for 'this'.
1121 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), codeBlock->m_numParameters, 0);
1122 newCallFrame->uncheckedR(newCallFrame->hostThisRegister()) = JSValue(thisObj);
1124 Profiler** profiler = Profiler::enabledProfilerReference();
1126 (*profiler)->willExecute(callFrame, eval->sourceURL(), eval->lineNo());
1130 SamplingTool::CallRecord callRecord(m_sampler.get());
1135 #if ENABLE(INTERPRETER)
1136 if (callFrame->globalData().canUseJIT())
1138 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData);
1139 #if ENABLE(INTERPRETER)
1143 #if ENABLE(INTERPRETER)
1144 result = privateExecute(Normal, &m_registerFile, newCallFrame);
1150 (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo());
1152 m_registerFile.shrink(oldEnd);
1155 return checkedReturn(result);
1158 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
1160 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
1164 switch (debugHookID) {
1165 case DidEnterCallFrame:
1166 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1168 case WillLeaveCallFrame:
1169 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1171 case WillExecuteStatement:
1172 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1174 case WillExecuteProgram:
1175 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine);
1177 case DidExecuteProgram:
1178 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1180 case DidReachBreakpoint:
1181 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine);
1186 #if ENABLE(INTERPRETER)
1187 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
1189 int dst = vPC[1].u.operand;
1190 CodeBlock* codeBlock = callFrame->codeBlock();
1191 Identifier& property = codeBlock->identifier(vPC[2].u.operand);
1192 JSValue value = callFrame->r(vPC[3].u.operand).jsValue();
1193 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
1194 callFrame->uncheckedR(dst) = JSValue(scope);
1196 return callFrame->scopeChain()->push(scope);
1199 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
1201 // Recursive invocation may already have specialized this instruction.
1202 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1205 if (!baseValue.isCell())
1208 // Uncacheable: give up.
1209 if (!slot.isCacheable()) {
1210 vPC[0] = getOpcode(op_put_by_id_generic);
1214 JSCell* baseCell = baseValue.asCell();
1215 Structure* structure = baseCell->structure();
1217 if (structure->isUncacheableDictionary()) {
1218 vPC[0] = getOpcode(op_put_by_id_generic);
1222 // Cache miss: record Structure to compare against next time.
1223 Structure* lastStructure = vPC[4].u.structure.get();
1224 if (structure != lastStructure) {
1225 // First miss: record Structure to compare against next time.
1226 if (!lastStructure) {
1227 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1231 // Second miss: give up.
1232 vPC[0] = getOpcode(op_put_by_id_generic);
1236 // Cache hit: Specialize instruction and ref Structures.
1238 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1239 if (baseCell != slot.base()) {
1240 vPC[0] = getOpcode(op_put_by_id_generic);
1244 // Structure transition, cache transition info
1245 if (slot.type() == PutPropertySlot::NewProperty) {
1246 if (structure->isDictionary()) {
1247 vPC[0] = getOpcode(op_put_by_id_generic);
1251 // put_by_id_transition checks the prototype chain for setters.
1252 normalizePrototypeChain(callFrame, baseCell);
1253 JSCell* owner = codeBlock->ownerExecutable();
1254 JSGlobalData& globalData = callFrame->globalData();
1255 vPC[0] = getOpcode(op_put_by_id_transition);
1256 vPC[4].u.structure.set(globalData, owner, structure->previousID());
1257 vPC[5].u.structure.set(globalData, owner, structure);
1258 vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
1259 ASSERT(vPC[6].u.structureChain);
1260 vPC[7] = slot.cachedOffset();
1264 vPC[0] = getOpcode(op_put_by_id_replace);
1265 vPC[5] = slot.cachedOffset();
1268 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)
1270 vPC[0] = getOpcode(op_put_by_id);
1274 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
1276 // Recursive invocation may already have specialized this instruction.
1277 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1280 // FIXME: Cache property access for immediates.
1281 if (!baseValue.isCell()) {
1282 vPC[0] = getOpcode(op_get_by_id_generic);
1286 JSGlobalData* globalData = &callFrame->globalData();
1287 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1288 vPC[0] = getOpcode(op_get_array_length);
1292 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1293 vPC[0] = getOpcode(op_get_string_length);
1297 // Uncacheable: give up.
1298 if (!slot.isCacheable()) {
1299 vPC[0] = getOpcode(op_get_by_id_generic);
1303 Structure* structure = baseValue.asCell()->structure();
1305 if (structure->isUncacheableDictionary()) {
1306 vPC[0] = getOpcode(op_get_by_id_generic);
1311 Structure* lastStructure = vPC[4].u.structure.get();
1312 if (structure != lastStructure) {
1313 // First miss: record Structure to compare against next time.
1314 if (!lastStructure) {
1315 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1319 // Second miss: give up.
1320 vPC[0] = getOpcode(op_get_by_id_generic);
1324 // Cache hit: Specialize instruction and ref Structures.
1326 if (slot.slotBase() == baseValue) {
1327 switch (slot.cachedPropertyType()) {
1328 case PropertySlot::Getter:
1329 vPC[0] = getOpcode(op_get_by_id_getter_self);
1330 vPC[5] = slot.cachedOffset();
1332 case PropertySlot::Custom:
1333 vPC[0] = getOpcode(op_get_by_id_custom_self);
1334 vPC[5] = slot.customGetter();
1337 vPC[0] = getOpcode(op_get_by_id_self);
1338 vPC[5] = slot.cachedOffset();
1344 if (structure->isDictionary()) {
1345 vPC[0] = getOpcode(op_get_by_id_generic);
1349 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1350 ASSERT(slot.slotBase().isObject());
1352 JSObject* baseObject = asObject(slot.slotBase());
1353 size_t offset = slot.cachedOffset();
1355 // Since we're accessing a prototype in a loop, it's a good bet that it
1356 // should not be treated as a dictionary.
1357 if (baseObject->structure()->isDictionary()) {
1358 baseObject->flattenDictionaryObject(callFrame->globalData());
1359 offset = baseObject->structure()->get(callFrame->globalData(), propertyName);
1362 ASSERT(!baseObject->structure()->isUncacheableDictionary());
1364 switch (slot.cachedPropertyType()) {
1365 case PropertySlot::Getter:
1366 vPC[0] = getOpcode(op_get_by_id_getter_proto);
1369 case PropertySlot::Custom:
1370 vPC[0] = getOpcode(op_get_by_id_custom_proto);
1371 vPC[6] = slot.customGetter();
1374 vPC[0] = getOpcode(op_get_by_id_proto);
1378 vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());
1382 size_t offset = slot.cachedOffset();
1383 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
1385 vPC[0] = getOpcode(op_get_by_id_generic);
1390 switch (slot.cachedPropertyType()) {
1391 case PropertySlot::Getter:
1392 vPC[0] = getOpcode(op_get_by_id_getter_chain);
1395 case PropertySlot::Custom:
1396 vPC[0] = getOpcode(op_get_by_id_custom_chain);
1397 vPC[7] = slot.customGetter();
1400 vPC[0] = getOpcode(op_get_by_id_chain);
1404 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
1405 vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure->prototypeChain(callFrame));
1409 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)
1411 vPC[0] = getOpcode(op_get_by_id);
1415 #endif // ENABLE(INTERPRETER)
1417 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)
1419 // One-time initialization of our address tables. We have to put this code
1420 // here because our labels are only in scope inside this function.
1421 if (UNLIKELY(flag == InitializeAndReturn)) {
1422 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1423 #define LIST_OPCODE_LABEL(id, length) &&id,
1424 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };
1425 for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)
1426 m_opcodeTable[i] = labels[i];
1427 #undef LIST_OPCODE_LABEL
1428 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
1433 #if ENABLE(INTERPRETER)
1434 // Mixing Interpreter + JIT is not supported.
1435 if (callFrame->globalData().canUseJIT())
1437 ASSERT_NOT_REACHED();
1440 #if !ENABLE(INTERPRETER)
1441 UNUSED_PARAM(registerFile);
1442 UNUSED_PARAM(callFrame);
1446 JSGlobalData* globalData = &callFrame->globalData();
1447 JSValue exceptionValue;
1448 HandlerInfo* handler = 0;
1450 CodeBlock* codeBlock = callFrame->codeBlock();
1451 Instruction* vPC = codeBlock->instructions().begin();
1452 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1453 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
1454 JSValue functionReturnValue;
1456 #define CHECK_FOR_EXCEPTION() \
1458 if (UNLIKELY(globalData->exception != JSValue())) { \
1459 exceptionValue = globalData->exception; \
1464 #if ENABLE(OPCODE_STATS)
1465 OpcodeStats::resetLastInstruction();
1468 #define CHECK_FOR_TIMEOUT() \
1469 if (!--tickCount) { \
1470 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
1471 exceptionValue = jsNull(); \
1474 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1477 #if ENABLE(OPCODE_SAMPLING)
1478 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1480 #define SAMPLE(codeBlock, vPC)
1483 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1484 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
1485 #if ENABLE(OPCODE_STATS)
1486 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1488 #define DEFINE_OPCODE(opcode) opcode:
1492 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
1493 #if ENABLE(OPCODE_STATS)
1494 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1496 #define DEFINE_OPCODE(opcode) case opcode:
1498 while (1) { // iterator loop begins
1499 interpreterLoopStart:;
1500 switch (vPC->u.opcode)
1503 DEFINE_OPCODE(op_new_object) {
1504 /* new_object dst(r)
1506 Constructs a new empty Object instance using the original
1507 constructor, and puts the result in register dst.
1509 int dst = vPC[1].u.operand;
1510 callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));
1512 vPC += OPCODE_LENGTH(op_new_object);
1515 DEFINE_OPCODE(op_new_array) {
1516 /* new_array dst(r) firstArg(r) argCount(n)
1518 Constructs a new Array instance using the original
1519 constructor, and puts the result in register dst.
1520 The array will contain argCount elements with values
1521 taken from registers starting at register firstArg.
1523 int dst = vPC[1].u.operand;
1524 int firstArg = vPC[2].u.operand;
1525 int argCount = vPC[3].u.operand;
1526 ArgList args(callFrame->registers() + firstArg, argCount);
1527 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, args));
1529 vPC += OPCODE_LENGTH(op_new_array);
1532 DEFINE_OPCODE(op_new_regexp) {
1533 /* new_regexp dst(r) regExp(re)
1535 Constructs a new RegExp instance using the original
1536 constructor from regexp regExp, and puts the result in
1539 int dst = vPC[1].u.operand;
1540 RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);
1541 if (!regExp->isValid()) {
1542 exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
1545 callFrame->uncheckedR(dst) = JSValue(new (globalData) RegExpObject(callFrame->lexicalGlobalObject(), callFrame->scopeChain()->globalObject->regExpStructure(), regExp));
1547 vPC += OPCODE_LENGTH(op_new_regexp);
1550 DEFINE_OPCODE(op_mov) {
1551 /* mov dst(r) src(r)
1553 Copies register src to register dst.
1555 int dst = vPC[1].u.operand;
1556 int src = vPC[2].u.operand;
1558 callFrame->uncheckedR(dst) = callFrame->r(src);
1560 vPC += OPCODE_LENGTH(op_mov);
1563 DEFINE_OPCODE(op_eq) {
1564 /* eq dst(r) src1(r) src2(r)
1566 Checks whether register src1 and register src2 are equal,
1567 as with the ECMAScript '==' operator, and puts the result
1568 as a boolean in register dst.
1570 int dst = vPC[1].u.operand;
1571 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1572 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1573 if (src1.isInt32() && src2.isInt32())
1574 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
1576 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
1577 CHECK_FOR_EXCEPTION();
1578 callFrame->uncheckedR(dst) = result;
1581 vPC += OPCODE_LENGTH(op_eq);
1584 DEFINE_OPCODE(op_eq_null) {
1585 /* eq_null dst(r) src(r)
1587 Checks whether register src is null, as with the ECMAScript '!='
1588 operator, and puts the result as a boolean in register dst.
1590 int dst = vPC[1].u.operand;
1591 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1593 if (src.isUndefinedOrNull()) {
1594 callFrame->uncheckedR(dst) = jsBoolean(true);
1595 vPC += OPCODE_LENGTH(op_eq_null);
1599 callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1600 vPC += OPCODE_LENGTH(op_eq_null);
1603 DEFINE_OPCODE(op_neq) {
1604 /* neq dst(r) src1(r) src2(r)
1606 Checks whether register src1 and register src2 are not
1607 equal, as with the ECMAScript '!=' operator, and puts the
1608 result as a boolean in register dst.
1610 int dst = vPC[1].u.operand;
1611 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1612 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1613 if (src1.isInt32() && src2.isInt32())
1614 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
1616 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
1617 CHECK_FOR_EXCEPTION();
1618 callFrame->uncheckedR(dst) = result;
1621 vPC += OPCODE_LENGTH(op_neq);
1624 DEFINE_OPCODE(op_neq_null) {
1625 /* neq_null dst(r) src(r)
1627 Checks whether register src is not null, as with the ECMAScript '!='
1628 operator, and puts the result as a boolean in register dst.
1630 int dst = vPC[1].u.operand;
1631 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1633 if (src.isUndefinedOrNull()) {
1634 callFrame->uncheckedR(dst) = jsBoolean(false);
1635 vPC += OPCODE_LENGTH(op_neq_null);
1639 callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1640 vPC += OPCODE_LENGTH(op_neq_null);
1643 DEFINE_OPCODE(op_stricteq) {
1644 /* stricteq dst(r) src1(r) src2(r)
1646 Checks whether register src1 and register src2 are strictly
1647 equal, as with the ECMAScript '===' operator, and puts the
1648 result as a boolean in register dst.
1650 int dst = vPC[1].u.operand;
1651 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1652 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1653 bool result = JSValue::strictEqual(callFrame, src1, src2);
1654 CHECK_FOR_EXCEPTION();
1655 callFrame->uncheckedR(dst) = jsBoolean(result);
1657 vPC += OPCODE_LENGTH(op_stricteq);
1660 DEFINE_OPCODE(op_nstricteq) {
1661 /* nstricteq dst(r) src1(r) src2(r)
1663 Checks whether register src1 and register src2 are not
1664 strictly equal, as with the ECMAScript '!==' operator, and
1665 puts the result as a boolean in register dst.
1667 int dst = vPC[1].u.operand;
1668 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1669 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1670 bool result = !JSValue::strictEqual(callFrame, src1, src2);
1671 CHECK_FOR_EXCEPTION();
1672 callFrame->uncheckedR(dst) = jsBoolean(result);
1674 vPC += OPCODE_LENGTH(op_nstricteq);
1677 DEFINE_OPCODE(op_less) {
1678 /* less dst(r) src1(r) src2(r)
1680 Checks whether register src1 is less than register src2, as
1681 with the ECMAScript '<' operator, and puts the result as
1682 a boolean in register dst.
1684 int dst = vPC[1].u.operand;
1685 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1686 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1687 JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
1688 CHECK_FOR_EXCEPTION();
1689 callFrame->uncheckedR(dst) = result;
1691 vPC += OPCODE_LENGTH(op_less);
1694 DEFINE_OPCODE(op_lesseq) {
1695 /* lesseq dst(r) src1(r) src2(r)
1697 Checks whether register src1 is less than or equal to
1698 register src2, as with the ECMAScript '<=' operator, and
1699 puts the result as a boolean in register dst.
1701 int dst = vPC[1].u.operand;
1702 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1703 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1704 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
1705 CHECK_FOR_EXCEPTION();
1706 callFrame->uncheckedR(dst) = result;
1708 vPC += OPCODE_LENGTH(op_lesseq);
1711 DEFINE_OPCODE(op_pre_inc) {
1712 /* pre_inc srcDst(r)
1714 Converts register srcDst to number, adds one, and puts the result
1715 back in register srcDst.
1717 int srcDst = vPC[1].u.operand;
1718 JSValue v = callFrame->r(srcDst).jsValue();
1719 if (v.isInt32() && v.asInt32() < INT_MAX)
1720 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
1722 JSValue result = jsNumber(v.toNumber(callFrame) + 1);
1723 CHECK_FOR_EXCEPTION();
1724 callFrame->uncheckedR(srcDst) = result;
1727 vPC += OPCODE_LENGTH(op_pre_inc);
1730 DEFINE_OPCODE(op_pre_dec) {
1731 /* pre_dec srcDst(r)
1733 Converts register srcDst to number, subtracts one, and puts the result
1734 back in register srcDst.
1736 int srcDst = vPC[1].u.operand;
1737 JSValue v = callFrame->r(srcDst).jsValue();
1738 if (v.isInt32() && v.asInt32() > INT_MIN)
1739 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
1741 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
1742 CHECK_FOR_EXCEPTION();
1743 callFrame->uncheckedR(srcDst) = result;
1746 vPC += OPCODE_LENGTH(op_pre_dec);
1749 DEFINE_OPCODE(op_post_inc) {
1750 /* post_inc dst(r) srcDst(r)
1752 Converts register srcDst to number. The number itself is
1753 written to register dst, and the number plus one is written
1754 back to register srcDst.
1756 int dst = vPC[1].u.operand;
1757 int srcDst = vPC[2].u.operand;
1758 JSValue v = callFrame->r(srcDst).jsValue();
1759 if (v.isInt32() && v.asInt32() < INT_MAX) {
1760 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);
1761 callFrame->uncheckedR(dst) = v;
1763 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1764 CHECK_FOR_EXCEPTION();
1765 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() + 1);
1766 callFrame->uncheckedR(dst) = number;
1769 vPC += OPCODE_LENGTH(op_post_inc);
1772 DEFINE_OPCODE(op_post_dec) {
1773 /* post_dec dst(r) srcDst(r)
1775 Converts register srcDst to number. The number itself is
1776 written to register dst, and the number minus one is written
1777 back to register srcDst.
1779 int dst = vPC[1].u.operand;
1780 int srcDst = vPC[2].u.operand;
1781 JSValue v = callFrame->r(srcDst).jsValue();
1782 if (v.isInt32() && v.asInt32() > INT_MIN) {
1783 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);
1784 callFrame->uncheckedR(dst) = v;
1786 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1787 CHECK_FOR_EXCEPTION();
1788 callFrame->uncheckedR(srcDst) = jsNumber(number.uncheckedGetNumber() - 1);
1789 callFrame->uncheckedR(dst) = number;
1792 vPC += OPCODE_LENGTH(op_post_dec);
1795 DEFINE_OPCODE(op_to_jsnumber) {
1796 /* to_jsnumber dst(r) src(r)
1798 Converts register src to number, and puts the result
1801 int dst = vPC[1].u.operand;
1802 int src = vPC[2].u.operand;
1804 JSValue srcVal = callFrame->r(src).jsValue();
1806 if (LIKELY(srcVal.isNumber()))
1807 callFrame->uncheckedR(dst) = callFrame->r(src);
1809 JSValue result = srcVal.toJSNumber(callFrame);
1810 CHECK_FOR_EXCEPTION();
1811 callFrame->uncheckedR(dst) = result;
1814 vPC += OPCODE_LENGTH(op_to_jsnumber);
1817 DEFINE_OPCODE(op_negate) {
1818 /* negate dst(r) src(r)
1820 Converts register src to number, negates it, and puts the
1821 result in register dst.
1823 int dst = vPC[1].u.operand;
1824 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
1825 if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow
1826 callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());
1828 JSValue result = jsNumber(-src.toNumber(callFrame));
1829 CHECK_FOR_EXCEPTION();
1830 callFrame->uncheckedR(dst) = result;
1833 vPC += OPCODE_LENGTH(op_negate);
1836 DEFINE_OPCODE(op_add) {
1837 /* add dst(r) src1(r) src2(r)
1839 Adds register src1 and register src2, and puts the result
1840 in register dst. (JS add may be string concatenation or
1841 numeric add, depending on the types of the operands.)
1843 int dst = vPC[1].u.operand;
1844 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1845 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1846 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1847 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());
1849 JSValue result = jsAdd(callFrame, src1, src2);
1850 CHECK_FOR_EXCEPTION();
1851 callFrame->uncheckedR(dst) = result;
1853 vPC += OPCODE_LENGTH(op_add);
1856 DEFINE_OPCODE(op_mul) {
1857 /* mul dst(r) src1(r) src2(r)
1859 Multiplies register src1 and register src2 (converted to
1860 numbers), and puts the product in register dst.
1862 int dst = vPC[1].u.operand;
1863 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1864 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1865 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
1866 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());
1868 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));
1869 CHECK_FOR_EXCEPTION();
1870 callFrame->uncheckedR(dst) = result;
1873 vPC += OPCODE_LENGTH(op_mul);
1876 DEFINE_OPCODE(op_div) {
1877 /* div dst(r) dividend(r) divisor(r)
1879 Divides register dividend (converted to number) by the
1880 register divisor (converted to number), and puts the
1881 quotient in register dst.
1883 int dst = vPC[1].u.operand;
1884 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1885 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1887 JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
1888 CHECK_FOR_EXCEPTION();
1889 callFrame->uncheckedR(dst) = result;
1891 vPC += OPCODE_LENGTH(op_div);
1894 DEFINE_OPCODE(op_mod) {
1895 /* mod dst(r) dividend(r) divisor(r)
1897 Divides register dividend (converted to number) by
1898 register divisor (converted to number), and puts the
1899 remainder in register dst.
1901 int dst = vPC[1].u.operand;
1902 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();
1903 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();
1905 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
1906 JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());
1908 callFrame->uncheckedR(dst) = result;
1909 vPC += OPCODE_LENGTH(op_mod);
1913 // Conversion to double must happen outside the call to fmod since the
1914 // order of argument evaluation is not guaranteed.
1915 double d1 = dividend.toNumber(callFrame);
1916 double d2 = divisor.toNumber(callFrame);
1917 JSValue result = jsNumber(fmod(d1, d2));
1918 CHECK_FOR_EXCEPTION();
1919 callFrame->uncheckedR(dst) = result;
1920 vPC += OPCODE_LENGTH(op_mod);
1923 DEFINE_OPCODE(op_sub) {
1924 /* sub dst(r) src1(r) src2(r)
1926 Subtracts register src2 (converted to number) from register
1927 src1 (converted to number), and puts the difference in
1930 int dst = vPC[1].u.operand;
1931 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
1932 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
1933 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow
1934 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());
1936 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
1937 CHECK_FOR_EXCEPTION();
1938 callFrame->uncheckedR(dst) = result;
1940 vPC += OPCODE_LENGTH(op_sub);
1943 DEFINE_OPCODE(op_lshift) {
1944 /* lshift dst(r) val(r) shift(r)
1946 Performs left shift of register val (converted to int32) by
1947 register shift (converted to uint32), and puts the result
1950 int dst = vPC[1].u.operand;
1951 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1952 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1954 if (val.isInt32() && shift.isInt32())
1955 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));
1957 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
1958 CHECK_FOR_EXCEPTION();
1959 callFrame->uncheckedR(dst) = result;
1962 vPC += OPCODE_LENGTH(op_lshift);
1965 DEFINE_OPCODE(op_rshift) {
1966 /* rshift dst(r) val(r) shift(r)
1968 Performs arithmetic right shift of register val (converted
1969 to int32) by register shift (converted to
1970 uint32), and puts the result in register dst.
1972 int dst = vPC[1].u.operand;
1973 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1974 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1976 if (val.isInt32() && shift.isInt32())
1977 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
1979 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1980 CHECK_FOR_EXCEPTION();
1981 callFrame->uncheckedR(dst) = result;
1984 vPC += OPCODE_LENGTH(op_rshift);
1987 DEFINE_OPCODE(op_urshift) {
1988 /* rshift dst(r) val(r) shift(r)
1990 Performs logical right shift of register val (converted
1991 to uint32) by register shift (converted to
1992 uint32), and puts the result in register dst.
1994 int dst = vPC[1].u.operand;
1995 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();
1996 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();
1997 if (val.isUInt32() && shift.isInt32())
1998 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));
2000 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2001 CHECK_FOR_EXCEPTION();
2002 callFrame->uncheckedR(dst) = result;
2005 vPC += OPCODE_LENGTH(op_urshift);
2008 DEFINE_OPCODE(op_bitand) {
2009 /* bitand dst(r) src1(r) src2(r)
2011 Computes bitwise AND of register src1 (converted to int32)
2012 and register src2 (converted to int32), and puts the result
2015 int dst = vPC[1].u.operand;
2016 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2017 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2018 if (src1.isInt32() && src2.isInt32())
2019 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());
2021 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
2022 CHECK_FOR_EXCEPTION();
2023 callFrame->uncheckedR(dst) = result;
2026 vPC += OPCODE_LENGTH(op_bitand);
2029 DEFINE_OPCODE(op_bitxor) {
2030 /* bitxor dst(r) src1(r) src2(r)
2032 Computes bitwise XOR of register src1 (converted to int32)
2033 and register src2 (converted to int32), and puts the result
2036 int dst = vPC[1].u.operand;
2037 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2038 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2039 if (src1.isInt32() && src2.isInt32())
2040 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());
2042 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
2043 CHECK_FOR_EXCEPTION();
2044 callFrame->uncheckedR(dst) = result;
2047 vPC += OPCODE_LENGTH(op_bitxor);
2050 DEFINE_OPCODE(op_bitor) {
2051 /* bitor dst(r) src1(r) src2(r)
2053 Computes bitwise OR of register src1 (converted to int32)
2054 and register src2 (converted to int32), and puts the
2055 result in register dst.
2057 int dst = vPC[1].u.operand;
2058 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();
2059 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();
2060 if (src1.isInt32() && src2.isInt32())
2061 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());
2063 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
2064 CHECK_FOR_EXCEPTION();
2065 callFrame->uncheckedR(dst) = result;
2068 vPC += OPCODE_LENGTH(op_bitor);
2071 DEFINE_OPCODE(op_bitnot) {
2072 /* bitnot dst(r) src(r)
2074 Computes bitwise NOT of register src1 (converted to int32),
2075 and puts the result in register dst.
2077 int dst = vPC[1].u.operand;
2078 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();
2080 callFrame->uncheckedR(dst) = jsNumber(~src.asInt32());
2082 JSValue result = jsNumber(~src.toInt32(callFrame));
2083 CHECK_FOR_EXCEPTION();
2084 callFrame->uncheckedR(dst) = result;
2086 vPC += OPCODE_LENGTH(op_bitnot);
2089 DEFINE_OPCODE(op_not) {
2090 /* not dst(r) src(r)
2092 Computes logical NOT of register src (converted to
2093 boolean), and puts the result in register dst.
2095 int dst = vPC[1].u.operand;
2096 int src = vPC[2].u.operand;
2097 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
2098 CHECK_FOR_EXCEPTION();
2099 callFrame->uncheckedR(dst) = result;
2101 vPC += OPCODE_LENGTH(op_not);
2104 DEFINE_OPCODE(op_check_has_instance) {
2105 /* check_has_instance constructor(r)
2107 Check 'constructor' is an object with the internal property
2108 [HasInstance] (i.e. is a function ... *shakes head sadly at
2109 JSC API*). Raises an exception if register constructor is not
2110 an valid parameter for instanceof.
2112 int base = vPC[1].u.operand;
2113 JSValue baseVal = callFrame->r(base).jsValue();
2115 if (isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue))
2118 vPC += OPCODE_LENGTH(op_check_has_instance);
2121 DEFINE_OPCODE(op_instanceof) {
2122 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2124 Tests whether register value is an instance of register
2125 constructor, and puts the boolean result in register
2126 dst. Register constructorProto must contain the "prototype"
2127 property (not the actual prototype) of the object in
2128 register constructor. This lookup is separated so that
2129 polymorphic inline caching can apply.
2131 Raises an exception if register constructor is not an
2134 int dst = vPC[1].u.operand;
2135 int value = vPC[2].u.operand;
2136 int base = vPC[3].u.operand;
2137 int baseProto = vPC[4].u.operand;
2139 JSValue baseVal = callFrame->r(base).jsValue();
2141 ASSERT(!isInvalidParamForInstanceOf(callFrame, baseVal, exceptionValue));
2143 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
2144 CHECK_FOR_EXCEPTION();
2145 callFrame->uncheckedR(dst) = jsBoolean(result);
2147 vPC += OPCODE_LENGTH(op_instanceof);
2150 DEFINE_OPCODE(op_typeof) {
2151 /* typeof dst(r) src(r)
2153 Determines the type string for src according to ECMAScript
2154 rules, and puts the result in register dst.
2156 int dst = vPC[1].u.operand;
2157 int src = vPC[2].u.operand;
2158 callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
2160 vPC += OPCODE_LENGTH(op_typeof);
2163 DEFINE_OPCODE(op_is_undefined) {
2164 /* is_undefined dst(r) src(r)
2166 Determines whether the type string for src according to
2167 the ECMAScript rules is "undefined", and puts the result
2170 int dst = vPC[1].u.operand;
2171 int src = vPC[2].u.operand;
2172 JSValue v = callFrame->r(src).jsValue();
2173 callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
2175 vPC += OPCODE_LENGTH(op_is_undefined);
2178 DEFINE_OPCODE(op_is_boolean) {
2179 /* is_boolean dst(r) src(r)
2181 Determines whether the type string for src according to
2182 the ECMAScript rules is "boolean", and puts the result
2185 int dst = vPC[1].u.operand;
2186 int src = vPC[2].u.operand;
2187 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
2189 vPC += OPCODE_LENGTH(op_is_boolean);
2192 DEFINE_OPCODE(op_is_number) {
2193 /* is_number dst(r) src(r)
2195 Determines whether the type string for src according to
2196 the ECMAScript rules is "number", and puts the result
2199 int dst = vPC[1].u.operand;
2200 int src = vPC[2].u.operand;
2201 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
2203 vPC += OPCODE_LENGTH(op_is_number);
2206 DEFINE_OPCODE(op_is_string) {
2207 /* is_string dst(r) src(r)
2209 Determines whether the type string for src according to
2210 the ECMAScript rules is "string", and puts the result
2213 int dst = vPC[1].u.operand;
2214 int src = vPC[2].u.operand;
2215 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
2217 vPC += OPCODE_LENGTH(op_is_string);
2220 DEFINE_OPCODE(op_is_object) {
2221 /* is_object dst(r) src(r)
2223 Determines whether the type string for src according to
2224 the ECMAScript rules is "object", and puts the result
2227 int dst = vPC[1].u.operand;
2228 int src = vPC[2].u.operand;
2229 callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
2231 vPC += OPCODE_LENGTH(op_is_object);
2234 DEFINE_OPCODE(op_is_function) {
2235 /* is_function dst(r) src(r)
2237 Determines whether the type string for src according to
2238 the ECMAScript rules is "function", and puts the result
2241 int dst = vPC[1].u.operand;
2242 int src = vPC[2].u.operand;
2243 callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
2245 vPC += OPCODE_LENGTH(op_is_function);
2248 DEFINE_OPCODE(op_in) {
2249 /* in dst(r) property(r) base(r)
2251 Tests whether register base has a property named register
2252 property, and puts the boolean result in register dst.
2254 Raises an exception if register constructor is not an
2257 int dst = vPC[1].u.operand;
2258 int property = vPC[2].u.operand;
2259 int base = vPC[3].u.operand;
2261 JSValue baseVal = callFrame->r(base).jsValue();
2262 if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))
2265 JSObject* baseObj = asObject(baseVal);
2267 JSValue propName = callFrame->r(property).jsValue();
2270 if (propName.getUInt32(i))
2271 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
2273 Identifier property(callFrame, propName.toString(callFrame));
2274 CHECK_FOR_EXCEPTION();
2275 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
2278 vPC += OPCODE_LENGTH(op_in);
2281 DEFINE_OPCODE(op_resolve) {
2282 /* resolve dst(r) property(id)
2284 Looks up the property named by identifier property in the
2285 scope chain, and writes the resulting value to register
2286 dst. If the property is not found, raises an exception.
2288 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
2291 vPC += OPCODE_LENGTH(op_resolve);
2294 DEFINE_OPCODE(op_resolve_skip) {
2295 /* resolve_skip dst(r) property(id) skip(n)
2297 Looks up the property named by identifier property in the
2298 scope chain skipping the top 'skip' levels, and writes the resulting
2299 value to register dst. If the property is not found, raises an exception.
2301 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
2304 vPC += OPCODE_LENGTH(op_resolve_skip);
2308 DEFINE_OPCODE(op_resolve_global) {
2309 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2311 Performs a dynamic property lookup for the given property, on the provided
2312 global object. If structure matches the Structure of the global then perform
2313 a fast lookup using the case offset, otherwise fall back to a full resolve and
2314 cache the new structure and offset
2316 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
2319 vPC += OPCODE_LENGTH(op_resolve_global);
2323 DEFINE_OPCODE(op_resolve_global_dynamic) {
2324 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2326 Performs a dynamic property lookup for the given property, on the provided
2327 global object. If structure matches the Structure of the global then perform
2328 a fast lookup using the case offset, otherwise fall back to a full resolve and
2329 cache the new structure and offset.
2331 This walks through n levels of the scope chain to verify that none of those levels
2332 in the scope chain include dynamically added properties.
2334 if (UNLIKELY(!resolveGlobalDynamic(callFrame, vPC, exceptionValue)))
2337 vPC += OPCODE_LENGTH(op_resolve_global_dynamic);
2341 DEFINE_OPCODE(op_get_global_var) {
2342 /* get_global_var dst(r) globalObject(c) index(n)
2344 Gets the global var at global slot index and places it in register dst.
2346 int dst = vPC[1].u.operand;
2347 JSGlobalObject* scope = codeBlock->globalObject();
2348 ASSERT(scope->isGlobalObject());
2349 int index = vPC[2].u.operand;
2351 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2352 vPC += OPCODE_LENGTH(op_get_global_var);
2355 DEFINE_OPCODE(op_put_global_var) {
2356 /* put_global_var globalObject(c) index(n) value(r)
2358 Puts value into global slot index.
2360 JSGlobalObject* scope = codeBlock->globalObject();
2361 ASSERT(scope->isGlobalObject());
2362 int index = vPC[1].u.operand;
2363 int value = vPC[2].u.operand;
2365 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2366 vPC += OPCODE_LENGTH(op_put_global_var);
2369 DEFINE_OPCODE(op_get_scoped_var) {
2370 /* get_scoped_var dst(r) index(n) skip(n)
2372 Loads the contents of the index-th local from the scope skip nodes from
2373 the top of the scope chain, and places it in register dst.
2375 int dst = vPC[1].u.operand;
2376 int index = vPC[2].u.operand;
2377 int skip = vPC[3].u.operand;
2379 ScopeChainNode* scopeChain = callFrame->scopeChain();
2380 ScopeChainIterator iter = scopeChain->begin();
2381 ScopeChainIterator end = scopeChain->end();
2382 ASSERT(iter != end);
2383 ASSERT(codeBlock == callFrame->codeBlock());
2384 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2385 ASSERT(skip || !checkTopLevel);
2386 if (checkTopLevel && skip--) {
2387 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2392 ASSERT(iter != end);
2394 ASSERT((*iter)->isVariableObject());
2395 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2396 callFrame->uncheckedR(dst) = scope->registerAt(index).get();
2397 ASSERT(callFrame->r(dst).jsValue());
2398 vPC += OPCODE_LENGTH(op_get_scoped_var);
2401 DEFINE_OPCODE(op_put_scoped_var) {
2402 /* put_scoped_var index(n) skip(n) value(r)
2405 int index = vPC[1].u.operand;
2406 int skip = vPC[2].u.operand;
2407 int value = vPC[3].u.operand;
2409 ScopeChainNode* scopeChain = callFrame->scopeChain();
2410 ScopeChainIterator iter = scopeChain->begin();
2411 ScopeChainIterator end = scopeChain->end();
2412 ASSERT(codeBlock == callFrame->codeBlock());
2413 ASSERT(iter != end);
2414 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2415 ASSERT(skip || !checkTopLevel);
2416 if (checkTopLevel && skip--) {
2417 if (callFrame->r(codeBlock->activationRegister()).jsValue())
2422 ASSERT(iter != end);
2425 ASSERT((*iter)->isVariableObject());
2426 JSVariableObject* scope = static_cast<JSVariableObject*>(iter->get());
2427 ASSERT(callFrame->r(value).jsValue());
2428 scope->registerAt(index).set(*globalData, scope, callFrame->r(value).jsValue());
2429 vPC += OPCODE_LENGTH(op_put_scoped_var);
2432 DEFINE_OPCODE(op_resolve_base) {
2433 /* resolve_base dst(r) property(id) isStrict(bool)
2435 Searches the scope chain for an object containing
2436 identifier property, and if one is found, writes it to
2437 register dst. If none is found and isStrict is false, the
2438 outermost scope (which will be the global object) is
2439 stored in register dst.
2441 resolveBase(callFrame, vPC);
2442 CHECK_FOR_EXCEPTION();
2444 vPC += OPCODE_LENGTH(op_resolve_base);
2447 DEFINE_OPCODE(op_ensure_property_exists) {
2448 /* ensure_property_exists base(r) property(id)
2450 Throws an exception if property does not exist on base
2452 int base = vPC[1].u.operand;
2453 int property = vPC[2].u.operand;
2454 Identifier& ident = codeBlock->identifier(property);
2456 JSValue baseVal = callFrame->r(base).jsValue();
2457 JSObject* baseObject = asObject(baseVal);
2458 PropertySlot slot(baseVal);
2459 if (!baseObject->getPropertySlot(callFrame, ident, slot)) {
2460 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.ustring());
2464 vPC += OPCODE_LENGTH(op_ensure_property_exists);
2467 DEFINE_OPCODE(op_resolve_with_base) {
2468 /* resolve_with_base baseDst(r) propDst(r) property(id)
2470 Searches the scope chain for an object containing
2471 identifier property, and if one is found, writes it to
2472 register srcDst, and the retrieved property value to register
2473 propDst. If the property is not found, raises an exception.
2475 This is more efficient than doing resolve_base followed by
2476 resolve, or resolve_base followed by get_by_id, as it
2477 avoids duplicate hash lookups.
2479 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2482 vPC += OPCODE_LENGTH(op_resolve_with_base);
2485 DEFINE_OPCODE(op_get_by_id) {
2486 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2488 Generic property access: Gets the property named by identifier
2489 property from the value base, and puts the result in register dst.
2491 int dst = vPC[1].u.operand;
2492 int base = vPC[2].u.operand;
2493 int property = vPC[3].u.operand;
2495 Identifier& ident = codeBlock->identifier(property);
2496 JSValue baseValue = callFrame->r(base).jsValue();
2497 PropertySlot slot(baseValue);
2498 JSValue result = baseValue.get(callFrame, ident, slot);
2499 CHECK_FOR_EXCEPTION();
2501 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2503 callFrame->uncheckedR(dst) = result;
2504 vPC += OPCODE_LENGTH(op_get_by_id);
2507 DEFINE_OPCODE(op_get_by_id_self) {
2508 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2510 Cached property access: Attempts to get a cached property from the
2511 value base. If the cache misses, op_get_by_id_self reverts to
2514 int base = vPC[2].u.operand;
2515 JSValue baseValue = callFrame->r(base).jsValue();
2517 if (LIKELY(baseValue.isCell())) {
2518 JSCell* baseCell = baseValue.asCell();
2519 Structure* structure = vPC[4].u.structure.get();
2521 if (LIKELY(baseCell->structure() == structure)) {
2522 ASSERT(baseCell->isObject());
2523 JSObject* baseObject = asObject(baseCell);
2524 int dst = vPC[1].u.operand;
2525 int offset = vPC[5].u.operand;
2527 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2528 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
2530 vPC += OPCODE_LENGTH(op_get_by_id_self);
2535 uncacheGetByID(codeBlock, vPC);
2538 DEFINE_OPCODE(op_get_by_id_proto) {
2539 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2541 Cached property access: Attempts to get a cached property from the
2542 value base's prototype. If the cache misses, op_get_by_id_proto
2543 reverts to op_get_by_id.
2545 int base = vPC[2].u.operand;
2546 JSValue baseValue = callFrame->r(base).jsValue();
2548 if (LIKELY(baseValue.isCell())) {
2549 JSCell* baseCell = baseValue.asCell();
2550 Structure* structure = vPC[4].u.structure.get();
2552 if (LIKELY(baseCell->structure() == structure)) {
2553 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2554 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2555 Structure* prototypeStructure = vPC[5].u.structure.get();
2557 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2558 int dst = vPC[1].u.operand;
2559 int offset = vPC[6].u.operand;
2561 ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2562 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2563 callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));
2565 vPC += OPCODE_LENGTH(op_get_by_id_proto);
2571 uncacheGetByID(codeBlock, vPC);
2574 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2575 goto *(&&skip_id_getter_proto);
2577 DEFINE_OPCODE(op_get_by_id_getter_proto) {
2578 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2580 Cached property access: Attempts to get a cached getter property from the
2581 value base's prototype. If the cache misses, op_get_by_id_getter_proto
2582 reverts to op_get_by_id.
2584 int base = vPC[2].u.operand;
2585 JSValue baseValue = callFrame->r(base).jsValue();
2587 if (LIKELY(baseValue.isCell())) {
2588 JSCell* baseCell = baseValue.asCell();
2589 Structure* structure = vPC[4].u.structure.get();
2591 if (LIKELY(baseCell->structure() == structure)) {
2592 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2593 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2594 Structure* prototypeStructure = vPC[5].u.structure.get();
2596 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2597 int dst = vPC[1].u.operand;
2598 int offset = vPC[6].u.operand;
2599 if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {
2600 JSObject* getter = getterSetter->getter();
2602 CallType callType = getter->getCallData(callData);
2603 JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());
2604 CHECK_FOR_EXCEPTION();
2605 callFrame->uncheckedR(dst) = result;
2607 callFrame->uncheckedR(dst) = jsUndefined();
2608 vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);
2613 uncacheGetByID(codeBlock, vPC);
2616 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2617 skip_id_getter_proto:
2619 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2620 goto *(&&skip_id_custom_proto);
2622 DEFINE_OPCODE(op_get_by_id_custom_proto) {
2623 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2625 Cached property access: Attempts to use a cached named property getter
2626 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
2627 reverts to op_get_by_id.
2629 int base = vPC[2].u.operand;
2630 JSValue baseValue = callFrame->r(base).jsValue();
2632 if (LIKELY(baseValue.isCell())) {
2633 JSCell* baseCell = baseValue.asCell();
2634 Structure* structure = vPC[4].u.structure.get();
2636 if (LIKELY(baseCell->structure() == structure)) {
2637 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2638 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2639 Structure* prototypeStructure = vPC[5].u.structure.get();
2641 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2642 int dst = vPC[1].u.operand;
2643 int property = vPC[3].u.operand;
2644 Identifier& ident = codeBlock->identifier(property);
2646 PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;
2647 JSValue result = getter(callFrame, protoObject, ident);
2648 CHECK_FOR_EXCEPTION();
2649 callFrame->uncheckedR(dst) = result;
2650 vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);
2655 uncacheGetByID(codeBlock, vPC);
2658 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2659 skip_id_custom_proto:
2661 DEFINE_OPCODE(op_get_by_id_self_list) {
2662 // Polymorphic self access caching currently only supported when JITting.
2663 ASSERT_NOT_REACHED();
2664 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2665 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
2668 DEFINE_OPCODE(op_get_by_id_proto_list) {
2669 // Polymorphic prototype access caching currently only supported when JITting.
2670 ASSERT_NOT_REACHED();
2671 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2672 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2675 DEFINE_OPCODE(op_get_by_id_getter_self_list) {
2676 // Polymorphic self access caching currently only supported when JITting.
2677 ASSERT_NOT_REACHED();
2678 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2679 vPC += OPCODE_LENGTH(op_get_by_id_self_list);
2682 DEFINE_OPCODE(op_get_by_id_getter_proto_list) {
2683 // Polymorphic prototype access caching currently only supported when JITting.
2684 ASSERT_NOT_REACHED();
2685 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2686 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2689 DEFINE_OPCODE(op_get_by_id_custom_self_list) {
2690 // Polymorphic self access caching currently only supported when JITting.
2691 ASSERT_NOT_REACHED();
2692 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2693 vPC += OPCODE_LENGTH(op_get_by_id_custom_self_list);
2696 DEFINE_OPCODE(op_get_by_id_custom_proto_list) {
2697 // Polymorphic prototype access caching currently only supported when JITting.
2698 ASSERT_NOT_REACHED();
2699 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2700 vPC += OPCODE_LENGTH(op_get_by_id_proto_list);
2703 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2704 goto *(&&skip_get_by_id_chain);
2706 DEFINE_OPCODE(op_get_by_id_chain) {
2707 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2709 Cached property access: Attempts to get a cached property from the
2710 value base's prototype chain. If the cache misses, op_get_by_id_chain
2711 reverts to op_get_by_id.
2713 int base = vPC[2].u.operand;
2714 JSValue baseValue = callFrame->r(base).jsValue();
2716 if (LIKELY(baseValue.isCell())) {
2717 JSCell* baseCell = baseValue.asCell();
2718 Structure* structure = vPC[4].u.structure.get();
2720 if (LIKELY(baseCell->structure() == structure)) {
2721 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
2722 size_t count = vPC[6].u.operand;
2723 WriteBarrier<Structure>* end = it + count;
2726 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2728 if (UNLIKELY(baseObject->structure() != (*it).get()))
2732 int dst = vPC[1].u.operand;
2733 int offset = vPC[7].u.operand;
2735 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2736 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2737 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));
2739 vPC += OPCODE_LENGTH(op_get_by_id_chain);
2743 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2744 baseCell = baseObject;
2749 uncacheGetByID(codeBlock, vPC);
2752 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2753 skip_get_by_id_chain:
2754 goto *(&&skip_id_getter_self);
2756 DEFINE_OPCODE(op_get_by_id_getter_self) {
2757 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2759 Cached property access: Attempts to get a cached property from the
2760 value base. If the cache misses, op_get_by_id_getter_self reverts to
2763 int base = vPC[2].u.operand;
2764 JSValue baseValue = callFrame->r(base).jsValue();
2766 if (LIKELY(baseValue.isCell())) {
2767 JSCell* baseCell = baseValue.asCell();
2768 Structure* structure = vPC[4].u.structure.get();
2770 if (LIKELY(baseCell->structure() == structure)) {
2771 ASSERT(baseCell->isObject());
2772 JSObject* baseObject = asObject(baseCell);
2773 int dst = vPC[1].u.operand;
2774 int offset = vPC[5].u.operand;
2776 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
2777 JSObject* getter = getterSetter->getter();
2779 CallType callType = getter->getCallData(callData);
2780 JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());
2781 CHECK_FOR_EXCEPTION();
2782 callFrame->uncheckedR(dst) = result;
2784 callFrame->uncheckedR(dst) = jsUndefined();
2786 vPC += OPCODE_LENGTH(op_get_by_id_getter_self);
2790 uncacheGetByID(codeBlock, vPC);
2793 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2794 skip_id_getter_self:
2796 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2797 goto *(&&skip_id_custom_self);
2799 DEFINE_OPCODE(op_get_by_id_custom_self) {
2800 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2802 Cached property access: Attempts to use a cached named property getter
2803 from the value base. If the cache misses, op_get_by_id_custom_self reverts to
2806 int base = vPC[2].u.operand;
2807 JSValue baseValue = callFrame->r(base).jsValue();
2809 if (LIKELY(baseValue.isCell())) {
2810 JSCell* baseCell = baseValue.asCell();
2811 Structure* structure = vPC[4].u.structure.get();
2813 if (LIKELY(baseCell->structure() == structure)) {
2814 ASSERT(baseCell->isObject());
2815 int dst = vPC[1].u.operand;
2816 int property = vPC[3].u.operand;
2817 Identifier& ident = codeBlock->identifier(property);
2819 PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;
2820 JSValue result = getter(callFrame, baseValue, ident);
2821 CHECK_FOR_EXCEPTION();
2822 callFrame->uncheckedR(dst) = result;
2823 vPC += OPCODE_LENGTH(op_get_by_id_custom_self);
2827 uncacheGetByID(codeBlock, vPC);
2830 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2831 skip_id_custom_self:
2833 DEFINE_OPCODE(op_get_by_id_generic) {
2834 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2836 Generic property access: Gets the property named by identifier
2837 property from the value base, and puts the result in register dst.
2839 int dst = vPC[1].u.operand;
2840 int base = vPC[2].u.operand;
2841 int property = vPC[3].u.operand;
2843 Identifier& ident = codeBlock->identifier(property);
2844 JSValue baseValue = callFrame->r(base).jsValue();
2845 PropertySlot slot(baseValue);
2846 JSValue result = baseValue.get(callFrame, ident, slot);
2847 CHECK_FOR_EXCEPTION();
2849 callFrame->uncheckedR(dst) = result;
2850 vPC += OPCODE_LENGTH(op_get_by_id_generic);
2853 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2854 goto *(&&skip_id_getter_chain);
2856 DEFINE_OPCODE(op_get_by_id_getter_chain) {
2857 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2859 Cached property access: Attempts to get a cached property from the
2860 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
2861 reverts to op_get_by_id.
2863 int base = vPC[2].u.operand;
2864 JSValue baseValue = callFrame->r(base).jsValue();
2866 if (LIKELY(baseValue.isCell())) {
2867 JSCell* baseCell = baseValue.asCell();
2868 Structure* structure = vPC[4].u.structure.get();
2870 if (LIKELY(baseCell->structure() == structure)) {
2871 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
2872 size_t count = vPC[6].u.operand;
2873 WriteBarrier<Structure>* end = it + count;
2876 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2878 if (UNLIKELY(baseObject->structure() != (*it).get()))
2882 int dst = vPC[1].u.operand;
2883 int offset = vPC[7].u.operand;
2884 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {
2885 JSObject* getter = getterSetter->getter();
2887 CallType callType = getter->getCallData(callData);
2888 JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());
2889 CHECK_FOR_EXCEPTION();
2890 callFrame->uncheckedR(dst) = result;
2892 callFrame->uncheckedR(dst) = jsUndefined();
2893 vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);
2897 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2898 baseCell = baseObject;
2902 uncacheGetByID(codeBlock, vPC);
2905 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2906 skip_id_getter_chain:
2908 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2909 goto *(&&skip_id_custom_chain);
2911 DEFINE_OPCODE(op_get_by_id_custom_chain) {
2912 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2914 Cached property access: Attempts to use a cached named property getter on the
2915 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
2916 reverts to op_get_by_id.
2918 int base = vPC[2].u.operand;
2919 JSValue baseValue = callFrame->r(base).jsValue();
2921 if (LIKELY(baseValue.isCell())) {
2922 JSCell* baseCell = baseValue.asCell();
2923 Structure* structure = vPC[4].u.structure.get();
2925 if (LIKELY(baseCell->structure() == structure)) {
2926 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();
2927 size_t count = vPC[6].u.operand;
2928 WriteBarrier<Structure>* end = it + count;
2931 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2933 if (UNLIKELY(baseObject->structure() != (*it).get()))
2937 int dst = vPC[1].u.operand;
2938 int property = vPC[3].u.operand;
2939 Identifier& ident = codeBlock->identifier(property);
2941 PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;
2942 JSValue result = getter(callFrame, baseObject, ident);
2943 CHECK_FOR_EXCEPTION();
2944 callFrame->uncheckedR(dst) = result;
2945 vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);
2949 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2950 baseCell = baseObject;
2954 uncacheGetByID(codeBlock, vPC);
2957 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2958 skip_id_custom_chain:
2959 goto *(&&skip_get_array_length);
2961 DEFINE_OPCODE(op_get_array_length) {
2962 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2964 Cached property access: Gets the length of the array in register base,
2965 and puts the result in register dst. If register base does not hold
2966 an array, op_get_array_length reverts to op_get_by_id.
2969 int base = vPC[2].u.operand;
2970 JSValue baseValue = callFrame->r(base).jsValue();
2971 if (LIKELY(isJSArray(globalData, baseValue))) {
2972 int dst = vPC[1].u.operand;
2973 callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());
2974 vPC += OPCODE_LENGTH(op_get_array_length);
2978 uncacheGetByID(codeBlock, vPC);
2981 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2982 skip_get_array_length:
2983 goto *(&&skip_get_string_length);
2985 DEFINE_OPCODE(op_get_string_length) {
2986 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2988 Cached property access: Gets the length of the string in register base,
2989 and puts the result in register dst. If register base does not hold
2990 a string, op_get_string_length reverts to op_get_by_id.
2993 int base = vPC[2].u.operand;
2994 JSValue baseValue = callFrame->r(base).jsValue();
2995 if (LIKELY(isJSString(globalData, baseValue))) {
2996 int dst = vPC[1].u.operand;
2997 callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());
2998 vPC += OPCODE_LENGTH(op_get_string_length);
3002 uncacheGetByID(codeBlock, vPC);
3005 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3006 skip_get_string_length:
3007 goto *(&&skip_put_by_id);
3009 DEFINE_OPCODE(op_put_by_id) {
3010 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3012 Generic property access: Sets the property named by identifier
3013 property, belonging to register base, to register value.
3015 Unlike many opcodes, this one does not write any output to
3018 The "direct" flag should only be set this put_by_id is to initialize
3022 int base = vPC[1].u.operand;
3023 int property = vPC[2].u.operand;
3024 int value = vPC[3].u.operand;
3025 int direct = vPC[8].u.operand;
3027 JSValue baseValue = callFrame->r(base).jsValue();
3028 Identifier& ident = codeBlock->identifier(property);
3029 PutPropertySlot slot(codeBlock->isStrictMode());
3031 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3032 ASSERT(slot.base() == baseValue);
3034 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
3035 CHECK_FOR_EXCEPTION();
3037 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
3039 vPC += OPCODE_LENGTH(op_put_by_id);
3042 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3045 DEFINE_OPCODE(op_put_by_id_transition) {
3046 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
3048 Cached property access: Attempts to set a new property with a cached transition
3049 property named by identifier property, belonging to register base,
3050 to register value. If the cache misses, op_put_by_id_transition
3051 reverts to op_put_by_id_generic.
3053 Unlike many opcodes, this one does not write any output to
3056 int base = vPC[1].u.operand;
3057 JSValue baseValue = callFrame->r(base).jsValue();
3059 if (LIKELY(baseValue.isCell())) {
3060 JSCell* baseCell = baseValue.asCell();
3061 Structure* oldStructure = vPC[4].u.structure.get();
3062 Structure* newStructure = vPC[5].u.structure.get();
3064 if (LIKELY(baseCell->structure() == oldStructure)) {
3065 ASSERT(baseCell->isObject());
3066 JSObject* baseObject = asObject(baseCell);
3067 int direct = vPC[8].u.operand;
3070 WriteBarrier<Structure>* it = vPC[6].u.structureChain->head();
3072 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
3073 while (!proto.isNull()) {
3074 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
3075 uncachePutByID(codeBlock, vPC);
3079 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
3082 baseObject->transitionTo(*globalData, newStructure);
3084 int value = vPC[3].u.operand;
3085 unsigned offset = vPC[7].u.operand;
3086 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3087 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
3089 vPC += OPCODE_LENGTH(op_put_by_id_transition);
3094 uncachePutByID(codeBlock, vPC);
3097 DEFINE_OPCODE(op_put_by_id_replace) {
3098 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
3100 Cached property access: Attempts to set a pre-existing, cached
3101 property named by identifier property, belonging to register base,
3102 to register value. If the cache misses, op_put_by_id_replace
3103 reverts to op_put_by_id.
3105 Unlike many opcodes, this one does not write any output to
3108 int base = vPC[1].u.operand;
3109 JSValue baseValue = callFrame->r(base).jsValue();
3111 if (LIKELY(baseValue.isCell())) {
3112 JSCell* baseCell = baseValue.asCell();
3113 Structure* structure = vPC[4].u.structure.get();
3115 if (LIKELY(baseCell->structure() == structure)) {
3116 ASSERT(baseCell->isObject());
3117 JSObject* baseObject = asObject(baseCell);
3118 int value = vPC[3].u.operand;
3119 unsigned offset = vPC[5].u.operand;
3121 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);
3122 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());
3124 vPC += OPCODE_LENGTH(op_put_by_id_replace);
3129 uncachePutByID(codeBlock, vPC);
3132 DEFINE_OPCODE(op_put_by_id_generic) {
3133 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3135 Generic property access: Sets the property named by identifier
3136 property, belonging to register base, to register value.
3138 Unlike many opcodes, this one does not write any output to
3141 int base = vPC[1].u.operand;
3142 int property = vPC[2].u.operand;
3143 int value = vPC[3].u.operand;
3144 int direct = vPC[8].u.operand;
3146 JSValue baseValue = callFrame->r(base).jsValue();
3147 Identifier& ident = codeBlock->identifier(property);
3148 PutPropertySlot slot(codeBlock->isStrictMode());
3150 baseValue.putDirect(callFrame, ident, callFrame->r(value).jsValue(), slot);
3151 ASSERT(slot.base() == baseValue);
3153 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
3154 CHECK_FOR_EXCEPTION();
3156 vPC += OPCODE_LENGTH(op_put_by_id_generic);
3159 DEFINE_OPCODE(op_del_by_id) {
3160 /* del_by_id dst(r) base(r) property(id)
3162 Converts register base to Object, deletes the property
3163 named by identifier property from the object, and writes a
3164 boolean indicating success (if true) or failure (if false)
3167 int dst = vPC[1].u.operand;
3168 int base = vPC[2].u.operand;
3169 int property = vPC[3].u.operand;
3171 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
3172 Identifier& ident = codeBlock->identifier(property);
3173 bool result = baseObj->deleteProperty(callFrame, ident);
3174 if (!result && codeBlock->isStrictMode()) {
3175 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3178 CHECK_FOR_EXCEPTION();
3179 callFrame->uncheckedR(dst) = jsBoolean(result);
3180 vPC += OPCODE_LENGTH(op_del_by_id);
3183 DEFINE_OPCODE(op_get_by_pname) {
3184 int dst = vPC[1].u.operand;
3185 int base = vPC[2].u.operand;
3186 int property = vPC[3].u.operand;
3187 int expected = vPC[4].u.operand;
3188 int iter = vPC[5].u.operand;
3189 int i = vPC[6].u.operand;
3191 JSValue baseValue = callFrame->r(base).jsValue();
3192 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3193 JSValue subscript = callFrame->r(property).jsValue();
3194 JSValue expectedSubscript = callFrame->r(expected).jsValue();
3195 int index = callFrame->r(i).i() - 1;
3198 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {
3199 callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));
3200 vPC += OPCODE_LENGTH(op_get_by_pname);
3204 Identifier propertyName(callFrame, subscript.toString(callFrame));
3205 result = baseValue.get(callFrame, propertyName);
3207 CHECK_FOR_EXCEPTION();
3208 callFrame->uncheckedR(dst) = result;
3209 vPC += OPCODE_LENGTH(op_get_by_pname);
3212 DEFINE_OPCODE(op_get_arguments_length) {
3213 int dst = vPC[1].u.operand;
3214 int argumentsRegister = vPC[2].u.operand;
3215 int property = vPC[3].u.operand;
3216 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3218 Identifier& ident = codeBlock->identifier(property);
3219 PropertySlot slot(arguments);
3220 JSValue result = arguments.get(callFrame, ident, slot);
3221 CHECK_FOR_EXCEPTION();
3222 callFrame->uncheckedR(dst) = result;
3224 callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());
3226 vPC += OPCODE_LENGTH(op_get_arguments_length);
3229 DEFINE_OPCODE(op_get_argument_by_val) {
3230 int dst = vPC[1].u.operand;
3231 int argumentsRegister = vPC[2].u.operand;
3232 int property = vPC[3].u.operand;
3233 JSValue arguments = callFrame->r(argumentsRegister).jsValue();
3234 JSValue subscript = callFrame->r(property).jsValue();
3235 if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {
3236 unsigned arg = subscript.asUInt32() + 1;
3237 unsigned numParameters = callFrame->codeBlock()->m_numParameters;
3238 if (arg < numParameters)
3239 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters);
3241 callFrame->uncheckedR(dst) = callFrame->r(arg - RegisterFile::CallFrameHeaderSize - numParameters - callFrame->argumentCount() - 1);
3242 vPC += OPCODE_LENGTH(op_get_argument_by_val);
3246 Arguments* arguments = new (globalData) Arguments(callFrame);
3247 callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);
3248 callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);
3252 DEFINE_OPCODE(op_get_by_val) {
3253 /* get_by_val dst(r) base(r) property(r)
3255 Converts register base to Object, gets the property named
3256 by register property from the object, and puts the result
3257 in register dst. property is nominally converted to string
3258 but numbers are treated more efficiently.
3260 int dst = vPC[1].u.operand;
3261 int base = vPC[2].u.operand;
3262 int property = vPC[3].u.operand;
3264 JSValue baseValue = callFrame->r(base).jsValue();
3265 JSValue subscript = callFrame->r(property).jsValue();
3269 if (LIKELY(subscript.isUInt32())) {
3270 uint32_t i = subscript.asUInt32();
3271 if (isJSArray(globalData, baseValue)) {
3272 JSArray* jsArray = asArray(baseValue);
3273 if (jsArray->canGetIndex(i))
3274 result = jsArray->getIndex(i);
3276 result = jsArray->JSArray::get(callFrame, i);
3277 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
3278 result = asString(baseValue)->getIndex(callFrame, i);
3279 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
3280 result = asByteArray(baseValue)->getIndex(callFrame, i);
3282 result = baseValue.get(callFrame, i);
3284 Identifier property(callFrame, subscript.toString(callFrame));
3285 result = baseValue.get(callFrame, property);
3288 CHECK_FOR_EXCEPTION();
3289 callFrame->uncheckedR(dst) = result;
3290 vPC += OPCODE_LENGTH(op_get_by_val);
3293 DEFINE_OPCODE(op_put_by_val) {
3294 /* put_by_val base(r) property(r) value(r)
3296 Sets register value on register base as the property named
3297 by register property. Base is converted to object
3298 first. register property is nominally converted to string
3299 but numbers are treated more efficiently.
3301 Unlike many opcodes, this one does not write any output to
3304 int base = vPC[1].u.operand;
3305 int property = vPC[2].u.operand;
3306 int value = vPC[3].u.operand;
3308 JSValue baseValue = callFrame->r(base).jsValue();
3309 JSValue subscript = callFrame->r(property).jsValue();
3311 if (LIKELY(subscript.isUInt32())) {
3312 uint32_t i = subscript.asUInt32();
3313 if (isJSArray(globalData, baseValue)) {
3314 JSArray* jsArray = asArray(baseValue);
3315 if (jsArray->canSetIndex(i))
3316 jsArray->setIndex(*globalData, i, callFrame->r(value).jsValue());
3318 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
3319 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
3320 JSByteArray* jsByteArray = asByteArray(baseValue);
3322 JSValue jsValue = callFrame->r(value).jsValue();
3323 if (jsValue.isInt32())
3324 jsByteArray->setIndex(i, jsValue.asInt32());
3325 else if (jsValue.getNumber(dValue))
3326 jsByteArray->setIndex(i, dValue);
3328 baseValue.put(callFrame, i, jsValue);
3330 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
3332 Identifier property(callFrame, subscript.toString(callFrame));
3333 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
3334 PutPropertySlot slot(codeBlock->isStrictMode());
3335 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
3339 CHECK_FOR_EXCEPTION();
3340 vPC += OPCODE_LENGTH(op_put_by_val);
3343 DEFINE_OPCODE(op_del_by_val) {
3344 /* del_by_val dst(r) base(r) property(r)
3346 Converts register base to Object, deletes the property
3347 named by register property from the object, and writes a
3348 boolean indicating success (if true) or failure (if false)
3351 int dst = vPC[1].u.operand;
3352 int base = vPC[2].u.operand;
3353 int property = vPC[3].u.operand;
3355 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
3357 JSValue subscript = callFrame->r(property).jsValue();
3360 if (subscript.getUInt32(i))
3361 result = baseObj->deleteProperty(callFrame, i);
3363 CHECK_FOR_EXCEPTION();
3364 Identifier property(callFrame, subscript.toString(callFrame));
3365 CHECK_FOR_EXCEPTION();
3366 result = baseObj->deleteProperty(callFrame, property);
3368 if (!result && codeBlock->isStrictMode()) {
3369 exceptionValue = createTypeError(callFrame, "Unable to delete property.");
3372 CHECK_FOR_EXCEPTION();
3373 callFrame->uncheckedR(dst) = jsBoolean(result);
3374 vPC += OPCODE_LENGTH(op_del_by_val);
3377 DEFINE_OPCODE(op_put_by_index) {
3378 /* put_by_index base(r) property(n) value(r)
3380 Sets register value on register base as the property named
3381 by the immediate number property. Base is converted to
3384 Unlike many opcodes, this one does not write any output to
3387 This opcode is mainly used to initialize array literals.
3389 int base = vPC[1].u.operand;
3390 unsigned property = vPC[2].u.operand;
3391 int value = vPC[3].u.operand;
3393 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
3395 vPC += OPCODE_LENGTH(op_put_by_index);
3398 DEFINE_OPCODE(op_loop) {
3399 /* loop target(offset)
3401 Jumps unconditionally to offset target from the current
3404 Additionally this loop instruction may terminate JS execution is
3405 the JS timeout is reached.
3407 #if ENABLE(OPCODE_STATS)
3408 OpcodeStats::resetLastInstruction();
3410 int target = vPC[1].u.operand;
3411 CHECK_FOR_TIMEOUT();
3415 DEFINE_OPCODE(op_jmp) {
3416 /* jmp target(offset)
3418 Jumps unconditionally to offset target from the current
3421 #if ENABLE(OPCODE_STATS)
3422 OpcodeStats::resetLastInstruction();
3424 int target = vPC[1].u.operand;
3429 DEFINE_OPCODE(op_loop_if_true) {
3430 /* loop_if_true cond(r) target(offset)
3432 Jumps to offset target from the current instruction, if and
3433 only if register cond converts to boolean as true.
3435 Additionally this loop instruction may terminate JS execution is
3436 the JS timeout is reached.
3438 int cond = vPC[1].u.operand;
3439 int target = vPC[2].u.operand;
3440 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3442 CHECK_FOR_TIMEOUT();
3446 vPC += OPCODE_LENGTH(op_loop_if_true);
3449 DEFINE_OPCODE(op_loop_if_false) {
3450 /* loop_if_true cond(r) target(offset)
3452 Jumps to offset target from the current instruction, if and
3453 only if register cond converts to boolean as false.
3455 Additionally this loop instruction may terminate JS execution is
3456 the JS timeout is reached.
3458 int cond = vPC[1].u.operand;
3459 int target = vPC[2].u.operand;
3460 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3462 CHECK_FOR_TIMEOUT();
3466 vPC += OPCODE_LENGTH(op_loop_if_true);
3469 DEFINE_OPCODE(op_jtrue) {
3470 /* jtrue cond(r) target(offset)
3472 Jumps to offset target from the current instruction, if and
3473 only if register cond converts to boolean as true.
3475 int cond = vPC[1].u.operand;
3476 int target = vPC[2].u.operand;
3477 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3482 vPC += OPCODE_LENGTH(op_jtrue);
3485 DEFINE_OPCODE(op_jfalse) {
3486 /* jfalse cond(r) target(offset)
3488 Jumps to offset target from the current instruction, if and
3489 only if register cond converts to boolean as false.
3491 int cond = vPC[1].u.operand;
3492 int target = vPC[2].u.operand;
3493 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
3498 vPC += OPCODE_LENGTH(op_jfalse);
3501 DEFINE_OPCODE(op_jeq_null) {
3502 /* jeq_null src(r) target(offset)
3504 Jumps to offset target from the current instruction, if and
3505 only if register src is null.
3507 int src = vPC[1].u.operand;
3508 int target = vPC[2].u.operand;
3509 JSValue srcValue = callFrame->r(src).jsValue();
3511 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3516 vPC += OPCODE_LENGTH(op_jeq_null);
3519 DEFINE_OPCODE(op_jneq_null) {
3520 /* jneq_null src(r) target(offset)
3522 Jumps to offset target from the current instruction, if and
3523 only if register src is not null.
3525 int src = vPC[1].u.operand;
3526 int target = vPC[2].u.operand;
3527 JSValue srcValue = callFrame->r(src).jsValue();
3529 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3534 vPC += OPCODE_LENGTH(op_jneq_null);
3537 DEFINE_OPCODE(op_jneq_ptr) {
3538 /* jneq_ptr src(r) ptr(jsCell) target(offset)
3540 Jumps to offset target from the current instruction, if the value r is equal
3541 to ptr, using pointer equality.
3543 int src = vPC[1].u.operand;
3544 int target = vPC[3].u.operand;
3545 JSValue srcValue = callFrame->r(src).jsValue();
3546 if (srcValue != vPC[2].u.jsCell.get()) {
3551 vPC += OPCODE_LENGTH(op_jneq_ptr);
3554 DEFINE_OPCODE(op_loop_if_less) {
3555 /* loop_if_less src1(r) src2(r) target(offset)
3557 Checks whether register src1 is less than register src2, as
3558 with the ECMAScript '<' operator, and then jumps to offset
3559 target from the current instruction, if and only if the
3560 result of the comparison is true.
3562 Additionally this loop instruction may terminate JS execution is
3563 the JS timeout is reached.
3565 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3566 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3567 int target = vPC[3].u.operand;
3569 bool result = jsLess(callFrame, src1, src2);
3570 CHECK_FOR_EXCEPTION();
3574 CHECK_FOR_TIMEOUT();
3578 vPC += OPCODE_LENGTH(op_loop_if_less);
3581 DEFINE_OPCODE(op_loop_if_lesseq) {
3582 /* loop_if_lesseq src1(r) src2(r) target(offset)
3584 Checks whether register src1 is less than or equal to register
3585 src2, as with the ECMAScript '<=' operator, and then jumps to
3586 offset target from the current instruction, if and only if the
3587 result of the comparison is true.
3589 Additionally this loop instruction may terminate JS execution is
3590 the JS timeout is reached.
3592 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3593 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3594 int target = vPC[3].u.operand;
3596 bool result = jsLessEq(callFrame, src1, src2);
3597 CHECK_FOR_EXCEPTION();
3601 CHECK_FOR_TIMEOUT();
3605 vPC += OPCODE_LENGTH(op_loop_if_lesseq);
3608 DEFINE_OPCODE(op_jnless) {
3609 /* jnless src1(r) src2(r) target(offset)
3611 Checks whether register src1 is less than register src2, as
3612 with the ECMAScript '<' operator, and then jumps to offset
3613 target from the current instruction, if and only if the
3614 result of the comparison is false.
3616 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3617 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3618 int target = vPC[3].u.operand;
3620 bool result = jsLess(callFrame, src1, src2);
3621 CHECK_FOR_EXCEPTION();
3628 vPC += OPCODE_LENGTH(op_jnless);
3631 DEFINE_OPCODE(op_jless) {
3632 /* jless src1(r) src2(r) target(offset)
3634 Checks whether register src1 is less than register src2, as
3635 with the ECMAScript '<' operator, and then jumps to offset
3636 target from the current instruction, if and only if the
3637 result of the comparison is true.
3639 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3640 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3641 int target = vPC[3].u.operand;
3643 bool result = jsLess(callFrame, src1, src2);
3644 CHECK_FOR_EXCEPTION();
3651 vPC += OPCODE_LENGTH(op_jless);
3654 DEFINE_OPCODE(op_jnlesseq) {
3655 /* jnlesseq src1(r) src2(r) target(offset)
3657 Checks whether register src1 is less than or equal to
3658 register src2, as with the ECMAScript '<=' operator,
3659 and then jumps to offset target from the current instruction,
3660 if and only if theresult of the comparison is false.
3662 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3663 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3664 int target = vPC[3].u.operand;
3666 bool result = jsLessEq(callFrame, src1, src2);
3667 CHECK_FOR_EXCEPTION();
3674 vPC += OPCODE_LENGTH(op_jnlesseq);
3677 DEFINE_OPCODE(op_jlesseq) {
3678 /* jlesseq src1(r) src2(r) target(offset)
3680 Checks whether register src1 is less than or equal to
3681 register src2, as with the ECMAScript '<=' operator,
3682 and then jumps to offset target from the current instruction,
3683 if and only if the result of the comparison is true.
3685 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();
3686 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();
3687 int target = vPC[3].u.operand;
3689 bool result = jsLessEq(callFrame, src1, src2);
3690 CHECK_FOR_EXCEPTION();
3697 vPC += OPCODE_LENGTH(op_jlesseq);
3700 DEFINE_OPCODE(op_switch_imm) {
3701 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3703 Performs a range checked switch on the scrutinee value, using
3704 the tableIndex-th immediate switch jump table. If the scrutinee value
3705 is an immediate number in the range covered by the referenced jump
3706 table, and the value at jumpTable[scrutinee value] is non-zero, then
3707 that value is used as the jump offset, otherwise defaultOffset is used.
3709 int tableIndex = vPC[1].u.operand;
3710 int defaultOffset = vPC[2].u.operand;
3711 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
3712 if (scrutinee.isInt32())
3713 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
3717 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
3718 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
3720 vPC += defaultOffset;
3724 DEFINE_OPCODE(op_switch_char) {
3725 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3727 Performs a range checked switch on the scrutinee value, using
3728 the tableIndex-th character switch jump table. If the scrutinee value
3729 is a single character string in the range covered by the referenced jump
3730 table, and the value at jumpTable[scrutinee value] is non-zero, then
3731 that value is used as the jump offset, otherwise defaultOffset is used.
3733 int tableIndex = vPC[1].u.operand;
3734 int defaultOffset = vPC[2].u.operand;
3735 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
3736 if (!scrutinee.isString())
3737 vPC += defaultOffset;
3739 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
3740 if (value->length() != 1)
3741 vPC += defaultOffset;
3743 vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue(value->characters()[0], defaultOffset);
3747 DEFINE_OPCODE(op_switch_string) {
3748 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3750 Performs a sparse hashmap based switch on the value in the scrutinee
3751 register, using the tableIndex-th string switch jump table. If the
3752 scrutinee value is a string that exists as a key in the referenced
3753 jump table, then the value associated with the string is used as the
3754 jump offset, otherwise defaultOffset is used.
3756 int tableIndex = vPC[1].u.operand;
3757 int defaultOffset = vPC[2].u.operand;
3758 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();
3759 if (!scrutinee.isString())
3760 vPC += defaultOffset;
3762 vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);
3765 DEFINE_OPCODE(op_new_func) {
3766 /* new_func dst(r) func(f)
3768 Constructs a new Function instance from function func and
3769 the current scope chain using the original Function
3770 constructor, using the rules for function declarations, and
3771 puts the result in register dst.
3773 int dst = vPC[1].u.operand;
3774 int func = vPC[2].u.operand;
3775 int shouldCheck = vPC[3].u.operand;
3776 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
3777 if (!shouldCheck || !callFrame->r(dst).jsValue())
3778 callFrame->uncheckedR(dst) = JSValue(codeBlock->functionDecl(func)->make(callFrame, callFrame->scopeChain()));
3780 vPC += OPCODE_LENGTH(op_new_func);
3783 DEFINE_OPCODE(op_new_func_exp) {
3784 /* new_func_exp dst(r) func(f)
3786 Constructs a new Function instance from function func and
3787 the current scope chain using the original Function
3788 constructor, using the rules for function expressions, and
3789 puts the result in register dst.
3791 int dst = vPC[1].u.operand;
3792 int funcIndex = vPC[2].u.operand;
3794 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
3795 FunctionExecutable* function = codeBlock->functionExpr(funcIndex);
3796 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
3799 The Identifier in a FunctionExpression can be referenced from inside
3800 the FunctionExpression's FunctionBody to allow the function to call
3801 itself recursively. However, unlike in a FunctionDeclaration, the
3802 Identifier in a FunctionExpression cannot be referenced from and
3803 does not affect the scope enclosing the FunctionExpression.
3805 if (!function->name().isNull()) {
3806 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
3807 func->setScope(*globalData, func->scope()->push(functionScopeObject));
3810 callFrame->uncheckedR(dst) = JSValue(func);
3812 vPC += OPCODE_LENGTH(op_new_func_exp);
3815 DEFINE_OPCODE(op_call_eval) {
3816 /* call_eval func(r) argCount(n) registerOffset(n)
3818 Call a function named "eval" with no explicit "this" value
3819 (which may therefore be the eval operator). If register
3820 thisVal is the global object, and register func contains
3821 that global object's original global eval function, then
3822 perform the eval operator in local scope (interpreting
3823 the argument registers as for the "call"
3824 opcode). Otherwise, act exactly as the "call" opcode would.
3827 int func = vPC[1].u.operand;
3828 int argCount = vPC[2].u.operand;
3829 int registerOffset = vPC[3].u.operand;
3831 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
3832 JSValue funcVal = callFrame->r(func).jsValue();
3834 Register* newCallFrame = callFrame->registers() + registerOffset;
3835 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
3836 JSValue thisValue = argv[0].jsValue();
3837 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
3839 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
3840 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset);
3841 if ((exceptionValue = globalData->exception))
3843 functionReturnValue = result;
3845 vPC += OPCODE_LENGTH(op_call_eval);
3849 // We didn't find the blessed version of eval, so process this
3850 // instruction as a normal function call.
3851 // fall through to op_call
3853 DEFINE_OPCODE(op_call) {
3854 /* call func(r) argCount(n) registerOffset(n)
3856 Perform a function call.
3858 registerOffset is the distance the callFrame pointer should move
3859 before the VM initializes the new call frame's header.
3861 dst is where op_ret should store its result.
3864 int func = vPC[1].u.operand;
3865 int argCount = vPC[2].u.operand;
3866 int registerOffset = vPC[3].u.operand;
3868 JSValue v = callFrame->r(func).jsValue();
3871 CallType callType = getCallData(v, callData);
3873 if (callType == CallTypeJS) {
3874 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3876 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
3877 if (UNLIKELY(!!error)) {
3878 exceptionValue = error;
3882 CallFrame* previousCallFrame = callFrame;
3883 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
3884 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3885 if (UNLIKELY(!callFrame)) {
3886 callFrame = previousCallFrame;
3887 exceptionValue = createStackOverflowError(callFrame);
3891 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
3892 codeBlock = newCodeBlock;
3893 ASSERT(codeBlock == callFrame->codeBlock());
3894 vPC = newCodeBlock->instructions().begin();
3896 #if ENABLE(OPCODE_STATS)
3897 OpcodeStats::resetLastInstruction();
3903 if (callType == CallTypeHost) {
3904 ScopeChainNode* scopeChain = callFrame->scopeChain();
3905 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3906 if (!registerFile->grow(newCallFrame->registers())) {
3907 exceptionValue = createStackOverflowError(callFrame);
3911 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scopeChain, callFrame, argCount, asObject(v));
3913 JSValue returnValue;
3915 SamplingTool::HostCallRecord callRecord(m_sampler.get());
3916 returnValue = JSValue::decode(callData.native.function(newCallFrame));
3918 CHECK_FOR_EXCEPTION();
3920 functionReturnValue = returnValue;
3922 vPC += OPCODE_LENGTH(op_call);
3926 ASSERT(callType == CallTypeNone);
3928 exceptionValue = createNotAFunctionError(callFrame, v);
3931 DEFINE_OPCODE(op_load_varargs) {
3932 int argCountDst = vPC[1].u.operand;
3933 int argsOffset = vPC[2].u.operand;
3935 JSValue arguments = callFrame->r(argsOffset).jsValue();
3936 uint32_t argCount = 0;
3938 argCount = (uint32_t)(callFrame->argumentCount());
3939 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
3940 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3941 Register* newEnd = callFrame->registers() + sizeDelta;
3942 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3943 exceptionValue = createStackOverflowError(callFrame);
3946 ASSERT(!asFunction(callFrame->callee())->isHostFunction());
3947 int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
3948 int32_t inplaceArgs = min(static_cast<int32_t>(argCount), expectedParams);
3950 Register* argStore = callFrame->registers() + argsOffset;
3952 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3953 for (; i < inplaceArgs; i++)
3954 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
3955 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3956 for (; i < static_cast<int32_t>(argCount); i++)
3957 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - static_cast<int32_t>(argCount) - 1];
3958 } else if (!arguments.isUndefinedOrNull()) {
3959 if (!arguments.isObject()) {
3960 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
3963 if (asObject(arguments)->classInfo() == &Arguments::s_info) {
3964 Arguments* args = asArguments(arguments);
3965 argCount = args->numProvidedArguments(callFrame);
3966 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
3967 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3968 Register* newEnd = callFrame->registers() + sizeDelta;
3969 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3970 exceptionValue = createStackOverflowError(callFrame);
3973 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3974 } else if (isJSArray(&callFrame->globalData(), arguments)) {
3975 JSArray* array = asArray(arguments);
3976 argCount = array->length();
3977 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
3978 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3979 Register* newEnd = callFrame->registers() + sizeDelta;
3980 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3981 exceptionValue = createStackOverflowError(callFrame);
3984 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3985 } else if (asObject(arguments)->inherits(&JSArray::s_info)) {
3986 JSObject* argObject = asObject(arguments);
3987 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
3988 argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
3989 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3990 Register* newEnd = callFrame->registers() + sizeDelta;
3991 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3992 exceptionValue = createStackOverflowError(callFrame);
3995 Register* argsBuffer = callFrame->registers() + argsOffset;
3996 for (uint32_t i = 0; i < argCount; ++i) {
3997 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
3998 CHECK_FOR_EXCEPTION();
4001 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
4005 CHECK_FOR_EXCEPTION();
4006 callFrame->uncheckedR(argCountDst) = Register::withInt(argCount + 1);
4007 vPC += OPCODE_LENGTH(op_load_varargs);
4010 DEFINE_OPCODE(op_call_varargs) {
4011 /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
4013 Perform a function call with a dynamic set of arguments.
4015 registerOffset is the distance the callFrame pointer should move
4016 before the VM initializes the new call frame's header, excluding
4017 space for arguments.
4019 dst is where op_ret should store its result.
4022 int func = vPC[1].u.operand;
4023 int argCountReg = vPC[2].u.operand;
4024 int registerOffset = vPC[3].u.operand;
4026 JSValue v = callFrame->r(func).jsValue();
4027 int argCount = callFrame->r(argCountReg).i();
4028 registerOffset += argCount;
4030 CallType callType = getCallData(v, callData);
4032 if (callType == CallTypeJS) {
4033 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
4035 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScopeChain);
4036 if (UNLIKELY(!!error)) {
4037 exceptionValue = error;
4041 CallFrame* previousCallFrame = callFrame;
4042 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();
4043 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4044 if (UNLIKELY(!callFrame)) {
4045 callFrame = previousCallFrame;
4046 exceptionValue = createStackOverflowError(callFrame);
4050 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4051 codeBlock = newCodeBlock;
4052 ASSERT(codeBlock == callFrame->codeBlock());
4053 vPC = newCodeBlock->instructions().begin();
4055 #if ENABLE(OPCODE_STATS)
4056 OpcodeStats::resetLastInstruction();
4062 if (callType == CallTypeHost) {
4063 ScopeChainNode* scopeChain = callFrame->scopeChain();
4064 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
4065 if (!registerFile->grow(newCallFrame->registers())) {
4066 exceptionValue = createStackOverflowError(callFrame);
4069 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scopeChain, callFrame, argCount, asObject(v));
4071 JSValue returnValue;
4073 SamplingTool::HostCallRecord callRecord(m_sampler.get());
4074 returnValue = JSValue::decode(callData.native.function(newCallFrame));
4076 CHECK_FOR_EXCEPTION();
4078 functionReturnValue = returnValue;
4080 vPC += OPCODE_LENGTH(op_call_varargs);
4084 ASSERT(callType == CallTypeNone);
4086 exceptionValue = createNotAFunctionError(callFrame, v);
4089 DEFINE_OPCODE(op_tear_off_activation) {
4090 /* tear_off_activation activation(r) arguments(r)
4092 Copy locals and named parameters from the register file to the heap.
4093 Point the bindings in 'activation' and 'arguments' to this new backing
4094 store. (Note that 'arguments' may not have been created. If created,
4095 'arguments' already holds a copy of any extra / unnamed parameters.)
4097 This opcode appears before op_ret in functions that require full scope chains.
4100 int activation = vPC[1].u.operand;
4101 int arguments = vPC[2].u.operand;
4102 ASSERT(codeBlock->needsFullScopeChain());
4103 JSValue activationValue = callFrame->r(activation).jsValue();
4104 if (activationValue) {
4105 asActivation(activationValue)->copyRegisters(*globalData);
4107 if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4108 if (!codeBlock->isStrictMode())
4109 asArguments(argumentsValue)->setActivation(*globalData, asActivation(activationValue));
4111 } else if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {
4112 if (!codeBlock->isStrictMode())
4113 asArguments(argumentsValue)->copyRegisters(*globalData);
4116 vPC += OPCODE_LENGTH(op_tear_off_activation);
4119 DEFINE_OPCODE(op_tear_off_arguments) {
4120 /* tear_off_arguments arguments(r)
4122 Copy named parameters from the register file to the heap. Point the
4123 bindings in 'arguments' to this new backing store. (Note that
4124 'arguments' may not have been created. If created, 'arguments' already
4125 holds a copy of any extra / unnamed parameters.)
4127 This opcode appears before op_ret in functions that don't require full
4128 scope chains, but do use 'arguments'.
4131 int src1 = vPC[1].u.operand;
4132 ASSERT(!codeBlock->needsFullScopeChain() && codeBlock->ownerExecutable()->usesArguments());
4134 if (JSValue arguments = callFrame->r(unmodifiedArgumentsRegister(src1)).jsValue())
4135 asArguments(arguments)->copyRegisters(*globalData);
4137 vPC += OPCODE_LENGTH(op_tear_off_arguments);
4140 DEFINE_OPCODE(op_ret) {
4143 Return register result as the return value of the current
4144 function call, writing it into functionReturnValue.
4145 In addition, unwind one call frame and restore the scope
4146 chain, code block instruction pointer and register base
4147 to those of the calling function.
4150 int result = vPC[1].u.operand;
4152 JSValue returnValue = callFrame->r(result).jsValue();
4154 vPC = callFrame->returnVPC();
4155 callFrame = callFrame->callerFrame();
4157 if (callFrame->hasHostCallFrameFlag())
4160 functionReturnValue = returnValue;
4161 codeBlock = callFrame->codeBlock();
4162 ASSERT(codeBlock == callFrame->codeBlock());
4166 DEFINE_OPCODE(op_call_put_result) {
4167 /* op_call_put_result result(r)
4169 Move call result from functionReturnValue to caller's
4170 expected return value register.
4173 callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;
4175 vPC += OPCODE_LENGTH(op_call_put_result);
4178 DEFINE_OPCODE(op_ret_object_or_this) {
4181 Return register result as the return value of the current
4182 function call, writing it into the caller's expected return
4183 value register. In addition, unwind one call frame and
4184 restore the scope chain, code block instruction pointer and
4185 register base to those of the calling function.
4188 int result = vPC[1].u.operand;
4190 JSValue returnValue = callFrame->r(result).jsValue();
4192 if (UNLIKELY(!returnValue.isObject()))
4193 returnValue = callFrame->r(vPC[2].u.operand).jsValue();
4195 vPC = callFrame->returnVPC();
4196 callFrame = callFrame->callerFrame();
4198 if (callFrame->hasHostCallFrameFlag())
4201 functionReturnValue = returnValue;
4202 codeBlock = callFrame->codeBlock();
4203 ASSERT(codeBlock == callFrame->codeBlock());
4207 DEFINE_OPCODE(op_enter) {
4210 Initializes local variables to undefined. If the code block requires
4211 an activation, enter_with_activation is used instead.
4213 This opcode appears only at the beginning of a code block.
4217 for (size_t count = codeBlock->m_numVars; i < count; ++i)
4218 callFrame->uncheckedR(i) = jsUndefined();
4220 vPC += OPCODE_LENGTH(op_enter);
4223 DEFINE_OPCODE(op_create_activation) {
4224 /* create_activation dst(r)
4226 If the activation object for this callframe has not yet been created,
4227 this creates it and writes it back to dst.
4230 int activationReg = vPC[1].u.operand;
4231 if (!callFrame->r(activationReg).jsValue()) {
4232 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));
4233 callFrame->r(activationReg) = JSValue(activation);
4234 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
4236 vPC += OPCODE_LENGTH(op_create_activation);
4239 DEFINE_OPCODE(op_get_callee) {
4240 /* op_get_callee callee(r)
4242 Move callee into a register.
4245 callFrame->uncheckedR(vPC[1].u.operand) = JSValue(callFrame->callee());
4247 vPC += OPCODE_LENGTH(op_get_callee);
4250 DEFINE_OPCODE(op_create_this) {
4251 /* op_create_this this(r) proto(r)
4253 Allocate an object as 'this', fr use in construction.
4255 This opcode should only be used at the beginning of a code
4259 int thisRegister = vPC[1].u.operand;
4260 int protoRegister = vPC[2].u.operand;
4262 JSFunction* constructor = asFunction(callFrame->callee());
4263 #if !ASSERT_DISABLED
4264 ConstructData constructData;
4265 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
4268 Structure* structure;
4269 JSValue proto = callFrame->r(protoRegister).jsValue();
4270 if (proto.isObject())
4271 structure = asObject(proto)->inheritorID(callFrame->globalData());
4273 structure = constructor->scope()->globalObject->emptyObjectStructure();
4274 callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);
4276 vPC += OPCODE_LENGTH(op_create_this);
4279 DEFINE_OPCODE(op_convert_this) {
4280 /* convert_this this(r)
4282 Takes the value in the 'this' register, converts it to a
4283 value that is suitable for use as the 'this' value, and
4284 stores it in the 'this' register. This opcode is emitted
4285 to avoid doing the conversion in the caller unnecessarily.
4287 This opcode should only be used at the beginning of a code
4291 int thisRegister = vPC[1].u.operand;
4292 JSValue thisVal = callFrame->r(thisRegister).jsValue();
4293 if (thisVal.needsThisConversion())
4294 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
4296 vPC += OPCODE_LENGTH(op_convert_this);
4299 DEFINE_OPCODE(op_convert_this_strict) {
4300 /* convert_this_strict this(r)
4302 Takes the value in the 'this' register, and converts it to
4303 its "this" form if (and only if) "this" is an object with a
4304 custom this conversion
4306 This opcode should only be used at the beginning of a code
4310 int thisRegister = vPC[1].u.operand;
4311 JSValue thisVal = callFrame->r(thisRegister).jsValue();
4312 if (thisVal.isObject() && thisVal.needsThisConversion())
4313 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toStrictThisObject(callFrame));
4315 vPC += OPCODE_LENGTH(op_convert_this_strict);
4318 DEFINE_OPCODE(op_init_lazy_reg) {
4319 /* init_lazy_reg dst(r)
4321 Initialises dst(r) to JSValue().
4323 This opcode appears only at the beginning of a code block.
4325 int dst = vPC[1].u.operand;
4327 callFrame->uncheckedR(dst) = JSValue();
4328 vPC += OPCODE_LENGTH(op_init_lazy_reg);
4331 DEFINE_OPCODE(op_create_arguments) {
4332 /* create_arguments dst(r)
4334 Creates the 'arguments' object and places it in both the
4335 'arguments' call frame slot and the local 'arguments'
4336 register, if it has not already been initialised.
4339 int dst = vPC[1].u.operand;
4341 if (!callFrame->r(dst).jsValue()) {
4342 Arguments* arguments = new (globalData) Arguments(callFrame);
4343 callFrame->uncheckedR(dst) = JSValue(arguments);
4344 callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);
4346 vPC += OPCODE_LENGTH(op_create_arguments);
4349 DEFINE_OPCODE(op_construct) {
4350 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
4352 Invoke register "func" as a constructor. For JS
4353 functions, the calling convention is exactly as for the
4354 "call" opcode, except that the "this" value is a newly
4355 created Object. For native constructors, no "this"
4356 value is passed. In either case, the argCount and registerOffset
4357 registers are interpreted as for the "call" opcode.
4359 Register proto must contain the prototype property of
4360 register func. This is to enable polymorphic inline
4361 caching of this lookup.
4364 int func = vPC[1].u.operand;
4365 int argCount = vPC[2].u.operand;
4366 int registerOffset = vPC[3].u.operand;
4368 JSValue v = callFrame->r(func).jsValue();
4370 ConstructData constructData;
4371 ConstructType constructType = getConstructData(v, constructData);
4373 if (constructType == ConstructTypeJS) {
4374 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
4376 JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScopeChain);
4377 if (UNLIKELY(!!error)) {
4378 exceptionValue = error;
4382 CallFrame* previousCallFrame = callFrame;
4383 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();
4384 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
4385 if (UNLIKELY(!callFrame)) {
4386 callFrame = previousCallFrame;
4387 exceptionValue = createStackOverflowError(callFrame);
4391 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScopeChain, previousCallFrame, argCount, asFunction(v));
4392 codeBlock = newCodeBlock;
4393 vPC = newCodeBlock->instructions().begin();
4394 #if ENABLE(OPCODE_STATS)
4395 OpcodeStats::resetLastInstruction();
4401 if (constructType == ConstructTypeHost) {
4402 ScopeChainNode* scopeChain = callFrame->scopeChain();
4403 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
4404 if (!registerFile->grow(newCallFrame->registers())) {
4405 exceptionValue = createStackOverflowError(callFrame);
4408 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scopeChain, callFrame, argCount, asObject(v));
4410 JSValue returnValue;
4412 SamplingTool::HostCallRecord callRecord(m_sampler.get());
4413 returnValue = JSValue::decode(constructData.native.function(newCallFrame));
4415 CHECK_FOR_EXCEPTION();
4416 functionReturnValue = returnValue;
4418 vPC += OPCODE_LENGTH(op_construct);
4422 ASSERT(constructType == ConstructTypeNone);
4424 exceptionValue = createNotAConstructorError(callFrame, v);
4427 DEFINE_OPCODE(op_strcat) {
4428 /* strcat dst(r) src(r) count(n)
4430 Construct a new String instance using the original
4431 constructor, and puts the result in register dst.
4432 The string will be the result of concatenating count
4433 strings with values taken from registers starting at
4436 int dst = vPC[1].u.operand;
4437 int src = vPC[2].u.operand;
4438 int count = vPC[3].u.operand;
4440 callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
4441 CHECK_FOR_EXCEPTION();
4442 vPC += OPCODE_LENGTH(op_strcat);
4446 DEFINE_OPCODE(op_to_primitive) {
4447 int dst = vPC[1].u.operand;
4448 int src = vPC[2].u.operand;
4450 callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
4451 vPC += OPCODE_LENGTH(op_to_primitive);
4455 DEFINE_OPCODE(op_push_scope) {
4456 /* push_scope scope(r)
4458 Converts register scope to object, and pushes it onto the top
4459 of the current scope chain. The contents of the register scope
4460 are replaced by the result of toObject conversion of the scope.
4462 int scope = vPC[1].u.operand;
4463 JSValue v = callFrame->r(scope).jsValue();
4464 JSObject* o = v.toObject(callFrame);
4465 CHECK_FOR_EXCEPTION();
4467 callFrame->uncheckedR(scope) = JSValue(o);
4468 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
4470 vPC += OPCODE_LENGTH(op_push_scope);
4473 DEFINE_OPCODE(op_pop_scope) {
4476 Removes the top item from the current scope chain.
4478 callFrame->setScopeChain(callFrame->scopeChain()->pop());
4480 vPC += OPCODE_LENGTH(op_pop_scope);
4483 DEFINE_OPCODE(op_get_pnames) {
4484 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
4486 Creates a property name list for register base and puts it
4487 in register dst, initializing i and size for iteration. If
4488 base is undefined or null, jumps to breakTarget.
4490 int dst = vPC[1].u.operand;
4491 int base = vPC[2].u.operand;
4492 int i = vPC[3].u.operand;
4493 int size = vPC[4].u.operand;
4494 int breakTarget = vPC[5].u.operand;
4496 JSValue v = callFrame->r(base).jsValue();
4497 if (v.isUndefinedOrNull()) {
4502 JSObject* o = v.toObject(callFrame);
4503 Structure* structure = o->structure();
4504 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
4505 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
4506 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
4508 callFrame->uncheckedR(dst) = jsPropertyNameIterator;
4509 callFrame->uncheckedR(base) = JSValue(o);
4510 callFrame->uncheckedR(i) = Register::withInt(0);
4511 callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());
4512 vPC += OPCODE_LENGTH(op_get_pnames);
4515 DEFINE_OPCODE(op_next_pname) {
4516 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
4518 Copies the next name from the property name list in
4519 register iter to dst, then jumps to offset target. If there are no
4520 names left, invalidates the iterator and continues to the next
4523 int dst = vPC[1].u.operand;
4524 int base = vPC[2].u.operand;
4525 int i = vPC[3].u.operand;
4526 int size = vPC[4].u.operand;
4527 int iter = vPC[5].u.operand;
4528 int target = vPC[6].u.operand;
4530 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
4531 while (callFrame->r(i).i() != callFrame->r(size).i()) {
4532 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());
4533 CHECK_FOR_EXCEPTION();
4534 callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);
4536 CHECK_FOR_TIMEOUT();
4537 callFrame->uncheckedR(dst) = key;
4543 vPC += OPCODE_LENGTH(op_next_pname);
4546 DEFINE_OPCODE(op_jmp_scopes) {
4547 /* jmp_scopes count(n) target(offset)
4549 Removes the a number of items from the current scope chain
4550 specified by immediate number count, then jumps to offset
4553 int count = vPC[1].u.operand;
4554 int target = vPC[2].u.operand;
4556 ScopeChainNode* tmp = callFrame->scopeChain();
4559 callFrame->setScopeChain(tmp);
4564 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4566 goto *(&&skip_new_scope);
4568 DEFINE_OPCODE(op_push_new_scope) {
4569 /* new_scope dst(r) property(id) value(r)
4571 Constructs a new StaticScopeObject with property set to value. That scope
4572 object is then pushed onto the ScopeChain. The scope object is then stored
4575 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
4577 vPC += OPCODE_LENGTH(op_push_new_scope);
4580 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4583 DEFINE_OPCODE(op_catch) {
4586 Retrieves the VM's current exception and puts it in register
4587 ex. This is only valid after an exception has been raised,
4588 and usually forms the beginning of an exception handler.
4590 ASSERT(exceptionValue);
4591 ASSERT(!globalData->exception);
4592 int ex = vPC[1].u.operand;
4593 callFrame->uncheckedR(ex) = exceptionValue;
4594 exceptionValue = JSValue();
4596 vPC += OPCODE_LENGTH(op_catch);
4599 DEFINE_OPCODE(op_throw) {
4602 Throws register ex as an exception. This involves three
4603 steps: first, it is set as the current exception in the
4604 VM's internal state, then the stack is unwound until an
4605 exception handler or a native code boundary is found, and
4606 then control resumes at the exception handler if any or
4607 else the script returns control to the nearest native caller.
4610 int ex = vPC[1].u.operand;
4611 exceptionValue = callFrame->r(ex).jsValue();
4613 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
4615 return throwError(callFrame, exceptionValue);
4617 codeBlock = callFrame->codeBlock();
4618 vPC = codeBlock->instructions().begin() + handler->target;
4621 DEFINE_OPCODE(op_throw_reference_error) {
4622 /* op_throw_reference_error message(k)
4624 Constructs a new reference Error instance using the
4625 original constructor, using constant message as the
4626 message string. The result is thrown.
4628 UString message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame);
4629 exceptionValue = JSValue(createReferenceError(callFrame, message));
4632 DEFINE_OPCODE(op_end) {
4635 Return register result as the value of a global or eval
4636 program. Return control to the calling native code.
4639 int result = vPC[1].u.operand;
4640 return callFrame->r(result).jsValue();
4642 DEFINE_OPCODE(op_put_getter) {
4643 /* put_getter base(r) property(id) function(r)
4645 Sets register function on register base as the getter named
4646 by identifier property. Base and function are assumed to be
4647 objects as this op should only be used for getters defined
4648 in object literal form.
4650 Unlike many opcodes, this one does not write any output to
4653 int base = vPC[1].u.operand;
4654 int property = vPC[2].u.operand;
4655 int function = vPC[3].u.operand;
4657 ASSERT(callFrame->r(base).jsValue().isObject());
4658 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
4659 Identifier& ident = codeBlock->identifier(property);
4660 ASSERT(callFrame->r(function).jsValue().isObject());
4661 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
4663 vPC += OPCODE_LENGTH(op_put_getter);
4666 DEFINE_OPCODE(op_put_setter) {
4667 /* put_setter base(r) property(id) function(r)
4669 Sets register function on register base as the setter named
4670 by identifier property. Base and function are assumed to be
4671 objects as this op should only be used for setters defined
4672 in object literal form.
4674 Unlike many opcodes, this one does not write any output to
4677 int base = vPC[1].u.operand;
4678 int property = vPC[2].u.operand;
4679 int function = vPC[3].u.operand;
4681 ASSERT(callFrame->r(base).jsValue().isObject());
4682 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
4683 Identifier& ident = codeBlock->identifier(property);
4684 ASSERT(callFrame->r(function).jsValue().isObject());
4685 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0);
4687 vPC += OPCODE_LENGTH(op_put_setter);
4690 DEFINE_OPCODE(op_method_check) {
4694 DEFINE_OPCODE(op_jsr) {
4695 /* jsr retAddrDst(r) target(offset)
4697 Places the address of the next instruction into the retAddrDst
4698 register and jumps to offset target from the current instruction.
4700 int retAddrDst = vPC[1].u.operand;
4701 int target = vPC[2].u.operand;
4702 callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr);
4707 DEFINE_OPCODE(op_sret) {
4708 /* sret retAddrSrc(r)
4710 Jumps to the address stored in the retAddrSrc register. This
4711 differs from op_jmp because the target address is stored in a
4712 register, not as an immediate.
4714 int retAddrSrc = vPC[1].u.operand;
4715 vPC = callFrame->r(retAddrSrc).vPC();
4718 DEFINE_OPCODE(op_debug) {
4719 /* debug debugHookID(n) firstLine(n) lastLine(n)
4721 Notifies the debugger of the current state of execution. This opcode
4722 is only generated while the debugger is attached.
4724 int debugHookID = vPC[1].u.operand;
4725 int firstLine = vPC[2].u.operand;
4726 int lastLine = vPC[3].u.operand;
4728 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
4730 vPC += OPCODE_LENGTH(op_debug);
4733 DEFINE_OPCODE(op_profile_will_call) {
4734 /* op_profile_will_call function(r)
4736 Notifies the profiler of the beginning of a function call. This opcode
4737 is only generated if developer tools are enabled.
4739 int function = vPC[1].u.operand;
4741 if (*enabledProfilerReference)
4742 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue());
4744 vPC += OPCODE_LENGTH(op_profile_will_call);
4747 DEFINE_OPCODE(op_profile_did_call) {
4748 /* op_profile_did_call function(r)
4750 Notifies the profiler of the end of a function call. This opcode
4751 is only generated if developer tools are enabled.
4753 int function = vPC[1].u.operand;
4755 if (*enabledProfilerReference)
4756 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue());
4758 vPC += OPCODE_LENGTH(op_profile_did_call);
4762 globalData->exception = JSValue();
4764 // The exceptionValue is a lie! (GCC produces bad code for reasons I
4765 // cannot fathom if we don't assign to the exceptionValue before branching)
4766 exceptionValue = createInterruptedExecutionException(globalData);
4768 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
4769 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());
4771 // Can't use the callframe at this point as the scopechain, etc have
4773 return throwError(globalObject->globalExec(), exceptionValue);
4776 codeBlock = callFrame->codeBlock();
4777 vPC = codeBlock->instructions().begin() + handler->target;
4781 #if !ENABLE(COMPUTED_GOTO_INTERPRETER)
4782 } // iterator loop ends
4784 #undef NEXT_INSTRUCTION
4785 #undef DEFINE_OPCODE
4786 #undef CHECK_FOR_EXCEPTION
4787 #undef CHECK_FOR_TIMEOUT
4788 #endif // ENABLE(INTERPRETER)
4791 JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
4793 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4794 if (!functionCallFrame)
4797 CodeBlock* codeBlock = functionCallFrame->codeBlock();
4798 if (codeBlock->usesArguments()) {
4799 ASSERT(codeBlock->codeType() == FunctionCode);
4800 int argumentsRegister = codeBlock->argumentsRegister();
4801 int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
4802 if (JSValue arguments = functionCallFrame->uncheckedR(argumentsRegister).jsValue())
4804 JSValue arguments = JSValue(new (callFrame) Arguments(functionCallFrame));
4805 functionCallFrame->r(argumentsRegister) = arguments;
4806 functionCallFrame->r(realArgumentsRegister) = arguments;
4810 Arguments* arguments = new (functionCallFrame) Arguments(functionCallFrame);
4811 arguments->copyRegisters(functionCallFrame->globalData());
4815 JSValue Interpreter::retrieveCaller(CallFrame* callFrame, JSFunction* function) const
4817 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
4818 if (!functionCallFrame)
4821 CallFrame* callerFrame = functionCallFrame->callerFrame();
4822 if (callerFrame->hasHostCallFrameFlag())
4825 JSValue caller = callerFrame->callee();
4832 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
4834 function = JSValue();
4836 sourceURL = UString();
4838 CallFrame* callerFrame = callFrame->callerFrame();
4839 if (callerFrame->hasHostCallFrameFlag())
4842 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
4843 if (!callerCodeBlock)
4845 unsigned bytecodeOffset = 0;
4846 #if ENABLE(INTERPRETER)
4847 if (!callerFrame->globalData().canUseJIT())
4848 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
4851 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
4854 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
4856 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
4857 sourceID = callerCodeBlock->ownerExecutable()->sourceID();
4858 sourceURL = callerCodeBlock->ownerExecutable()->sourceURL();
4859 function = callerFrame->callee();
4862 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, JSFunction* function)
4864 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
4865 if (candidate->callee() == function)
4871 void Interpreter::enableSampler()
4873 #if ENABLE(OPCODE_SAMPLING)
4875 m_sampler.set(new SamplingTool(this));
4880 void Interpreter::dumpSampleData(ExecState* exec)
4882 #if ENABLE(OPCODE_SAMPLING)
4884 m_sampler->dump(exec);
4889 void Interpreter::startSampling()
4891 #if ENABLE(SAMPLING_THREAD)
4892 if (!m_sampleEntryDepth)
4893 SamplingThread::start();
4895 m_sampleEntryDepth++;
4898 void Interpreter::stopSampling()
4900 #if ENABLE(SAMPLING_THREAD)
4901 m_sampleEntryDepth--;
4902 if (!m_sampleEntryDepth)
4903 SamplingThread::stop();