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
.characters(), programSource
.length(), 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();
582 // Because of how the JIT records call site->bytecode offset
583 // information the JIT reports the bytecodeOffset for the returnPC
584 // to be at the beginning of the opcode that has caused the call.
585 // In the interpreter we have an actual return address, which is
586 // the beginning of next instruction to execute. To get an offset
587 // inside the call instruction that triggered the exception we
588 // have to subtract 1.
589 #if ENABLE(JIT) && ENABLE(INTERPRETER)
590 if (callerFrame
->globalData().canUseJIT())
591 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnPC());
593 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnVPC()) - 1;
595 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnPC());
597 bytecodeOffset
= codeBlock
->bytecodeOffset(callFrame
->returnVPC()) - 1;
600 callFrame
= callerFrame
;
604 static void appendSourceToError(CallFrame
* callFrame
, ErrorInstance
* exception
, unsigned bytecodeOffset
)
606 exception
->clearAppendSourceToMessage();
608 if (!callFrame
->codeBlock()->hasExpressionInfo())
615 CodeBlock
* codeBlock
= callFrame
->codeBlock();
616 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divotPoint
, startOffset
, endOffset
);
618 int expressionStart
= divotPoint
- startOffset
;
619 int expressionStop
= divotPoint
+ endOffset
;
621 if (!expressionStop
|| expressionStart
> codeBlock
->source()->length())
624 JSGlobalData
* globalData
= &callFrame
->globalData();
625 JSValue jsMessage
= exception
->getDirect(*globalData
, globalData
->propertyNames
->message
);
626 if (!jsMessage
|| !jsMessage
.isString())
629 UString message
= asString(jsMessage
)->value(callFrame
);
631 if (expressionStart
< expressionStop
)
632 message
= makeUString(message
, " (evaluating '", codeBlock
->source()->getRange(expressionStart
, expressionStop
), "')");
634 // No range information, so give a few characters of context
635 const UChar
* data
= codeBlock
->source()->data();
636 int dataLength
= codeBlock
->source()->length();
637 int start
= expressionStart
;
638 int stop
= expressionStart
;
639 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
640 // then strip whitespace.
641 while (start
> 0 && (expressionStart
- start
< 20) && data
[start
- 1] != '\n')
643 while (start
< (expressionStart
- 1) && isStrWhiteSpace(data
[start
]))
645 while (stop
< dataLength
&& (stop
- expressionStart
< 20) && data
[stop
] != '\n')
647 while (stop
> expressionStart
&& isStrWhiteSpace(data
[stop
- 1]))
649 message
= makeUString(message
, " (near '...", codeBlock
->source()->getRange(start
, stop
), "...')");
652 exception
->putDirect(*globalData
, globalData
->propertyNames
->message
, jsString(globalData
, message
));
655 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
)
657 CodeBlock
* codeBlock
= callFrame
->codeBlock();
658 bool isInterrupt
= false;
660 // Set up the exception object
661 if (exceptionValue
.isObject()) {
662 JSObject
* exception
= asObject(exceptionValue
);
664 if (exception
->isErrorInstance() && static_cast<ErrorInstance
*>(exception
)->appendSourceToMessage())
665 appendSourceToError(callFrame
, static_cast<ErrorInstance
*>(exception
), bytecodeOffset
);
667 // Using hasExpressionInfo to imply we are interested in rich exception info.
668 if (codeBlock
->hasExpressionInfo() && !hasErrorInfo(callFrame
, exception
)) {
669 ASSERT(codeBlock
->hasLineInfo());
671 // FIXME: should only really be adding these properties to VM generated exceptions,
672 // but the inspector currently requires these for all thrown objects.
673 addErrorInfo(callFrame
, exception
, codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), codeBlock
->ownerExecutable()->source());
676 ComplType exceptionType
= exception
->exceptionType();
677 isInterrupt
= exceptionType
== Interrupted
|| exceptionType
== Terminated
;
680 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
681 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
682 bool hasHandler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
683 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), hasHandler
);
686 // Calculate an exception handler vPC, unwinding call frames as necessary.
687 HandlerInfo
* handler
= 0;
688 while (isInterrupt
|| !(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
689 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
690 if (Profiler
* profiler
= *Profiler::enabledProfilerReference())
691 profiler
->exceptionUnwind(callFrame
);
696 if (Profiler
* profiler
= *Profiler::enabledProfilerReference())
697 profiler
->exceptionUnwind(callFrame
);
699 // Shrink the JS stack, in case stack overflow made it huge.
700 Register
* highWaterMark
= 0;
701 for (CallFrame
* callerFrame
= callFrame
; callerFrame
; callerFrame
= callerFrame
->callerFrame()->removeHostCallFrameFlag()) {
702 CodeBlock
* codeBlock
= callerFrame
->codeBlock();
705 Register
* callerHighWaterMark
= callerFrame
->registers() + codeBlock
->m_numCalleeRegisters
;
706 highWaterMark
= max(highWaterMark
, callerHighWaterMark
);
708 m_registerFile
.shrink(highWaterMark
);
710 // Unwind the scope chain within the exception handler's call frame.
711 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
713 if (!codeBlock
->needsFullScopeChain() || codeBlock
->codeType() != FunctionCode
714 || callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue())
715 scopeDelta
= depth(codeBlock
, scopeChain
) - handler
->scopeDepth
;
716 ASSERT(scopeDelta
>= 0);
718 scopeChain
= scopeChain
->pop();
719 callFrame
->setScopeChain(scopeChain
);
724 static inline JSValue
checkedReturn(JSValue returnValue
)
730 static inline JSObject
* checkedReturn(JSObject
* returnValue
)
736 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
)
738 ASSERT(!scopeChain
->globalData
->exception
);
739 ASSERT(!callFrame
->globalData().isCollectorBusy());
740 if (callFrame
->globalData().isCollectorBusy())
743 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
744 return checkedReturn(throwStackOverflowError(callFrame
));
746 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
747 LiteralParser
literalParser(callFrame
, program
->source().data(), program
->source().length(), LiteralParser::JSONP
);
748 Vector
<LiteralParser::JSONPData
> JSONPData
;
749 if (literalParser
.tryJSONPParse(JSONPData
, scopeChain
->globalObject
->supportsRichSourceInfo())) {
750 JSGlobalObject
* globalObject
= scopeChain
->globalObject
.get();
752 for (unsigned entry
= 0; entry
< JSONPData
.size(); entry
++) {
753 Vector
<LiteralParser::JSONPPathEntry
> JSONPPath
;
754 JSONPPath
.swap(JSONPData
[entry
].m_path
);
755 JSValue JSONPValue
= JSONPData
[entry
].m_value
.get();
756 if (JSONPPath
.size() == 1 && JSONPPath
[0].m_type
== LiteralParser::JSONPPathEntryTypeDeclare
) {
757 if (globalObject
->hasProperty(callFrame
, JSONPPath
[0].m_pathEntryName
)) {
758 PutPropertySlot slot
;
759 globalObject
->put(callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, slot
);
761 globalObject
->putWithAttributes(callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, DontEnum
| DontDelete
);
762 // var declarations return undefined
763 result
= jsUndefined();
766 JSValue
baseObject(globalObject
);
767 for (unsigned i
= 0; i
< JSONPPath
.size() - 1; i
++) {
768 ASSERT(JSONPPath
[i
].m_type
!= LiteralParser::JSONPPathEntryTypeDeclare
);
769 switch (JSONPPath
[i
].m_type
) {
770 case LiteralParser::JSONPPathEntryTypeDot
: {
772 PropertySlot
slot(globalObject
);
773 if (!globalObject
->getPropertySlot(callFrame
, JSONPPath
[i
].m_pathEntryName
, slot
)) {
775 return throwError(callFrame
, createUndefinedVariableError(globalObject
->globalExec(), JSONPPath
[i
].m_pathEntryName
));
778 baseObject
= slot
.getValue(callFrame
, JSONPPath
[i
].m_pathEntryName
);
780 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathEntryName
);
781 if (callFrame
->hadException())
782 return jsUndefined();
785 case LiteralParser::JSONPPathEntryTypeLookup
: {
786 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathIndex
);
787 if (callFrame
->hadException())
788 return jsUndefined();
792 ASSERT_NOT_REACHED();
793 return jsUndefined();
796 PutPropertySlot slot
;
797 switch (JSONPPath
.last().m_type
) {
798 case LiteralParser::JSONPPathEntryTypeCall
: {
799 JSValue function
= baseObject
.get(callFrame
, JSONPPath
.last().m_pathEntryName
);
800 if (callFrame
->hadException())
801 return jsUndefined();
803 CallType callType
= getCallData(function
, callData
);
804 if (callType
== CallTypeNone
)
805 return throwError(callFrame
, createNotAFunctionError(callFrame
, function
));
806 MarkedArgumentBuffer jsonArg
;
807 jsonArg
.append(JSONPValue
);
808 JSValue thisValue
= JSONPPath
.size() == 1 ? jsUndefined(): baseObject
;
809 JSONPValue
= JSC::call(callFrame
, function
, callType
, callData
, thisValue
, jsonArg
);
810 if (callFrame
->hadException())
811 return jsUndefined();
814 case LiteralParser::JSONPPathEntryTypeDot
: {
815 baseObject
.put(callFrame
, JSONPPath
.last().m_pathEntryName
, JSONPValue
, slot
);
816 if (callFrame
->hadException())
817 return jsUndefined();
820 case LiteralParser::JSONPPathEntryTypeLookup
: {
821 baseObject
.put(callFrame
, JSONPPath
.last().m_pathIndex
, JSONPValue
);
822 if (callFrame
->hadException())
823 return jsUndefined();
827 ASSERT_NOT_REACHED();
828 return jsUndefined();
835 JSObject
* error
= program
->compile(callFrame
, scopeChain
);
837 return checkedReturn(throwError(callFrame
, error
));
838 CodeBlock
* codeBlock
= &program
->generatedBytecode();
840 Register
* oldEnd
= m_registerFile
.end();
841 Register
* newEnd
= oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->m_numCalleeRegisters
;
842 if (!m_registerFile
.grow(newEnd
))
843 return checkedReturn(throwStackOverflowError(callFrame
));
845 JSGlobalObject
* lastGlobalObject
= m_registerFile
.globalObject();
846 JSGlobalObject
* globalObject
= callFrame
->dynamicGlobalObject();
847 globalObject
->copyGlobalsTo(m_registerFile
);
849 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
);
850 ASSERT(codeBlock
->m_numParameters
== 1); // 1 parameter for 'this'.
851 newCallFrame
->init(codeBlock
, 0, scopeChain
, CallFrame::noCaller(), codeBlock
->m_numParameters
, 0);
852 newCallFrame
->uncheckedR(newCallFrame
->hostThisRegister()) = JSValue(thisObj
);
854 Profiler
** profiler
= Profiler::enabledProfilerReference();
856 (*profiler
)->willExecute(callFrame
, program
->sourceURL(), program
->lineNo());
860 SamplingTool::CallRecord
callRecord(m_sampler
.get());
864 if (callFrame
->globalData().canUseJIT())
865 result
= program
->generatedJITCode().execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
);
868 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
874 (*profiler
)->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
876 if (m_reentryDepth
&& lastGlobalObject
&& globalObject
!= lastGlobalObject
)
877 lastGlobalObject
->copyGlobalsTo(m_registerFile
);
879 m_registerFile
.shrink(oldEnd
);
881 return checkedReturn(result
);
884 JSValue
Interpreter::executeCall(CallFrame
* callFrame
, JSObject
* function
, CallType callType
, const CallData
& callData
, JSValue thisValue
, const ArgList
& args
)
886 ASSERT(!callFrame
->hadException());
887 ASSERT(!callFrame
->globalData().isCollectorBusy());
888 if (callFrame
->globalData().isCollectorBusy())
891 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
892 return checkedReturn(throwStackOverflowError(callFrame
));
894 Register
* oldEnd
= m_registerFile
.end();
895 int argCount
= 1 + args
.size(); // implicit "this" parameter
896 size_t registerOffset
= argCount
+ RegisterFile::CallFrameHeaderSize
;
898 if (!m_registerFile
.grow(oldEnd
+ registerOffset
))
899 return checkedReturn(throwStackOverflowError(callFrame
));
901 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
903 newCallFrame
->uncheckedR(0) = thisValue
;
904 ArgList::const_iterator end
= args
.end();
905 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
906 newCallFrame
->uncheckedR(++dst
) = *it
;
908 if (callType
== CallTypeJS
) {
909 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
911 DynamicGlobalObjectScope
globalObjectScope(*callDataScopeChain
->globalData
, callDataScopeChain
->globalObject
.get());
913 JSObject
* compileError
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
914 if (UNLIKELY(!!compileError
)) {
915 m_registerFile
.shrink(oldEnd
);
916 return checkedReturn(throwError(callFrame
, compileError
));
919 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
920 newCallFrame
= slideRegisterWindowForCall(newCodeBlock
, &m_registerFile
, newCallFrame
, registerOffset
, argCount
);
921 if (UNLIKELY(!newCallFrame
)) {
922 m_registerFile
.shrink(oldEnd
);
923 return checkedReturn(throwStackOverflowError(callFrame
));
926 newCallFrame
->init(newCodeBlock
, 0, callDataScopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, function
);
928 Profiler
** profiler
= Profiler::enabledProfilerReference();
930 (*profiler
)->willExecute(callFrame
, function
);
934 SamplingTool::CallRecord
callRecord(m_sampler
.get());
938 if (callFrame
->globalData().canUseJIT())
939 result
= callData
.js
.functionExecutable
->generatedJITCodeForCall().execute(&m_registerFile
, newCallFrame
, callDataScopeChain
->globalData
);
942 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
947 (*profiler
)->didExecute(callFrame
, function
);
949 m_registerFile
.shrink(oldEnd
);
950 return checkedReturn(result
);
953 ASSERT(callType
== CallTypeHost
);
954 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
955 newCallFrame
= CallFrame::create(newCallFrame
->registers() + registerOffset
);
956 newCallFrame
->init(0, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, function
);
958 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
960 Profiler
** profiler
= Profiler::enabledProfilerReference();
962 (*profiler
)->willExecute(callFrame
, function
);
966 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
967 result
= JSValue::decode(callData
.native
.function(newCallFrame
));
971 (*profiler
)->didExecute(callFrame
, function
);
973 m_registerFile
.shrink(oldEnd
);
974 return checkedReturn(result
);
977 JSObject
* Interpreter::executeConstruct(CallFrame
* callFrame
, JSObject
* constructor
, ConstructType constructType
, const ConstructData
& constructData
, const ArgList
& args
)
979 ASSERT(!callFrame
->hadException());
980 ASSERT(!callFrame
->globalData().isCollectorBusy());
981 // We throw in this case because we have to return something "valid" but we're
982 // already in an invalid state.
983 if (callFrame
->globalData().isCollectorBusy())
984 return checkedReturn(throwStackOverflowError(callFrame
));
986 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
987 return checkedReturn(throwStackOverflowError(callFrame
));
989 Register
* oldEnd
= m_registerFile
.end();
990 int argCount
= 1 + args
.size(); // implicit "this" parameter
991 size_t registerOffset
= argCount
+ RegisterFile::CallFrameHeaderSize
;
993 if (!m_registerFile
.grow(oldEnd
+ registerOffset
))
994 return checkedReturn(throwStackOverflowError(callFrame
));
996 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
998 ArgList::const_iterator end
= args
.end();
999 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
1000 newCallFrame
->uncheckedR(++dst
) = *it
;
1002 if (constructType
== ConstructTypeJS
) {
1003 ScopeChainNode
* constructDataScopeChain
= constructData
.js
.scopeChain
;
1005 DynamicGlobalObjectScope
globalObjectScope(*constructDataScopeChain
->globalData
, constructDataScopeChain
->globalObject
.get());
1007 JSObject
* compileError
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, constructDataScopeChain
);
1008 if (UNLIKELY(!!compileError
)) {
1009 m_registerFile
.shrink(oldEnd
);
1010 return checkedReturn(throwError(callFrame
, compileError
));
1013 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
1014 newCallFrame
= slideRegisterWindowForCall(newCodeBlock
, &m_registerFile
, newCallFrame
, registerOffset
, argCount
);
1015 if (UNLIKELY(!newCallFrame
)) {
1016 m_registerFile
.shrink(oldEnd
);
1017 return checkedReturn(throwStackOverflowError(callFrame
));
1020 newCallFrame
->init(newCodeBlock
, 0, constructDataScopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, constructor
);
1022 Profiler
** profiler
= Profiler::enabledProfilerReference();
1024 (*profiler
)->willExecute(callFrame
, constructor
);
1028 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1032 if (callFrame
->globalData().canUseJIT())
1033 result
= constructData
.js
.functionExecutable
->generatedJITCodeForConstruct().execute(&m_registerFile
, newCallFrame
, constructDataScopeChain
->globalData
);
1036 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1041 (*profiler
)->didExecute(callFrame
, constructor
);
1043 m_registerFile
.shrink(oldEnd
);
1044 if (callFrame
->hadException())
1046 ASSERT(result
.isObject());
1047 return checkedReturn(asObject(result
));
1050 ASSERT(constructType
== ConstructTypeHost
);
1051 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1052 newCallFrame
= CallFrame::create(newCallFrame
->registers() + registerOffset
);
1053 newCallFrame
->init(0, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argCount
, constructor
);
1055 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1057 Profiler
** profiler
= Profiler::enabledProfilerReference();
1059 (*profiler
)->willExecute(callFrame
, constructor
);
1063 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
1064 result
= JSValue::decode(constructData
.native
.function(newCallFrame
));
1068 (*profiler
)->didExecute(callFrame
, constructor
);
1070 m_registerFile
.shrink(oldEnd
);
1071 if (callFrame
->hadException())
1073 ASSERT(result
.isObject());
1074 return checkedReturn(asObject(result
));
1077 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* FunctionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argCount
, ScopeChainNode
* scopeChain
)
1079 ASSERT(!scopeChain
->globalData
->exception
);
1081 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
) {
1082 if (m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
) {
1083 throwStackOverflowError(callFrame
);
1084 return CallFrameClosure();
1088 Register
* oldEnd
= m_registerFile
.end();
1089 int argc
= 1 + argCount
; // implicit "this" parameter
1091 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
1092 throwStackOverflowError(callFrame
);
1093 return CallFrameClosure();
1096 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
1097 // We initialise |this| unnecessarily here for the sake of code clarity
1099 for (int i
= 0; i
< argc
; ++i
)
1100 newCallFrame
->uncheckedR(dst
++) = jsUndefined();
1102 JSObject
* error
= FunctionExecutable
->compileForCall(callFrame
, scopeChain
);
1104 throwError(callFrame
, error
);
1105 m_registerFile
.shrink(oldEnd
);
1106 return CallFrameClosure();
1108 CodeBlock
* codeBlock
= &FunctionExecutable
->generatedBytecodeForCall();
1110 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
1111 if (UNLIKELY(!newCallFrame
)) {
1112 throwStackOverflowError(callFrame
);
1113 m_registerFile
.shrink(oldEnd
);
1114 return CallFrameClosure();
1116 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), argc
, function
);
1117 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, FunctionExecutable
, scopeChain
->globalData
, oldEnd
, scopeChain
, codeBlock
->m_numParameters
, argc
};
1121 JSValue
Interpreter::execute(CallFrameClosure
& closure
)
1123 ASSERT(!closure
.oldCallFrame
->globalData().isCollectorBusy());
1124 if (closure
.oldCallFrame
->globalData().isCollectorBusy())
1126 closure
.resetCallFrame();
1127 Profiler
** profiler
= Profiler::enabledProfilerReference();
1129 (*profiler
)->willExecute(closure
.oldCallFrame
, closure
.function
);
1133 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1137 #if ENABLE(INTERPRETER)
1138 if (closure
.newCallFrame
->globalData().canUseJIT())
1140 result
= closure
.functionExecutable
->generatedJITCodeForCall().execute(&m_registerFile
, closure
.newCallFrame
, closure
.globalData
);
1141 #if ENABLE(INTERPRETER)
1145 #if ENABLE(INTERPRETER)
1146 result
= privateExecute(Normal
, &m_registerFile
, closure
.newCallFrame
);
1152 (*profiler
)->didExecute(closure
.oldCallFrame
, closure
.function
);
1153 return checkedReturn(result
);
1156 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
1158 m_registerFile
.shrink(closure
.oldEnd
);
1161 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, ScopeChainNode
* scopeChain
)
1163 JSObject
* compileError
= eval
->compile(callFrame
, scopeChain
);
1164 if (UNLIKELY(!!compileError
))
1165 return checkedReturn(throwError(callFrame
, compileError
));
1166 return execute(eval
, callFrame
, thisObj
, m_registerFile
.size() + eval
->generatedBytecode().m_numParameters
+ RegisterFile::CallFrameHeaderSize
, scopeChain
);
1169 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, int globalRegisterOffset
, ScopeChainNode
* scopeChain
)
1171 ASSERT(!scopeChain
->globalData
->exception
);
1172 ASSERT(!callFrame
->globalData().isCollectorBusy());
1173 if (callFrame
->globalData().isCollectorBusy())
1176 DynamicGlobalObjectScope
globalObjectScope(*scopeChain
->globalData
, scopeChain
->globalObject
.get());
1178 if (m_reentryDepth
>= MaxSmallThreadReentryDepth
&& m_reentryDepth
>= callFrame
->globalData().maxReentryDepth
)
1179 return checkedReturn(throwStackOverflowError(callFrame
));
1181 JSObject
* compileError
= eval
->compile(callFrame
, scopeChain
);
1182 if (UNLIKELY(!!compileError
))
1183 return checkedReturn(throwError(callFrame
, compileError
));
1184 EvalCodeBlock
* codeBlock
= &eval
->generatedBytecode();
1186 JSObject
* variableObject
;
1187 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
.get()) {
1189 if (node
->object
->isVariableObject()) {
1190 variableObject
= static_cast<JSVariableObject
*>(node
->object
.get());
1195 unsigned numVariables
= codeBlock
->numVariables();
1196 int numFunctions
= codeBlock
->numberOfFunctionDecls();
1197 bool pushedScope
= false;
1198 if (numVariables
|| numFunctions
) {
1199 if (codeBlock
->isStrictMode()) {
1200 variableObject
= new (callFrame
) StrictEvalActivation(callFrame
);
1201 scopeChain
= scopeChain
->push(variableObject
);
1204 // Scope for BatchedTransitionOptimizer
1205 BatchedTransitionOptimizer
optimizer(callFrame
->globalData(), variableObject
);
1207 for (unsigned i
= 0; i
< numVariables
; ++i
) {
1208 const Identifier
& ident
= codeBlock
->variable(i
);
1209 if (!variableObject
->hasProperty(callFrame
, ident
)) {
1210 PutPropertySlot slot
;
1211 variableObject
->put(callFrame
, ident
, jsUndefined(), slot
);
1215 for (int i
= 0; i
< numFunctions
; ++i
) {
1216 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
1217 PutPropertySlot slot
;
1218 variableObject
->put(callFrame
, function
->name(), function
->make(callFrame
, scopeChain
), slot
);
1222 Register
* oldEnd
= m_registerFile
.end();
1223 Register
* newEnd
= m_registerFile
.start() + globalRegisterOffset
+ codeBlock
->m_numCalleeRegisters
;
1224 if (!m_registerFile
.grow(newEnd
)) {
1227 return checkedReturn(throwStackOverflowError(callFrame
));
1230 CallFrame
* newCallFrame
= CallFrame::create(m_registerFile
.start() + globalRegisterOffset
);
1232 ASSERT(codeBlock
->m_numParameters
== 1); // 1 parameter for 'this'.
1233 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), codeBlock
->m_numParameters
, 0);
1234 newCallFrame
->uncheckedR(newCallFrame
->hostThisRegister()) = JSValue(thisObj
);
1236 Profiler
** profiler
= Profiler::enabledProfilerReference();
1238 (*profiler
)->willExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1242 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1247 #if ENABLE(INTERPRETER)
1248 if (callFrame
->globalData().canUseJIT())
1250 result
= eval
->generatedJITCode().execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
);
1251 #if ENABLE(INTERPRETER)
1255 #if ENABLE(INTERPRETER)
1256 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
);
1262 (*profiler
)->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1264 m_registerFile
.shrink(oldEnd
);
1267 return checkedReturn(result
);
1270 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
)
1272 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
1276 switch (debugHookID
) {
1277 case DidEnterCallFrame
:
1278 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1280 case WillLeaveCallFrame
:
1281 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1283 case WillExecuteStatement
:
1284 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1286 case WillExecuteProgram
:
1287 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
1289 case DidExecuteProgram
:
1290 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1292 case DidReachBreakpoint
:
1293 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
1298 #if ENABLE(INTERPRETER)
1299 NEVER_INLINE ScopeChainNode
* Interpreter::createExceptionScope(CallFrame
* callFrame
, const Instruction
* vPC
)
1301 int dst
= vPC
[1].u
.operand
;
1302 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1303 Identifier
& property
= codeBlock
->identifier(vPC
[2].u
.operand
);
1304 JSValue value
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1305 JSObject
* scope
= new (callFrame
) JSStaticScopeObject(callFrame
, property
, value
, DontDelete
);
1306 callFrame
->uncheckedR(dst
) = JSValue(scope
);
1308 return callFrame
->scopeChain()->push(scope
);
1311 NEVER_INLINE
void Interpreter::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const PutPropertySlot
& slot
)
1313 // Recursive invocation may already have specialized this instruction.
1314 if (vPC
[0].u
.opcode
!= getOpcode(op_put_by_id
))
1317 if (!baseValue
.isCell())
1320 // Uncacheable: give up.
1321 if (!slot
.isCacheable()) {
1322 vPC
[0] = getOpcode(op_put_by_id_generic
);
1326 JSCell
* baseCell
= baseValue
.asCell();
1327 Structure
* structure
= baseCell
->structure();
1329 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
1330 vPC
[0] = getOpcode(op_put_by_id_generic
);
1334 // Cache miss: record Structure to compare against next time.
1335 Structure
* lastStructure
= vPC
[4].u
.structure
.get();
1336 if (structure
!= lastStructure
) {
1337 // First miss: record Structure to compare against next time.
1338 if (!lastStructure
) {
1339 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1343 // Second miss: give up.
1344 vPC
[0] = getOpcode(op_put_by_id_generic
);
1348 // Cache hit: Specialize instruction and ref Structures.
1350 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1351 if (baseCell
!= slot
.base()) {
1352 vPC
[0] = getOpcode(op_put_by_id_generic
);
1356 // Structure transition, cache transition info
1357 if (slot
.type() == PutPropertySlot::NewProperty
) {
1358 if (structure
->isDictionary()) {
1359 vPC
[0] = getOpcode(op_put_by_id_generic
);
1363 // put_by_id_transition checks the prototype chain for setters.
1364 normalizePrototypeChain(callFrame
, baseCell
);
1365 JSCell
* owner
= codeBlock
->ownerExecutable();
1366 JSGlobalData
& globalData
= callFrame
->globalData();
1367 // Get the prototype here because the call to prototypeChain could cause a
1368 // GC allocation, which we don't want to happen while we're in the middle of
1369 // initializing the union.
1370 StructureChain
* prototypeChain
= structure
->prototypeChain(callFrame
);
1371 vPC
[0] = getOpcode(op_put_by_id_transition
);
1372 vPC
[4].u
.structure
.set(globalData
, owner
, structure
->previousID());
1373 vPC
[5].u
.structure
.set(globalData
, owner
, structure
);
1374 vPC
[6].u
.structureChain
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), prototypeChain
);
1375 ASSERT(vPC
[6].u
.structureChain
);
1376 vPC
[7] = slot
.cachedOffset();
1380 vPC
[0] = getOpcode(op_put_by_id_replace
);
1381 vPC
[5] = slot
.cachedOffset();
1384 NEVER_INLINE
void Interpreter::uncachePutByID(CodeBlock
*, Instruction
* vPC
)
1386 vPC
[0] = getOpcode(op_put_by_id
);
1390 NEVER_INLINE
void Interpreter::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
)
1392 // Recursive invocation may already have specialized this instruction.
1393 if (vPC
[0].u
.opcode
!= getOpcode(op_get_by_id
))
1396 // FIXME: Cache property access for immediates.
1397 if (!baseValue
.isCell()) {
1398 vPC
[0] = getOpcode(op_get_by_id_generic
);
1402 JSGlobalData
* globalData
= &callFrame
->globalData();
1403 if (isJSArray(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1404 vPC
[0] = getOpcode(op_get_array_length
);
1408 if (isJSString(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
1409 vPC
[0] = getOpcode(op_get_string_length
);
1413 // Uncacheable: give up.
1414 if (!slot
.isCacheable()) {
1415 vPC
[0] = getOpcode(op_get_by_id_generic
);
1419 Structure
* structure
= baseValue
.asCell()->structure();
1421 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
1422 vPC
[0] = getOpcode(op_get_by_id_generic
);
1427 Structure
* lastStructure
= vPC
[4].u
.structure
.get();
1428 if (structure
!= lastStructure
) {
1429 // First miss: record Structure to compare against next time.
1430 if (!lastStructure
) {
1431 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1435 // Second miss: give up.
1436 vPC
[0] = getOpcode(op_get_by_id_generic
);
1440 // Cache hit: Specialize instruction and ref Structures.
1442 if (slot
.slotBase() == baseValue
) {
1443 switch (slot
.cachedPropertyType()) {
1444 case PropertySlot::Getter
:
1445 vPC
[0] = getOpcode(op_get_by_id_getter_self
);
1446 vPC
[5] = slot
.cachedOffset();
1448 case PropertySlot::Custom
:
1449 vPC
[0] = getOpcode(op_get_by_id_custom_self
);
1450 vPC
[5] = slot
.customGetter();
1453 vPC
[0] = getOpcode(op_get_by_id_self
);
1454 vPC
[5] = slot
.cachedOffset();
1460 if (structure
->isDictionary()) {
1461 vPC
[0] = getOpcode(op_get_by_id_generic
);
1465 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1466 ASSERT(slot
.slotBase().isObject());
1468 JSObject
* baseObject
= asObject(slot
.slotBase());
1469 size_t offset
= slot
.cachedOffset();
1471 // Since we're accessing a prototype in a loop, it's a good bet that it
1472 // should not be treated as a dictionary.
1473 if (baseObject
->structure()->isDictionary()) {
1474 baseObject
->flattenDictionaryObject(callFrame
->globalData());
1475 offset
= baseObject
->structure()->get(callFrame
->globalData(), propertyName
);
1478 ASSERT(!baseObject
->structure()->isUncacheableDictionary());
1480 switch (slot
.cachedPropertyType()) {
1481 case PropertySlot::Getter
:
1482 vPC
[0] = getOpcode(op_get_by_id_getter_proto
);
1485 case PropertySlot::Custom
:
1486 vPC
[0] = getOpcode(op_get_by_id_custom_proto
);
1487 vPC
[6] = slot
.customGetter();
1490 vPC
[0] = getOpcode(op_get_by_id_proto
);
1494 vPC
[5].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), baseObject
->structure());
1498 size_t offset
= slot
.cachedOffset();
1499 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
1501 vPC
[0] = getOpcode(op_get_by_id_generic
);
1506 switch (slot
.cachedPropertyType()) {
1507 case PropertySlot::Getter
:
1508 vPC
[0] = getOpcode(op_get_by_id_getter_chain
);
1511 case PropertySlot::Custom
:
1512 vPC
[0] = getOpcode(op_get_by_id_custom_chain
);
1513 vPC
[7] = slot
.customGetter();
1516 vPC
[0] = getOpcode(op_get_by_id_chain
);
1520 vPC
[4].u
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
1521 vPC
[5].u
.structureChain
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
->prototypeChain(callFrame
));
1525 NEVER_INLINE
void Interpreter::uncacheGetByID(CodeBlock
*, Instruction
* vPC
)
1527 vPC
[0] = getOpcode(op_get_by_id
);
1531 #endif // ENABLE(INTERPRETER)
1533 JSValue
Interpreter::privateExecute(ExecutionFlag flag
, RegisterFile
* registerFile
, CallFrame
* callFrame
)
1535 // One-time initialization of our address tables. We have to put this code
1536 // here because our labels are only in scope inside this function.
1537 if (UNLIKELY(flag
== InitializeAndReturn
)) {
1538 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1539 #define LIST_OPCODE_LABEL(id, length) &&id,
1540 static Opcode labels
[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL
) };
1541 for (size_t i
= 0; i
< WTF_ARRAY_LENGTH(labels
); ++i
)
1542 m_opcodeTable
[i
] = labels
[i
];
1543 #undef LIST_OPCODE_LABEL
1544 #endif // ENABLE(COMPUTED_GOTO_INTERPRETER)
1549 #if ENABLE(INTERPRETER)
1550 // Mixing Interpreter + JIT is not supported.
1551 if (callFrame
->globalData().canUseJIT())
1553 ASSERT_NOT_REACHED();
1556 #if !ENABLE(INTERPRETER)
1557 UNUSED_PARAM(registerFile
);
1558 UNUSED_PARAM(callFrame
);
1562 JSGlobalData
* globalData
= &callFrame
->globalData();
1563 JSValue exceptionValue
;
1564 HandlerInfo
* handler
= 0;
1566 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1567 Instruction
* vPC
= codeBlock
->instructions().begin();
1568 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1569 unsigned tickCount
= globalData
->timeoutChecker
.ticksUntilNextCheck();
1570 JSValue functionReturnValue
;
1572 #define CHECK_FOR_EXCEPTION() \
1574 if (UNLIKELY(globalData->exception != JSValue())) { \
1575 exceptionValue = globalData->exception; \
1580 #if ENABLE(OPCODE_STATS)
1581 OpcodeStats::resetLastInstruction();
1584 #define CHECK_FOR_TIMEOUT() \
1585 if (!--tickCount) { \
1586 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \
1587 exceptionValue = jsNull(); \
1590 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1593 #if ENABLE(OPCODE_SAMPLING)
1594 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1596 #define SAMPLE(codeBlock, vPC)
1599 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
1600 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode
1601 #if ENABLE(OPCODE_STATS)
1602 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1604 #define DEFINE_OPCODE(opcode) opcode:
1608 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart
1609 #if ENABLE(OPCODE_STATS)
1610 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1612 #define DEFINE_OPCODE(opcode) case opcode:
1614 while (1) { // iterator loop begins
1615 interpreterLoopStart
:;
1616 switch (vPC
->u
.opcode
)
1619 DEFINE_OPCODE(op_new_object
) {
1620 /* new_object dst(r)
1622 Constructs a new empty Object instance using the original
1623 constructor, and puts the result in register dst.
1625 int dst
= vPC
[1].u
.operand
;
1626 callFrame
->uncheckedR(dst
) = JSValue(constructEmptyObject(callFrame
));
1628 vPC
+= OPCODE_LENGTH(op_new_object
);
1631 DEFINE_OPCODE(op_new_array
) {
1632 /* new_array dst(r) firstArg(r) argCount(n)
1634 Constructs a new Array instance using the original
1635 constructor, and puts the result in register dst.
1636 The array will contain argCount elements with values
1637 taken from registers starting at register firstArg.
1639 int dst
= vPC
[1].u
.operand
;
1640 int firstArg
= vPC
[2].u
.operand
;
1641 int argCount
= vPC
[3].u
.operand
;
1642 ArgList
args(callFrame
->registers() + firstArg
, argCount
);
1643 callFrame
->uncheckedR(dst
) = JSValue(constructArray(callFrame
, args
));
1645 vPC
+= OPCODE_LENGTH(op_new_array
);
1648 DEFINE_OPCODE(op_new_array_buffer
) {
1649 /* new_array_buffer dst(r) index(n) argCount(n)
1651 Constructs a new Array instance using the original
1652 constructor, and puts the result in register dst.
1653 The array be initialized with the values from constantBuffer[index]
1655 int dst
= vPC
[1].u
.operand
;
1656 int firstArg
= vPC
[2].u
.operand
;
1657 int argCount
= vPC
[3].u
.operand
;
1658 ArgList
args(codeBlock
->constantBuffer(firstArg
), argCount
);
1659 callFrame
->uncheckedR(dst
) = JSValue(constructArray(callFrame
, args
));
1661 vPC
+= OPCODE_LENGTH(op_new_array
);
1664 DEFINE_OPCODE(op_new_regexp
) {
1665 /* new_regexp dst(r) regExp(re)
1667 Constructs a new RegExp instance using the original
1668 constructor from regexp regExp, and puts the result in
1671 int dst
= vPC
[1].u
.operand
;
1672 RegExp
* regExp
= codeBlock
->regexp(vPC
[2].u
.operand
);
1673 if (!regExp
->isValid()) {
1674 exceptionValue
= createSyntaxError(callFrame
, "Invalid flags supplied to RegExp constructor.");
1677 callFrame
->uncheckedR(dst
) = JSValue(new (globalData
) RegExpObject(callFrame
->lexicalGlobalObject(), callFrame
->scopeChain()->globalObject
->regExpStructure(), regExp
));
1679 vPC
+= OPCODE_LENGTH(op_new_regexp
);
1682 DEFINE_OPCODE(op_mov
) {
1683 /* mov dst(r) src(r)
1685 Copies register src to register dst.
1687 int dst
= vPC
[1].u
.operand
;
1688 int src
= vPC
[2].u
.operand
;
1690 callFrame
->uncheckedR(dst
) = callFrame
->r(src
);
1692 vPC
+= OPCODE_LENGTH(op_mov
);
1695 DEFINE_OPCODE(op_eq
) {
1696 /* eq dst(r) src1(r) src2(r)
1698 Checks whether register src1 and register src2 are equal,
1699 as with the ECMAScript '==' operator, and puts the result
1700 as a boolean in register dst.
1702 int dst
= vPC
[1].u
.operand
;
1703 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1704 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1705 if (src1
.isInt32() && src2
.isInt32())
1706 callFrame
->uncheckedR(dst
) = jsBoolean(src1
.asInt32() == src2
.asInt32());
1708 JSValue result
= jsBoolean(JSValue::equalSlowCase(callFrame
, src1
, src2
));
1709 CHECK_FOR_EXCEPTION();
1710 callFrame
->uncheckedR(dst
) = result
;
1713 vPC
+= OPCODE_LENGTH(op_eq
);
1716 DEFINE_OPCODE(op_eq_null
) {
1717 /* eq_null dst(r) src(r)
1719 Checks whether register src is null, as with the ECMAScript '!='
1720 operator, and puts the result as a boolean in register dst.
1722 int dst
= vPC
[1].u
.operand
;
1723 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1725 if (src
.isUndefinedOrNull()) {
1726 callFrame
->uncheckedR(dst
) = jsBoolean(true);
1727 vPC
+= OPCODE_LENGTH(op_eq_null
);
1731 callFrame
->uncheckedR(dst
) = jsBoolean(src
.isCell() && src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1732 vPC
+= OPCODE_LENGTH(op_eq_null
);
1735 DEFINE_OPCODE(op_neq
) {
1736 /* neq dst(r) src1(r) src2(r)
1738 Checks whether register src1 and register src2 are not
1739 equal, as with the ECMAScript '!=' operator, and puts the
1740 result as a boolean in register dst.
1742 int dst
= vPC
[1].u
.operand
;
1743 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1744 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1745 if (src1
.isInt32() && src2
.isInt32())
1746 callFrame
->uncheckedR(dst
) = jsBoolean(src1
.asInt32() != src2
.asInt32());
1748 JSValue result
= jsBoolean(!JSValue::equalSlowCase(callFrame
, src1
, src2
));
1749 CHECK_FOR_EXCEPTION();
1750 callFrame
->uncheckedR(dst
) = result
;
1753 vPC
+= OPCODE_LENGTH(op_neq
);
1756 DEFINE_OPCODE(op_neq_null
) {
1757 /* neq_null dst(r) src(r)
1759 Checks whether register src is not null, as with the ECMAScript '!='
1760 operator, and puts the result as a boolean in register dst.
1762 int dst
= vPC
[1].u
.operand
;
1763 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1765 if (src
.isUndefinedOrNull()) {
1766 callFrame
->uncheckedR(dst
) = jsBoolean(false);
1767 vPC
+= OPCODE_LENGTH(op_neq_null
);
1771 callFrame
->uncheckedR(dst
) = jsBoolean(!src
.isCell() || !src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1772 vPC
+= OPCODE_LENGTH(op_neq_null
);
1775 DEFINE_OPCODE(op_stricteq
) {
1776 /* stricteq dst(r) src1(r) src2(r)
1778 Checks whether register src1 and register src2 are strictly
1779 equal, as with the ECMAScript '===' operator, and puts the
1780 result as a boolean in register dst.
1782 int dst
= vPC
[1].u
.operand
;
1783 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1784 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1785 bool result
= JSValue::strictEqual(callFrame
, src1
, src2
);
1786 CHECK_FOR_EXCEPTION();
1787 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
1789 vPC
+= OPCODE_LENGTH(op_stricteq
);
1792 DEFINE_OPCODE(op_nstricteq
) {
1793 /* nstricteq dst(r) src1(r) src2(r)
1795 Checks whether register src1 and register src2 are not
1796 strictly equal, as with the ECMAScript '!==' operator, and
1797 puts the result as a boolean in register dst.
1799 int dst
= vPC
[1].u
.operand
;
1800 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1801 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1802 bool result
= !JSValue::strictEqual(callFrame
, src1
, src2
);
1803 CHECK_FOR_EXCEPTION();
1804 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
1806 vPC
+= OPCODE_LENGTH(op_nstricteq
);
1809 DEFINE_OPCODE(op_less
) {
1810 /* less dst(r) src1(r) src2(r)
1812 Checks whether register src1 is less than register src2, as
1813 with the ECMAScript '<' operator, and puts the result as
1814 a boolean in register dst.
1816 int dst
= vPC
[1].u
.operand
;
1817 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1818 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1819 JSValue result
= jsBoolean(jsLess(callFrame
, src1
, src2
));
1820 CHECK_FOR_EXCEPTION();
1821 callFrame
->uncheckedR(dst
) = result
;
1823 vPC
+= OPCODE_LENGTH(op_less
);
1826 DEFINE_OPCODE(op_lesseq
) {
1827 /* lesseq dst(r) src1(r) src2(r)
1829 Checks whether register src1 is less than or equal to
1830 register src2, as with the ECMAScript '<=' operator, and
1831 puts the result as a boolean in register dst.
1833 int dst
= vPC
[1].u
.operand
;
1834 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1835 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1836 JSValue result
= jsBoolean(jsLessEq(callFrame
, src1
, src2
));
1837 CHECK_FOR_EXCEPTION();
1838 callFrame
->uncheckedR(dst
) = result
;
1840 vPC
+= OPCODE_LENGTH(op_lesseq
);
1843 DEFINE_OPCODE(op_pre_inc
) {
1844 /* pre_inc srcDst(r)
1846 Converts register srcDst to number, adds one, and puts the result
1847 back in register srcDst.
1849 int srcDst
= vPC
[1].u
.operand
;
1850 JSValue v
= callFrame
->r(srcDst
).jsValue();
1851 if (v
.isInt32() && v
.asInt32() < INT_MAX
)
1852 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() + 1);
1854 JSValue result
= jsNumber(v
.toNumber(callFrame
) + 1);
1855 CHECK_FOR_EXCEPTION();
1856 callFrame
->uncheckedR(srcDst
) = result
;
1859 vPC
+= OPCODE_LENGTH(op_pre_inc
);
1862 DEFINE_OPCODE(op_pre_dec
) {
1863 /* pre_dec srcDst(r)
1865 Converts register srcDst to number, subtracts one, and puts the result
1866 back in register srcDst.
1868 int srcDst
= vPC
[1].u
.operand
;
1869 JSValue v
= callFrame
->r(srcDst
).jsValue();
1870 if (v
.isInt32() && v
.asInt32() > INT_MIN
)
1871 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() - 1);
1873 JSValue result
= jsNumber(v
.toNumber(callFrame
) - 1);
1874 CHECK_FOR_EXCEPTION();
1875 callFrame
->uncheckedR(srcDst
) = result
;
1878 vPC
+= OPCODE_LENGTH(op_pre_dec
);
1881 DEFINE_OPCODE(op_post_inc
) {
1882 /* post_inc dst(r) srcDst(r)
1884 Converts register srcDst to number. The number itself is
1885 written to register dst, and the number plus one is written
1886 back to register srcDst.
1888 int dst
= vPC
[1].u
.operand
;
1889 int srcDst
= vPC
[2].u
.operand
;
1890 JSValue v
= callFrame
->r(srcDst
).jsValue();
1891 if (v
.isInt32() && v
.asInt32() < INT_MAX
) {
1892 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() + 1);
1893 callFrame
->uncheckedR(dst
) = v
;
1895 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1896 CHECK_FOR_EXCEPTION();
1897 callFrame
->uncheckedR(srcDst
) = jsNumber(number
.uncheckedGetNumber() + 1);
1898 callFrame
->uncheckedR(dst
) = number
;
1901 vPC
+= OPCODE_LENGTH(op_post_inc
);
1904 DEFINE_OPCODE(op_post_dec
) {
1905 /* post_dec dst(r) srcDst(r)
1907 Converts register srcDst to number. The number itself is
1908 written to register dst, and the number minus one is written
1909 back to register srcDst.
1911 int dst
= vPC
[1].u
.operand
;
1912 int srcDst
= vPC
[2].u
.operand
;
1913 JSValue v
= callFrame
->r(srcDst
).jsValue();
1914 if (v
.isInt32() && v
.asInt32() > INT_MIN
) {
1915 callFrame
->uncheckedR(srcDst
) = jsNumber(v
.asInt32() - 1);
1916 callFrame
->uncheckedR(dst
) = v
;
1918 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1919 CHECK_FOR_EXCEPTION();
1920 callFrame
->uncheckedR(srcDst
) = jsNumber(number
.uncheckedGetNumber() - 1);
1921 callFrame
->uncheckedR(dst
) = number
;
1924 vPC
+= OPCODE_LENGTH(op_post_dec
);
1927 DEFINE_OPCODE(op_to_jsnumber
) {
1928 /* to_jsnumber dst(r) src(r)
1930 Converts register src to number, and puts the result
1933 int dst
= vPC
[1].u
.operand
;
1934 int src
= vPC
[2].u
.operand
;
1936 JSValue srcVal
= callFrame
->r(src
).jsValue();
1938 if (LIKELY(srcVal
.isNumber()))
1939 callFrame
->uncheckedR(dst
) = callFrame
->r(src
);
1941 JSValue result
= srcVal
.toJSNumber(callFrame
);
1942 CHECK_FOR_EXCEPTION();
1943 callFrame
->uncheckedR(dst
) = result
;
1946 vPC
+= OPCODE_LENGTH(op_to_jsnumber
);
1949 DEFINE_OPCODE(op_negate
) {
1950 /* negate dst(r) src(r)
1952 Converts register src to number, negates it, and puts the
1953 result in register dst.
1955 int dst
= vPC
[1].u
.operand
;
1956 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1957 if (src
.isInt32() && (src
.asInt32() & 0x7fffffff)) // non-zero and no overflow
1958 callFrame
->uncheckedR(dst
) = jsNumber(-src
.asInt32());
1960 JSValue result
= jsNumber(-src
.toNumber(callFrame
));
1961 CHECK_FOR_EXCEPTION();
1962 callFrame
->uncheckedR(dst
) = result
;
1965 vPC
+= OPCODE_LENGTH(op_negate
);
1968 DEFINE_OPCODE(op_add
) {
1969 /* add dst(r) src1(r) src2(r)
1971 Adds register src1 and register src2, and puts the result
1972 in register dst. (JS add may be string concatenation or
1973 numeric add, depending on the types of the operands.)
1975 int dst
= vPC
[1].u
.operand
;
1976 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1977 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1978 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
1979 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() + src2
.asInt32());
1981 JSValue result
= jsAdd(callFrame
, src1
, src2
);
1982 CHECK_FOR_EXCEPTION();
1983 callFrame
->uncheckedR(dst
) = result
;
1985 vPC
+= OPCODE_LENGTH(op_add
);
1988 DEFINE_OPCODE(op_mul
) {
1989 /* mul dst(r) src1(r) src2(r)
1991 Multiplies register src1 and register src2 (converted to
1992 numbers), and puts the product in register dst.
1994 int dst
= vPC
[1].u
.operand
;
1995 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1996 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1997 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() >> 15)) // no overflow
1998 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() * src2
.asInt32());
2000 JSValue result
= jsNumber(src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
2001 CHECK_FOR_EXCEPTION();
2002 callFrame
->uncheckedR(dst
) = result
;
2005 vPC
+= OPCODE_LENGTH(op_mul
);
2008 DEFINE_OPCODE(op_div
) {
2009 /* div dst(r) dividend(r) divisor(r)
2011 Divides register dividend (converted to number) by the
2012 register divisor (converted to number), and puts the
2013 quotient in register dst.
2015 int dst
= vPC
[1].u
.operand
;
2016 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2017 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2019 JSValue result
= jsNumber(dividend
.toNumber(callFrame
) / divisor
.toNumber(callFrame
));
2020 CHECK_FOR_EXCEPTION();
2021 callFrame
->uncheckedR(dst
) = result
;
2023 vPC
+= OPCODE_LENGTH(op_div
);
2026 DEFINE_OPCODE(op_mod
) {
2027 /* mod dst(r) dividend(r) divisor(r)
2029 Divides register dividend (converted to number) by
2030 register divisor (converted to number), and puts the
2031 remainder in register dst.
2033 int dst
= vPC
[1].u
.operand
;
2034 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2035 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2037 if (dividend
.isInt32() && divisor
.isInt32() && divisor
.asInt32() != 0) {
2038 JSValue result
= jsNumber(dividend
.asInt32() % divisor
.asInt32());
2040 callFrame
->uncheckedR(dst
) = result
;
2041 vPC
+= OPCODE_LENGTH(op_mod
);
2045 // Conversion to double must happen outside the call to fmod since the
2046 // order of argument evaluation is not guaranteed.
2047 double d1
= dividend
.toNumber(callFrame
);
2048 double d2
= divisor
.toNumber(callFrame
);
2049 JSValue result
= jsNumber(fmod(d1
, d2
));
2050 CHECK_FOR_EXCEPTION();
2051 callFrame
->uncheckedR(dst
) = result
;
2052 vPC
+= OPCODE_LENGTH(op_mod
);
2055 DEFINE_OPCODE(op_sub
) {
2056 /* sub dst(r) src1(r) src2(r)
2058 Subtracts register src2 (converted to number) from register
2059 src1 (converted to number), and puts the difference in
2062 int dst
= vPC
[1].u
.operand
;
2063 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2064 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2065 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
2066 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() - src2
.asInt32());
2068 JSValue result
= jsNumber(src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
2069 CHECK_FOR_EXCEPTION();
2070 callFrame
->uncheckedR(dst
) = result
;
2072 vPC
+= OPCODE_LENGTH(op_sub
);
2075 DEFINE_OPCODE(op_lshift
) {
2076 /* lshift dst(r) val(r) shift(r)
2078 Performs left shift of register val (converted to int32) by
2079 register shift (converted to uint32), and puts the result
2082 int dst
= vPC
[1].u
.operand
;
2083 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2084 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2086 if (val
.isInt32() && shift
.isInt32())
2087 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() << (shift
.asInt32() & 0x1f));
2089 JSValue result
= jsNumber((val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
2090 CHECK_FOR_EXCEPTION();
2091 callFrame
->uncheckedR(dst
) = result
;
2094 vPC
+= OPCODE_LENGTH(op_lshift
);
2097 DEFINE_OPCODE(op_rshift
) {
2098 /* rshift dst(r) val(r) shift(r)
2100 Performs arithmetic right shift of register val (converted
2101 to int32) by register shift (converted to
2102 uint32), and puts the result in register dst.
2104 int dst
= vPC
[1].u
.operand
;
2105 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2106 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2108 if (val
.isInt32() && shift
.isInt32())
2109 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() >> (shift
.asInt32() & 0x1f));
2111 JSValue result
= jsNumber((val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
2112 CHECK_FOR_EXCEPTION();
2113 callFrame
->uncheckedR(dst
) = result
;
2116 vPC
+= OPCODE_LENGTH(op_rshift
);
2119 DEFINE_OPCODE(op_urshift
) {
2120 /* rshift dst(r) val(r) shift(r)
2122 Performs logical right shift of register val (converted
2123 to uint32) by register shift (converted to
2124 uint32), and puts the result in register dst.
2126 int dst
= vPC
[1].u
.operand
;
2127 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2128 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2129 if (val
.isUInt32() && shift
.isInt32())
2130 callFrame
->uncheckedR(dst
) = jsNumber(val
.asInt32() >> (shift
.asInt32() & 0x1f));
2132 JSValue result
= jsNumber((val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
2133 CHECK_FOR_EXCEPTION();
2134 callFrame
->uncheckedR(dst
) = result
;
2137 vPC
+= OPCODE_LENGTH(op_urshift
);
2140 DEFINE_OPCODE(op_bitand
) {
2141 /* bitand dst(r) src1(r) src2(r)
2143 Computes bitwise AND of register src1 (converted to int32)
2144 and register src2 (converted to int32), and puts the result
2147 int dst
= vPC
[1].u
.operand
;
2148 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2149 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2150 if (src1
.isInt32() && src2
.isInt32())
2151 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() & src2
.asInt32());
2153 JSValue result
= jsNumber(src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
2154 CHECK_FOR_EXCEPTION();
2155 callFrame
->uncheckedR(dst
) = result
;
2158 vPC
+= OPCODE_LENGTH(op_bitand
);
2161 DEFINE_OPCODE(op_bitxor
) {
2162 /* bitxor dst(r) src1(r) src2(r)
2164 Computes bitwise XOR of register src1 (converted to int32)
2165 and register src2 (converted to int32), and puts the result
2168 int dst
= vPC
[1].u
.operand
;
2169 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2170 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2171 if (src1
.isInt32() && src2
.isInt32())
2172 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() ^ src2
.asInt32());
2174 JSValue result
= jsNumber(src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
2175 CHECK_FOR_EXCEPTION();
2176 callFrame
->uncheckedR(dst
) = result
;
2179 vPC
+= OPCODE_LENGTH(op_bitxor
);
2182 DEFINE_OPCODE(op_bitor
) {
2183 /* bitor dst(r) src1(r) src2(r)
2185 Computes bitwise OR of register src1 (converted to int32)
2186 and register src2 (converted to int32), and puts the
2187 result in register dst.
2189 int dst
= vPC
[1].u
.operand
;
2190 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2191 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2192 if (src1
.isInt32() && src2
.isInt32())
2193 callFrame
->uncheckedR(dst
) = jsNumber(src1
.asInt32() | src2
.asInt32());
2195 JSValue result
= jsNumber(src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
2196 CHECK_FOR_EXCEPTION();
2197 callFrame
->uncheckedR(dst
) = result
;
2200 vPC
+= OPCODE_LENGTH(op_bitor
);
2203 DEFINE_OPCODE(op_bitnot
) {
2204 /* bitnot dst(r) src(r)
2206 Computes bitwise NOT of register src1 (converted to int32),
2207 and puts the result in register dst.
2209 int dst
= vPC
[1].u
.operand
;
2210 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2212 callFrame
->uncheckedR(dst
) = jsNumber(~src
.asInt32());
2214 JSValue result
= jsNumber(~src
.toInt32(callFrame
));
2215 CHECK_FOR_EXCEPTION();
2216 callFrame
->uncheckedR(dst
) = result
;
2218 vPC
+= OPCODE_LENGTH(op_bitnot
);
2221 DEFINE_OPCODE(op_not
) {
2222 /* not dst(r) src(r)
2224 Computes logical NOT of register src (converted to
2225 boolean), and puts the result in register dst.
2227 int dst
= vPC
[1].u
.operand
;
2228 int src
= vPC
[2].u
.operand
;
2229 JSValue result
= jsBoolean(!callFrame
->r(src
).jsValue().toBoolean(callFrame
));
2230 CHECK_FOR_EXCEPTION();
2231 callFrame
->uncheckedR(dst
) = result
;
2233 vPC
+= OPCODE_LENGTH(op_not
);
2236 DEFINE_OPCODE(op_check_has_instance
) {
2237 /* check_has_instance constructor(r)
2239 Check 'constructor' is an object with the internal property
2240 [HasInstance] (i.e. is a function ... *shakes head sadly at
2241 JSC API*). Raises an exception if register constructor is not
2242 an valid parameter for instanceof.
2244 int base
= vPC
[1].u
.operand
;
2245 JSValue baseVal
= callFrame
->r(base
).jsValue();
2247 if (isInvalidParamForInstanceOf(callFrame
, baseVal
, exceptionValue
))
2250 vPC
+= OPCODE_LENGTH(op_check_has_instance
);
2253 DEFINE_OPCODE(op_instanceof
) {
2254 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2256 Tests whether register value is an instance of register
2257 constructor, and puts the boolean result in register
2258 dst. Register constructorProto must contain the "prototype"
2259 property (not the actual prototype) of the object in
2260 register constructor. This lookup is separated so that
2261 polymorphic inline caching can apply.
2263 Raises an exception if register constructor is not an
2266 int dst
= vPC
[1].u
.operand
;
2267 int value
= vPC
[2].u
.operand
;
2268 int base
= vPC
[3].u
.operand
;
2269 int baseProto
= vPC
[4].u
.operand
;
2271 JSValue baseVal
= callFrame
->r(base
).jsValue();
2273 ASSERT(!isInvalidParamForInstanceOf(callFrame
, baseVal
, exceptionValue
));
2275 bool result
= asObject(baseVal
)->hasInstance(callFrame
, callFrame
->r(value
).jsValue(), callFrame
->r(baseProto
).jsValue());
2276 CHECK_FOR_EXCEPTION();
2277 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
2279 vPC
+= OPCODE_LENGTH(op_instanceof
);
2282 DEFINE_OPCODE(op_typeof
) {
2283 /* typeof dst(r) src(r)
2285 Determines the type string for src according to ECMAScript
2286 rules, and puts the result in register dst.
2288 int dst
= vPC
[1].u
.operand
;
2289 int src
= vPC
[2].u
.operand
;
2290 callFrame
->uncheckedR(dst
) = JSValue(jsTypeStringForValue(callFrame
, callFrame
->r(src
).jsValue()));
2292 vPC
+= OPCODE_LENGTH(op_typeof
);
2295 DEFINE_OPCODE(op_is_undefined
) {
2296 /* is_undefined dst(r) src(r)
2298 Determines whether the type string for src according to
2299 the ECMAScript rules is "undefined", and puts the result
2302 int dst
= vPC
[1].u
.operand
;
2303 int src
= vPC
[2].u
.operand
;
2304 JSValue v
= callFrame
->r(src
).jsValue();
2305 callFrame
->uncheckedR(dst
) = jsBoolean(v
.isCell() ? v
.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v
.isUndefined());
2307 vPC
+= OPCODE_LENGTH(op_is_undefined
);
2310 DEFINE_OPCODE(op_is_boolean
) {
2311 /* is_boolean dst(r) src(r)
2313 Determines whether the type string for src according to
2314 the ECMAScript rules is "boolean", and puts the result
2317 int dst
= vPC
[1].u
.operand
;
2318 int src
= vPC
[2].u
.operand
;
2319 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isBoolean());
2321 vPC
+= OPCODE_LENGTH(op_is_boolean
);
2324 DEFINE_OPCODE(op_is_number
) {
2325 /* is_number dst(r) src(r)
2327 Determines whether the type string for src according to
2328 the ECMAScript rules is "number", and puts the result
2331 int dst
= vPC
[1].u
.operand
;
2332 int src
= vPC
[2].u
.operand
;
2333 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isNumber());
2335 vPC
+= OPCODE_LENGTH(op_is_number
);
2338 DEFINE_OPCODE(op_is_string
) {
2339 /* is_string dst(r) src(r)
2341 Determines whether the type string for src according to
2342 the ECMAScript rules is "string", and puts the result
2345 int dst
= vPC
[1].u
.operand
;
2346 int src
= vPC
[2].u
.operand
;
2347 callFrame
->uncheckedR(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isString());
2349 vPC
+= OPCODE_LENGTH(op_is_string
);
2352 DEFINE_OPCODE(op_is_object
) {
2353 /* is_object dst(r) src(r)
2355 Determines whether the type string for src according to
2356 the ECMAScript rules is "object", and puts the result
2359 int dst
= vPC
[1].u
.operand
;
2360 int src
= vPC
[2].u
.operand
;
2361 callFrame
->uncheckedR(dst
) = jsBoolean(jsIsObjectType(callFrame
->r(src
).jsValue()));
2363 vPC
+= OPCODE_LENGTH(op_is_object
);
2366 DEFINE_OPCODE(op_is_function
) {
2367 /* is_function dst(r) src(r)
2369 Determines whether the type string for src according to
2370 the ECMAScript rules is "function", and puts the result
2373 int dst
= vPC
[1].u
.operand
;
2374 int src
= vPC
[2].u
.operand
;
2375 callFrame
->uncheckedR(dst
) = jsBoolean(jsIsFunctionType(callFrame
->r(src
).jsValue()));
2377 vPC
+= OPCODE_LENGTH(op_is_function
);
2380 DEFINE_OPCODE(op_in
) {
2381 /* in dst(r) property(r) base(r)
2383 Tests whether register base has a property named register
2384 property, and puts the boolean result in register dst.
2386 Raises an exception if register constructor is not an
2389 int dst
= vPC
[1].u
.operand
;
2390 int property
= vPC
[2].u
.operand
;
2391 int base
= vPC
[3].u
.operand
;
2393 JSValue baseVal
= callFrame
->r(base
).jsValue();
2394 if (isInvalidParamForIn(callFrame
, baseVal
, exceptionValue
))
2397 JSObject
* baseObj
= asObject(baseVal
);
2399 JSValue propName
= callFrame
->r(property
).jsValue();
2402 if (propName
.getUInt32(i
))
2403 callFrame
->uncheckedR(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, i
));
2405 Identifier
property(callFrame
, propName
.toString(callFrame
));
2406 CHECK_FOR_EXCEPTION();
2407 callFrame
->uncheckedR(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, property
));
2410 vPC
+= OPCODE_LENGTH(op_in
);
2413 DEFINE_OPCODE(op_resolve
) {
2414 /* resolve dst(r) property(id)
2416 Looks up the property named by identifier property in the
2417 scope chain, and writes the resulting value to register
2418 dst. If the property is not found, raises an exception.
2420 if (UNLIKELY(!resolve(callFrame
, vPC
, exceptionValue
)))
2423 vPC
+= OPCODE_LENGTH(op_resolve
);
2426 DEFINE_OPCODE(op_resolve_skip
) {
2427 /* resolve_skip dst(r) property(id) skip(n)
2429 Looks up the property named by identifier property in the
2430 scope chain skipping the top 'skip' levels, and writes the resulting
2431 value to register dst. If the property is not found, raises an exception.
2433 if (UNLIKELY(!resolveSkip(callFrame
, vPC
, exceptionValue
)))
2436 vPC
+= OPCODE_LENGTH(op_resolve_skip
);
2440 DEFINE_OPCODE(op_resolve_global
) {
2441 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
2443 Performs a dynamic property lookup for the given property, on the provided
2444 global object. If structure matches the Structure of the global then perform
2445 a fast lookup using the case offset, otherwise fall back to a full resolve and
2446 cache the new structure and offset
2448 if (UNLIKELY(!resolveGlobal(callFrame
, vPC
, exceptionValue
)))
2451 vPC
+= OPCODE_LENGTH(op_resolve_global
);
2455 DEFINE_OPCODE(op_resolve_global_dynamic
) {
2456 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)
2458 Performs a dynamic property lookup for the given property, on the provided
2459 global object. If structure matches the Structure of the global then perform
2460 a fast lookup using the case offset, otherwise fall back to a full resolve and
2461 cache the new structure and offset.
2463 This walks through n levels of the scope chain to verify that none of those levels
2464 in the scope chain include dynamically added properties.
2466 if (UNLIKELY(!resolveGlobalDynamic(callFrame
, vPC
, exceptionValue
)))
2469 vPC
+= OPCODE_LENGTH(op_resolve_global_dynamic
);
2473 DEFINE_OPCODE(op_get_global_var
) {
2474 /* get_global_var dst(r) globalObject(c) index(n)
2476 Gets the global var at global slot index and places it in register dst.
2478 int dst
= vPC
[1].u
.operand
;
2479 JSGlobalObject
* scope
= codeBlock
->globalObject();
2480 ASSERT(scope
->isGlobalObject());
2481 int index
= vPC
[2].u
.operand
;
2483 callFrame
->uncheckedR(dst
) = scope
->registerAt(index
).get();
2484 vPC
+= OPCODE_LENGTH(op_get_global_var
);
2487 DEFINE_OPCODE(op_put_global_var
) {
2488 /* put_global_var globalObject(c) index(n) value(r)
2490 Puts value into global slot index.
2492 JSGlobalObject
* scope
= codeBlock
->globalObject();
2493 ASSERT(scope
->isGlobalObject());
2494 int index
= vPC
[1].u
.operand
;
2495 int value
= vPC
[2].u
.operand
;
2497 scope
->registerAt(index
).set(*globalData
, scope
, callFrame
->r(value
).jsValue());
2498 vPC
+= OPCODE_LENGTH(op_put_global_var
);
2501 DEFINE_OPCODE(op_get_scoped_var
) {
2502 /* get_scoped_var dst(r) index(n) skip(n)
2504 Loads the contents of the index-th local from the scope skip nodes from
2505 the top of the scope chain, and places it in register dst.
2507 int dst
= vPC
[1].u
.operand
;
2508 int index
= vPC
[2].u
.operand
;
2509 int skip
= vPC
[3].u
.operand
;
2511 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2512 ScopeChainIterator iter
= scopeChain
->begin();
2513 ScopeChainIterator end
= scopeChain
->end();
2514 ASSERT(iter
!= end
);
2515 ASSERT(codeBlock
== callFrame
->codeBlock());
2516 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
2517 ASSERT(skip
|| !checkTopLevel
);
2518 if (checkTopLevel
&& skip
--) {
2519 if (callFrame
->r(codeBlock
->activationRegister()).jsValue())
2524 ASSERT(iter
!= end
);
2526 ASSERT((*iter
)->isVariableObject());
2527 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(iter
->get());
2528 callFrame
->uncheckedR(dst
) = scope
->registerAt(index
).get();
2529 ASSERT(callFrame
->r(dst
).jsValue());
2530 vPC
+= OPCODE_LENGTH(op_get_scoped_var
);
2533 DEFINE_OPCODE(op_put_scoped_var
) {
2534 /* put_scoped_var index(n) skip(n) value(r)
2537 int index
= vPC
[1].u
.operand
;
2538 int skip
= vPC
[2].u
.operand
;
2539 int value
= vPC
[3].u
.operand
;
2541 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2542 ScopeChainIterator iter
= scopeChain
->begin();
2543 ScopeChainIterator end
= scopeChain
->end();
2544 ASSERT(codeBlock
== callFrame
->codeBlock());
2545 ASSERT(iter
!= end
);
2546 bool checkTopLevel
= codeBlock
->codeType() == FunctionCode
&& codeBlock
->needsFullScopeChain();
2547 ASSERT(skip
|| !checkTopLevel
);
2548 if (checkTopLevel
&& skip
--) {
2549 if (callFrame
->r(codeBlock
->activationRegister()).jsValue())
2554 ASSERT(iter
!= end
);
2557 ASSERT((*iter
)->isVariableObject());
2558 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(iter
->get());
2559 ASSERT(callFrame
->r(value
).jsValue());
2560 scope
->registerAt(index
).set(*globalData
, scope
, callFrame
->r(value
).jsValue());
2561 vPC
+= OPCODE_LENGTH(op_put_scoped_var
);
2564 DEFINE_OPCODE(op_resolve_base
) {
2565 /* resolve_base dst(r) property(id) isStrict(bool)
2567 Searches the scope chain for an object containing
2568 identifier property, and if one is found, writes it to
2569 register dst. If none is found and isStrict is false, the
2570 outermost scope (which will be the global object) is
2571 stored in register dst.
2573 resolveBase(callFrame
, vPC
);
2574 CHECK_FOR_EXCEPTION();
2576 vPC
+= OPCODE_LENGTH(op_resolve_base
);
2579 DEFINE_OPCODE(op_ensure_property_exists
) {
2580 /* ensure_property_exists base(r) property(id)
2582 Throws an exception if property does not exist on base
2584 int base
= vPC
[1].u
.operand
;
2585 int property
= vPC
[2].u
.operand
;
2586 Identifier
& ident
= codeBlock
->identifier(property
);
2588 JSValue baseVal
= callFrame
->r(base
).jsValue();
2589 JSObject
* baseObject
= asObject(baseVal
);
2590 PropertySlot
slot(baseVal
);
2591 if (!baseObject
->getPropertySlot(callFrame
, ident
, slot
)) {
2592 exceptionValue
= createErrorForInvalidGlobalAssignment(callFrame
, ident
.ustring());
2596 vPC
+= OPCODE_LENGTH(op_ensure_property_exists
);
2599 DEFINE_OPCODE(op_resolve_with_base
) {
2600 /* resolve_with_base baseDst(r) propDst(r) property(id)
2602 Searches the scope chain for an object containing
2603 identifier property, and if one is found, writes it to
2604 register srcDst, and the retrieved property value to register
2605 propDst. If the property is not found, raises an exception.
2607 This is more efficient than doing resolve_base followed by
2608 resolve, or resolve_base followed by get_by_id, as it
2609 avoids duplicate hash lookups.
2611 if (UNLIKELY(!resolveBaseAndProperty(callFrame
, vPC
, exceptionValue
)))
2614 vPC
+= OPCODE_LENGTH(op_resolve_with_base
);
2617 DEFINE_OPCODE(op_get_by_id
) {
2618 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2620 Generic property access: Gets the property named by identifier
2621 property from the value base, and puts the result in register dst.
2623 int dst
= vPC
[1].u
.operand
;
2624 int base
= vPC
[2].u
.operand
;
2625 int property
= vPC
[3].u
.operand
;
2627 Identifier
& ident
= codeBlock
->identifier(property
);
2628 JSValue baseValue
= callFrame
->r(base
).jsValue();
2629 PropertySlot
slot(baseValue
);
2630 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2631 CHECK_FOR_EXCEPTION();
2633 tryCacheGetByID(callFrame
, codeBlock
, vPC
, baseValue
, ident
, slot
);
2635 callFrame
->uncheckedR(dst
) = result
;
2636 vPC
+= OPCODE_LENGTH(op_get_by_id
);
2639 DEFINE_OPCODE(op_get_by_id_self
) {
2640 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2642 Cached property access: Attempts to get a cached property from the
2643 value base. If the cache misses, op_get_by_id_self reverts to
2646 int base
= vPC
[2].u
.operand
;
2647 JSValue baseValue
= callFrame
->r(base
).jsValue();
2649 if (LIKELY(baseValue
.isCell())) {
2650 JSCell
* baseCell
= baseValue
.asCell();
2651 Structure
* structure
= vPC
[4].u
.structure
.get();
2653 if (LIKELY(baseCell
->structure() == structure
)) {
2654 ASSERT(baseCell
->isObject());
2655 JSObject
* baseObject
= asObject(baseCell
);
2656 int dst
= vPC
[1].u
.operand
;
2657 int offset
= vPC
[5].u
.operand
;
2659 ASSERT(baseObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2660 callFrame
->uncheckedR(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2662 vPC
+= OPCODE_LENGTH(op_get_by_id_self
);
2667 uncacheGetByID(codeBlock
, vPC
);
2670 DEFINE_OPCODE(op_get_by_id_proto
) {
2671 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2673 Cached property access: Attempts to get a cached property from the
2674 value base's prototype. If the cache misses, op_get_by_id_proto
2675 reverts to op_get_by_id.
2677 int base
= vPC
[2].u
.operand
;
2678 JSValue baseValue
= callFrame
->r(base
).jsValue();
2680 if (LIKELY(baseValue
.isCell())) {
2681 JSCell
* baseCell
= baseValue
.asCell();
2682 Structure
* structure
= vPC
[4].u
.structure
.get();
2684 if (LIKELY(baseCell
->structure() == structure
)) {
2685 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2686 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2687 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
2689 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2690 int dst
= vPC
[1].u
.operand
;
2691 int offset
= vPC
[6].u
.operand
;
2693 ASSERT(protoObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2694 ASSERT(baseValue
.get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2695 callFrame
->uncheckedR(dst
) = JSValue(protoObject
->getDirectOffset(offset
));
2697 vPC
+= OPCODE_LENGTH(op_get_by_id_proto
);
2703 uncacheGetByID(codeBlock
, vPC
);
2706 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2707 goto *(&&skip_id_getter_proto
);
2709 DEFINE_OPCODE(op_get_by_id_getter_proto
) {
2710 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2712 Cached property access: Attempts to get a cached getter property from the
2713 value base's prototype. If the cache misses, op_get_by_id_getter_proto
2714 reverts to op_get_by_id.
2716 int base
= vPC
[2].u
.operand
;
2717 JSValue baseValue
= callFrame
->r(base
).jsValue();
2719 if (LIKELY(baseValue
.isCell())) {
2720 JSCell
* baseCell
= baseValue
.asCell();
2721 Structure
* structure
= vPC
[4].u
.structure
.get();
2723 if (LIKELY(baseCell
->structure() == structure
)) {
2724 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2725 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2726 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
2728 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2729 int dst
= vPC
[1].u
.operand
;
2730 int offset
= vPC
[6].u
.operand
;
2731 if (GetterSetter
* getterSetter
= asGetterSetter(protoObject
->getDirectOffset(offset
).asCell())) {
2732 JSObject
* getter
= getterSetter
->getter();
2734 CallType callType
= getter
->getCallData(callData
);
2735 JSValue result
= call(callFrame
, getter
, callType
, callData
, asObject(baseCell
), ArgList());
2736 CHECK_FOR_EXCEPTION();
2737 callFrame
->uncheckedR(dst
) = result
;
2739 callFrame
->uncheckedR(dst
) = jsUndefined();
2740 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_proto
);
2745 uncacheGetByID(codeBlock
, vPC
);
2748 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2749 skip_id_getter_proto
:
2751 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2752 goto *(&&skip_id_custom_proto
);
2754 DEFINE_OPCODE(op_get_by_id_custom_proto
) {
2755 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2757 Cached property access: Attempts to use a cached named property getter
2758 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto
2759 reverts to op_get_by_id.
2761 int base
= vPC
[2].u
.operand
;
2762 JSValue baseValue
= callFrame
->r(base
).jsValue();
2764 if (LIKELY(baseValue
.isCell())) {
2765 JSCell
* baseCell
= baseValue
.asCell();
2766 Structure
* structure
= vPC
[4].u
.structure
.get();
2768 if (LIKELY(baseCell
->structure() == structure
)) {
2769 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2770 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2771 Structure
* prototypeStructure
= vPC
[5].u
.structure
.get();
2773 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2774 int dst
= vPC
[1].u
.operand
;
2775 int property
= vPC
[3].u
.operand
;
2776 Identifier
& ident
= codeBlock
->identifier(property
);
2778 PropertySlot::GetValueFunc getter
= vPC
[6].u
.getterFunc
;
2779 JSValue result
= getter(callFrame
, protoObject
, ident
);
2780 CHECK_FOR_EXCEPTION();
2781 callFrame
->uncheckedR(dst
) = result
;
2782 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_proto
);
2787 uncacheGetByID(codeBlock
, vPC
);
2790 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2791 skip_id_custom_proto
:
2793 DEFINE_OPCODE(op_get_by_id_self_list
) {
2794 // Polymorphic self access caching currently only supported when JITting.
2795 ASSERT_NOT_REACHED();
2796 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2797 vPC
+= OPCODE_LENGTH(op_get_by_id_self_list
);
2800 DEFINE_OPCODE(op_get_by_id_proto_list
) {
2801 // Polymorphic prototype access caching currently only supported when JITting.
2802 ASSERT_NOT_REACHED();
2803 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2804 vPC
+= OPCODE_LENGTH(op_get_by_id_proto_list
);
2807 DEFINE_OPCODE(op_get_by_id_getter_self_list
) {
2808 // Polymorphic self access caching currently only supported when JITting.
2809 ASSERT_NOT_REACHED();
2810 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2811 vPC
+= OPCODE_LENGTH(op_get_by_id_self_list
);
2814 DEFINE_OPCODE(op_get_by_id_getter_proto_list
) {
2815 // Polymorphic prototype access caching currently only supported when JITting.
2816 ASSERT_NOT_REACHED();
2817 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2818 vPC
+= OPCODE_LENGTH(op_get_by_id_proto_list
);
2821 DEFINE_OPCODE(op_get_by_id_custom_self_list
) {
2822 // Polymorphic self access caching currently only supported when JITting.
2823 ASSERT_NOT_REACHED();
2824 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2825 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_self_list
);
2828 DEFINE_OPCODE(op_get_by_id_custom_proto_list
) {
2829 // Polymorphic prototype access caching currently only supported when JITting.
2830 ASSERT_NOT_REACHED();
2831 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2832 vPC
+= OPCODE_LENGTH(op_get_by_id_proto_list
);
2835 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2836 goto *(&&skip_get_by_id_chain
);
2838 DEFINE_OPCODE(op_get_by_id_chain
) {
2839 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2841 Cached property access: Attempts to get a cached property from the
2842 value base's prototype chain. If the cache misses, op_get_by_id_chain
2843 reverts to op_get_by_id.
2845 int base
= vPC
[2].u
.operand
;
2846 JSValue baseValue
= callFrame
->r(base
).jsValue();
2848 if (LIKELY(baseValue
.isCell())) {
2849 JSCell
* baseCell
= baseValue
.asCell();
2850 Structure
* structure
= vPC
[4].u
.structure
.get();
2852 if (LIKELY(baseCell
->structure() == structure
)) {
2853 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
2854 size_t count
= vPC
[6].u
.operand
;
2855 WriteBarrier
<Structure
>* end
= it
+ count
;
2858 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
2860 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
2864 int dst
= vPC
[1].u
.operand
;
2865 int offset
= vPC
[7].u
.operand
;
2867 ASSERT(baseObject
->get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2868 ASSERT(baseValue
.get(callFrame
, codeBlock
->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2869 callFrame
->uncheckedR(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2871 vPC
+= OPCODE_LENGTH(op_get_by_id_chain
);
2875 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2876 baseCell
= baseObject
;
2881 uncacheGetByID(codeBlock
, vPC
);
2884 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2885 skip_get_by_id_chain
:
2886 goto *(&&skip_id_getter_self
);
2888 DEFINE_OPCODE(op_get_by_id_getter_self
) {
2889 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2891 Cached property access: Attempts to get a cached property from the
2892 value base. If the cache misses, op_get_by_id_getter_self reverts to
2895 int base
= vPC
[2].u
.operand
;
2896 JSValue baseValue
= callFrame
->r(base
).jsValue();
2898 if (LIKELY(baseValue
.isCell())) {
2899 JSCell
* baseCell
= baseValue
.asCell();
2900 Structure
* structure
= vPC
[4].u
.structure
.get();
2902 if (LIKELY(baseCell
->structure() == structure
)) {
2903 ASSERT(baseCell
->isObject());
2904 JSObject
* baseObject
= asObject(baseCell
);
2905 int dst
= vPC
[1].u
.operand
;
2906 int offset
= vPC
[5].u
.operand
;
2908 if (GetterSetter
* getterSetter
= asGetterSetter(baseObject
->getDirectOffset(offset
).asCell())) {
2909 JSObject
* getter
= getterSetter
->getter();
2911 CallType callType
= getter
->getCallData(callData
);
2912 JSValue result
= call(callFrame
, getter
, callType
, callData
, baseObject
, ArgList());
2913 CHECK_FOR_EXCEPTION();
2914 callFrame
->uncheckedR(dst
) = result
;
2916 callFrame
->uncheckedR(dst
) = jsUndefined();
2918 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_self
);
2922 uncacheGetByID(codeBlock
, vPC
);
2925 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2926 skip_id_getter_self
:
2928 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2929 goto *(&&skip_id_custom_self
);
2931 DEFINE_OPCODE(op_get_by_id_custom_self
) {
2932 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2934 Cached property access: Attempts to use a cached named property getter
2935 from the value base. If the cache misses, op_get_by_id_custom_self reverts to
2938 int base
= vPC
[2].u
.operand
;
2939 JSValue baseValue
= callFrame
->r(base
).jsValue();
2941 if (LIKELY(baseValue
.isCell())) {
2942 JSCell
* baseCell
= baseValue
.asCell();
2943 Structure
* structure
= vPC
[4].u
.structure
.get();
2945 if (LIKELY(baseCell
->structure() == structure
)) {
2946 ASSERT(baseCell
->isObject());
2947 int dst
= vPC
[1].u
.operand
;
2948 int property
= vPC
[3].u
.operand
;
2949 Identifier
& ident
= codeBlock
->identifier(property
);
2951 PropertySlot::GetValueFunc getter
= vPC
[5].u
.getterFunc
;
2952 JSValue result
= getter(callFrame
, baseValue
, ident
);
2953 CHECK_FOR_EXCEPTION();
2954 callFrame
->uncheckedR(dst
) = result
;
2955 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_self
);
2959 uncacheGetByID(codeBlock
, vPC
);
2962 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2963 skip_id_custom_self
:
2965 DEFINE_OPCODE(op_get_by_id_generic
) {
2966 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2968 Generic property access: Gets the property named by identifier
2969 property from the value base, and puts the result in register dst.
2971 int dst
= vPC
[1].u
.operand
;
2972 int base
= vPC
[2].u
.operand
;
2973 int property
= vPC
[3].u
.operand
;
2975 Identifier
& ident
= codeBlock
->identifier(property
);
2976 JSValue baseValue
= callFrame
->r(base
).jsValue();
2977 PropertySlot
slot(baseValue
);
2978 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2979 CHECK_FOR_EXCEPTION();
2981 callFrame
->uncheckedR(dst
) = result
;
2982 vPC
+= OPCODE_LENGTH(op_get_by_id_generic
);
2985 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
2986 goto *(&&skip_id_getter_chain
);
2988 DEFINE_OPCODE(op_get_by_id_getter_chain
) {
2989 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2991 Cached property access: Attempts to get a cached property from the
2992 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain
2993 reverts to op_get_by_id.
2995 int base
= vPC
[2].u
.operand
;
2996 JSValue baseValue
= callFrame
->r(base
).jsValue();
2998 if (LIKELY(baseValue
.isCell())) {
2999 JSCell
* baseCell
= baseValue
.asCell();
3000 Structure
* structure
= vPC
[4].u
.structure
.get();
3002 if (LIKELY(baseCell
->structure() == structure
)) {
3003 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
3004 size_t count
= vPC
[6].u
.operand
;
3005 WriteBarrier
<Structure
>* end
= it
+ count
;
3008 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
3010 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
3014 int dst
= vPC
[1].u
.operand
;
3015 int offset
= vPC
[7].u
.operand
;
3016 if (GetterSetter
* getterSetter
= asGetterSetter(baseObject
->getDirectOffset(offset
).asCell())) {
3017 JSObject
* getter
= getterSetter
->getter();
3019 CallType callType
= getter
->getCallData(callData
);
3020 JSValue result
= call(callFrame
, getter
, callType
, callData
, baseValue
, ArgList());
3021 CHECK_FOR_EXCEPTION();
3022 callFrame
->uncheckedR(dst
) = result
;
3024 callFrame
->uncheckedR(dst
) = jsUndefined();
3025 vPC
+= OPCODE_LENGTH(op_get_by_id_getter_chain
);
3029 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3030 baseCell
= baseObject
;
3034 uncacheGetByID(codeBlock
, vPC
);
3037 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3038 skip_id_getter_chain
:
3040 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3041 goto *(&&skip_id_custom_chain
);
3043 DEFINE_OPCODE(op_get_by_id_custom_chain
) {
3044 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
3046 Cached property access: Attempts to use a cached named property getter on the
3047 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain
3048 reverts to op_get_by_id.
3050 int base
= vPC
[2].u
.operand
;
3051 JSValue baseValue
= callFrame
->r(base
).jsValue();
3053 if (LIKELY(baseValue
.isCell())) {
3054 JSCell
* baseCell
= baseValue
.asCell();
3055 Structure
* structure
= vPC
[4].u
.structure
.get();
3057 if (LIKELY(baseCell
->structure() == structure
)) {
3058 WriteBarrier
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
3059 size_t count
= vPC
[6].u
.operand
;
3060 WriteBarrier
<Structure
>* end
= it
+ count
;
3063 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
3065 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
3069 int dst
= vPC
[1].u
.operand
;
3070 int property
= vPC
[3].u
.operand
;
3071 Identifier
& ident
= codeBlock
->identifier(property
);
3073 PropertySlot::GetValueFunc getter
= vPC
[7].u
.getterFunc
;
3074 JSValue result
= getter(callFrame
, baseObject
, ident
);
3075 CHECK_FOR_EXCEPTION();
3076 callFrame
->uncheckedR(dst
) = result
;
3077 vPC
+= OPCODE_LENGTH(op_get_by_id_custom_chain
);
3081 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
3082 baseCell
= baseObject
;
3086 uncacheGetByID(codeBlock
, vPC
);
3089 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3090 skip_id_custom_chain
:
3091 goto *(&&skip_get_array_length
);
3093 DEFINE_OPCODE(op_get_array_length
) {
3094 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3096 Cached property access: Gets the length of the array in register base,
3097 and puts the result in register dst. If register base does not hold
3098 an array, op_get_array_length reverts to op_get_by_id.
3101 int base
= vPC
[2].u
.operand
;
3102 JSValue baseValue
= callFrame
->r(base
).jsValue();
3103 if (LIKELY(isJSArray(globalData
, baseValue
))) {
3104 int dst
= vPC
[1].u
.operand
;
3105 callFrame
->uncheckedR(dst
) = jsNumber(asArray(baseValue
)->length());
3106 vPC
+= OPCODE_LENGTH(op_get_array_length
);
3110 uncacheGetByID(codeBlock
, vPC
);
3113 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3114 skip_get_array_length
:
3115 goto *(&&skip_get_string_length
);
3117 DEFINE_OPCODE(op_get_string_length
) {
3118 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
3120 Cached property access: Gets the length of the string in register base,
3121 and puts the result in register dst. If register base does not hold
3122 a string, op_get_string_length reverts to op_get_by_id.
3125 int base
= vPC
[2].u
.operand
;
3126 JSValue baseValue
= callFrame
->r(base
).jsValue();
3127 if (LIKELY(isJSString(globalData
, baseValue
))) {
3128 int dst
= vPC
[1].u
.operand
;
3129 callFrame
->uncheckedR(dst
) = jsNumber(asString(baseValue
)->length());
3130 vPC
+= OPCODE_LENGTH(op_get_string_length
);
3134 uncacheGetByID(codeBlock
, vPC
);
3137 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3138 skip_get_string_length
:
3139 goto *(&&skip_put_by_id
);
3141 DEFINE_OPCODE(op_put_by_id
) {
3142 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3144 Generic property access: Sets the property named by identifier
3145 property, belonging to register base, to register value.
3147 Unlike many opcodes, this one does not write any output to
3150 The "direct" flag should only be set this put_by_id is to initialize
3154 int base
= vPC
[1].u
.operand
;
3155 int property
= vPC
[2].u
.operand
;
3156 int value
= vPC
[3].u
.operand
;
3157 int direct
= vPC
[8].u
.operand
;
3159 JSValue baseValue
= callFrame
->r(base
).jsValue();
3160 Identifier
& ident
= codeBlock
->identifier(property
);
3161 PutPropertySlot
slot(codeBlock
->isStrictMode());
3163 baseValue
.putDirect(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3164 ASSERT(slot
.base() == baseValue
);
3166 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3167 CHECK_FOR_EXCEPTION();
3169 tryCachePutByID(callFrame
, codeBlock
, vPC
, baseValue
, slot
);
3171 vPC
+= OPCODE_LENGTH(op_put_by_id
);
3174 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)
3177 DEFINE_OPCODE(op_put_by_id_transition
) {
3178 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)
3180 Cached property access: Attempts to set a new property with a cached transition
3181 property named by identifier property, belonging to register base,
3182 to register value. If the cache misses, op_put_by_id_transition
3183 reverts to op_put_by_id_generic.
3185 Unlike many opcodes, this one does not write any output to
3188 int base
= vPC
[1].u
.operand
;
3189 JSValue baseValue
= callFrame
->r(base
).jsValue();
3191 if (LIKELY(baseValue
.isCell())) {
3192 JSCell
* baseCell
= baseValue
.asCell();
3193 Structure
* oldStructure
= vPC
[4].u
.structure
.get();
3194 Structure
* newStructure
= vPC
[5].u
.structure
.get();
3196 if (LIKELY(baseCell
->structure() == oldStructure
)) {
3197 ASSERT(baseCell
->isObject());
3198 JSObject
* baseObject
= asObject(baseCell
);
3199 int direct
= vPC
[8].u
.operand
;
3202 WriteBarrier
<Structure
>* it
= vPC
[6].u
.structureChain
->head();
3204 JSValue proto
= baseObject
->structure()->prototypeForLookup(callFrame
);
3205 while (!proto
.isNull()) {
3206 if (UNLIKELY(asObject(proto
)->structure() != (*it
).get())) {
3207 uncachePutByID(codeBlock
, vPC
);
3211 proto
= asObject(proto
)->structure()->prototypeForLookup(callFrame
);
3214 baseObject
->transitionTo(*globalData
, newStructure
);
3216 int value
= vPC
[3].u
.operand
;
3217 unsigned offset
= vPC
[7].u
.operand
;
3218 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(*globalData
, codeBlock
->identifier(vPC
[2].u
.operand
))) == offset
);
3219 baseObject
->putDirectOffset(callFrame
->globalData(), offset
, callFrame
->r(value
).jsValue());
3221 vPC
+= OPCODE_LENGTH(op_put_by_id_transition
);
3226 uncachePutByID(codeBlock
, vPC
);
3229 DEFINE_OPCODE(op_put_by_id_replace
) {
3230 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)
3232 Cached property access: Attempts to set a pre-existing, cached
3233 property named by identifier property, belonging to register base,
3234 to register value. If the cache misses, op_put_by_id_replace
3235 reverts to op_put_by_id.
3237 Unlike many opcodes, this one does not write any output to
3240 int base
= vPC
[1].u
.operand
;
3241 JSValue baseValue
= callFrame
->r(base
).jsValue();
3243 if (LIKELY(baseValue
.isCell())) {
3244 JSCell
* baseCell
= baseValue
.asCell();
3245 Structure
* structure
= vPC
[4].u
.structure
.get();
3247 if (LIKELY(baseCell
->structure() == structure
)) {
3248 ASSERT(baseCell
->isObject());
3249 JSObject
* baseObject
= asObject(baseCell
);
3250 int value
= vPC
[3].u
.operand
;
3251 unsigned offset
= vPC
[5].u
.operand
;
3253 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(*globalData
, codeBlock
->identifier(vPC
[2].u
.operand
))) == offset
);
3254 baseObject
->putDirectOffset(callFrame
->globalData(), offset
, callFrame
->r(value
).jsValue());
3256 vPC
+= OPCODE_LENGTH(op_put_by_id_replace
);
3261 uncachePutByID(codeBlock
, vPC
);
3264 DEFINE_OPCODE(op_put_by_id_generic
) {
3265 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)
3267 Generic property access: Sets the property named by identifier
3268 property, belonging to register base, to register value.
3270 Unlike many opcodes, this one does not write any output to
3273 int base
= vPC
[1].u
.operand
;
3274 int property
= vPC
[2].u
.operand
;
3275 int value
= vPC
[3].u
.operand
;
3276 int direct
= vPC
[8].u
.operand
;
3278 JSValue baseValue
= callFrame
->r(base
).jsValue();
3279 Identifier
& ident
= codeBlock
->identifier(property
);
3280 PutPropertySlot
slot(codeBlock
->isStrictMode());
3282 baseValue
.putDirect(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3283 ASSERT(slot
.base() == baseValue
);
3285 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
3286 CHECK_FOR_EXCEPTION();
3288 vPC
+= OPCODE_LENGTH(op_put_by_id_generic
);
3291 DEFINE_OPCODE(op_del_by_id
) {
3292 /* del_by_id dst(r) base(r) property(id)
3294 Converts register base to Object, deletes the property
3295 named by identifier property from the object, and writes a
3296 boolean indicating success (if true) or failure (if false)
3299 int dst
= vPC
[1].u
.operand
;
3300 int base
= vPC
[2].u
.operand
;
3301 int property
= vPC
[3].u
.operand
;
3303 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
);
3304 Identifier
& ident
= codeBlock
->identifier(property
);
3305 bool result
= baseObj
->deleteProperty(callFrame
, ident
);
3306 if (!result
&& codeBlock
->isStrictMode()) {
3307 exceptionValue
= createTypeError(callFrame
, "Unable to delete property.");
3310 CHECK_FOR_EXCEPTION();
3311 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
3312 vPC
+= OPCODE_LENGTH(op_del_by_id
);
3315 DEFINE_OPCODE(op_get_by_pname
) {
3316 int dst
= vPC
[1].u
.operand
;
3317 int base
= vPC
[2].u
.operand
;
3318 int property
= vPC
[3].u
.operand
;
3319 int expected
= vPC
[4].u
.operand
;
3320 int iter
= vPC
[5].u
.operand
;
3321 int i
= vPC
[6].u
.operand
;
3323 JSValue baseValue
= callFrame
->r(base
).jsValue();
3324 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
3325 JSValue subscript
= callFrame
->r(property
).jsValue();
3326 JSValue expectedSubscript
= callFrame
->r(expected
).jsValue();
3327 int index
= callFrame
->r(i
).i() - 1;
3330 if (subscript
== expectedSubscript
&& baseValue
.isCell() && (baseValue
.asCell()->structure() == it
->cachedStructure()) && it
->getOffset(index
, offset
)) {
3331 callFrame
->uncheckedR(dst
) = JSValue(asObject(baseValue
)->getDirectOffset(offset
));
3332 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
3336 Identifier
propertyName(callFrame
, subscript
.toString(callFrame
));
3337 result
= baseValue
.get(callFrame
, propertyName
);
3339 CHECK_FOR_EXCEPTION();
3340 callFrame
->uncheckedR(dst
) = result
;
3341 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
3344 DEFINE_OPCODE(op_get_arguments_length
) {
3345 int dst
= vPC
[1].u
.operand
;
3346 int argumentsRegister
= vPC
[2].u
.operand
;
3347 int property
= vPC
[3].u
.operand
;
3348 JSValue arguments
= callFrame
->r(argumentsRegister
).jsValue();
3350 Identifier
& ident
= codeBlock
->identifier(property
);
3351 PropertySlot
slot(arguments
);
3352 JSValue result
= arguments
.get(callFrame
, ident
, slot
);
3353 CHECK_FOR_EXCEPTION();
3354 callFrame
->uncheckedR(dst
) = result
;
3356 callFrame
->uncheckedR(dst
) = jsNumber(callFrame
->argumentCount());
3358 vPC
+= OPCODE_LENGTH(op_get_arguments_length
);
3361 DEFINE_OPCODE(op_get_argument_by_val
) {
3362 int dst
= vPC
[1].u
.operand
;
3363 int argumentsRegister
= vPC
[2].u
.operand
;
3364 int property
= vPC
[3].u
.operand
;
3365 JSValue arguments
= callFrame
->r(argumentsRegister
).jsValue();
3366 JSValue subscript
= callFrame
->r(property
).jsValue();
3367 if (!arguments
&& subscript
.isUInt32() && subscript
.asUInt32() < callFrame
->argumentCount()) {
3368 unsigned arg
= subscript
.asUInt32() + 1;
3369 unsigned numParameters
= callFrame
->codeBlock()->m_numParameters
;
3370 if (arg
< numParameters
)
3371 callFrame
->uncheckedR(dst
) = callFrame
->r(arg
- RegisterFile::CallFrameHeaderSize
- numParameters
);
3373 callFrame
->uncheckedR(dst
) = callFrame
->r(arg
- RegisterFile::CallFrameHeaderSize
- numParameters
- callFrame
->argumentCount() - 1);
3374 vPC
+= OPCODE_LENGTH(op_get_argument_by_val
);
3378 Arguments
* arguments
= new (globalData
) Arguments(callFrame
);
3379 callFrame
->uncheckedR(argumentsRegister
) = JSValue(arguments
);
3380 callFrame
->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister
)) = JSValue(arguments
);
3384 DEFINE_OPCODE(op_get_by_val
) {
3385 /* get_by_val dst(r) base(r) property(r)
3387 Converts register base to Object, gets the property named
3388 by register property from the object, and puts the result
3389 in register dst. property is nominally converted to string
3390 but numbers are treated more efficiently.
3392 int dst
= vPC
[1].u
.operand
;
3393 int base
= vPC
[2].u
.operand
;
3394 int property
= vPC
[3].u
.operand
;
3396 JSValue baseValue
= callFrame
->r(base
).jsValue();
3397 JSValue subscript
= callFrame
->r(property
).jsValue();
3401 if (LIKELY(subscript
.isUInt32())) {
3402 uint32_t i
= subscript
.asUInt32();
3403 if (isJSArray(globalData
, baseValue
)) {
3404 JSArray
* jsArray
= asArray(baseValue
);
3405 if (jsArray
->canGetIndex(i
))
3406 result
= jsArray
->getIndex(i
);
3408 result
= jsArray
->JSArray::get(callFrame
, i
);
3409 } else if (isJSString(globalData
, baseValue
) && asString(baseValue
)->canGetIndex(i
))
3410 result
= asString(baseValue
)->getIndex(callFrame
, i
);
3411 else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
))
3412 result
= asByteArray(baseValue
)->getIndex(callFrame
, i
);
3414 result
= baseValue
.get(callFrame
, i
);
3416 Identifier
property(callFrame
, subscript
.toString(callFrame
));
3417 result
= baseValue
.get(callFrame
, property
);
3420 CHECK_FOR_EXCEPTION();
3421 callFrame
->uncheckedR(dst
) = result
;
3422 vPC
+= OPCODE_LENGTH(op_get_by_val
);
3425 DEFINE_OPCODE(op_put_by_val
) {
3426 /* put_by_val base(r) property(r) value(r)
3428 Sets register value on register base as the property named
3429 by register property. Base is converted to object
3430 first. register property is nominally converted to string
3431 but numbers are treated more efficiently.
3433 Unlike many opcodes, this one does not write any output to
3436 int base
= vPC
[1].u
.operand
;
3437 int property
= vPC
[2].u
.operand
;
3438 int value
= vPC
[3].u
.operand
;
3440 JSValue baseValue
= callFrame
->r(base
).jsValue();
3441 JSValue subscript
= callFrame
->r(property
).jsValue();
3443 if (LIKELY(subscript
.isUInt32())) {
3444 uint32_t i
= subscript
.asUInt32();
3445 if (isJSArray(globalData
, baseValue
)) {
3446 JSArray
* jsArray
= asArray(baseValue
);
3447 if (jsArray
->canSetIndex(i
))
3448 jsArray
->setIndex(*globalData
, i
, callFrame
->r(value
).jsValue());
3450 jsArray
->JSArray::put(callFrame
, i
, callFrame
->r(value
).jsValue());
3451 } else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
)) {
3452 JSByteArray
* jsByteArray
= asByteArray(baseValue
);
3454 JSValue jsValue
= callFrame
->r(value
).jsValue();
3455 if (jsValue
.isInt32())
3456 jsByteArray
->setIndex(i
, jsValue
.asInt32());
3457 else if (jsValue
.getNumber(dValue
))
3458 jsByteArray
->setIndex(i
, dValue
);
3460 baseValue
.put(callFrame
, i
, jsValue
);
3462 baseValue
.put(callFrame
, i
, callFrame
->r(value
).jsValue());
3464 Identifier
property(callFrame
, subscript
.toString(callFrame
));
3465 if (!globalData
->exception
) { // Don't put to an object if toString threw an exception.
3466 PutPropertySlot
slot(codeBlock
->isStrictMode());
3467 baseValue
.put(callFrame
, property
, callFrame
->r(value
).jsValue(), slot
);
3471 CHECK_FOR_EXCEPTION();
3472 vPC
+= OPCODE_LENGTH(op_put_by_val
);
3475 DEFINE_OPCODE(op_del_by_val
) {
3476 /* del_by_val dst(r) base(r) property(r)
3478 Converts register base to Object, deletes the property
3479 named by register property from the object, and writes a
3480 boolean indicating success (if true) or failure (if false)
3483 int dst
= vPC
[1].u
.operand
;
3484 int base
= vPC
[2].u
.operand
;
3485 int property
= vPC
[3].u
.operand
;
3487 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
); // may throw
3489 JSValue subscript
= callFrame
->r(property
).jsValue();
3492 if (subscript
.getUInt32(i
))
3493 result
= baseObj
->deleteProperty(callFrame
, i
);
3495 CHECK_FOR_EXCEPTION();
3496 Identifier
property(callFrame
, subscript
.toString(callFrame
));
3497 CHECK_FOR_EXCEPTION();
3498 result
= baseObj
->deleteProperty(callFrame
, property
);
3500 if (!result
&& codeBlock
->isStrictMode()) {
3501 exceptionValue
= createTypeError(callFrame
, "Unable to delete property.");
3504 CHECK_FOR_EXCEPTION();
3505 callFrame
->uncheckedR(dst
) = jsBoolean(result
);
3506 vPC
+= OPCODE_LENGTH(op_del_by_val
);
3509 DEFINE_OPCODE(op_put_by_index
) {
3510 /* put_by_index base(r) property(n) value(r)
3512 Sets register value on register base as the property named
3513 by the immediate number property. Base is converted to
3516 Unlike many opcodes, this one does not write any output to
3519 This opcode is mainly used to initialize array literals.
3521 int base
= vPC
[1].u
.operand
;
3522 unsigned property
= vPC
[2].u
.operand
;
3523 int value
= vPC
[3].u
.operand
;
3525 callFrame
->r(base
).jsValue().put(callFrame
, property
, callFrame
->r(value
).jsValue());
3527 vPC
+= OPCODE_LENGTH(op_put_by_index
);
3530 DEFINE_OPCODE(op_loop
) {
3531 /* loop target(offset)
3533 Jumps unconditionally to offset target from the current
3536 Additionally this loop instruction may terminate JS execution is
3537 the JS timeout is reached.
3539 #if ENABLE(OPCODE_STATS)
3540 OpcodeStats::resetLastInstruction();
3542 int target
= vPC
[1].u
.operand
;
3543 CHECK_FOR_TIMEOUT();
3547 DEFINE_OPCODE(op_jmp
) {
3548 /* jmp target(offset)
3550 Jumps unconditionally to offset target from the current
3553 #if ENABLE(OPCODE_STATS)
3554 OpcodeStats::resetLastInstruction();
3556 int target
= vPC
[1].u
.operand
;
3561 DEFINE_OPCODE(op_loop_if_true
) {
3562 /* loop_if_true cond(r) target(offset)
3564 Jumps to offset target from the current instruction, if and
3565 only if register cond converts to boolean as true.
3567 Additionally this loop instruction may terminate JS execution is
3568 the JS timeout is reached.
3570 int cond
= vPC
[1].u
.operand
;
3571 int target
= vPC
[2].u
.operand
;
3572 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3574 CHECK_FOR_TIMEOUT();
3578 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
3581 DEFINE_OPCODE(op_loop_if_false
) {
3582 /* loop_if_true cond(r) target(offset)
3584 Jumps to offset target from the current instruction, if and
3585 only if register cond converts to boolean as false.
3587 Additionally this loop instruction may terminate JS execution is
3588 the JS timeout is reached.
3590 int cond
= vPC
[1].u
.operand
;
3591 int target
= vPC
[2].u
.operand
;
3592 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3594 CHECK_FOR_TIMEOUT();
3598 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
3601 DEFINE_OPCODE(op_jtrue
) {
3602 /* jtrue cond(r) target(offset)
3604 Jumps to offset target from the current instruction, if and
3605 only if register cond converts to boolean as true.
3607 int cond
= vPC
[1].u
.operand
;
3608 int target
= vPC
[2].u
.operand
;
3609 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3614 vPC
+= OPCODE_LENGTH(op_jtrue
);
3617 DEFINE_OPCODE(op_jfalse
) {
3618 /* jfalse cond(r) target(offset)
3620 Jumps to offset target from the current instruction, if and
3621 only if register cond converts to boolean as false.
3623 int cond
= vPC
[1].u
.operand
;
3624 int target
= vPC
[2].u
.operand
;
3625 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
3630 vPC
+= OPCODE_LENGTH(op_jfalse
);
3633 DEFINE_OPCODE(op_jeq_null
) {
3634 /* jeq_null src(r) target(offset)
3636 Jumps to offset target from the current instruction, if and
3637 only if register src is null.
3639 int src
= vPC
[1].u
.operand
;
3640 int target
= vPC
[2].u
.operand
;
3641 JSValue srcValue
= callFrame
->r(src
).jsValue();
3643 if (srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3648 vPC
+= OPCODE_LENGTH(op_jeq_null
);
3651 DEFINE_OPCODE(op_jneq_null
) {
3652 /* jneq_null src(r) target(offset)
3654 Jumps to offset target from the current instruction, if and
3655 only if register src is not null.
3657 int src
= vPC
[1].u
.operand
;
3658 int target
= vPC
[2].u
.operand
;
3659 JSValue srcValue
= callFrame
->r(src
).jsValue();
3661 if (!srcValue
.isUndefinedOrNull() && (!srcValue
.isCell() || !srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
3666 vPC
+= OPCODE_LENGTH(op_jneq_null
);
3669 DEFINE_OPCODE(op_jneq_ptr
) {
3670 /* jneq_ptr src(r) ptr(jsCell) target(offset)
3672 Jumps to offset target from the current instruction, if the value r is equal
3673 to ptr, using pointer equality.
3675 int src
= vPC
[1].u
.operand
;
3676 int target
= vPC
[3].u
.operand
;
3677 JSValue srcValue
= callFrame
->r(src
).jsValue();
3678 if (srcValue
!= vPC
[2].u
.jsCell
.get()) {
3683 vPC
+= OPCODE_LENGTH(op_jneq_ptr
);
3686 DEFINE_OPCODE(op_loop_if_less
) {
3687 /* loop_if_less src1(r) src2(r) target(offset)
3689 Checks whether register src1 is less than register src2, as
3690 with the ECMAScript '<' operator, and then jumps to offset
3691 target from the current instruction, if and only if the
3692 result of the comparison is true.
3694 Additionally this loop instruction may terminate JS execution is
3695 the JS timeout is reached.
3697 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3698 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3699 int target
= vPC
[3].u
.operand
;
3701 bool result
= jsLess(callFrame
, src1
, src2
);
3702 CHECK_FOR_EXCEPTION();
3706 CHECK_FOR_TIMEOUT();
3710 vPC
+= OPCODE_LENGTH(op_loop_if_less
);
3713 DEFINE_OPCODE(op_loop_if_lesseq
) {
3714 /* loop_if_lesseq src1(r) src2(r) target(offset)
3716 Checks whether register src1 is less than or equal to register
3717 src2, as with the ECMAScript '<=' operator, and then jumps to
3718 offset target from the current instruction, if and only if the
3719 result of the comparison is true.
3721 Additionally this loop instruction may terminate JS execution is
3722 the JS timeout is reached.
3724 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3725 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3726 int target
= vPC
[3].u
.operand
;
3728 bool result
= jsLessEq(callFrame
, src1
, src2
);
3729 CHECK_FOR_EXCEPTION();
3733 CHECK_FOR_TIMEOUT();
3737 vPC
+= OPCODE_LENGTH(op_loop_if_lesseq
);
3740 DEFINE_OPCODE(op_jnless
) {
3741 /* jnless src1(r) src2(r) target(offset)
3743 Checks whether register src1 is less than register src2, as
3744 with the ECMAScript '<' operator, and then jumps to offset
3745 target from the current instruction, if and only if the
3746 result of the comparison is false.
3748 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3749 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3750 int target
= vPC
[3].u
.operand
;
3752 bool result
= jsLess(callFrame
, src1
, src2
);
3753 CHECK_FOR_EXCEPTION();
3760 vPC
+= OPCODE_LENGTH(op_jnless
);
3763 DEFINE_OPCODE(op_jless
) {
3764 /* jless src1(r) src2(r) target(offset)
3766 Checks whether register src1 is less than register src2, as
3767 with the ECMAScript '<' operator, and then jumps to offset
3768 target from the current instruction, if and only if the
3769 result of the comparison is true.
3771 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3772 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3773 int target
= vPC
[3].u
.operand
;
3775 bool result
= jsLess(callFrame
, src1
, src2
);
3776 CHECK_FOR_EXCEPTION();
3783 vPC
+= OPCODE_LENGTH(op_jless
);
3786 DEFINE_OPCODE(op_jnlesseq
) {
3787 /* jnlesseq src1(r) src2(r) target(offset)
3789 Checks whether register src1 is less than or equal to
3790 register src2, as with the ECMAScript '<=' operator,
3791 and then jumps to offset target from the current instruction,
3792 if and only if theresult of the comparison is false.
3794 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3795 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3796 int target
= vPC
[3].u
.operand
;
3798 bool result
= jsLessEq(callFrame
, src1
, src2
);
3799 CHECK_FOR_EXCEPTION();
3806 vPC
+= OPCODE_LENGTH(op_jnlesseq
);
3809 DEFINE_OPCODE(op_jlesseq
) {
3810 /* jlesseq src1(r) src2(r) target(offset)
3812 Checks whether register src1 is less than or equal to
3813 register src2, as with the ECMAScript '<=' operator,
3814 and then jumps to offset target from the current instruction,
3815 if and only if the result of the comparison is true.
3817 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
3818 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
3819 int target
= vPC
[3].u
.operand
;
3821 bool result
= jsLessEq(callFrame
, src1
, src2
);
3822 CHECK_FOR_EXCEPTION();
3829 vPC
+= OPCODE_LENGTH(op_jlesseq
);
3832 DEFINE_OPCODE(op_switch_imm
) {
3833 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
3835 Performs a range checked switch on the scrutinee value, using
3836 the tableIndex-th immediate switch jump table. If the scrutinee value
3837 is an immediate number in the range covered by the referenced jump
3838 table, and the value at jumpTable[scrutinee value] is non-zero, then
3839 that value is used as the jump offset, otherwise defaultOffset is used.
3841 int tableIndex
= vPC
[1].u
.operand
;
3842 int defaultOffset
= vPC
[2].u
.operand
;
3843 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
3844 if (scrutinee
.isInt32())
3845 vPC
+= codeBlock
->immediateSwitchJumpTable(tableIndex
).offsetForValue(scrutinee
.asInt32(), defaultOffset
);
3849 if (scrutinee
.getNumber(value
) && ((intValue
= static_cast<int32_t>(value
)) == value
))
3850 vPC
+= codeBlock
->immediateSwitchJumpTable(tableIndex
).offsetForValue(intValue
, defaultOffset
);
3852 vPC
+= defaultOffset
;
3856 DEFINE_OPCODE(op_switch_char
) {
3857 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3859 Performs a range checked switch on the scrutinee value, using
3860 the tableIndex-th character switch jump table. If the scrutinee value
3861 is a single character string in the range covered by the referenced jump
3862 table, and the value at jumpTable[scrutinee value] is non-zero, then
3863 that value is used as the jump offset, otherwise defaultOffset is used.
3865 int tableIndex
= vPC
[1].u
.operand
;
3866 int defaultOffset
= vPC
[2].u
.operand
;
3867 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
3868 if (!scrutinee
.isString())
3869 vPC
+= defaultOffset
;
3871 StringImpl
* value
= asString(scrutinee
)->value(callFrame
).impl();
3872 if (value
->length() != 1)
3873 vPC
+= defaultOffset
;
3875 vPC
+= codeBlock
->characterSwitchJumpTable(tableIndex
).offsetForValue(value
->characters()[0], defaultOffset
);
3879 DEFINE_OPCODE(op_switch_string
) {
3880 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3882 Performs a sparse hashmap based switch on the value in the scrutinee
3883 register, using the tableIndex-th string switch jump table. If the
3884 scrutinee value is a string that exists as a key in the referenced
3885 jump table, then the value associated with the string is used as the
3886 jump offset, otherwise defaultOffset is used.
3888 int tableIndex
= vPC
[1].u
.operand
;
3889 int defaultOffset
= vPC
[2].u
.operand
;
3890 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
3891 if (!scrutinee
.isString())
3892 vPC
+= defaultOffset
;
3894 vPC
+= codeBlock
->stringSwitchJumpTable(tableIndex
).offsetForValue(asString(scrutinee
)->value(callFrame
).impl(), defaultOffset
);
3897 DEFINE_OPCODE(op_new_func
) {
3898 /* new_func dst(r) func(f)
3900 Constructs a new Function instance from function func and
3901 the current scope chain using the original Function
3902 constructor, using the rules for function declarations, and
3903 puts the result in register dst.
3905 int dst
= vPC
[1].u
.operand
;
3906 int func
= vPC
[2].u
.operand
;
3907 int shouldCheck
= vPC
[3].u
.operand
;
3908 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
3909 if (!shouldCheck
|| !callFrame
->r(dst
).jsValue())
3910 callFrame
->uncheckedR(dst
) = JSValue(codeBlock
->functionDecl(func
)->make(callFrame
, callFrame
->scopeChain()));
3912 vPC
+= OPCODE_LENGTH(op_new_func
);
3915 DEFINE_OPCODE(op_new_func_exp
) {
3916 /* new_func_exp dst(r) func(f)
3918 Constructs a new Function instance from function func and
3919 the current scope chain using the original Function
3920 constructor, using the rules for function expressions, and
3921 puts the result in register dst.
3923 int dst
= vPC
[1].u
.operand
;
3924 int funcIndex
= vPC
[2].u
.operand
;
3926 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
3927 FunctionExecutable
* function
= codeBlock
->functionExpr(funcIndex
);
3928 JSFunction
* func
= function
->make(callFrame
, callFrame
->scopeChain());
3931 The Identifier in a FunctionExpression can be referenced from inside
3932 the FunctionExpression's FunctionBody to allow the function to call
3933 itself recursively. However, unlike in a FunctionDeclaration, the
3934 Identifier in a FunctionExpression cannot be referenced from and
3935 does not affect the scope enclosing the FunctionExpression.
3937 if (!function
->name().isNull()) {
3938 JSStaticScopeObject
* functionScopeObject
= new (callFrame
) JSStaticScopeObject(callFrame
, function
->name(), func
, ReadOnly
| DontDelete
);
3939 func
->setScope(*globalData
, func
->scope()->push(functionScopeObject
));
3942 callFrame
->uncheckedR(dst
) = JSValue(func
);
3944 vPC
+= OPCODE_LENGTH(op_new_func_exp
);
3947 DEFINE_OPCODE(op_call_eval
) {
3948 /* call_eval func(r) argCount(n) registerOffset(n)
3950 Call a function named "eval" with no explicit "this" value
3951 (which may therefore be the eval operator). If register
3952 thisVal is the global object, and register func contains
3953 that global object's original global eval function, then
3954 perform the eval operator in local scope (interpreting
3955 the argument registers as for the "call"
3956 opcode). Otherwise, act exactly as the "call" opcode would.
3959 int func
= vPC
[1].u
.operand
;
3960 int argCount
= vPC
[2].u
.operand
;
3961 int registerOffset
= vPC
[3].u
.operand
;
3963 ASSERT(codeBlock
->codeType() != FunctionCode
|| !codeBlock
->needsFullScopeChain() || callFrame
->r(codeBlock
->activationRegister()).jsValue());
3964 JSValue funcVal
= callFrame
->r(func
).jsValue();
3966 Register
* newCallFrame
= callFrame
->registers() + registerOffset
;
3967 Register
* argv
= newCallFrame
- RegisterFile::CallFrameHeaderSize
- argCount
;
3968 JSValue thisValue
= argv
[0].jsValue();
3969 JSGlobalObject
* globalObject
= callFrame
->scopeChain()->globalObject
.get();
3971 if (thisValue
== globalObject
&& funcVal
== globalObject
->evalFunction()) {
3972 JSValue result
= callEval(callFrame
, registerFile
, argv
, argCount
, registerOffset
);
3973 if ((exceptionValue
= globalData
->exception
))
3975 functionReturnValue
= result
;
3977 vPC
+= OPCODE_LENGTH(op_call_eval
);
3981 // We didn't find the blessed version of eval, so process this
3982 // instruction as a normal function call.
3983 // fall through to op_call
3985 DEFINE_OPCODE(op_call
) {
3986 /* call func(r) argCount(n) registerOffset(n)
3988 Perform a function call.
3990 registerOffset is the distance the callFrame pointer should move
3991 before the VM initializes the new call frame's header.
3993 dst is where op_ret should store its result.
3996 int func
= vPC
[1].u
.operand
;
3997 int argCount
= vPC
[2].u
.operand
;
3998 int registerOffset
= vPC
[3].u
.operand
;
4000 JSValue v
= callFrame
->r(func
).jsValue();
4003 CallType callType
= getCallData(v
, callData
);
4005 if (callType
== CallTypeJS
) {
4006 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
4008 JSObject
* error
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
4009 if (UNLIKELY(!!error
)) {
4010 exceptionValue
= error
;
4014 CallFrame
* previousCallFrame
= callFrame
;
4015 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
4016 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
4017 if (UNLIKELY(!callFrame
)) {
4018 callFrame
= previousCallFrame
;
4019 exceptionValue
= createStackOverflowError(callFrame
);
4023 callFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_call
), callDataScopeChain
, previousCallFrame
, argCount
, asFunction(v
));
4024 codeBlock
= newCodeBlock
;
4025 ASSERT(codeBlock
== callFrame
->codeBlock());
4026 vPC
= newCodeBlock
->instructions().begin();
4028 #if ENABLE(OPCODE_STATS)
4029 OpcodeStats::resetLastInstruction();
4035 if (callType
== CallTypeHost
) {
4036 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4037 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4038 if (!registerFile
->grow(newCallFrame
->registers())) {
4039 exceptionValue
= createStackOverflowError(callFrame
);
4043 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_call
), scopeChain
, callFrame
, argCount
, asObject(v
));
4045 JSValue returnValue
;
4047 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4048 returnValue
= JSValue::decode(callData
.native
.function(newCallFrame
));
4050 CHECK_FOR_EXCEPTION();
4052 functionReturnValue
= returnValue
;
4054 vPC
+= OPCODE_LENGTH(op_call
);
4058 ASSERT(callType
== CallTypeNone
);
4060 exceptionValue
= createNotAFunctionError(callFrame
, v
);
4063 DEFINE_OPCODE(op_load_varargs
) {
4064 int argCountDst
= vPC
[1].u
.operand
;
4065 int argsOffset
= vPC
[2].u
.operand
;
4067 JSValue arguments
= callFrame
->r(argsOffset
).jsValue();
4068 uint32_t argCount
= 0;
4070 argCount
= (uint32_t)(callFrame
->argumentCount());
4071 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
4072 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
4073 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
4074 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
4075 exceptionValue
= createStackOverflowError(callFrame
);
4078 ASSERT(!asFunction(callFrame
->callee())->isHostFunction());
4079 int32_t expectedParams
= asFunction(callFrame
->callee())->jsExecutable()->parameterCount();
4080 int32_t inplaceArgs
= min(static_cast<int32_t>(argCount
), expectedParams
);
4082 Register
* argStore
= callFrame
->registers() + argsOffset
;
4084 // First step is to copy the "expected" parameters from their normal location relative to the callframe
4085 for (; i
< inplaceArgs
; i
++)
4086 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
];
4087 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
4088 for (; i
< static_cast<int32_t>(argCount
); i
++)
4089 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
- static_cast<int32_t>(argCount
) - 1];
4090 } else if (!arguments
.isUndefinedOrNull()) {
4091 if (!arguments
.isObject()) {
4092 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
);
4095 if (asObject(arguments
)->classInfo() == &Arguments::s_info
) {
4096 Arguments
* args
= asArguments(arguments
);
4097 argCount
= args
->numProvidedArguments(callFrame
);
4098 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
4099 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
4100 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
4101 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
4102 exceptionValue
= createStackOverflowError(callFrame
);
4105 args
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
4106 } else if (isJSArray(&callFrame
->globalData(), arguments
)) {
4107 JSArray
* array
= asArray(arguments
);
4108 argCount
= array
->length();
4109 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
4110 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
4111 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
4112 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
4113 exceptionValue
= createStackOverflowError(callFrame
);
4116 array
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
4117 } else if (asObject(arguments
)->inherits(&JSArray::s_info
)) {
4118 JSObject
* argObject
= asObject(arguments
);
4119 argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
4120 argCount
= min
<uint32_t>(argCount
, Arguments::MaxArguments
);
4121 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
4122 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
4123 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
4124 exceptionValue
= createStackOverflowError(callFrame
);
4127 Register
* argsBuffer
= callFrame
->registers() + argsOffset
;
4128 for (uint32_t i
= 0; i
< argCount
; ++i
) {
4129 argsBuffer
[i
] = asObject(arguments
)->get(callFrame
, i
);
4130 CHECK_FOR_EXCEPTION();
4133 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
);
4137 CHECK_FOR_EXCEPTION();
4138 callFrame
->uncheckedR(argCountDst
) = Register::withInt(argCount
+ 1);
4139 vPC
+= OPCODE_LENGTH(op_load_varargs
);
4142 DEFINE_OPCODE(op_call_varargs
) {
4143 /* call_varargs func(r) argCountReg(r) baseRegisterOffset(n)
4145 Perform a function call with a dynamic set of arguments.
4147 registerOffset is the distance the callFrame pointer should move
4148 before the VM initializes the new call frame's header, excluding
4149 space for arguments.
4151 dst is where op_ret should store its result.
4154 int func
= vPC
[1].u
.operand
;
4155 int argCountReg
= vPC
[2].u
.operand
;
4156 int registerOffset
= vPC
[3].u
.operand
;
4158 JSValue v
= callFrame
->r(func
).jsValue();
4159 int argCount
= callFrame
->r(argCountReg
).i();
4160 registerOffset
+= argCount
;
4162 CallType callType
= getCallData(v
, callData
);
4164 if (callType
== CallTypeJS
) {
4165 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
4167 JSObject
* error
= callData
.js
.functionExecutable
->compileForCall(callFrame
, callDataScopeChain
);
4168 if (UNLIKELY(!!error
)) {
4169 exceptionValue
= error
;
4173 CallFrame
* previousCallFrame
= callFrame
;
4174 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
4175 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
4176 if (UNLIKELY(!callFrame
)) {
4177 callFrame
= previousCallFrame
;
4178 exceptionValue
= createStackOverflowError(callFrame
);
4182 callFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_call_varargs
), callDataScopeChain
, previousCallFrame
, argCount
, asFunction(v
));
4183 codeBlock
= newCodeBlock
;
4184 ASSERT(codeBlock
== callFrame
->codeBlock());
4185 vPC
= newCodeBlock
->instructions().begin();
4187 #if ENABLE(OPCODE_STATS)
4188 OpcodeStats::resetLastInstruction();
4194 if (callType
== CallTypeHost
) {
4195 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4196 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4197 if (!registerFile
->grow(newCallFrame
->registers())) {
4198 exceptionValue
= createStackOverflowError(callFrame
);
4201 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_call_varargs
), scopeChain
, callFrame
, argCount
, asObject(v
));
4203 JSValue returnValue
;
4205 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4206 returnValue
= JSValue::decode(callData
.native
.function(newCallFrame
));
4208 CHECK_FOR_EXCEPTION();
4210 functionReturnValue
= returnValue
;
4212 vPC
+= OPCODE_LENGTH(op_call_varargs
);
4216 ASSERT(callType
== CallTypeNone
);
4218 exceptionValue
= createNotAFunctionError(callFrame
, v
);
4221 DEFINE_OPCODE(op_tear_off_activation
) {
4222 /* tear_off_activation activation(r) arguments(r)
4224 Copy locals and named parameters from the register file to the heap.
4225 Point the bindings in 'activation' and 'arguments' to this new backing
4226 store. (Note that 'arguments' may not have been created. If created,
4227 'arguments' already holds a copy of any extra / unnamed parameters.)
4229 This opcode appears before op_ret in functions that require full scope chains.
4232 int activation
= vPC
[1].u
.operand
;
4233 int arguments
= vPC
[2].u
.operand
;
4234 ASSERT(codeBlock
->needsFullScopeChain());
4235 JSValue activationValue
= callFrame
->r(activation
).jsValue();
4236 if (activationValue
) {
4237 asActivation(activationValue
)->copyRegisters(*globalData
);
4239 if (JSValue argumentsValue
= callFrame
->r(unmodifiedArgumentsRegister(arguments
)).jsValue()) {
4240 if (!codeBlock
->isStrictMode())
4241 asArguments(argumentsValue
)->setActivation(*globalData
, asActivation(activationValue
));
4243 } else if (JSValue argumentsValue
= callFrame
->r(unmodifiedArgumentsRegister(arguments
)).jsValue()) {
4244 if (!codeBlock
->isStrictMode())
4245 asArguments(argumentsValue
)->copyRegisters(*globalData
);
4248 vPC
+= OPCODE_LENGTH(op_tear_off_activation
);
4251 DEFINE_OPCODE(op_tear_off_arguments
) {
4252 /* tear_off_arguments arguments(r)
4254 Copy named parameters from the register file to the heap. Point the
4255 bindings in 'arguments' to this new backing store. (Note that
4256 'arguments' may not have been created. If created, 'arguments' already
4257 holds a copy of any extra / unnamed parameters.)
4259 This opcode appears before op_ret in functions that don't require full
4260 scope chains, but do use 'arguments'.
4263 int src1
= vPC
[1].u
.operand
;
4264 ASSERT(!codeBlock
->needsFullScopeChain() && codeBlock
->ownerExecutable()->usesArguments());
4266 if (JSValue arguments
= callFrame
->r(unmodifiedArgumentsRegister(src1
)).jsValue())
4267 asArguments(arguments
)->copyRegisters(*globalData
);
4269 vPC
+= OPCODE_LENGTH(op_tear_off_arguments
);
4272 DEFINE_OPCODE(op_ret
) {
4275 Return register result as the return value of the current
4276 function call, writing it into functionReturnValue.
4277 In addition, unwind one call frame and restore the scope
4278 chain, code block instruction pointer and register base
4279 to those of the calling function.
4282 int result
= vPC
[1].u
.operand
;
4284 JSValue returnValue
= callFrame
->r(result
).jsValue();
4286 vPC
= callFrame
->returnVPC();
4287 callFrame
= callFrame
->callerFrame();
4289 if (callFrame
->hasHostCallFrameFlag())
4292 functionReturnValue
= returnValue
;
4293 codeBlock
= callFrame
->codeBlock();
4294 ASSERT(codeBlock
== callFrame
->codeBlock());
4298 DEFINE_OPCODE(op_call_put_result
) {
4299 /* op_call_put_result result(r)
4301 Move call result from functionReturnValue to caller's
4302 expected return value register.
4305 callFrame
->uncheckedR(vPC
[1].u
.operand
) = functionReturnValue
;
4307 vPC
+= OPCODE_LENGTH(op_call_put_result
);
4310 DEFINE_OPCODE(op_ret_object_or_this
) {
4313 Return register result as the return value of the current
4314 function call, writing it into the caller's expected return
4315 value register. In addition, unwind one call frame and
4316 restore the scope chain, code block instruction pointer and
4317 register base to those of the calling function.
4320 int result
= vPC
[1].u
.operand
;
4322 JSValue returnValue
= callFrame
->r(result
).jsValue();
4324 if (UNLIKELY(!returnValue
.isObject()))
4325 returnValue
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
4327 vPC
= callFrame
->returnVPC();
4328 callFrame
= callFrame
->callerFrame();
4330 if (callFrame
->hasHostCallFrameFlag())
4333 functionReturnValue
= returnValue
;
4334 codeBlock
= callFrame
->codeBlock();
4335 ASSERT(codeBlock
== callFrame
->codeBlock());
4339 DEFINE_OPCODE(op_enter
) {
4342 Initializes local variables to undefined. If the code block requires
4343 an activation, enter_with_activation is used instead.
4345 This opcode appears only at the beginning of a code block.
4349 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
4350 callFrame
->uncheckedR(i
) = jsUndefined();
4352 vPC
+= OPCODE_LENGTH(op_enter
);
4355 DEFINE_OPCODE(op_create_activation
) {
4356 /* create_activation dst(r)
4358 If the activation object for this callframe has not yet been created,
4359 this creates it and writes it back to dst.
4362 int activationReg
= vPC
[1].u
.operand
;
4363 if (!callFrame
->r(activationReg
).jsValue()) {
4364 JSActivation
* activation
= new (globalData
) JSActivation(callFrame
, static_cast<FunctionExecutable
*>(codeBlock
->ownerExecutable()));
4365 callFrame
->r(activationReg
) = JSValue(activation
);
4366 callFrame
->setScopeChain(callFrame
->scopeChain()->push(activation
));
4368 vPC
+= OPCODE_LENGTH(op_create_activation
);
4371 DEFINE_OPCODE(op_get_callee
) {
4372 /* op_get_callee callee(r)
4374 Move callee into a register.
4377 callFrame
->uncheckedR(vPC
[1].u
.operand
) = JSValue(callFrame
->callee());
4379 vPC
+= OPCODE_LENGTH(op_get_callee
);
4382 DEFINE_OPCODE(op_create_this
) {
4383 /* op_create_this this(r) proto(r)
4385 Allocate an object as 'this', fr use in construction.
4387 This opcode should only be used at the beginning of a code
4391 int thisRegister
= vPC
[1].u
.operand
;
4392 int protoRegister
= vPC
[2].u
.operand
;
4394 JSFunction
* constructor
= asFunction(callFrame
->callee());
4395 #if !ASSERT_DISABLED
4396 ConstructData constructData
;
4397 ASSERT(constructor
->getConstructData(constructData
) == ConstructTypeJS
);
4400 Structure
* structure
;
4401 JSValue proto
= callFrame
->r(protoRegister
).jsValue();
4402 if (proto
.isObject())
4403 structure
= asObject(proto
)->inheritorID(callFrame
->globalData());
4405 structure
= constructor
->scope()->globalObject
->emptyObjectStructure();
4406 callFrame
->uncheckedR(thisRegister
) = constructEmptyObject(callFrame
, structure
);
4408 vPC
+= OPCODE_LENGTH(op_create_this
);
4411 DEFINE_OPCODE(op_convert_this
) {
4412 /* convert_this this(r)
4414 Takes the value in the 'this' register, converts it to a
4415 value that is suitable for use as the 'this' value, and
4416 stores it in the 'this' register. This opcode is emitted
4417 to avoid doing the conversion in the caller unnecessarily.
4419 This opcode should only be used at the beginning of a code
4423 int thisRegister
= vPC
[1].u
.operand
;
4424 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
4425 if (thisVal
.needsThisConversion())
4426 callFrame
->uncheckedR(thisRegister
) = JSValue(thisVal
.toThisObject(callFrame
));
4428 vPC
+= OPCODE_LENGTH(op_convert_this
);
4431 DEFINE_OPCODE(op_convert_this_strict
) {
4432 /* convert_this_strict this(r)
4434 Takes the value in the 'this' register, and converts it to
4435 its "this" form if (and only if) "this" is an object with a
4436 custom this conversion
4438 This opcode should only be used at the beginning of a code
4442 int thisRegister
= vPC
[1].u
.operand
;
4443 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
4444 if (thisVal
.isObject() && thisVal
.needsThisConversion())
4445 callFrame
->uncheckedR(thisRegister
) = JSValue(thisVal
.toStrictThisObject(callFrame
));
4447 vPC
+= OPCODE_LENGTH(op_convert_this_strict
);
4450 DEFINE_OPCODE(op_init_lazy_reg
) {
4451 /* init_lazy_reg dst(r)
4453 Initialises dst(r) to JSValue().
4455 This opcode appears only at the beginning of a code block.
4457 int dst
= vPC
[1].u
.operand
;
4459 callFrame
->uncheckedR(dst
) = JSValue();
4460 vPC
+= OPCODE_LENGTH(op_init_lazy_reg
);
4463 DEFINE_OPCODE(op_create_arguments
) {
4464 /* create_arguments dst(r)
4466 Creates the 'arguments' object and places it in both the
4467 'arguments' call frame slot and the local 'arguments'
4468 register, if it has not already been initialised.
4471 int dst
= vPC
[1].u
.operand
;
4473 if (!callFrame
->r(dst
).jsValue()) {
4474 Arguments
* arguments
= new (globalData
) Arguments(callFrame
);
4475 callFrame
->uncheckedR(dst
) = JSValue(arguments
);
4476 callFrame
->uncheckedR(unmodifiedArgumentsRegister(dst
)) = JSValue(arguments
);
4478 vPC
+= OPCODE_LENGTH(op_create_arguments
);
4481 DEFINE_OPCODE(op_construct
) {
4482 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
4484 Invoke register "func" as a constructor. For JS
4485 functions, the calling convention is exactly as for the
4486 "call" opcode, except that the "this" value is a newly
4487 created Object. For native constructors, no "this"
4488 value is passed. In either case, the argCount and registerOffset
4489 registers are interpreted as for the "call" opcode.
4491 Register proto must contain the prototype property of
4492 register func. This is to enable polymorphic inline
4493 caching of this lookup.
4496 int func
= vPC
[1].u
.operand
;
4497 int argCount
= vPC
[2].u
.operand
;
4498 int registerOffset
= vPC
[3].u
.operand
;
4500 JSValue v
= callFrame
->r(func
).jsValue();
4502 ConstructData constructData
;
4503 ConstructType constructType
= getConstructData(v
, constructData
);
4505 if (constructType
== ConstructTypeJS
) {
4506 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
4508 JSObject
* error
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, callDataScopeChain
);
4509 if (UNLIKELY(!!error
)) {
4510 exceptionValue
= error
;
4514 CallFrame
* previousCallFrame
= callFrame
;
4515 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
4516 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
4517 if (UNLIKELY(!callFrame
)) {
4518 callFrame
= previousCallFrame
;
4519 exceptionValue
= createStackOverflowError(callFrame
);
4523 callFrame
->init(newCodeBlock
, vPC
+ OPCODE_LENGTH(op_construct
), callDataScopeChain
, previousCallFrame
, argCount
, asFunction(v
));
4524 codeBlock
= newCodeBlock
;
4525 vPC
= newCodeBlock
->instructions().begin();
4526 #if ENABLE(OPCODE_STATS)
4527 OpcodeStats::resetLastInstruction();
4533 if (constructType
== ConstructTypeHost
) {
4534 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
4535 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
4536 if (!registerFile
->grow(newCallFrame
->registers())) {
4537 exceptionValue
= createStackOverflowError(callFrame
);
4540 newCallFrame
->init(0, vPC
+ OPCODE_LENGTH(op_construct
), scopeChain
, callFrame
, argCount
, asObject(v
));
4542 JSValue returnValue
;
4544 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
4545 returnValue
= JSValue::decode(constructData
.native
.function(newCallFrame
));
4547 CHECK_FOR_EXCEPTION();
4548 functionReturnValue
= returnValue
;
4550 vPC
+= OPCODE_LENGTH(op_construct
);
4554 ASSERT(constructType
== ConstructTypeNone
);
4556 exceptionValue
= createNotAConstructorError(callFrame
, v
);
4559 DEFINE_OPCODE(op_strcat
) {
4560 /* strcat dst(r) src(r) count(n)
4562 Construct a new String instance using the original
4563 constructor, and puts the result in register dst.
4564 The string will be the result of concatenating count
4565 strings with values taken from registers starting at
4568 int dst
= vPC
[1].u
.operand
;
4569 int src
= vPC
[2].u
.operand
;
4570 int count
= vPC
[3].u
.operand
;
4572 callFrame
->uncheckedR(dst
) = concatenateStrings(callFrame
, &callFrame
->registers()[src
], count
);
4573 CHECK_FOR_EXCEPTION();
4574 vPC
+= OPCODE_LENGTH(op_strcat
);
4578 DEFINE_OPCODE(op_to_primitive
) {
4579 int dst
= vPC
[1].u
.operand
;
4580 int src
= vPC
[2].u
.operand
;
4582 callFrame
->uncheckedR(dst
) = callFrame
->r(src
).jsValue().toPrimitive(callFrame
);
4583 vPC
+= OPCODE_LENGTH(op_to_primitive
);
4587 DEFINE_OPCODE(op_push_scope
) {
4588 /* push_scope scope(r)
4590 Converts register scope to object, and pushes it onto the top
4591 of the current scope chain. The contents of the register scope
4592 are replaced by the result of toObject conversion of the scope.
4594 int scope
= vPC
[1].u
.operand
;
4595 JSValue v
= callFrame
->r(scope
).jsValue();
4596 JSObject
* o
= v
.toObject(callFrame
);
4597 CHECK_FOR_EXCEPTION();
4599 callFrame
->uncheckedR(scope
) = JSValue(o
);
4600 callFrame
->setScopeChain(callFrame
->scopeChain()->push(o
));
4602 vPC
+= OPCODE_LENGTH(op_push_scope
);
4605 DEFINE_OPCODE(op_pop_scope
) {
4608 Removes the top item from the current scope chain.
4610 callFrame
->setScopeChain(callFrame
->scopeChain()->pop());
4612 vPC
+= OPCODE_LENGTH(op_pop_scope
);
4615 DEFINE_OPCODE(op_get_pnames
) {
4616 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
4618 Creates a property name list for register base and puts it
4619 in register dst, initializing i and size for iteration. If
4620 base is undefined or null, jumps to breakTarget.
4622 int dst
= vPC
[1].u
.operand
;
4623 int base
= vPC
[2].u
.operand
;
4624 int i
= vPC
[3].u
.operand
;
4625 int size
= vPC
[4].u
.operand
;
4626 int breakTarget
= vPC
[5].u
.operand
;
4628 JSValue v
= callFrame
->r(base
).jsValue();
4629 if (v
.isUndefinedOrNull()) {
4634 JSObject
* o
= v
.toObject(callFrame
);
4635 Structure
* structure
= o
->structure();
4636 JSPropertyNameIterator
* jsPropertyNameIterator
= structure
->enumerationCache();
4637 if (!jsPropertyNameIterator
|| jsPropertyNameIterator
->cachedPrototypeChain() != structure
->prototypeChain(callFrame
))
4638 jsPropertyNameIterator
= JSPropertyNameIterator::create(callFrame
, o
);
4640 callFrame
->uncheckedR(dst
) = jsPropertyNameIterator
;
4641 callFrame
->uncheckedR(base
) = JSValue(o
);
4642 callFrame
->uncheckedR(i
) = Register::withInt(0);
4643 callFrame
->uncheckedR(size
) = Register::withInt(jsPropertyNameIterator
->size());
4644 vPC
+= OPCODE_LENGTH(op_get_pnames
);
4647 DEFINE_OPCODE(op_next_pname
) {
4648 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
4650 Copies the next name from the property name list in
4651 register iter to dst, then jumps to offset target. If there are no
4652 names left, invalidates the iterator and continues to the next
4655 int dst
= vPC
[1].u
.operand
;
4656 int base
= vPC
[2].u
.operand
;
4657 int i
= vPC
[3].u
.operand
;
4658 int size
= vPC
[4].u
.operand
;
4659 int iter
= vPC
[5].u
.operand
;
4660 int target
= vPC
[6].u
.operand
;
4662 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
4663 while (callFrame
->r(i
).i() != callFrame
->r(size
).i()) {
4664 JSValue key
= it
->get(callFrame
, asObject(callFrame
->r(base
).jsValue()), callFrame
->r(i
).i());
4665 CHECK_FOR_EXCEPTION();
4666 callFrame
->uncheckedR(i
) = Register::withInt(callFrame
->r(i
).i() + 1);
4668 CHECK_FOR_TIMEOUT();
4669 callFrame
->uncheckedR(dst
) = key
;
4675 vPC
+= OPCODE_LENGTH(op_next_pname
);
4678 DEFINE_OPCODE(op_jmp_scopes
) {
4679 /* jmp_scopes count(n) target(offset)
4681 Removes the a number of items from the current scope chain
4682 specified by immediate number count, then jumps to offset
4685 int count
= vPC
[1].u
.operand
;
4686 int target
= vPC
[2].u
.operand
;
4688 ScopeChainNode
* tmp
= callFrame
->scopeChain();
4691 callFrame
->setScopeChain(tmp
);
4696 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4698 goto *(&&skip_new_scope
);
4700 DEFINE_OPCODE(op_push_new_scope
) {
4701 /* new_scope dst(r) property(id) value(r)
4703 Constructs a new StaticScopeObject with property set to value. That scope
4704 object is then pushed onto the ScopeChain. The scope object is then stored
4707 callFrame
->setScopeChain(createExceptionScope(callFrame
, vPC
));
4709 vPC
+= OPCODE_LENGTH(op_push_new_scope
);
4712 #if ENABLE(COMPUTED_GOTO_INTERPRETER)
4715 DEFINE_OPCODE(op_catch
) {
4718 Retrieves the VM's current exception and puts it in register
4719 ex. This is only valid after an exception has been raised,
4720 and usually forms the beginning of an exception handler.
4722 ASSERT(exceptionValue
);
4723 ASSERT(!globalData
->exception
);
4724 int ex
= vPC
[1].u
.operand
;
4725 callFrame
->uncheckedR(ex
) = exceptionValue
;
4726 exceptionValue
= JSValue();
4728 vPC
+= OPCODE_LENGTH(op_catch
);
4731 DEFINE_OPCODE(op_throw
) {
4734 Throws register ex as an exception. This involves three
4735 steps: first, it is set as the current exception in the
4736 VM's internal state, then the stack is unwound until an
4737 exception handler or a native code boundary is found, and
4738 then control resumes at the exception handler if any or
4739 else the script returns control to the nearest native caller.
4742 int ex
= vPC
[1].u
.operand
;
4743 exceptionValue
= callFrame
->r(ex
).jsValue();
4745 handler
= throwException(callFrame
, exceptionValue
, vPC
- codeBlock
->instructions().begin());
4747 return throwError(callFrame
, exceptionValue
);
4749 codeBlock
= callFrame
->codeBlock();
4750 vPC
= codeBlock
->instructions().begin() + handler
->target
;
4753 DEFINE_OPCODE(op_throw_reference_error
) {
4754 /* op_throw_reference_error message(k)
4756 Constructs a new reference Error instance using the
4757 original constructor, using constant message as the
4758 message string. The result is thrown.
4760 UString message
= callFrame
->r(vPC
[1].u
.operand
).jsValue().toString(callFrame
);
4761 exceptionValue
= JSValue(createReferenceError(callFrame
, message
));
4764 DEFINE_OPCODE(op_end
) {
4767 Return register result as the value of a global or eval
4768 program. Return control to the calling native code.
4771 int result
= vPC
[1].u
.operand
;
4772 return callFrame
->r(result
).jsValue();
4774 DEFINE_OPCODE(op_put_getter
) {
4775 /* put_getter base(r) property(id) function(r)
4777 Sets register function on register base as the getter named
4778 by identifier property. Base and function are assumed to be
4779 objects as this op should only be used for getters defined
4780 in object literal form.
4782 Unlike many opcodes, this one does not write any output to
4785 int base
= vPC
[1].u
.operand
;
4786 int property
= vPC
[2].u
.operand
;
4787 int function
= vPC
[3].u
.operand
;
4789 ASSERT(callFrame
->r(base
).jsValue().isObject());
4790 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
4791 Identifier
& ident
= codeBlock
->identifier(property
);
4792 ASSERT(callFrame
->r(function
).jsValue().isObject());
4793 baseObj
->defineGetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()));
4795 vPC
+= OPCODE_LENGTH(op_put_getter
);
4798 DEFINE_OPCODE(op_put_setter
) {
4799 /* put_setter base(r) property(id) function(r)
4801 Sets register function on register base as the setter named
4802 by identifier property. Base and function are assumed to be
4803 objects as this op should only be used for setters defined
4804 in object literal form.
4806 Unlike many opcodes, this one does not write any output to
4809 int base
= vPC
[1].u
.operand
;
4810 int property
= vPC
[2].u
.operand
;
4811 int function
= vPC
[3].u
.operand
;
4813 ASSERT(callFrame
->r(base
).jsValue().isObject());
4814 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
4815 Identifier
& ident
= codeBlock
->identifier(property
);
4816 ASSERT(callFrame
->r(function
).jsValue().isObject());
4817 baseObj
->defineSetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()), 0);
4819 vPC
+= OPCODE_LENGTH(op_put_setter
);
4822 DEFINE_OPCODE(op_method_check
) {
4826 DEFINE_OPCODE(op_jsr
) {
4827 /* jsr retAddrDst(r) target(offset)
4829 Places the address of the next instruction into the retAddrDst
4830 register and jumps to offset target from the current instruction.
4832 int retAddrDst
= vPC
[1].u
.operand
;
4833 int target
= vPC
[2].u
.operand
;
4834 callFrame
->r(retAddrDst
) = vPC
+ OPCODE_LENGTH(op_jsr
);
4839 DEFINE_OPCODE(op_sret
) {
4840 /* sret retAddrSrc(r)
4842 Jumps to the address stored in the retAddrSrc register. This
4843 differs from op_jmp because the target address is stored in a
4844 register, not as an immediate.
4846 int retAddrSrc
= vPC
[1].u
.operand
;
4847 vPC
= callFrame
->r(retAddrSrc
).vPC();
4850 DEFINE_OPCODE(op_debug
) {
4851 /* debug debugHookID(n) firstLine(n) lastLine(n)
4853 Notifies the debugger of the current state of execution. This opcode
4854 is only generated while the debugger is attached.
4856 int debugHookID
= vPC
[1].u
.operand
;
4857 int firstLine
= vPC
[2].u
.operand
;
4858 int lastLine
= vPC
[3].u
.operand
;
4860 debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
4862 vPC
+= OPCODE_LENGTH(op_debug
);
4865 DEFINE_OPCODE(op_profile_will_call
) {
4866 /* op_profile_will_call function(r)
4868 Notifies the profiler of the beginning of a function call. This opcode
4869 is only generated if developer tools are enabled.
4871 int function
= vPC
[1].u
.operand
;
4873 if (*enabledProfilerReference
)
4874 (*enabledProfilerReference
)->willExecute(callFrame
, callFrame
->r(function
).jsValue());
4876 vPC
+= OPCODE_LENGTH(op_profile_will_call
);
4879 DEFINE_OPCODE(op_profile_did_call
) {
4880 /* op_profile_did_call function(r)
4882 Notifies the profiler of the end of a function call. This opcode
4883 is only generated if developer tools are enabled.
4885 int function
= vPC
[1].u
.operand
;
4887 if (*enabledProfilerReference
)
4888 (*enabledProfilerReference
)->didExecute(callFrame
, callFrame
->r(function
).jsValue());
4890 vPC
+= OPCODE_LENGTH(op_profile_did_call
);
4894 globalData
->exception
= JSValue();
4896 // The exceptionValue is a lie! (GCC produces bad code for reasons I
4897 // cannot fathom if we don't assign to the exceptionValue before branching)
4898 exceptionValue
= createInterruptedExecutionException(globalData
);
4900 JSGlobalObject
* globalObject
= callFrame
->lexicalGlobalObject();
4901 handler
= throwException(callFrame
, exceptionValue
, vPC
- codeBlock
->instructions().begin());
4903 // Can't use the callframe at this point as the scopechain, etc have
4905 return throwError(globalObject
->globalExec(), exceptionValue
);
4908 codeBlock
= callFrame
->codeBlock();
4909 vPC
= codeBlock
->instructions().begin() + handler
->target
;
4913 #if !ENABLE(COMPUTED_GOTO_INTERPRETER)
4914 } // iterator loop ends
4916 #undef NEXT_INSTRUCTION
4917 #undef DEFINE_OPCODE
4918 #undef CHECK_FOR_EXCEPTION
4919 #undef CHECK_FOR_TIMEOUT
4920 #endif // ENABLE(INTERPRETER)
4923 JSValue
Interpreter::retrieveArguments(CallFrame
* callFrame
, JSFunction
* function
) const
4925 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
4926 if (!functionCallFrame
)
4929 CodeBlock
* codeBlock
= functionCallFrame
->codeBlock();
4930 if (codeBlock
->usesArguments()) {
4931 ASSERT(codeBlock
->codeType() == FunctionCode
);
4932 int argumentsRegister
= codeBlock
->argumentsRegister();
4933 int realArgumentsRegister
= unmodifiedArgumentsRegister(argumentsRegister
);
4934 if (JSValue arguments
= functionCallFrame
->uncheckedR(argumentsRegister
).jsValue())
4936 JSValue arguments
= JSValue(new (callFrame
) Arguments(functionCallFrame
));
4937 functionCallFrame
->r(argumentsRegister
) = arguments
;
4938 functionCallFrame
->r(realArgumentsRegister
) = arguments
;
4942 Arguments
* arguments
= new (functionCallFrame
) Arguments(functionCallFrame
);
4943 arguments
->copyRegisters(functionCallFrame
->globalData());
4947 JSValue
Interpreter::retrieveCaller(CallFrame
* callFrame
, JSFunction
* function
) const
4949 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
4950 if (!functionCallFrame
)
4953 CallFrame
* callerFrame
= functionCallFrame
->callerFrame();
4954 if (callerFrame
->hasHostCallFrameFlag())
4957 JSValue caller
= callerFrame
->callee();
4964 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const
4966 function
= JSValue();
4968 sourceURL
= UString();
4970 CallFrame
* callerFrame
= callFrame
->callerFrame();
4971 if (callerFrame
->hasHostCallFrameFlag())
4974 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
4975 if (!callerCodeBlock
)
4977 unsigned bytecodeOffset
= 0;
4978 #if ENABLE(INTERPRETER)
4979 if (!callerFrame
->globalData().canUseJIT())
4980 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callFrame
->returnVPC());
4983 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callFrame
->returnPC());
4986 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callFrame
->returnPC());
4988 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
4989 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
4990 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
4991 function
= callerFrame
->callee();
4994 CallFrame
* Interpreter::findFunctionCallFrame(CallFrame
* callFrame
, JSFunction
* function
)
4996 for (CallFrame
* candidate
= callFrame
; candidate
; candidate
= candidate
->callerFrame()->removeHostCallFrameFlag()) {
4997 if (candidate
->callee() == function
)
5003 void Interpreter::enableSampler()
5005 #if ENABLE(OPCODE_SAMPLING)
5007 m_sampler
.set(new SamplingTool(this));
5012 void Interpreter::dumpSampleData(ExecState
* exec
)
5014 #if ENABLE(OPCODE_SAMPLING)
5016 m_sampler
->dump(exec
);
5021 void Interpreter::startSampling()
5023 #if ENABLE(SAMPLING_THREAD)
5024 if (!m_sampleEntryDepth
)
5025 SamplingThread::start();
5027 m_sampleEntryDepth
++;
5030 void Interpreter::stopSampling()
5032 #if ENABLE(SAMPLING_THREAD)
5033 m_sampleEntryDepth
--;
5034 if (!m_sampleEntryDepth
)
5035 SamplingThread::stop();