2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
38 #include "Collector.h"
40 #include "DebuggerCallFrame.h"
41 #include "EvalCodeCache.h"
42 #include "ExceptionHelpers.h"
43 #include "GlobalEvalFunction.h"
44 #include "JSActivation.h"
46 #include "JSByteArray.h"
47 #include "JSFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "LiteralParser.h"
51 #include "JSStaticScopeObject.h"
53 #include "ObjectPrototype.h"
54 #include "Operations.h"
57 #include "RegExpObject.h"
58 #include "RegExpPrototype.h"
60 #include "SamplingTool.h"
63 #include <wtf/Threading.h>
73 static ALWAYS_INLINE
unsigned bytecodeOffsetForPC(CallFrame
* callFrame
, CodeBlock
* codeBlock
, void* pc
)
76 return codeBlock
->getBytecodeIndex(callFrame
, ReturnAddressPtr(pc
));
78 UNUSED_PARAM(callFrame
);
79 return static_cast<Instruction
*>(pc
) - codeBlock
->instructions().begin();
83 // Returns the depth of the scope chain within a given call frame.
84 static int depth(CodeBlock
* codeBlock
, ScopeChain
& sc
)
86 if (!codeBlock
->needsFullScopeChain())
88 return sc
.localDepth();
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
);
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
->r(dst
) = JSValue(result
);
115 } while (++iter
!= end
);
116 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
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
+ codeBlock
->needsFullScopeChain();
128 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
129 ScopeChainIterator iter
= scopeChain
->begin();
130 ScopeChainIterator end
= scopeChain
->end();
136 Identifier
& ident
= codeBlock
->identifier(property
);
139 PropertySlot
slot(o
);
140 if (o
->getPropertySlot(callFrame
, ident
, slot
)) {
141 JSValue result
= slot
.getValue(callFrame
, ident
);
142 exceptionValue
= callFrame
->globalData().exception
;
145 callFrame
->r(dst
) = JSValue(result
);
148 } while (++iter
!= end
);
149 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
153 NEVER_INLINE
bool Interpreter::resolveGlobal(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
155 int dst
= vPC
[1].u
.operand
;
156 JSGlobalObject
* globalObject
= static_cast<JSGlobalObject
*>(vPC
[2].u
.jsCell
);
157 ASSERT(globalObject
->isGlobalObject());
158 int property
= vPC
[3].u
.operand
;
159 Structure
* structure
= vPC
[4].u
.structure
;
160 int offset
= vPC
[5].u
.operand
;
162 if (structure
== globalObject
->structure()) {
163 callFrame
->r(dst
) = JSValue(globalObject
->getDirectOffset(offset
));
167 CodeBlock
* codeBlock
= callFrame
->codeBlock();
168 Identifier
& ident
= codeBlock
->identifier(property
);
169 PropertySlot
slot(globalObject
);
170 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
171 JSValue result
= slot
.getValue(callFrame
, ident
);
172 if (slot
.isCacheable() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
173 if (vPC
[4].u
.structure
)
174 vPC
[4].u
.structure
->deref();
175 globalObject
->structure()->ref();
176 vPC
[4] = globalObject
->structure();
177 vPC
[5] = slot
.cachedOffset();
178 callFrame
->r(dst
) = JSValue(result
);
182 exceptionValue
= callFrame
->globalData().exception
;
185 callFrame
->r(dst
) = JSValue(result
);
189 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
193 NEVER_INLINE
void Interpreter::resolveBase(CallFrame
* callFrame
, Instruction
* vPC
)
195 int dst
= vPC
[1].u
.operand
;
196 int property
= vPC
[2].u
.operand
;
197 callFrame
->r(dst
) = JSValue(JSC::resolveBase(callFrame
, callFrame
->codeBlock()->identifier(property
), callFrame
->scopeChain()));
200 NEVER_INLINE
bool Interpreter::resolveBaseAndProperty(CallFrame
* callFrame
, Instruction
* vPC
, JSValue
& exceptionValue
)
202 int baseDst
= vPC
[1].u
.operand
;
203 int propDst
= vPC
[2].u
.operand
;
204 int property
= vPC
[3].u
.operand
;
206 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
207 ScopeChainIterator iter
= scopeChain
->begin();
208 ScopeChainIterator end
= scopeChain
->end();
210 // FIXME: add scopeDepthIsZero optimization
214 CodeBlock
* codeBlock
= callFrame
->codeBlock();
215 Identifier
& ident
= codeBlock
->identifier(property
);
219 PropertySlot
slot(base
);
220 if (base
->getPropertySlot(callFrame
, ident
, slot
)) {
221 JSValue result
= slot
.getValue(callFrame
, ident
);
222 exceptionValue
= callFrame
->globalData().exception
;
225 callFrame
->r(propDst
) = JSValue(result
);
226 callFrame
->r(baseDst
) = JSValue(base
);
230 } while (iter
!= end
);
232 exceptionValue
= createUndefinedVariableError(callFrame
, ident
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
236 #endif // USE(INTERPRETER)
238 ALWAYS_INLINE CallFrame
* Interpreter::slideRegisterWindowForCall(CodeBlock
* newCodeBlock
, RegisterFile
* registerFile
, CallFrame
* callFrame
, size_t registerOffset
, int argc
)
240 Register
* r
= callFrame
->registers();
241 Register
* newEnd
= r
+ registerOffset
+ newCodeBlock
->m_numCalleeRegisters
;
243 if (LIKELY(argc
== newCodeBlock
->m_numParameters
)) { // correct number of arguments
244 if (UNLIKELY(!registerFile
->grow(newEnd
)))
247 } else if (argc
< newCodeBlock
->m_numParameters
) { // too few arguments -- fill in the blanks
248 size_t omittedArgCount
= newCodeBlock
->m_numParameters
- argc
;
249 registerOffset
+= omittedArgCount
;
250 newEnd
+= omittedArgCount
;
251 if (!registerFile
->grow(newEnd
))
255 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- omittedArgCount
;
256 for (size_t i
= 0; i
< omittedArgCount
; ++i
)
257 argv
[i
] = jsUndefined();
258 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
259 size_t numParameters
= newCodeBlock
->m_numParameters
;
260 registerOffset
+= numParameters
;
261 newEnd
+= numParameters
;
263 if (!registerFile
->grow(newEnd
))
267 Register
* argv
= r
- RegisterFile::CallFrameHeaderSize
- numParameters
- argc
;
268 for (size_t i
= 0; i
< numParameters
; ++i
)
269 argv
[i
+ argc
] = argv
[i
];
272 return CallFrame::create(r
);
276 static NEVER_INLINE
bool isInvalidParamForIn(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
278 if (value
.isObject())
280 exceptionData
= createInvalidParamError(callFrame
, "in" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
284 static NEVER_INLINE
bool isInvalidParamForInstanceOf(CallFrame
* callFrame
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue value
, JSValue
& exceptionData
)
286 if (value
.isObject() && asObject(value
)->structure()->typeInfo().implementsHasInstance())
288 exceptionData
= createInvalidParamError(callFrame
, "instanceof" , value
, vPC
- codeBlock
->instructions().begin(), codeBlock
);
293 NEVER_INLINE JSValue
Interpreter::callEval(CallFrame
* callFrame
, RegisterFile
* registerFile
, Register
* argv
, int argc
, int registerOffset
, JSValue
& exceptionValue
)
296 return jsUndefined();
298 JSValue program
= argv
[1].jsValue();
300 if (!program
.isString())
303 UString programSource
= asString(program
)->value(callFrame
);
305 LiteralParser
preparser(callFrame
, programSource
, LiteralParser::NonStrictJSON
);
306 if (JSValue parsedObject
= preparser
.tryLiteralParse())
309 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
310 CodeBlock
* codeBlock
= callFrame
->codeBlock();
311 RefPtr
<EvalExecutable
> eval
= codeBlock
->evalCodeCache().get(callFrame
, programSource
, scopeChain
, exceptionValue
);
313 JSValue result
= jsUndefined();
315 result
= callFrame
->globalData().interpreter
->execute(eval
.get(), callFrame
, callFrame
->thisValue().toThisObject(callFrame
), callFrame
->registers() - registerFile
->start() + registerOffset
, scopeChain
, &exceptionValue
);
320 Interpreter::Interpreter()
321 : m_sampleEntryDepth(0)
324 #if HAVE(COMPUTED_GOTO)
325 privateExecute(InitializeAndReturn
, 0, 0, 0);
327 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
328 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
329 #endif // HAVE(COMPUTED_GOTO)
331 #if ENABLE(OPCODE_SAMPLING)
338 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
340 callFrame
->codeBlock()->dump(callFrame
);
341 dumpRegisters(callFrame
);
344 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
346 printf("Register frame: \n\n");
347 printf("-----------------------------------------------------------------------------\n");
348 printf(" use | address | value \n");
349 printf("-----------------------------------------------------------------------------\n");
351 CodeBlock
* codeBlock
= callFrame
->codeBlock();
352 RegisterFile
* registerFile
= &callFrame
->scopeChain()->globalObject
->globalData()->interpreter
->registerFile();
357 if (codeBlock
->codeType() == GlobalCode
) {
358 it
= registerFile
->lastGlobal();
359 end
= it
+ registerFile
->numGlobals();
362 #if USE(JSVALUE32_64)
363 printf("[global var] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
365 printf("[global var] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
369 printf("-----------------------------------------------------------------------------\n");
372 it
= callFrame
->registers() - RegisterFile::CallFrameHeaderSize
- codeBlock
->m_numParameters
;
374 #if USE(JSVALUE32_64)
375 printf("[this] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
377 printf("[this] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
)); ++it
;
379 end
= it
+ max(codeBlock
->m_numParameters
- 1, 0); // - 1 to skip "this"
383 #if USE(JSVALUE32_64)
384 printf("[param] | %10p | %-16s 0x%llx \n", it
, v
.description(), JSValue::encode(v
));
386 printf("[param] | %10p | %-16s %p \n", it
, v
.description(), JSValue::encode(v
));
391 printf("-----------------------------------------------------------------------------\n");
392 printf("[CodeBlock] | %10p | %p \n", it
, (*it
).codeBlock()); ++it
;
393 printf("[ScopeChain] | %10p | %p \n", it
, (*it
).scopeChain()); ++it
;
394 printf("[CallerRegisters] | %10p | %d \n", it
, (*it
).i()); ++it
;
395 printf("[ReturnPC] | %10p | %p \n", it
, (*it
).vPC()); ++it
;
396 printf("[ReturnValueRegister] | %10p | %d \n", it
, (*it
).i()); ++it
;
397 printf("[ArgumentCount] | %10p | %d \n", it
, (*it
).i()); ++it
;
398 printf("[Callee] | %10p | %p \n", it
, (*it
).function()); ++it
;
399 printf("[OptionalCalleeArguments] | %10p | %p \n", it
, (*it
).arguments()); ++it
;
400 printf("-----------------------------------------------------------------------------\n");
402 int registerCount
= 0;
404 end
= it
+ codeBlock
->m_numVars
;
408 #if USE(JSVALUE32_64)
409 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
411 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
417 printf("-----------------------------------------------------------------------------\n");
419 end
= it
+ codeBlock
->m_numCalleeRegisters
- codeBlock
->m_numVars
;
423 #if USE(JSVALUE32_64)
424 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
426 printf("[r%2d] | %10p | %-16s %p \n", registerCount
, it
, v
.description(), JSValue::encode(v
));
432 printf("-----------------------------------------------------------------------------\n");
437 bool Interpreter::isOpcode(Opcode opcode
)
439 #if HAVE(COMPUTED_GOTO)
440 return opcode
!= HashTraits
<Opcode
>::emptyValue()
441 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
442 && m_opcodeIDTable
.contains(opcode
);
444 return opcode
>= 0 && opcode
<= op_end
;
448 NEVER_INLINE
bool Interpreter::unwindCallFrame(CallFrame
*& callFrame
, JSValue exceptionValue
, unsigned& bytecodeOffset
, CodeBlock
*& codeBlock
)
450 CodeBlock
* oldCodeBlock
= codeBlock
;
451 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
453 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
454 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
455 if (callFrame
->callee())
456 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
458 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine());
461 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
462 if (callFrame
->callee())
463 profiler
->didExecute(callFrame
, callFrame
->callee());
465 profiler
->didExecute(callFrame
, codeBlock
->ownerExecutable()->sourceURL(), codeBlock
->ownerExecutable()->lineNo());
468 // If this call frame created an activation or an 'arguments' object, tear it off.
469 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->needsFullScopeChain()) {
470 while (!scopeChain
->object
->inherits(&JSActivation::info
))
471 scopeChain
= scopeChain
->pop();
472 static_cast<JSActivation
*>(scopeChain
->object
)->copyRegisters(callFrame
->optionalCalleeArguments());
473 } else if (Arguments
* arguments
= callFrame
->optionalCalleeArguments()) {
474 if (!arguments
->isTornOff())
475 arguments
->copyRegisters();
478 if (oldCodeBlock
->needsFullScopeChain())
481 void* returnPC
= callFrame
->returnPC();
482 callFrame
= callFrame
->callerFrame();
483 if (callFrame
->hasHostCallFrameFlag())
486 codeBlock
= callFrame
->codeBlock();
487 bytecodeOffset
= bytecodeOffsetForPC(callFrame
, codeBlock
, returnPC
);
491 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
, bool explicitThrow
)
493 // Set up the exception object
495 CodeBlock
* codeBlock
= callFrame
->codeBlock();
496 if (exceptionValue
.isObject()) {
497 JSObject
* exception
= asObject(exceptionValue
);
498 if (exception
->isNotAnObjectErrorStub()) {
499 exception
= createNotAnObjectError(callFrame
, static_cast<JSNotAnObjectErrorStub
*>(exception
), bytecodeOffset
, codeBlock
);
500 exceptionValue
= exception
;
502 if (!exception
->hasProperty(callFrame
, Identifier(callFrame
, "line")) &&
503 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceId")) &&
504 !exception
->hasProperty(callFrame
, Identifier(callFrame
, "sourceURL")) &&
505 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
)) &&
506 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionCaretOffsetPropertyName
)) &&
507 !exception
->hasProperty(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
))) {
512 int line
= codeBlock
->expressionRangeForBytecodeOffset(callFrame
, bytecodeOffset
, divotPoint
, startOffset
, endOffset
);
513 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, line
), ReadOnly
| DontDelete
);
515 // We only hit this path for error messages and throw statements, which don't have a specific failure position
516 // So we just give the full range of the error/throw statement.
517 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionBeginOffsetPropertyName
), jsNumber(callFrame
, divotPoint
- startOffset
), ReadOnly
| DontDelete
);
518 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, expressionEndOffsetPropertyName
), jsNumber(callFrame
, divotPoint
+ endOffset
), ReadOnly
| DontDelete
);
520 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "line"), jsNumber(callFrame
, codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
)), ReadOnly
| DontDelete
);
521 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceId"), jsNumber(callFrame
, codeBlock
->ownerExecutable()->sourceID()), ReadOnly
| DontDelete
);
522 exception
->putWithAttributes(callFrame
, Identifier(callFrame
, "sourceURL"), jsOwnedString(callFrame
, codeBlock
->ownerExecutable()->sourceURL()), ReadOnly
| DontDelete
);
525 if (exception
->isWatchdogException()) {
526 while (unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
527 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
534 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
535 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
536 bool hasHandler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
537 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
), hasHandler
);
540 // If we throw in the middle of a call instruction, we need to notify
541 // the profiler manually that the call instruction has returned, since
542 // we'll never reach the relevant op_profile_did_call.
543 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
545 if (isCallBytecode(codeBlock
->instructions()[bytecodeOffset
].u
.opcode
))
546 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 2].u
.operand
).jsValue());
547 else if (codeBlock
->instructions().size() > (bytecodeOffset
+ 8) && codeBlock
->instructions()[bytecodeOffset
+ 8].u
.opcode
== getOpcode(op_construct
))
548 profiler
->didExecute(callFrame
, callFrame
->r(codeBlock
->instructions()[bytecodeOffset
+ 10].u
.operand
).jsValue());
550 int functionRegisterIndex
;
551 if (codeBlock
->functionRegisterForBytecodeOffset(bytecodeOffset
, functionRegisterIndex
))
552 profiler
->didExecute(callFrame
, callFrame
->r(functionRegisterIndex
).jsValue());
556 // Calculate an exception handler vPC, unwinding call frames as necessary.
558 HandlerInfo
* handler
= 0;
559 while (!(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
560 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
))
564 // Now unwind the scope chain within the exception handler's call frame.
566 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
567 ScopeChain
sc(scopeChain
);
568 int scopeDelta
= depth(codeBlock
, sc
) - handler
->scopeDepth
;
569 ASSERT(scopeDelta
>= 0);
571 scopeChain
= scopeChain
->pop();
572 callFrame
->setScopeChain(scopeChain
);
577 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
, JSValue
* exception
)
579 ASSERT(!scopeChain
->globalData
->exception
);
581 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
582 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
583 *exception
= createStackOverflowError(callFrame
);
588 CodeBlock
* codeBlock
= &program
->bytecode(callFrame
, scopeChain
);
590 Register
* oldEnd
= m_registerFile
.end();
591 Register
* newEnd
= oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->m_numCalleeRegisters
;
592 if (!m_registerFile
.grow(newEnd
)) {
593 *exception
= createStackOverflowError(callFrame
);
597 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
599 JSGlobalObject
* lastGlobalObject
= m_registerFile
.globalObject();
600 JSGlobalObject
* globalObject
= callFrame
->dynamicGlobalObject();
601 globalObject
->copyGlobalsTo(m_registerFile
);
603 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
+ codeBlock
->m_numParameters
+ RegisterFile::CallFrameHeaderSize
);
604 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
605 newCallFrame
->init(codeBlock
, 0, scopeChain
, CallFrame::noCaller(), 0, 0, 0);
607 if (codeBlock
->needsFullScopeChain())
610 Profiler
** profiler
= Profiler::enabledProfilerReference();
612 (*profiler
)->willExecute(newCallFrame
, program
->sourceURL(), program
->lineNo());
616 SamplingTool::CallRecord
callRecord(m_sampler
.get());
620 result
= program
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
622 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
628 (*profiler
)->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
630 if (m_reentryDepth
&& lastGlobalObject
&& globalObject
!= lastGlobalObject
)
631 lastGlobalObject
->copyGlobalsTo(m_registerFile
);
633 m_registerFile
.shrink(oldEnd
);
638 JSValue
Interpreter::execute(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, JSObject
* thisObj
, const ArgList
& args
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
640 ASSERT(!scopeChain
->globalData
->exception
);
642 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
643 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
644 *exception
= createStackOverflowError(callFrame
);
649 Register
* oldEnd
= m_registerFile
.end();
650 int argc
= 1 + args
.size(); // implicit "this" parameter
652 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
653 *exception
= createStackOverflowError(callFrame
);
657 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
659 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
661 newCallFrame
->r(0) = JSValue(thisObj
);
662 ArgList::const_iterator end
= args
.end();
663 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
664 newCallFrame
->r(++dst
) = *it
;
666 CodeBlock
* codeBlock
= &functionExecutable
->bytecode(callFrame
, scopeChain
);
667 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
668 if (UNLIKELY(!newCallFrame
)) {
669 *exception
= createStackOverflowError(callFrame
);
670 m_registerFile
.shrink(oldEnd
);
673 // a 0 codeBlock indicates a built-in caller
674 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
676 Profiler
** profiler
= Profiler::enabledProfilerReference();
678 (*profiler
)->willExecute(callFrame
, function
);
682 SamplingTool::CallRecord
callRecord(m_sampler
.get());
686 result
= functionExecutable
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
688 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
694 (*profiler
)->didExecute(callFrame
, function
);
696 m_registerFile
.shrink(oldEnd
);
700 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* FunctionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argCount
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
702 ASSERT(!scopeChain
->globalData
->exception
);
704 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
705 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
706 *exception
= createStackOverflowError(callFrame
);
707 return CallFrameClosure();
711 Register
* oldEnd
= m_registerFile
.end();
712 int argc
= 1 + argCount
; // implicit "this" parameter
714 if (!m_registerFile
.grow(oldEnd
+ argc
)) {
715 *exception
= createStackOverflowError(callFrame
);
716 return CallFrameClosure();
719 CallFrame
* newCallFrame
= CallFrame::create(oldEnd
);
721 for (int i
= 0; i
< argc
; ++i
)
722 newCallFrame
->r(++dst
) = jsUndefined();
724 CodeBlock
* codeBlock
= &FunctionExecutable
->bytecode(callFrame
, scopeChain
);
725 newCallFrame
= slideRegisterWindowForCall(codeBlock
, &m_registerFile
, newCallFrame
, argc
+ RegisterFile::CallFrameHeaderSize
, argc
);
726 if (UNLIKELY(!newCallFrame
)) {
727 *exception
= createStackOverflowError(callFrame
);
728 m_registerFile
.shrink(oldEnd
);
729 return CallFrameClosure();
731 // a 0 codeBlock indicates a built-in caller
732 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, argc
, function
);
734 FunctionExecutable
->jitCode(newCallFrame
, scopeChain
);
737 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, FunctionExecutable
, scopeChain
->globalData
, oldEnd
, scopeChain
, codeBlock
->m_numParameters
, argc
};
741 JSValue
Interpreter::execute(CallFrameClosure
& closure
, JSValue
* exception
)
743 closure
.resetCallFrame();
744 Profiler
** profiler
= Profiler::enabledProfilerReference();
746 (*profiler
)->willExecute(closure
.oldCallFrame
, closure
.function
);
750 SamplingTool::CallRecord
callRecord(m_sampler
.get());
754 result
= closure
.functionExecutable
->generatedJITCode().execute(&m_registerFile
, closure
.newCallFrame
, closure
.globalData
, exception
);
756 result
= privateExecute(Normal
, &m_registerFile
, closure
.newCallFrame
, exception
);
762 (*profiler
)->didExecute(closure
.oldCallFrame
, closure
.function
);
766 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
768 m_registerFile
.shrink(closure
.oldEnd
);
771 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
773 return execute(eval
, callFrame
, thisObj
, m_registerFile
.size() + eval
->bytecode(callFrame
, scopeChain
).m_numParameters
+ RegisterFile::CallFrameHeaderSize
, scopeChain
, exception
);
776 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSObject
* thisObj
, int globalRegisterOffset
, ScopeChainNode
* scopeChain
, JSValue
* exception
)
778 ASSERT(!scopeChain
->globalData
->exception
);
780 if (m_reentryDepth
>= MaxSecondaryThreadReentryDepth
) {
781 if (!isMainThread() || m_reentryDepth
>= MaxMainThreadReentryDepth
) {
782 *exception
= createStackOverflowError(callFrame
);
787 DynamicGlobalObjectScope
globalObjectScope(callFrame
, scopeChain
->globalObject
);
789 EvalCodeBlock
* codeBlock
= &eval
->bytecode(callFrame
, scopeChain
);
791 JSVariableObject
* variableObject
;
792 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
) {
794 if (node
->object
->isVariableObject()) {
795 variableObject
= static_cast<JSVariableObject
*>(node
->object
);
800 { // Scope for BatchedTransitionOptimizer
802 BatchedTransitionOptimizer
optimizer(variableObject
);
804 unsigned numVariables
= codeBlock
->numVariables();
805 for (unsigned i
= 0; i
< numVariables
; ++i
) {
806 const Identifier
& ident
= codeBlock
->variable(i
);
807 if (!variableObject
->hasProperty(callFrame
, ident
)) {
808 PutPropertySlot slot
;
809 variableObject
->put(callFrame
, ident
, jsUndefined(), slot
);
813 int numFunctions
= codeBlock
->numberOfFunctionDecls();
814 for (int i
= 0; i
< numFunctions
; ++i
) {
815 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
816 PutPropertySlot slot
;
817 variableObject
->put(callFrame
, function
->name(), function
->make(callFrame
, scopeChain
), slot
);
822 Register
* oldEnd
= m_registerFile
.end();
823 Register
* newEnd
= m_registerFile
.start() + globalRegisterOffset
+ codeBlock
->m_numCalleeRegisters
;
824 if (!m_registerFile
.grow(newEnd
)) {
825 *exception
= createStackOverflowError(callFrame
);
829 CallFrame
* newCallFrame
= CallFrame::create(m_registerFile
.start() + globalRegisterOffset
);
831 // a 0 codeBlock indicates a built-in caller
832 newCallFrame
->r(codeBlock
->thisRegister()) = JSValue(thisObj
);
833 newCallFrame
->init(codeBlock
, 0, scopeChain
, callFrame
->addHostCallFrameFlag(), 0, 0, 0);
835 if (codeBlock
->needsFullScopeChain())
838 Profiler
** profiler
= Profiler::enabledProfilerReference();
840 (*profiler
)->willExecute(newCallFrame
, eval
->sourceURL(), eval
->lineNo());
844 SamplingTool::CallRecord
callRecord(m_sampler
.get());
848 result
= eval
->jitCode(newCallFrame
, scopeChain
).execute(&m_registerFile
, newCallFrame
, scopeChain
->globalData
, exception
);
850 result
= privateExecute(Normal
, &m_registerFile
, newCallFrame
, exception
);
856 (*profiler
)->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
858 m_registerFile
.shrink(oldEnd
);
862 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
)
864 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
868 switch (debugHookID
) {
869 case DidEnterCallFrame
:
870 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
872 case WillLeaveCallFrame
:
873 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
875 case WillExecuteStatement
:
876 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
878 case WillExecuteProgram
:
879 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
);
881 case DidExecuteProgram
:
882 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
884 case DidReachBreakpoint
:
885 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
);
891 NEVER_INLINE ScopeChainNode
* Interpreter::createExceptionScope(CallFrame
* callFrame
, const Instruction
* vPC
)
893 int dst
= vPC
[1].u
.operand
;
894 CodeBlock
* codeBlock
= callFrame
->codeBlock();
895 Identifier
& property
= codeBlock
->identifier(vPC
[2].u
.operand
);
896 JSValue value
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
897 JSObject
* scope
= new (callFrame
) JSStaticScopeObject(callFrame
, property
, value
, DontDelete
);
898 callFrame
->r(dst
) = JSValue(scope
);
900 return callFrame
->scopeChain()->push(scope
);
903 NEVER_INLINE
void Interpreter::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const PutPropertySlot
& slot
)
905 // Recursive invocation may already have specialized this instruction.
906 if (vPC
[0].u
.opcode
!= getOpcode(op_put_by_id
))
909 if (!baseValue
.isCell())
912 // Uncacheable: give up.
913 if (!slot
.isCacheable()) {
914 vPC
[0] = getOpcode(op_put_by_id_generic
);
918 JSCell
* baseCell
= asCell(baseValue
);
919 Structure
* structure
= baseCell
->structure();
921 if (structure
->isUncacheableDictionary()) {
922 vPC
[0] = getOpcode(op_put_by_id_generic
);
926 // Cache miss: record Structure to compare against next time.
927 Structure
* lastStructure
= vPC
[4].u
.structure
;
928 if (structure
!= lastStructure
) {
929 // First miss: record Structure to compare against next time.
930 if (!lastStructure
) {
935 // Second miss: give up.
936 vPC
[0] = getOpcode(op_put_by_id_generic
);
940 // Cache hit: Specialize instruction and ref Structures.
942 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
943 if (baseCell
!= slot
.base()) {
944 vPC
[0] = getOpcode(op_put_by_id_generic
);
948 // Structure transition, cache transition info
949 if (slot
.type() == PutPropertySlot::NewProperty
) {
950 if (structure
->isDictionary()) {
951 vPC
[0] = getOpcode(op_put_by_id_generic
);
955 // put_by_id_transition checks the prototype chain for setters.
956 normalizePrototypeChain(callFrame
, baseCell
);
958 vPC
[0] = getOpcode(op_put_by_id_transition
);
959 vPC
[4] = structure
->previousID();
961 vPC
[6] = structure
->prototypeChain(callFrame
);
962 vPC
[7] = slot
.cachedOffset();
963 codeBlock
->refStructures(vPC
);
967 vPC
[0] = getOpcode(op_put_by_id_replace
);
968 vPC
[5] = slot
.cachedOffset();
969 codeBlock
->refStructures(vPC
);
972 NEVER_INLINE
void Interpreter::uncachePutByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
974 codeBlock
->derefStructures(vPC
);
975 vPC
[0] = getOpcode(op_put_by_id
);
979 NEVER_INLINE
void Interpreter::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
)
981 // Recursive invocation may already have specialized this instruction.
982 if (vPC
[0].u
.opcode
!= getOpcode(op_get_by_id
))
985 // FIXME: Cache property access for immediates.
986 if (!baseValue
.isCell()) {
987 vPC
[0] = getOpcode(op_get_by_id_generic
);
991 JSGlobalData
* globalData
= &callFrame
->globalData();
992 if (isJSArray(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
993 vPC
[0] = getOpcode(op_get_array_length
);
997 if (isJSString(globalData
, baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
998 vPC
[0] = getOpcode(op_get_string_length
);
1002 // Uncacheable: give up.
1003 if (!slot
.isCacheable()) {
1004 vPC
[0] = getOpcode(op_get_by_id_generic
);
1008 Structure
* structure
= asCell(baseValue
)->structure();
1010 if (structure
->isUncacheableDictionary()) {
1011 vPC
[0] = getOpcode(op_get_by_id_generic
);
1016 Structure
* lastStructure
= vPC
[4].u
.structure
;
1017 if (structure
!= lastStructure
) {
1018 // First miss: record Structure to compare against next time.
1019 if (!lastStructure
) {
1024 // Second miss: give up.
1025 vPC
[0] = getOpcode(op_get_by_id_generic
);
1029 // Cache hit: Specialize instruction and ref Structures.
1031 if (slot
.slotBase() == baseValue
) {
1032 vPC
[0] = getOpcode(op_get_by_id_self
);
1033 vPC
[5] = slot
.cachedOffset();
1035 codeBlock
->refStructures(vPC
);
1039 if (structure
->isDictionary()) {
1040 vPC
[0] = getOpcode(op_get_by_id_generic
);
1044 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1045 ASSERT(slot
.slotBase().isObject());
1047 JSObject
* baseObject
= asObject(slot
.slotBase());
1048 size_t offset
= slot
.cachedOffset();
1050 // Since we're accessing a prototype in a loop, it's a good bet that it
1051 // should not be treated as a dictionary.
1052 if (baseObject
->structure()->isDictionary()) {
1053 baseObject
->flattenDictionaryObject();
1054 offset
= baseObject
->structure()->get(propertyName
);
1057 ASSERT(!baseObject
->structure()->isUncacheableDictionary());
1059 vPC
[0] = getOpcode(op_get_by_id_proto
);
1060 vPC
[5] = baseObject
->structure();
1063 codeBlock
->refStructures(vPC
);
1067 size_t offset
= slot
.cachedOffset();
1068 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
1070 vPC
[0] = getOpcode(op_get_by_id_generic
);
1074 vPC
[0] = getOpcode(op_get_by_id_chain
);
1076 vPC
[5] = structure
->prototypeChain(callFrame
);
1079 codeBlock
->refStructures(vPC
);
1082 NEVER_INLINE
void Interpreter::uncacheGetByID(CodeBlock
* codeBlock
, Instruction
* vPC
)
1084 codeBlock
->derefStructures(vPC
);
1085 vPC
[0] = getOpcode(op_get_by_id
);
1089 #endif // USE(INTERPRETER)
1091 JSValue
Interpreter::privateExecute(ExecutionFlag flag
, RegisterFile
* registerFile
, CallFrame
* callFrame
, JSValue
* exception
)
1093 // One-time initialization of our address tables. We have to put this code
1094 // here because our labels are only in scope inside this function.
1095 if (UNLIKELY(flag
== InitializeAndReturn
)) {
1096 #if HAVE(COMPUTED_GOTO)
1097 #define LIST_OPCODE_LABEL(id, length) &&id,
1098 static Opcode labels
[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL
) };
1099 for (size_t i
= 0; i
< sizeof(labels
) / sizeof(Opcode
); ++i
)
1100 m_opcodeTable
[i
] = labels
[i
];
1101 #undef LIST_OPCODE_LABEL
1102 #endif // HAVE(COMPUTED_GOTO)
1107 // Mixing Interpreter + JIT is not supported.
1108 ASSERT_NOT_REACHED();
1110 #if !USE(INTERPRETER)
1111 UNUSED_PARAM(registerFile
);
1112 UNUSED_PARAM(callFrame
);
1113 UNUSED_PARAM(exception
);
1117 JSGlobalData
* globalData
= &callFrame
->globalData();
1118 JSValue exceptionValue
;
1119 HandlerInfo
* handler
= 0;
1121 Instruction
* vPC
= callFrame
->codeBlock()->instructions().begin();
1122 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1123 unsigned tickCount
= globalData
->timeoutChecker
.ticksUntilNextCheck();
1125 #define CHECK_FOR_EXCEPTION() \
1127 if (UNLIKELY(globalData->exception != JSValue())) { \
1128 exceptionValue = globalData->exception; \
1133 #if ENABLE(OPCODE_STATS)
1134 OpcodeStats::resetLastInstruction();
1137 #define CHECK_FOR_TIMEOUT() \
1138 if (!--tickCount) { \
1139 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
1140 exceptionValue = jsNull(); \
1143 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1146 #if ENABLE(OPCODE_SAMPLING)
1147 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1149 #define SAMPLE(codeBlock, vPC)
1152 #if HAVE(COMPUTED_GOTO)
1153 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1154 #if ENABLE(OPCODE_STATS)
1155 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1157 #define DEFINE_OPCODE(opcode) opcode:
1161 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1162 #if ENABLE(OPCODE_STATS)
1163 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1165 #define DEFINE_OPCODE(opcode) case opcode:
1167 while (1) { // iterator loop begins
1168 interpreterLoopStart
:;
1169 switch (vPC
->u
.opcode
)
1172 DEFINE_OPCODE(op_new_object
) {
1173 /* new_object dst(r)
1175 Constructs a new empty Object instance using the original
1176 constructor, and puts the result in register dst.
1178 int dst
= vPC
[1].u
.operand
;
1179 callFrame
->r(dst
) = JSValue(constructEmptyObject(callFrame
));
1181 vPC
+= OPCODE_LENGTH(op_new_object
);
1184 DEFINE_OPCODE(op_new_array
) {
1185 /* new_array dst(r) firstArg(r) argCount(n)
1187 Constructs a new Array instance using the original
1188 constructor, and puts the result in register dst.
1189 The array will contain argCount elements with values
1190 taken from registers starting at register firstArg.
1192 int dst
= vPC
[1].u
.operand
;
1193 int firstArg
= vPC
[2].u
.operand
;
1194 int argCount
= vPC
[3].u
.operand
;
1195 ArgList
args(callFrame
->registers() + firstArg
, argCount
);
1196 callFrame
->r(dst
) = JSValue(constructArray(callFrame
, args
));
1198 vPC
+= OPCODE_LENGTH(op_new_array
);
1201 DEFINE_OPCODE(op_new_regexp
) {
1202 /* new_regexp dst(r) regExp(re)
1204 Constructs a new RegExp instance using the original
1205 constructor from regexp regExp, and puts the result in
1208 int dst
= vPC
[1].u
.operand
;
1209 int regExp
= vPC
[2].u
.operand
;
1210 callFrame
->r(dst
) = JSValue(new (globalData
) RegExpObject(callFrame
->scopeChain()->globalObject
->regExpStructure(), callFrame
->codeBlock()->regexp(regExp
)));
1212 vPC
+= OPCODE_LENGTH(op_new_regexp
);
1215 DEFINE_OPCODE(op_mov
) {
1216 /* mov dst(r) src(r)
1218 Copies register src to register dst.
1220 int dst
= vPC
[1].u
.operand
;
1221 int src
= vPC
[2].u
.operand
;
1222 callFrame
->r(dst
) = callFrame
->r(src
);
1224 vPC
+= OPCODE_LENGTH(op_mov
);
1227 DEFINE_OPCODE(op_eq
) {
1228 /* eq dst(r) src1(r) src2(r)
1230 Checks whether register src1 and register src2 are equal,
1231 as with the ECMAScript '==' operator, and puts the result
1232 as a boolean in register dst.
1234 int dst
= vPC
[1].u
.operand
;
1235 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1236 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1237 if (src1
.isInt32() && src2
.isInt32())
1238 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() == src2
.asInt32());
1240 JSValue result
= jsBoolean(JSValue::equalSlowCase(callFrame
, src1
, src2
));
1241 CHECK_FOR_EXCEPTION();
1242 callFrame
->r(dst
) = result
;
1245 vPC
+= OPCODE_LENGTH(op_eq
);
1248 DEFINE_OPCODE(op_eq_null
) {
1249 /* eq_null dst(r) src(r)
1251 Checks whether register src is null, as with the ECMAScript '!='
1252 operator, and puts the result as a boolean in register dst.
1254 int dst
= vPC
[1].u
.operand
;
1255 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1257 if (src
.isUndefinedOrNull()) {
1258 callFrame
->r(dst
) = jsBoolean(true);
1259 vPC
+= OPCODE_LENGTH(op_eq_null
);
1263 callFrame
->r(dst
) = jsBoolean(src
.isCell() && src
.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1264 vPC
+= OPCODE_LENGTH(op_eq_null
);
1267 DEFINE_OPCODE(op_neq
) {
1268 /* neq dst(r) src1(r) src2(r)
1270 Checks whether register src1 and register src2 are not
1271 equal, as with the ECMAScript '!=' operator, and puts the
1272 result as a boolean in register dst.
1274 int dst
= vPC
[1].u
.operand
;
1275 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1276 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1277 if (src1
.isInt32() && src2
.isInt32())
1278 callFrame
->r(dst
) = jsBoolean(src1
.asInt32() != src2
.asInt32());
1280 JSValue result
= jsBoolean(!JSValue::equalSlowCase(callFrame
, src1
, src2
));
1281 CHECK_FOR_EXCEPTION();
1282 callFrame
->r(dst
) = result
;
1285 vPC
+= OPCODE_LENGTH(op_neq
);
1288 DEFINE_OPCODE(op_neq_null
) {
1289 /* neq_null dst(r) src(r)
1291 Checks whether register src is not null, as with the ECMAScript '!='
1292 operator, and puts the result as a boolean in register dst.
1294 int dst
= vPC
[1].u
.operand
;
1295 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1297 if (src
.isUndefinedOrNull()) {
1298 callFrame
->r(dst
) = jsBoolean(false);
1299 vPC
+= OPCODE_LENGTH(op_neq_null
);
1303 callFrame
->r(dst
) = jsBoolean(!src
.isCell() || !asCell(src
)->structure()->typeInfo().masqueradesAsUndefined());
1304 vPC
+= OPCODE_LENGTH(op_neq_null
);
1307 DEFINE_OPCODE(op_stricteq
) {
1308 /* stricteq dst(r) src1(r) src2(r)
1310 Checks whether register src1 and register src2 are strictly
1311 equal, as with the ECMAScript '===' operator, and puts the
1312 result as a boolean in register dst.
1314 int dst
= vPC
[1].u
.operand
;
1315 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1316 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1317 callFrame
->r(dst
) = jsBoolean(JSValue::strictEqual(callFrame
, src1
, src2
));
1319 vPC
+= OPCODE_LENGTH(op_stricteq
);
1322 DEFINE_OPCODE(op_nstricteq
) {
1323 /* nstricteq dst(r) src1(r) src2(r)
1325 Checks whether register src1 and register src2 are not
1326 strictly equal, as with the ECMAScript '!==' operator, and
1327 puts the result as a boolean in register dst.
1329 int dst
= vPC
[1].u
.operand
;
1330 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1331 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1332 callFrame
->r(dst
) = jsBoolean(!JSValue::strictEqual(callFrame
, src1
, src2
));
1334 vPC
+= OPCODE_LENGTH(op_nstricteq
);
1337 DEFINE_OPCODE(op_less
) {
1338 /* less dst(r) src1(r) src2(r)
1340 Checks whether register src1 is less than register src2, as
1341 with the ECMAScript '<' operator, and puts the result as
1342 a boolean in register dst.
1344 int dst
= vPC
[1].u
.operand
;
1345 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1346 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1347 JSValue result
= jsBoolean(jsLess(callFrame
, src1
, src2
));
1348 CHECK_FOR_EXCEPTION();
1349 callFrame
->r(dst
) = result
;
1351 vPC
+= OPCODE_LENGTH(op_less
);
1354 DEFINE_OPCODE(op_lesseq
) {
1355 /* lesseq dst(r) src1(r) src2(r)
1357 Checks whether register src1 is less than or equal to
1358 register src2, as with the ECMAScript '<=' operator, and
1359 puts the result as a boolean in register dst.
1361 int dst
= vPC
[1].u
.operand
;
1362 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1363 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1364 JSValue result
= jsBoolean(jsLessEq(callFrame
, src1
, src2
));
1365 CHECK_FOR_EXCEPTION();
1366 callFrame
->r(dst
) = result
;
1368 vPC
+= OPCODE_LENGTH(op_lesseq
);
1371 DEFINE_OPCODE(op_pre_inc
) {
1372 /* pre_inc srcDst(r)
1374 Converts register srcDst to number, adds one, and puts the result
1375 back in register srcDst.
1377 int srcDst
= vPC
[1].u
.operand
;
1378 JSValue v
= callFrame
->r(srcDst
).jsValue();
1379 if (v
.isInt32() && v
.asInt32() < INT_MAX
)
1380 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1382 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) + 1);
1383 CHECK_FOR_EXCEPTION();
1384 callFrame
->r(srcDst
) = result
;
1387 vPC
+= OPCODE_LENGTH(op_pre_inc
);
1390 DEFINE_OPCODE(op_pre_dec
) {
1391 /* pre_dec srcDst(r)
1393 Converts register srcDst to number, subtracts one, and puts the result
1394 back in register srcDst.
1396 int srcDst
= vPC
[1].u
.operand
;
1397 JSValue v
= callFrame
->r(srcDst
).jsValue();
1398 if (v
.isInt32() && v
.asInt32() > INT_MIN
)
1399 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1401 JSValue result
= jsNumber(callFrame
, v
.toNumber(callFrame
) - 1);
1402 CHECK_FOR_EXCEPTION();
1403 callFrame
->r(srcDst
) = result
;
1406 vPC
+= OPCODE_LENGTH(op_pre_dec
);
1409 DEFINE_OPCODE(op_post_inc
) {
1410 /* post_inc dst(r) srcDst(r)
1412 Converts register srcDst to number. The number itself is
1413 written to register dst, and the number plus one is written
1414 back to register srcDst.
1416 int dst
= vPC
[1].u
.operand
;
1417 int srcDst
= vPC
[2].u
.operand
;
1418 JSValue v
= callFrame
->r(srcDst
).jsValue();
1419 if (v
.isInt32() && v
.asInt32() < INT_MAX
) {
1420 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() + 1);
1421 callFrame
->r(dst
) = v
;
1423 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1424 CHECK_FOR_EXCEPTION();
1425 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() + 1);
1426 callFrame
->r(dst
) = number
;
1429 vPC
+= OPCODE_LENGTH(op_post_inc
);
1432 DEFINE_OPCODE(op_post_dec
) {
1433 /* post_dec dst(r) srcDst(r)
1435 Converts register srcDst to number. The number itself is
1436 written to register dst, and the number minus one is written
1437 back to register srcDst.
1439 int dst
= vPC
[1].u
.operand
;
1440 int srcDst
= vPC
[2].u
.operand
;
1441 JSValue v
= callFrame
->r(srcDst
).jsValue();
1442 if (v
.isInt32() && v
.asInt32() > INT_MIN
) {
1443 callFrame
->r(srcDst
) = jsNumber(callFrame
, v
.asInt32() - 1);
1444 callFrame
->r(dst
) = v
;
1446 JSValue number
= callFrame
->r(srcDst
).jsValue().toJSNumber(callFrame
);
1447 CHECK_FOR_EXCEPTION();
1448 callFrame
->r(srcDst
) = jsNumber(callFrame
, number
.uncheckedGetNumber() - 1);
1449 callFrame
->r(dst
) = number
;
1452 vPC
+= OPCODE_LENGTH(op_post_dec
);
1455 DEFINE_OPCODE(op_to_jsnumber
) {
1456 /* to_jsnumber dst(r) src(r)
1458 Converts register src to number, and puts the result
1461 int dst
= vPC
[1].u
.operand
;
1462 int src
= vPC
[2].u
.operand
;
1464 JSValue srcVal
= callFrame
->r(src
).jsValue();
1466 if (LIKELY(srcVal
.isNumber()))
1467 callFrame
->r(dst
) = callFrame
->r(src
);
1469 JSValue result
= srcVal
.toJSNumber(callFrame
);
1470 CHECK_FOR_EXCEPTION();
1471 callFrame
->r(dst
) = result
;
1474 vPC
+= OPCODE_LENGTH(op_to_jsnumber
);
1477 DEFINE_OPCODE(op_negate
) {
1478 /* negate dst(r) src(r)
1480 Converts register src to number, negates it, and puts the
1481 result in register dst.
1483 int dst
= vPC
[1].u
.operand
;
1484 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1485 if (src
.isInt32() && src
.asInt32())
1486 callFrame
->r(dst
) = jsNumber(callFrame
, -src
.asInt32());
1488 JSValue result
= jsNumber(callFrame
, -src
.toNumber(callFrame
));
1489 CHECK_FOR_EXCEPTION();
1490 callFrame
->r(dst
) = result
;
1493 vPC
+= OPCODE_LENGTH(op_negate
);
1496 DEFINE_OPCODE(op_add
) {
1497 /* add dst(r) src1(r) src2(r)
1499 Adds register src1 and register src2, and puts the result
1500 in register dst. (JS add may be string concatenation or
1501 numeric add, depending on the types of the operands.)
1503 int dst
= vPC
[1].u
.operand
;
1504 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1505 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1506 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
1507 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() + src2
.asInt32());
1509 JSValue result
= jsAdd(callFrame
, src1
, src2
);
1510 CHECK_FOR_EXCEPTION();
1511 callFrame
->r(dst
) = result
;
1513 vPC
+= OPCODE_LENGTH(op_add
);
1516 DEFINE_OPCODE(op_mul
) {
1517 /* mul dst(r) src1(r) src2(r)
1519 Multiplies register src1 and register src2 (converted to
1520 numbers), and puts the product in register dst.
1522 int dst
= vPC
[1].u
.operand
;
1523 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1524 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1525 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | src2
.asInt32() >> 15)) // no overflow
1526 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() * src2
.asInt32());
1528 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
1529 CHECK_FOR_EXCEPTION();
1530 callFrame
->r(dst
) = result
;
1533 vPC
+= OPCODE_LENGTH(op_mul
);
1536 DEFINE_OPCODE(op_div
) {
1537 /* div dst(r) dividend(r) divisor(r)
1539 Divides register dividend (converted to number) by the
1540 register divisor (converted to number), and puts the
1541 quotient in register dst.
1543 int dst
= vPC
[1].u
.operand
;
1544 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1545 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1547 JSValue result
= jsNumber(callFrame
, dividend
.toNumber(callFrame
) / divisor
.toNumber(callFrame
));
1548 CHECK_FOR_EXCEPTION();
1549 callFrame
->r(dst
) = result
;
1551 vPC
+= OPCODE_LENGTH(op_div
);
1554 DEFINE_OPCODE(op_mod
) {
1555 /* mod dst(r) dividend(r) divisor(r)
1557 Divides register dividend (converted to number) by
1558 register divisor (converted to number), and puts the
1559 remainder in register dst.
1561 int dst
= vPC
[1].u
.operand
;
1562 JSValue dividend
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1563 JSValue divisor
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1565 if (dividend
.isInt32() && divisor
.isInt32() && divisor
.asInt32() != 0) {
1566 JSValue result
= jsNumber(callFrame
, dividend
.asInt32() % divisor
.asInt32());
1568 callFrame
->r(dst
) = result
;
1569 vPC
+= OPCODE_LENGTH(op_mod
);
1573 // Conversion to double must happen outside the call to fmod since the
1574 // order of argument evaluation is not guaranteed.
1575 double d1
= dividend
.toNumber(callFrame
);
1576 double d2
= divisor
.toNumber(callFrame
);
1577 JSValue result
= jsNumber(callFrame
, fmod(d1
, d2
));
1578 CHECK_FOR_EXCEPTION();
1579 callFrame
->r(dst
) = result
;
1580 vPC
+= OPCODE_LENGTH(op_mod
);
1583 DEFINE_OPCODE(op_sub
) {
1584 /* sub dst(r) src1(r) src2(r)
1586 Subtracts register src2 (converted to number) from register
1587 src1 (converted to number), and puts the difference in
1590 int dst
= vPC
[1].u
.operand
;
1591 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1592 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1593 if (src1
.isInt32() && src2
.isInt32() && !(src1
.asInt32() | (src2
.asInt32() & 0xc0000000))) // no overflow
1594 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() - src2
.asInt32());
1596 JSValue result
= jsNumber(callFrame
, src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
1597 CHECK_FOR_EXCEPTION();
1598 callFrame
->r(dst
) = result
;
1600 vPC
+= OPCODE_LENGTH(op_sub
);
1603 DEFINE_OPCODE(op_lshift
) {
1604 /* lshift dst(r) val(r) shift(r)
1606 Performs left shift of register val (converted to int32) by
1607 register shift (converted to uint32), and puts the result
1610 int dst
= vPC
[1].u
.operand
;
1611 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1612 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1614 if (val
.isInt32() && shift
.isInt32())
1615 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() << (shift
.asInt32() & 0x1f));
1617 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
1618 CHECK_FOR_EXCEPTION();
1619 callFrame
->r(dst
) = result
;
1622 vPC
+= OPCODE_LENGTH(op_lshift
);
1625 DEFINE_OPCODE(op_rshift
) {
1626 /* rshift dst(r) val(r) shift(r)
1628 Performs arithmetic right shift of register val (converted
1629 to int32) by register shift (converted to
1630 uint32), and puts the result in register dst.
1632 int dst
= vPC
[1].u
.operand
;
1633 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1634 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1636 if (val
.isInt32() && shift
.isInt32())
1637 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1639 JSValue result
= jsNumber(callFrame
, (val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1640 CHECK_FOR_EXCEPTION();
1641 callFrame
->r(dst
) = result
;
1644 vPC
+= OPCODE_LENGTH(op_rshift
);
1647 DEFINE_OPCODE(op_urshift
) {
1648 /* rshift dst(r) val(r) shift(r)
1650 Performs logical right shift of register val (converted
1651 to uint32) by register shift (converted to
1652 uint32), and puts the result in register dst.
1654 int dst
= vPC
[1].u
.operand
;
1655 JSValue val
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1656 JSValue shift
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1657 if (val
.isUInt32() && shift
.isInt32())
1658 callFrame
->r(dst
) = jsNumber(callFrame
, val
.asInt32() >> (shift
.asInt32() & 0x1f));
1660 JSValue result
= jsNumber(callFrame
, (val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
1661 CHECK_FOR_EXCEPTION();
1662 callFrame
->r(dst
) = result
;
1665 vPC
+= OPCODE_LENGTH(op_urshift
);
1668 DEFINE_OPCODE(op_bitand
) {
1669 /* bitand dst(r) src1(r) src2(r)
1671 Computes bitwise AND of register src1 (converted to int32)
1672 and register src2 (converted to int32), and puts the result
1675 int dst
= vPC
[1].u
.operand
;
1676 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1677 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1678 if (src1
.isInt32() && src2
.isInt32())
1679 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() & src2
.asInt32());
1681 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
1682 CHECK_FOR_EXCEPTION();
1683 callFrame
->r(dst
) = result
;
1686 vPC
+= OPCODE_LENGTH(op_bitand
);
1689 DEFINE_OPCODE(op_bitxor
) {
1690 /* bitxor dst(r) src1(r) src2(r)
1692 Computes bitwise XOR of register src1 (converted to int32)
1693 and register src2 (converted to int32), and puts the result
1696 int dst
= vPC
[1].u
.operand
;
1697 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1698 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1699 if (src1
.isInt32() && src2
.isInt32())
1700 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() ^ src2
.asInt32());
1702 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
1703 CHECK_FOR_EXCEPTION();
1704 callFrame
->r(dst
) = result
;
1707 vPC
+= OPCODE_LENGTH(op_bitxor
);
1710 DEFINE_OPCODE(op_bitor
) {
1711 /* bitor dst(r) src1(r) src2(r)
1713 Computes bitwise OR of register src1 (converted to int32)
1714 and register src2 (converted to int32), and puts the
1715 result in register dst.
1717 int dst
= vPC
[1].u
.operand
;
1718 JSValue src1
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1719 JSValue src2
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
1720 if (src1
.isInt32() && src2
.isInt32())
1721 callFrame
->r(dst
) = jsNumber(callFrame
, src1
.asInt32() | src2
.asInt32());
1723 JSValue result
= jsNumber(callFrame
, src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
1724 CHECK_FOR_EXCEPTION();
1725 callFrame
->r(dst
) = result
;
1728 vPC
+= OPCODE_LENGTH(op_bitor
);
1731 DEFINE_OPCODE(op_bitnot
) {
1732 /* bitnot dst(r) src(r)
1734 Computes bitwise NOT of register src1 (converted to int32),
1735 and puts the result in register dst.
1737 int dst
= vPC
[1].u
.operand
;
1738 JSValue src
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
1740 callFrame
->r(dst
) = jsNumber(callFrame
, ~src
.asInt32());
1742 JSValue result
= jsNumber(callFrame
, ~src
.toInt32(callFrame
));
1743 CHECK_FOR_EXCEPTION();
1744 callFrame
->r(dst
) = result
;
1746 vPC
+= OPCODE_LENGTH(op_bitnot
);
1749 DEFINE_OPCODE(op_not
) {
1750 /* not dst(r) src(r)
1752 Computes logical NOT of register src (converted to
1753 boolean), and puts the result in register dst.
1755 int dst
= vPC
[1].u
.operand
;
1756 int src
= vPC
[2].u
.operand
;
1757 JSValue result
= jsBoolean(!callFrame
->r(src
).jsValue().toBoolean(callFrame
));
1758 CHECK_FOR_EXCEPTION();
1759 callFrame
->r(dst
) = result
;
1761 vPC
+= OPCODE_LENGTH(op_not
);
1764 DEFINE_OPCODE(op_instanceof
) {
1765 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1767 Tests whether register value is an instance of register
1768 constructor, and puts the boolean result in register
1769 dst. Register constructorProto must contain the "prototype"
1770 property (not the actual prototype) of the object in
1771 register constructor. This lookup is separated so that
1772 polymorphic inline caching can apply.
1774 Raises an exception if register constructor is not an
1777 int dst
= vPC
[1].u
.operand
;
1778 int value
= vPC
[2].u
.operand
;
1779 int base
= vPC
[3].u
.operand
;
1780 int baseProto
= vPC
[4].u
.operand
;
1782 JSValue baseVal
= callFrame
->r(base
).jsValue();
1784 if (isInvalidParamForInstanceOf(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1787 bool result
= asObject(baseVal
)->hasInstance(callFrame
, callFrame
->r(value
).jsValue(), callFrame
->r(baseProto
).jsValue());
1788 CHECK_FOR_EXCEPTION();
1789 callFrame
->r(dst
) = jsBoolean(result
);
1791 vPC
+= OPCODE_LENGTH(op_instanceof
);
1794 DEFINE_OPCODE(op_typeof
) {
1795 /* typeof dst(r) src(r)
1797 Determines the type string for src according to ECMAScript
1798 rules, and puts the result in register dst.
1800 int dst
= vPC
[1].u
.operand
;
1801 int src
= vPC
[2].u
.operand
;
1802 callFrame
->r(dst
) = JSValue(jsTypeStringForValue(callFrame
, callFrame
->r(src
).jsValue()));
1804 vPC
+= OPCODE_LENGTH(op_typeof
);
1807 DEFINE_OPCODE(op_is_undefined
) {
1808 /* is_undefined dst(r) src(r)
1810 Determines whether the type string for src according to
1811 the ECMAScript rules is "undefined", and puts the result
1814 int dst
= vPC
[1].u
.operand
;
1815 int src
= vPC
[2].u
.operand
;
1816 JSValue v
= callFrame
->r(src
).jsValue();
1817 callFrame
->r(dst
) = jsBoolean(v
.isCell() ? v
.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v
.isUndefined());
1819 vPC
+= OPCODE_LENGTH(op_is_undefined
);
1822 DEFINE_OPCODE(op_is_boolean
) {
1823 /* is_boolean dst(r) src(r)
1825 Determines whether the type string for src according to
1826 the ECMAScript rules is "boolean", and puts the result
1829 int dst
= vPC
[1].u
.operand
;
1830 int src
= vPC
[2].u
.operand
;
1831 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isBoolean());
1833 vPC
+= OPCODE_LENGTH(op_is_boolean
);
1836 DEFINE_OPCODE(op_is_number
) {
1837 /* is_number dst(r) src(r)
1839 Determines whether the type string for src according to
1840 the ECMAScript rules is "number", and puts the result
1843 int dst
= vPC
[1].u
.operand
;
1844 int src
= vPC
[2].u
.operand
;
1845 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isNumber());
1847 vPC
+= OPCODE_LENGTH(op_is_number
);
1850 DEFINE_OPCODE(op_is_string
) {
1851 /* is_string dst(r) src(r)
1853 Determines whether the type string for src according to
1854 the ECMAScript rules is "string", and puts the result
1857 int dst
= vPC
[1].u
.operand
;
1858 int src
= vPC
[2].u
.operand
;
1859 callFrame
->r(dst
) = jsBoolean(callFrame
->r(src
).jsValue().isString());
1861 vPC
+= OPCODE_LENGTH(op_is_string
);
1864 DEFINE_OPCODE(op_is_object
) {
1865 /* is_object dst(r) src(r)
1867 Determines whether the type string for src according to
1868 the ECMAScript rules is "object", and puts the result
1871 int dst
= vPC
[1].u
.operand
;
1872 int src
= vPC
[2].u
.operand
;
1873 callFrame
->r(dst
) = jsBoolean(jsIsObjectType(callFrame
->r(src
).jsValue()));
1875 vPC
+= OPCODE_LENGTH(op_is_object
);
1878 DEFINE_OPCODE(op_is_function
) {
1879 /* is_function dst(r) src(r)
1881 Determines whether the type string for src according to
1882 the ECMAScript rules is "function", and puts the result
1885 int dst
= vPC
[1].u
.operand
;
1886 int src
= vPC
[2].u
.operand
;
1887 callFrame
->r(dst
) = jsBoolean(jsIsFunctionType(callFrame
->r(src
).jsValue()));
1889 vPC
+= OPCODE_LENGTH(op_is_function
);
1892 DEFINE_OPCODE(op_in
) {
1893 /* in dst(r) property(r) base(r)
1895 Tests whether register base has a property named register
1896 property, and puts the boolean result in register dst.
1898 Raises an exception if register constructor is not an
1901 int dst
= vPC
[1].u
.operand
;
1902 int property
= vPC
[2].u
.operand
;
1903 int base
= vPC
[3].u
.operand
;
1905 JSValue baseVal
= callFrame
->r(base
).jsValue();
1906 if (isInvalidParamForIn(callFrame
, callFrame
->codeBlock(), vPC
, baseVal
, exceptionValue
))
1909 JSObject
* baseObj
= asObject(baseVal
);
1911 JSValue propName
= callFrame
->r(property
).jsValue();
1914 if (propName
.getUInt32(i
))
1915 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, i
));
1917 Identifier
property(callFrame
, propName
.toString(callFrame
));
1918 CHECK_FOR_EXCEPTION();
1919 callFrame
->r(dst
) = jsBoolean(baseObj
->hasProperty(callFrame
, property
));
1922 vPC
+= OPCODE_LENGTH(op_in
);
1925 DEFINE_OPCODE(op_resolve
) {
1926 /* resolve dst(r) property(id)
1928 Looks up the property named by identifier property in the
1929 scope chain, and writes the resulting value to register
1930 dst. If the property is not found, raises an exception.
1932 if (UNLIKELY(!resolve(callFrame
, vPC
, exceptionValue
)))
1935 vPC
+= OPCODE_LENGTH(op_resolve
);
1938 DEFINE_OPCODE(op_resolve_skip
) {
1939 /* resolve_skip dst(r) property(id) skip(n)
1941 Looks up the property named by identifier property in the
1942 scope chain skipping the top 'skip' levels, and writes the resulting
1943 value to register dst. If the property is not found, raises an exception.
1945 if (UNLIKELY(!resolveSkip(callFrame
, vPC
, exceptionValue
)))
1948 vPC
+= OPCODE_LENGTH(op_resolve_skip
);
1952 DEFINE_OPCODE(op_resolve_global
) {
1953 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1955 Performs a dynamic property lookup for the given property, on the provided
1956 global object. If structure matches the Structure of the global then perform
1957 a fast lookup using the case offset, otherwise fall back to a full resolve and
1958 cache the new structure and offset
1960 if (UNLIKELY(!resolveGlobal(callFrame
, vPC
, exceptionValue
)))
1963 vPC
+= OPCODE_LENGTH(op_resolve_global
);
1967 DEFINE_OPCODE(op_get_global_var
) {
1968 /* get_global_var dst(r) globalObject(c) index(n)
1970 Gets the global var at global slot index and places it in register dst.
1972 int dst
= vPC
[1].u
.operand
;
1973 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>(vPC
[2].u
.jsCell
);
1974 ASSERT(scope
->isGlobalObject());
1975 int index
= vPC
[3].u
.operand
;
1977 callFrame
->r(dst
) = scope
->registerAt(index
);
1978 vPC
+= OPCODE_LENGTH(op_get_global_var
);
1981 DEFINE_OPCODE(op_put_global_var
) {
1982 /* put_global_var globalObject(c) index(n) value(r)
1984 Puts value into global slot index.
1986 JSGlobalObject
* scope
= static_cast<JSGlobalObject
*>(vPC
[1].u
.jsCell
);
1987 ASSERT(scope
->isGlobalObject());
1988 int index
= vPC
[2].u
.operand
;
1989 int value
= vPC
[3].u
.operand
;
1991 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
1992 vPC
+= OPCODE_LENGTH(op_put_global_var
);
1995 DEFINE_OPCODE(op_get_scoped_var
) {
1996 /* get_scoped_var dst(r) index(n) skip(n)
1998 Loads the contents of the index-th local from the scope skip nodes from
1999 the top of the scope chain, and places it in register dst
2001 int dst
= vPC
[1].u
.operand
;
2002 int index
= vPC
[2].u
.operand
;
2003 int skip
= vPC
[3].u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2005 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2006 ScopeChainIterator iter
= scopeChain
->begin();
2007 ScopeChainIterator end
= scopeChain
->end();
2008 ASSERT(iter
!= end
);
2011 ASSERT(iter
!= end
);
2014 ASSERT((*iter
)->isVariableObject());
2015 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2016 callFrame
->r(dst
) = scope
->registerAt(index
);
2017 vPC
+= OPCODE_LENGTH(op_get_scoped_var
);
2020 DEFINE_OPCODE(op_put_scoped_var
) {
2021 /* put_scoped_var index(n) skip(n) value(r)
2024 int index
= vPC
[1].u
.operand
;
2025 int skip
= vPC
[2].u
.operand
+ callFrame
->codeBlock()->needsFullScopeChain();
2026 int value
= vPC
[3].u
.operand
;
2028 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2029 ScopeChainIterator iter
= scopeChain
->begin();
2030 ScopeChainIterator end
= scopeChain
->end();
2031 ASSERT(iter
!= end
);
2034 ASSERT(iter
!= end
);
2037 ASSERT((*iter
)->isVariableObject());
2038 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
2039 scope
->registerAt(index
) = JSValue(callFrame
->r(value
).jsValue());
2040 vPC
+= OPCODE_LENGTH(op_put_scoped_var
);
2043 DEFINE_OPCODE(op_resolve_base
) {
2044 /* resolve_base dst(r) property(id)
2046 Searches the scope chain for an object containing
2047 identifier property, and if one is found, writes it to
2048 register dst. If none is found, the outermost scope (which
2049 will be the global object) is stored in register dst.
2051 resolveBase(callFrame
, vPC
);
2053 vPC
+= OPCODE_LENGTH(op_resolve_base
);
2056 DEFINE_OPCODE(op_resolve_with_base
) {
2057 /* resolve_with_base baseDst(r) propDst(r) property(id)
2059 Searches the scope chain for an object containing
2060 identifier property, and if one is found, writes it to
2061 register srcDst, and the retrieved property value to register
2062 propDst. If the property is not found, raises an exception.
2064 This is more efficient than doing resolve_base followed by
2065 resolve, or resolve_base followed by get_by_id, as it
2066 avoids duplicate hash lookups.
2068 if (UNLIKELY(!resolveBaseAndProperty(callFrame
, vPC
, exceptionValue
)))
2071 vPC
+= OPCODE_LENGTH(op_resolve_with_base
);
2074 DEFINE_OPCODE(op_get_by_id
) {
2075 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2077 Generic property access: Gets the property named by identifier
2078 property from the value base, and puts the result in register dst.
2080 int dst
= vPC
[1].u
.operand
;
2081 int base
= vPC
[2].u
.operand
;
2082 int property
= vPC
[3].u
.operand
;
2084 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2085 Identifier
& ident
= codeBlock
->identifier(property
);
2086 JSValue baseValue
= callFrame
->r(base
).jsValue();
2087 PropertySlot
slot(baseValue
);
2088 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2089 CHECK_FOR_EXCEPTION();
2091 tryCacheGetByID(callFrame
, codeBlock
, vPC
, baseValue
, ident
, slot
);
2093 callFrame
->r(dst
) = result
;
2094 vPC
+= OPCODE_LENGTH(op_get_by_id
);
2097 DEFINE_OPCODE(op_get_by_id_self
) {
2098 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2100 Cached property access: Attempts to get a cached property from the
2101 value base. If the cache misses, op_get_by_id_self reverts to
2104 int base
= vPC
[2].u
.operand
;
2105 JSValue baseValue
= callFrame
->r(base
).jsValue();
2107 if (LIKELY(baseValue
.isCell())) {
2108 JSCell
* baseCell
= asCell(baseValue
);
2109 Structure
* structure
= vPC
[4].u
.structure
;
2111 if (LIKELY(baseCell
->structure() == structure
)) {
2112 ASSERT(baseCell
->isObject());
2113 JSObject
* baseObject
= asObject(baseCell
);
2114 int dst
= vPC
[1].u
.operand
;
2115 int offset
= vPC
[5].u
.operand
;
2117 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2118 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2120 vPC
+= OPCODE_LENGTH(op_get_by_id_self
);
2125 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2128 DEFINE_OPCODE(op_get_by_id_proto
) {
2129 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2131 Cached property access: Attempts to get a cached property from the
2132 value base's prototype. If the cache misses, op_get_by_id_proto
2133 reverts to op_get_by_id.
2135 int base
= vPC
[2].u
.operand
;
2136 JSValue baseValue
= callFrame
->r(base
).jsValue();
2138 if (LIKELY(baseValue
.isCell())) {
2139 JSCell
* baseCell
= asCell(baseValue
);
2140 Structure
* structure
= vPC
[4].u
.structure
;
2142 if (LIKELY(baseCell
->structure() == structure
)) {
2143 ASSERT(structure
->prototypeForLookup(callFrame
).isObject());
2144 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
2145 Structure
* prototypeStructure
= vPC
[5].u
.structure
;
2147 if (LIKELY(protoObject
->structure() == prototypeStructure
)) {
2148 int dst
= vPC
[1].u
.operand
;
2149 int offset
= vPC
[6].u
.operand
;
2151 ASSERT(protoObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2152 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == protoObject
->getDirectOffset(offset
));
2153 callFrame
->r(dst
) = JSValue(protoObject
->getDirectOffset(offset
));
2155 vPC
+= OPCODE_LENGTH(op_get_by_id_proto
);
2161 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2164 DEFINE_OPCODE(op_get_by_id_self_list
) {
2165 // Polymorphic self access caching currently only supported when JITting.
2166 ASSERT_NOT_REACHED();
2167 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2168 vPC
+= OPCODE_LENGTH(op_get_by_id_self_list
);
2171 DEFINE_OPCODE(op_get_by_id_proto_list
) {
2172 // Polymorphic prototype access caching currently only supported when JITting.
2173 ASSERT_NOT_REACHED();
2174 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2175 vPC
+= OPCODE_LENGTH(op_get_by_id_proto_list
);
2178 DEFINE_OPCODE(op_get_by_id_chain
) {
2179 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2181 Cached property access: Attempts to get a cached property from the
2182 value base's prototype chain. If the cache misses, op_get_by_id_chain
2183 reverts to op_get_by_id.
2185 int base
= vPC
[2].u
.operand
;
2186 JSValue baseValue
= callFrame
->r(base
).jsValue();
2188 if (LIKELY(baseValue
.isCell())) {
2189 JSCell
* baseCell
= asCell(baseValue
);
2190 Structure
* structure
= vPC
[4].u
.structure
;
2192 if (LIKELY(baseCell
->structure() == structure
)) {
2193 RefPtr
<Structure
>* it
= vPC
[5].u
.structureChain
->head();
2194 size_t count
= vPC
[6].u
.operand
;
2195 RefPtr
<Structure
>* end
= it
+ count
;
2198 JSObject
* baseObject
= asObject(baseCell
->structure()->prototypeForLookup(callFrame
));
2200 if (UNLIKELY(baseObject
->structure() != (*it
).get()))
2204 int dst
= vPC
[1].u
.operand
;
2205 int offset
= vPC
[7].u
.operand
;
2207 ASSERT(baseObject
->get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2208 ASSERT(baseValue
.get(callFrame
, callFrame
->codeBlock()->identifier(vPC
[3].u
.operand
)) == baseObject
->getDirectOffset(offset
));
2209 callFrame
->r(dst
) = JSValue(baseObject
->getDirectOffset(offset
));
2211 vPC
+= OPCODE_LENGTH(op_get_by_id_chain
);
2215 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2216 baseCell
= baseObject
;
2221 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2224 DEFINE_OPCODE(op_get_by_id_generic
) {
2225 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2227 Generic property access: Gets the property named by identifier
2228 property from the value base, and puts the result in register dst.
2230 int dst
= vPC
[1].u
.operand
;
2231 int base
= vPC
[2].u
.operand
;
2232 int property
= vPC
[3].u
.operand
;
2234 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2235 JSValue baseValue
= callFrame
->r(base
).jsValue();
2236 PropertySlot
slot(baseValue
);
2237 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
2238 CHECK_FOR_EXCEPTION();
2240 callFrame
->r(dst
) = result
;
2241 vPC
+= OPCODE_LENGTH(op_get_by_id_generic
);
2244 DEFINE_OPCODE(op_get_array_length
) {
2245 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2247 Cached property access: Gets the length of the array in register base,
2248 and puts the result in register dst. If register base does not hold
2249 an array, op_get_array_length reverts to op_get_by_id.
2252 int base
= vPC
[2].u
.operand
;
2253 JSValue baseValue
= callFrame
->r(base
).jsValue();
2254 if (LIKELY(isJSArray(globalData
, baseValue
))) {
2255 int dst
= vPC
[1].u
.operand
;
2256 callFrame
->r(dst
) = jsNumber(callFrame
, asArray(baseValue
)->length());
2257 vPC
+= OPCODE_LENGTH(op_get_array_length
);
2261 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2264 DEFINE_OPCODE(op_get_string_length
) {
2265 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2267 Cached property access: Gets the length of the string in register base,
2268 and puts the result in register dst. If register base does not hold
2269 a string, op_get_string_length reverts to op_get_by_id.
2272 int base
= vPC
[2].u
.operand
;
2273 JSValue baseValue
= callFrame
->r(base
).jsValue();
2274 if (LIKELY(isJSString(globalData
, baseValue
))) {
2275 int dst
= vPC
[1].u
.operand
;
2276 callFrame
->r(dst
) = jsNumber(callFrame
, asString(baseValue
)->length());
2277 vPC
+= OPCODE_LENGTH(op_get_string_length
);
2281 uncacheGetByID(callFrame
->codeBlock(), vPC
);
2284 DEFINE_OPCODE(op_put_by_id
) {
2285 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2287 Generic property access: Sets the property named by identifier
2288 property, belonging to register base, to register value.
2290 Unlike many opcodes, this one does not write any output to
2294 int base
= vPC
[1].u
.operand
;
2295 int property
= vPC
[2].u
.operand
;
2296 int value
= vPC
[3].u
.operand
;
2298 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2299 JSValue baseValue
= callFrame
->r(base
).jsValue();
2300 Identifier
& ident
= codeBlock
->identifier(property
);
2301 PutPropertySlot slot
;
2302 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2303 CHECK_FOR_EXCEPTION();
2305 tryCachePutByID(callFrame
, codeBlock
, vPC
, baseValue
, slot
);
2307 vPC
+= OPCODE_LENGTH(op_put_by_id
);
2310 DEFINE_OPCODE(op_put_by_id_transition
) {
2311 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2313 Cached property access: Attempts to set a new property with a cached transition
2314 property named by identifier property, belonging to register base,
2315 to register value. If the cache misses, op_put_by_id_transition
2316 reverts to op_put_by_id_generic.
2318 Unlike many opcodes, this one does not write any output to
2321 int base
= vPC
[1].u
.operand
;
2322 JSValue baseValue
= callFrame
->r(base
).jsValue();
2324 if (LIKELY(baseValue
.isCell())) {
2325 JSCell
* baseCell
= asCell(baseValue
);
2326 Structure
* oldStructure
= vPC
[4].u
.structure
;
2327 Structure
* newStructure
= vPC
[5].u
.structure
;
2329 if (LIKELY(baseCell
->structure() == oldStructure
)) {
2330 ASSERT(baseCell
->isObject());
2331 JSObject
* baseObject
= asObject(baseCell
);
2333 RefPtr
<Structure
>* it
= vPC
[6].u
.structureChain
->head();
2335 JSValue proto
= baseObject
->structure()->prototypeForLookup(callFrame
);
2336 while (!proto
.isNull()) {
2337 if (UNLIKELY(asObject(proto
)->structure() != (*it
).get())) {
2338 uncachePutByID(callFrame
->codeBlock(), vPC
);
2342 proto
= asObject(proto
)->structure()->prototypeForLookup(callFrame
);
2345 baseObject
->transitionTo(newStructure
);
2347 int value
= vPC
[3].u
.operand
;
2348 unsigned offset
= vPC
[7].u
.operand
;
2349 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2350 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2352 vPC
+= OPCODE_LENGTH(op_put_by_id_transition
);
2357 uncachePutByID(callFrame
->codeBlock(), vPC
);
2360 DEFINE_OPCODE(op_put_by_id_replace
) {
2361 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2363 Cached property access: Attempts to set a pre-existing, cached
2364 property named by identifier property, belonging to register base,
2365 to register value. If the cache misses, op_put_by_id_replace
2366 reverts to op_put_by_id.
2368 Unlike many opcodes, this one does not write any output to
2371 int base
= vPC
[1].u
.operand
;
2372 JSValue baseValue
= callFrame
->r(base
).jsValue();
2374 if (LIKELY(baseValue
.isCell())) {
2375 JSCell
* baseCell
= asCell(baseValue
);
2376 Structure
* structure
= vPC
[4].u
.structure
;
2378 if (LIKELY(baseCell
->structure() == structure
)) {
2379 ASSERT(baseCell
->isObject());
2380 JSObject
* baseObject
= asObject(baseCell
);
2381 int value
= vPC
[3].u
.operand
;
2382 unsigned offset
= vPC
[5].u
.operand
;
2384 ASSERT(baseObject
->offsetForLocation(baseObject
->getDirectLocation(callFrame
->codeBlock()->identifier(vPC
[2].u
.operand
))) == offset
);
2385 baseObject
->putDirectOffset(offset
, callFrame
->r(value
).jsValue());
2387 vPC
+= OPCODE_LENGTH(op_put_by_id_replace
);
2392 uncachePutByID(callFrame
->codeBlock(), vPC
);
2395 DEFINE_OPCODE(op_put_by_id_generic
) {
2396 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2398 Generic property access: Sets the property named by identifier
2399 property, belonging to register base, to register value.
2401 Unlike many opcodes, this one does not write any output to
2404 int base
= vPC
[1].u
.operand
;
2405 int property
= vPC
[2].u
.operand
;
2406 int value
= vPC
[3].u
.operand
;
2408 JSValue baseValue
= callFrame
->r(base
).jsValue();
2409 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2410 PutPropertySlot slot
;
2411 baseValue
.put(callFrame
, ident
, callFrame
->r(value
).jsValue(), slot
);
2412 CHECK_FOR_EXCEPTION();
2414 vPC
+= OPCODE_LENGTH(op_put_by_id_generic
);
2417 DEFINE_OPCODE(op_del_by_id
) {
2418 /* del_by_id dst(r) base(r) property(id)
2420 Converts register base to Object, deletes the property
2421 named by identifier property from the object, and writes a
2422 boolean indicating success (if true) or failure (if false)
2425 int dst
= vPC
[1].u
.operand
;
2426 int base
= vPC
[2].u
.operand
;
2427 int property
= vPC
[3].u
.operand
;
2429 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
);
2430 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
2431 JSValue result
= jsBoolean(baseObj
->deleteProperty(callFrame
, ident
));
2432 CHECK_FOR_EXCEPTION();
2433 callFrame
->r(dst
) = result
;
2434 vPC
+= OPCODE_LENGTH(op_del_by_id
);
2437 DEFINE_OPCODE(op_get_by_pname
) {
2438 int dst
= vPC
[1].u
.operand
;
2439 int base
= vPC
[2].u
.operand
;
2440 int property
= vPC
[3].u
.operand
;
2441 int expected
= vPC
[4].u
.operand
;
2442 int iter
= vPC
[5].u
.operand
;
2443 int i
= vPC
[6].u
.operand
;
2445 JSValue baseValue
= callFrame
->r(base
).jsValue();
2446 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
2447 JSValue subscript
= callFrame
->r(property
).jsValue();
2448 JSValue expectedSubscript
= callFrame
->r(expected
).jsValue();
2449 int index
= callFrame
->r(i
).i() - 1;
2452 if (subscript
== expectedSubscript
&& baseValue
.isCell() && (baseValue
.asCell()->structure() == it
->cachedStructure()) && it
->getOffset(index
, offset
)) {
2453 callFrame
->r(dst
) = asObject(baseValue
)->getDirectOffset(offset
);
2454 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
2457 Identifier
propertyName(callFrame
, subscript
.toString(callFrame
));
2458 result
= baseValue
.get(callFrame
, propertyName
);
2459 CHECK_FOR_EXCEPTION();
2460 callFrame
->r(dst
) = result
;
2461 vPC
+= OPCODE_LENGTH(op_get_by_pname
);
2464 DEFINE_OPCODE(op_get_by_val
) {
2465 /* get_by_val dst(r) base(r) property(r)
2467 Converts register base to Object, gets the property named
2468 by register property from the object, and puts the result
2469 in register dst. property is nominally converted to string
2470 but numbers are treated more efficiently.
2472 int dst
= vPC
[1].u
.operand
;
2473 int base
= vPC
[2].u
.operand
;
2474 int property
= vPC
[3].u
.operand
;
2476 JSValue baseValue
= callFrame
->r(base
).jsValue();
2477 JSValue subscript
= callFrame
->r(property
).jsValue();
2481 if (LIKELY(subscript
.isUInt32())) {
2482 uint32_t i
= subscript
.asUInt32();
2483 if (isJSArray(globalData
, baseValue
)) {
2484 JSArray
* jsArray
= asArray(baseValue
);
2485 if (jsArray
->canGetIndex(i
))
2486 result
= jsArray
->getIndex(i
);
2488 result
= jsArray
->JSArray::get(callFrame
, i
);
2489 } else if (isJSString(globalData
, baseValue
) && asString(baseValue
)->canGetIndex(i
))
2490 result
= asString(baseValue
)->getIndex(callFrame
, i
);
2491 else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
))
2492 result
= asByteArray(baseValue
)->getIndex(callFrame
, i
);
2494 result
= baseValue
.get(callFrame
, i
);
2496 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2497 result
= baseValue
.get(callFrame
, property
);
2500 CHECK_FOR_EXCEPTION();
2501 callFrame
->r(dst
) = result
;
2502 vPC
+= OPCODE_LENGTH(op_get_by_val
);
2505 DEFINE_OPCODE(op_put_by_val
) {
2506 /* put_by_val base(r) property(r) value(r)
2508 Sets register value on register base as the property named
2509 by register property. Base is converted to object
2510 first. register property is nominally converted to string
2511 but numbers are treated more efficiently.
2513 Unlike many opcodes, this one does not write any output to
2516 int base
= vPC
[1].u
.operand
;
2517 int property
= vPC
[2].u
.operand
;
2518 int value
= vPC
[3].u
.operand
;
2520 JSValue baseValue
= callFrame
->r(base
).jsValue();
2521 JSValue subscript
= callFrame
->r(property
).jsValue();
2523 if (LIKELY(subscript
.isUInt32())) {
2524 uint32_t i
= subscript
.asUInt32();
2525 if (isJSArray(globalData
, baseValue
)) {
2526 JSArray
* jsArray
= asArray(baseValue
);
2527 if (jsArray
->canSetIndex(i
))
2528 jsArray
->setIndex(i
, callFrame
->r(value
).jsValue());
2530 jsArray
->JSArray::put(callFrame
, i
, callFrame
->r(value
).jsValue());
2531 } else if (isJSByteArray(globalData
, baseValue
) && asByteArray(baseValue
)->canAccessIndex(i
)) {
2532 JSByteArray
* jsByteArray
= asByteArray(baseValue
);
2534 JSValue jsValue
= callFrame
->r(value
).jsValue();
2535 if (jsValue
.isInt32())
2536 jsByteArray
->setIndex(i
, jsValue
.asInt32());
2537 else if (jsValue
.getNumber(dValue
))
2538 jsByteArray
->setIndex(i
, dValue
);
2540 baseValue
.put(callFrame
, i
, jsValue
);
2542 baseValue
.put(callFrame
, i
, callFrame
->r(value
).jsValue());
2544 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2545 if (!globalData
->exception
) { // Don't put to an object if toString threw an exception.
2546 PutPropertySlot slot
;
2547 baseValue
.put(callFrame
, property
, callFrame
->r(value
).jsValue(), slot
);
2551 CHECK_FOR_EXCEPTION();
2552 vPC
+= OPCODE_LENGTH(op_put_by_val
);
2555 DEFINE_OPCODE(op_del_by_val
) {
2556 /* del_by_val dst(r) base(r) property(r)
2558 Converts register base to Object, deletes the property
2559 named by register property from the object, and writes a
2560 boolean indicating success (if true) or failure (if false)
2563 int dst
= vPC
[1].u
.operand
;
2564 int base
= vPC
[2].u
.operand
;
2565 int property
= vPC
[3].u
.operand
;
2567 JSObject
* baseObj
= callFrame
->r(base
).jsValue().toObject(callFrame
); // may throw
2569 JSValue subscript
= callFrame
->r(property
).jsValue();
2572 if (subscript
.getUInt32(i
))
2573 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, i
));
2575 CHECK_FOR_EXCEPTION();
2576 Identifier
property(callFrame
, subscript
.toString(callFrame
));
2577 CHECK_FOR_EXCEPTION();
2578 result
= jsBoolean(baseObj
->deleteProperty(callFrame
, property
));
2581 CHECK_FOR_EXCEPTION();
2582 callFrame
->r(dst
) = result
;
2583 vPC
+= OPCODE_LENGTH(op_del_by_val
);
2586 DEFINE_OPCODE(op_put_by_index
) {
2587 /* put_by_index base(r) property(n) value(r)
2589 Sets register value on register base as the property named
2590 by the immediate number property. Base is converted to
2593 Unlike many opcodes, this one does not write any output to
2596 This opcode is mainly used to initialize array literals.
2598 int base
= vPC
[1].u
.operand
;
2599 unsigned property
= vPC
[2].u
.operand
;
2600 int value
= vPC
[3].u
.operand
;
2602 callFrame
->r(base
).jsValue().put(callFrame
, property
, callFrame
->r(value
).jsValue());
2604 vPC
+= OPCODE_LENGTH(op_put_by_index
);
2607 DEFINE_OPCODE(op_loop
) {
2608 /* loop target(offset)
2610 Jumps unconditionally to offset target from the current
2613 Additionally this loop instruction may terminate JS execution is
2614 the JS timeout is reached.
2616 #if ENABLE(OPCODE_STATS)
2617 OpcodeStats::resetLastInstruction();
2619 int target
= vPC
[1].u
.operand
;
2620 CHECK_FOR_TIMEOUT();
2624 DEFINE_OPCODE(op_jmp
) {
2625 /* jmp target(offset)
2627 Jumps unconditionally to offset target from the current
2630 #if ENABLE(OPCODE_STATS)
2631 OpcodeStats::resetLastInstruction();
2633 int target
= vPC
[1].u
.operand
;
2638 DEFINE_OPCODE(op_loop_if_true
) {
2639 /* loop_if_true cond(r) target(offset)
2641 Jumps to offset target from the current instruction, if and
2642 only if register cond converts to boolean as true.
2644 Additionally this loop instruction may terminate JS execution is
2645 the JS timeout is reached.
2647 int cond
= vPC
[1].u
.operand
;
2648 int target
= vPC
[2].u
.operand
;
2649 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2651 CHECK_FOR_TIMEOUT();
2655 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
2658 DEFINE_OPCODE(op_loop_if_false
) {
2659 /* loop_if_true cond(r) target(offset)
2661 Jumps to offset target from the current instruction, if and
2662 only if register cond converts to boolean as false.
2664 Additionally this loop instruction may terminate JS execution is
2665 the JS timeout is reached.
2667 int cond
= vPC
[1].u
.operand
;
2668 int target
= vPC
[2].u
.operand
;
2669 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2671 CHECK_FOR_TIMEOUT();
2675 vPC
+= OPCODE_LENGTH(op_loop_if_true
);
2678 DEFINE_OPCODE(op_jtrue
) {
2679 /* jtrue cond(r) target(offset)
2681 Jumps to offset target from the current instruction, if and
2682 only if register cond converts to boolean as true.
2684 int cond
= vPC
[1].u
.operand
;
2685 int target
= vPC
[2].u
.operand
;
2686 if (callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2691 vPC
+= OPCODE_LENGTH(op_jtrue
);
2694 DEFINE_OPCODE(op_jfalse
) {
2695 /* jfalse cond(r) target(offset)
2697 Jumps to offset target from the current instruction, if and
2698 only if register cond converts to boolean as false.
2700 int cond
= vPC
[1].u
.operand
;
2701 int target
= vPC
[2].u
.operand
;
2702 if (!callFrame
->r(cond
).jsValue().toBoolean(callFrame
)) {
2707 vPC
+= OPCODE_LENGTH(op_jfalse
);
2710 DEFINE_OPCODE(op_jeq_null
) {
2711 /* jeq_null src(r) target(offset)
2713 Jumps to offset target from the current instruction, if and
2714 only if register src is null.
2716 int src
= vPC
[1].u
.operand
;
2717 int target
= vPC
[2].u
.operand
;
2718 JSValue srcValue
= callFrame
->r(src
).jsValue();
2720 if (srcValue
.isUndefinedOrNull() || (srcValue
.isCell() && srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2725 vPC
+= OPCODE_LENGTH(op_jeq_null
);
2728 DEFINE_OPCODE(op_jneq_null
) {
2729 /* jneq_null src(r) target(offset)
2731 Jumps to offset target from the current instruction, if and
2732 only if register src is not null.
2734 int src
= vPC
[1].u
.operand
;
2735 int target
= vPC
[2].u
.operand
;
2736 JSValue srcValue
= callFrame
->r(src
).jsValue();
2738 if (!srcValue
.isUndefinedOrNull() && (!srcValue
.isCell() || !srcValue
.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2743 vPC
+= OPCODE_LENGTH(op_jneq_null
);
2746 DEFINE_OPCODE(op_jneq_ptr
) {
2747 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2749 Jumps to offset target from the current instruction, if the value r is equal
2750 to ptr, using pointer equality.
2752 int src
= vPC
[1].u
.operand
;
2753 JSValue ptr
= JSValue(vPC
[2].u
.jsCell
);
2754 int target
= vPC
[3].u
.operand
;
2755 JSValue srcValue
= callFrame
->r(src
).jsValue();
2756 if (srcValue
!= ptr
) {
2761 vPC
+= OPCODE_LENGTH(op_jneq_ptr
);
2764 DEFINE_OPCODE(op_loop_if_less
) {
2765 /* loop_if_less src1(r) src2(r) target(offset)
2767 Checks whether register src1 is less than register src2, as
2768 with the ECMAScript '<' operator, and then jumps to offset
2769 target from the current instruction, if and only if the
2770 result of the comparison is true.
2772 Additionally this loop instruction may terminate JS execution is
2773 the JS timeout is reached.
2775 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2776 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2777 int target
= vPC
[3].u
.operand
;
2779 bool result
= jsLess(callFrame
, src1
, src2
);
2780 CHECK_FOR_EXCEPTION();
2784 CHECK_FOR_TIMEOUT();
2788 vPC
+= OPCODE_LENGTH(op_loop_if_less
);
2791 DEFINE_OPCODE(op_loop_if_lesseq
) {
2792 /* loop_if_lesseq src1(r) src2(r) target(offset)
2794 Checks whether register src1 is less than or equal to register
2795 src2, as with the ECMAScript '<=' operator, and then jumps to
2796 offset target from the current instruction, if and only if the
2797 result of the comparison is true.
2799 Additionally this loop instruction may terminate JS execution is
2800 the JS timeout is reached.
2802 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2803 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2804 int target
= vPC
[3].u
.operand
;
2806 bool result
= jsLessEq(callFrame
, src1
, src2
);
2807 CHECK_FOR_EXCEPTION();
2811 CHECK_FOR_TIMEOUT();
2815 vPC
+= OPCODE_LENGTH(op_loop_if_lesseq
);
2818 DEFINE_OPCODE(op_jnless
) {
2819 /* jnless src1(r) src2(r) target(offset)
2821 Checks whether register src1 is less than register src2, as
2822 with the ECMAScript '<' operator, and then jumps to offset
2823 target from the current instruction, if and only if the
2824 result of the comparison is false.
2826 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2827 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2828 int target
= vPC
[3].u
.operand
;
2830 bool result
= jsLess(callFrame
, src1
, src2
);
2831 CHECK_FOR_EXCEPTION();
2838 vPC
+= OPCODE_LENGTH(op_jnless
);
2841 DEFINE_OPCODE(op_jless
) {
2842 /* jless src1(r) src2(r) target(offset)
2844 Checks whether register src1 is less than register src2, as
2845 with the ECMAScript '<' operator, and then jumps to offset
2846 target from the current instruction, if and only if the
2847 result of the comparison is true.
2849 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2850 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2851 int target
= vPC
[3].u
.operand
;
2853 bool result
= jsLess(callFrame
, src1
, src2
);
2854 CHECK_FOR_EXCEPTION();
2861 vPC
+= OPCODE_LENGTH(op_jless
);
2864 DEFINE_OPCODE(op_jnlesseq
) {
2865 /* jnlesseq src1(r) src2(r) target(offset)
2867 Checks whether register src1 is less than or equal to
2868 register src2, as with the ECMAScript '<=' operator,
2869 and then jumps to offset target from the current instruction,
2870 if and only if theresult of the comparison is false.
2872 JSValue src1
= callFrame
->r(vPC
[1].u
.operand
).jsValue();
2873 JSValue src2
= callFrame
->r(vPC
[2].u
.operand
).jsValue();
2874 int target
= vPC
[3].u
.operand
;
2876 bool result
= jsLessEq(callFrame
, src1
, src2
);
2877 CHECK_FOR_EXCEPTION();
2884 vPC
+= OPCODE_LENGTH(op_jnlesseq
);
2887 DEFINE_OPCODE(op_switch_imm
) {
2888 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2890 Performs a range checked switch on the scrutinee value, using
2891 the tableIndex-th immediate switch jump table. If the scrutinee value
2892 is an immediate number in the range covered by the referenced jump
2893 table, and the value at jumpTable[scrutinee value] is non-zero, then
2894 that value is used as the jump offset, otherwise defaultOffset is used.
2896 int tableIndex
= vPC
[1].u
.operand
;
2897 int defaultOffset
= vPC
[2].u
.operand
;
2898 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2899 if (scrutinee
.isInt32())
2900 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(scrutinee
.asInt32(), defaultOffset
);
2904 if (scrutinee
.getNumber(value
) && ((intValue
= static_cast<int32_t>(value
)) == value
))
2905 vPC
+= callFrame
->codeBlock()->immediateSwitchJumpTable(tableIndex
).offsetForValue(intValue
, defaultOffset
);
2907 vPC
+= defaultOffset
;
2911 DEFINE_OPCODE(op_switch_char
) {
2912 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2914 Performs a range checked switch on the scrutinee value, using
2915 the tableIndex-th character switch jump table. If the scrutinee value
2916 is a single character string in the range covered by the referenced jump
2917 table, and the value at jumpTable[scrutinee value] is non-zero, then
2918 that value is used as the jump offset, otherwise defaultOffset is used.
2920 int tableIndex
= vPC
[1].u
.operand
;
2921 int defaultOffset
= vPC
[2].u
.operand
;
2922 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2923 if (!scrutinee
.isString())
2924 vPC
+= defaultOffset
;
2926 UString::Rep
* value
= asString(scrutinee
)->value(callFrame
).rep();
2927 if (value
->size() != 1)
2928 vPC
+= defaultOffset
;
2930 vPC
+= callFrame
->codeBlock()->characterSwitchJumpTable(tableIndex
).offsetForValue(value
->data()[0], defaultOffset
);
2934 DEFINE_OPCODE(op_switch_string
) {
2935 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2937 Performs a sparse hashmap based switch on the value in the scrutinee
2938 register, using the tableIndex-th string switch jump table. If the
2939 scrutinee value is a string that exists as a key in the referenced
2940 jump table, then the value associated with the string is used as the
2941 jump offset, otherwise defaultOffset is used.
2943 int tableIndex
= vPC
[1].u
.operand
;
2944 int defaultOffset
= vPC
[2].u
.operand
;
2945 JSValue scrutinee
= callFrame
->r(vPC
[3].u
.operand
).jsValue();
2946 if (!scrutinee
.isString())
2947 vPC
+= defaultOffset
;
2949 vPC
+= callFrame
->codeBlock()->stringSwitchJumpTable(tableIndex
).offsetForValue(asString(scrutinee
)->value(callFrame
).rep(), defaultOffset
);
2952 DEFINE_OPCODE(op_new_func
) {
2953 /* new_func dst(r) func(f)
2955 Constructs a new Function instance from function func and
2956 the current scope chain using the original Function
2957 constructor, using the rules for function declarations, and
2958 puts the result in register dst.
2960 int dst
= vPC
[1].u
.operand
;
2961 int func
= vPC
[2].u
.operand
;
2963 callFrame
->r(dst
) = JSValue(callFrame
->codeBlock()->functionDecl(func
)->make(callFrame
, callFrame
->scopeChain()));
2965 vPC
+= OPCODE_LENGTH(op_new_func
);
2968 DEFINE_OPCODE(op_new_func_exp
) {
2969 /* new_func_exp dst(r) func(f)
2971 Constructs a new Function instance from function func and
2972 the current scope chain using the original Function
2973 constructor, using the rules for function expressions, and
2974 puts the result in register dst.
2976 int dst
= vPC
[1].u
.operand
;
2977 int funcIndex
= vPC
[2].u
.operand
;
2979 FunctionExecutable
* function
= callFrame
->codeBlock()->functionExpr(funcIndex
);
2980 JSFunction
* func
= function
->make(callFrame
, callFrame
->scopeChain());
2983 The Identifier in a FunctionExpression can be referenced from inside
2984 the FunctionExpression's FunctionBody to allow the function to call
2985 itself recursively. However, unlike in a FunctionDeclaration, the
2986 Identifier in a FunctionExpression cannot be referenced from and
2987 does not affect the scope enclosing the FunctionExpression.
2989 if (!function
->name().isNull()) {
2990 JSStaticScopeObject
* functionScopeObject
= new (callFrame
) JSStaticScopeObject(callFrame
, function
->name(), func
, ReadOnly
| DontDelete
);
2991 func
->scope().push(functionScopeObject
);
2994 callFrame
->r(dst
) = JSValue(func
);
2996 vPC
+= OPCODE_LENGTH(op_new_func_exp
);
2999 DEFINE_OPCODE(op_call_eval
) {
3000 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
3002 Call a function named "eval" with no explicit "this" value
3003 (which may therefore be the eval operator). If register
3004 thisVal is the global object, and register func contains
3005 that global object's original global eval function, then
3006 perform the eval operator in local scope (interpreting
3007 the argument registers as for the "call"
3008 opcode). Otherwise, act exactly as the "call" opcode would.
3011 int dst
= vPC
[1].u
.operand
;
3012 int func
= vPC
[2].u
.operand
;
3013 int argCount
= vPC
[3].u
.operand
;
3014 int registerOffset
= vPC
[4].u
.operand
;
3016 JSValue funcVal
= callFrame
->r(func
).jsValue();
3018 Register
* newCallFrame
= callFrame
->registers() + registerOffset
;
3019 Register
* argv
= newCallFrame
- RegisterFile::CallFrameHeaderSize
- argCount
;
3020 JSValue thisValue
= argv
[0].jsValue();
3021 JSGlobalObject
* globalObject
= callFrame
->scopeChain()->globalObject
;
3023 if (thisValue
== globalObject
&& funcVal
== globalObject
->evalFunction()) {
3024 JSValue result
= callEval(callFrame
, registerFile
, argv
, argCount
, registerOffset
, exceptionValue
);
3027 callFrame
->r(dst
) = result
;
3029 vPC
+= OPCODE_LENGTH(op_call_eval
);
3033 // We didn't find the blessed version of eval, so process this
3034 // instruction as a normal function call.
3035 // fall through to op_call
3037 DEFINE_OPCODE(op_call
) {
3038 /* call dst(r) func(r) argCount(n) registerOffset(n)
3040 Perform a function call.
3042 registerOffset is the distance the callFrame pointer should move
3043 before the VM initializes the new call frame's header.
3045 dst is where op_ret should store its result.
3048 int dst
= vPC
[1].u
.operand
;
3049 int func
= vPC
[2].u
.operand
;
3050 int argCount
= vPC
[3].u
.operand
;
3051 int registerOffset
= vPC
[4].u
.operand
;
3053 JSValue v
= callFrame
->r(func
).jsValue();
3056 CallType callType
= v
.getCallData(callData
);
3058 if (callType
== CallTypeJS
) {
3059 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3060 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3062 CallFrame
* previousCallFrame
= callFrame
;
3064 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3065 if (UNLIKELY(!callFrame
)) {
3066 callFrame
= previousCallFrame
;
3067 exceptionValue
= createStackOverflowError(callFrame
);
3071 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3072 vPC
= newCodeBlock
->instructions().begin();
3074 #if ENABLE(OPCODE_STATS)
3075 OpcodeStats::resetLastInstruction();
3081 if (callType
== CallTypeHost
) {
3082 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3083 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3084 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3086 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3087 ArgList
args(thisRegister
+ 1, argCount
- 1);
3089 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3090 JSValue thisValue
= thisRegister
->jsValue();
3091 if (thisValue
== jsNull())
3092 thisValue
= callFrame
->globalThisValue();
3094 JSValue returnValue
;
3096 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3097 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3099 CHECK_FOR_EXCEPTION();
3101 callFrame
->r(dst
) = returnValue
;
3103 vPC
+= OPCODE_LENGTH(op_call
);
3107 ASSERT(callType
== CallTypeNone
);
3109 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3112 DEFINE_OPCODE(op_load_varargs
) {
3113 int argCountDst
= vPC
[1].u
.operand
;
3114 int argsOffset
= vPC
[2].u
.operand
;
3116 JSValue arguments
= callFrame
->r(argsOffset
).jsValue();
3117 int32_t argCount
= 0;
3119 argCount
= (uint32_t)(callFrame
->argumentCount()) - 1;
3120 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3121 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3122 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3123 exceptionValue
= createStackOverflowError(callFrame
);
3126 ASSERT(!callFrame
->callee()->isHostFunction());
3127 int32_t expectedParams
= callFrame
->callee()->jsExecutable()->parameterCount();
3128 int32_t inplaceArgs
= min(argCount
, expectedParams
);
3130 Register
* argStore
= callFrame
->registers() + argsOffset
;
3132 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3133 for (; i
< inplaceArgs
; i
++)
3134 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
];
3135 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3136 for (; i
< argCount
; i
++)
3137 argStore
[i
] = callFrame
->registers()[i
- RegisterFile::CallFrameHeaderSize
- expectedParams
- argCount
- 1];
3138 } else if (!arguments
.isUndefinedOrNull()) {
3139 if (!arguments
.isObject()) {
3140 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3143 if (asObject(arguments
)->classInfo() == &Arguments::info
) {
3144 Arguments
* args
= asArguments(arguments
);
3145 argCount
= args
->numProvidedArguments(callFrame
);
3146 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3147 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3148 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3149 exceptionValue
= createStackOverflowError(callFrame
);
3152 args
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3153 } else if (isJSArray(&callFrame
->globalData(), arguments
)) {
3154 JSArray
* array
= asArray(arguments
);
3155 argCount
= array
->length();
3156 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3157 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3158 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3159 exceptionValue
= createStackOverflowError(callFrame
);
3162 array
->copyToRegisters(callFrame
, callFrame
->registers() + argsOffset
, argCount
);
3163 } else if (asObject(arguments
)->inherits(&JSArray::info
)) {
3164 JSObject
* argObject
= asObject(arguments
);
3165 argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
3166 int32_t sizeDelta
= argsOffset
+ argCount
+ RegisterFile::CallFrameHeaderSize
;
3167 Register
* newEnd
= callFrame
->registers() + sizeDelta
;
3168 if (!registerFile
->grow(newEnd
) || ((newEnd
- callFrame
->registers()) != sizeDelta
)) {
3169 exceptionValue
= createStackOverflowError(callFrame
);
3172 Register
* argsBuffer
= callFrame
->registers() + argsOffset
;
3173 for (int32_t i
= 0; i
< argCount
; ++i
) {
3174 argsBuffer
[i
] = asObject(arguments
)->get(callFrame
, i
);
3175 CHECK_FOR_EXCEPTION();
3178 if (!arguments
.isObject()) {
3179 exceptionValue
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3184 CHECK_FOR_EXCEPTION();
3185 callFrame
->r(argCountDst
) = Register::withInt(argCount
+ 1);
3186 vPC
+= OPCODE_LENGTH(op_load_varargs
);
3189 DEFINE_OPCODE(op_call_varargs
) {
3190 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3192 Perform a function call with a dynamic set of arguments.
3194 registerOffset is the distance the callFrame pointer should move
3195 before the VM initializes the new call frame's header, excluding
3196 space for arguments.
3198 dst is where op_ret should store its result.
3201 int dst
= vPC
[1].u
.operand
;
3202 int func
= vPC
[2].u
.operand
;
3203 int argCountReg
= vPC
[3].u
.operand
;
3204 int registerOffset
= vPC
[4].u
.operand
;
3206 JSValue v
= callFrame
->r(func
).jsValue();
3207 int argCount
= callFrame
->r(argCountReg
).i();
3208 registerOffset
+= argCount
;
3210 CallType callType
= v
.getCallData(callData
);
3212 if (callType
== CallTypeJS
) {
3213 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
3214 CodeBlock
* newCodeBlock
= &callData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3216 CallFrame
* previousCallFrame
= callFrame
;
3218 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3219 if (UNLIKELY(!callFrame
)) {
3220 callFrame
= previousCallFrame
;
3221 exceptionValue
= createStackOverflowError(callFrame
);
3225 callFrame
->init(newCodeBlock
, vPC
+ 5, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3226 vPC
= newCodeBlock
->instructions().begin();
3228 #if ENABLE(OPCODE_STATS)
3229 OpcodeStats::resetLastInstruction();
3235 if (callType
== CallTypeHost
) {
3236 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3237 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3238 newCallFrame
->init(0, vPC
+ 5, scopeChain
, callFrame
, dst
, argCount
, 0);
3240 Register
* thisRegister
= newCallFrame
->registers() - RegisterFile::CallFrameHeaderSize
- argCount
;
3241 ArgList
args(thisRegister
+ 1, argCount
- 1);
3243 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3244 JSValue thisValue
= thisRegister
->jsValue();
3245 if (thisValue
== jsNull())
3246 thisValue
= callFrame
->globalThisValue();
3248 JSValue returnValue
;
3250 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3251 returnValue
= callData
.native
.function(newCallFrame
, asObject(v
), thisValue
, args
);
3253 CHECK_FOR_EXCEPTION();
3255 callFrame
->r(dst
) = returnValue
;
3257 vPC
+= OPCODE_LENGTH(op_call_varargs
);
3261 ASSERT(callType
== CallTypeNone
);
3263 exceptionValue
= createNotAFunctionError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3266 DEFINE_OPCODE(op_tear_off_activation
) {
3267 /* tear_off_activation activation(r)
3269 Copy all locals and parameters to new memory allocated on
3270 the heap, and make the passed activation use this memory
3271 in the future when looking up entries in the symbol table.
3272 If there is an 'arguments' object, then it will also use
3273 this memory for storing the named parameters, but not any
3276 This opcode should only be used immediately before op_ret.
3279 int src
= vPC
[1].u
.operand
;
3280 ASSERT(callFrame
->codeBlock()->needsFullScopeChain());
3282 asActivation(callFrame
->r(src
).jsValue())->copyRegisters(callFrame
->optionalCalleeArguments());
3284 vPC
+= OPCODE_LENGTH(op_tear_off_activation
);
3287 DEFINE_OPCODE(op_tear_off_arguments
) {
3288 /* tear_off_arguments
3290 Copy all arguments to new memory allocated on the heap,
3291 and make the 'arguments' object use this memory in the
3292 future when looking up named parameters, but not any
3293 extra arguments. If an activation object exists for the
3294 current function context, then the tear_off_activation
3295 opcode should be used instead.
3297 This opcode should only be used immediately before op_ret.
3300 ASSERT(callFrame
->codeBlock()->usesArguments() && !callFrame
->codeBlock()->needsFullScopeChain());
3302 if (callFrame
->optionalCalleeArguments())
3303 callFrame
->optionalCalleeArguments()->copyRegisters();
3305 vPC
+= OPCODE_LENGTH(op_tear_off_arguments
);
3308 DEFINE_OPCODE(op_ret
) {
3311 Return register result as the return value of the current
3312 function call, writing it into the caller's expected return
3313 value register. In addition, unwind one call frame and
3314 restore the scope chain, code block instruction pointer and
3315 register base to those of the calling function.
3318 int result
= vPC
[1].u
.operand
;
3320 if (callFrame
->codeBlock()->needsFullScopeChain())
3321 callFrame
->scopeChain()->deref();
3323 JSValue returnValue
= callFrame
->r(result
).jsValue();
3325 vPC
= callFrame
->returnPC();
3326 int dst
= callFrame
->returnValueRegister();
3327 callFrame
= callFrame
->callerFrame();
3329 if (callFrame
->hasHostCallFrameFlag())
3332 callFrame
->r(dst
) = returnValue
;
3336 DEFINE_OPCODE(op_enter
) {
3339 Initializes local variables to undefined and fills constant
3340 registers with their values. If the code block requires an
3341 activation, enter_with_activation should be used instead.
3343 This opcode should only be used at the beginning of a code
3348 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3350 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3351 callFrame
->r(i
) = jsUndefined();
3353 vPC
+= OPCODE_LENGTH(op_enter
);
3356 DEFINE_OPCODE(op_enter_with_activation
) {
3357 /* enter_with_activation dst(r)
3359 Initializes local variables to undefined, fills constant
3360 registers with their values, creates an activation object,
3361 and places the new activation both in dst and at the top
3362 of the scope chain. If the code block does not require an
3363 activation, enter should be used instead.
3365 This opcode should only be used at the beginning of a code
3370 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3372 for (size_t count
= codeBlock
->m_numVars
; i
< count
; ++i
)
3373 callFrame
->r(i
) = jsUndefined();
3375 int dst
= vPC
[1].u
.operand
;
3376 JSActivation
* activation
= new (globalData
) JSActivation(callFrame
, static_cast<FunctionExecutable
*>(codeBlock
->ownerExecutable()));
3377 callFrame
->r(dst
) = JSValue(activation
);
3378 callFrame
->setScopeChain(callFrame
->scopeChain()->copy()->push(activation
));
3380 vPC
+= OPCODE_LENGTH(op_enter_with_activation
);
3383 DEFINE_OPCODE(op_convert_this
) {
3384 /* convert_this this(r)
3386 Takes the value in the 'this' register, converts it to a
3387 value that is suitable for use as the 'this' value, and
3388 stores it in the 'this' register. This opcode is emitted
3389 to avoid doing the conversion in the caller unnecessarily.
3391 This opcode should only be used at the beginning of a code
3395 int thisRegister
= vPC
[1].u
.operand
;
3396 JSValue thisVal
= callFrame
->r(thisRegister
).jsValue();
3397 if (thisVal
.needsThisConversion())
3398 callFrame
->r(thisRegister
) = JSValue(thisVal
.toThisObject(callFrame
));
3400 vPC
+= OPCODE_LENGTH(op_convert_this
);
3403 DEFINE_OPCODE(op_init_arguments
) {
3406 Initialises the arguments object reference to null to ensure
3407 we can correctly detect that we need to create it later (or
3408 avoid creating it altogether).
3410 This opcode should only be used at the beginning of a code
3413 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue();
3414 vPC
+= OPCODE_LENGTH(op_init_arguments
);
3417 DEFINE_OPCODE(op_create_arguments
) {
3420 Creates the 'arguments' object and places it in both the
3421 'arguments' call frame slot and the local 'arguments'
3422 register, if it has not already been initialised.
3425 if (!callFrame
->r(RegisterFile::ArgumentsRegister
).jsValue()) {
3426 Arguments
* arguments
= new (globalData
) Arguments(callFrame
);
3427 callFrame
->setCalleeArguments(arguments
);
3428 callFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3430 vPC
+= OPCODE_LENGTH(op_create_arguments
);
3433 DEFINE_OPCODE(op_construct
) {
3434 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3436 Invoke register "func" as a constructor. For JS
3437 functions, the calling convention is exactly as for the
3438 "call" opcode, except that the "this" value is a newly
3439 created Object. For native constructors, no "this"
3440 value is passed. In either case, the argCount and registerOffset
3441 registers are interpreted as for the "call" opcode.
3443 Register proto must contain the prototype property of
3444 register func. This is to enable polymorphic inline
3445 caching of this lookup.
3448 int dst
= vPC
[1].u
.operand
;
3449 int func
= vPC
[2].u
.operand
;
3450 int argCount
= vPC
[3].u
.operand
;
3451 int registerOffset
= vPC
[4].u
.operand
;
3452 int proto
= vPC
[5].u
.operand
;
3453 int thisRegister
= vPC
[6].u
.operand
;
3455 JSValue v
= callFrame
->r(func
).jsValue();
3457 ConstructData constructData
;
3458 ConstructType constructType
= v
.getConstructData(constructData
);
3460 if (constructType
== ConstructTypeJS
) {
3461 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
3462 CodeBlock
* newCodeBlock
= &constructData
.js
.functionExecutable
->bytecode(callFrame
, callDataScopeChain
);
3464 Structure
* structure
;
3465 JSValue prototype
= callFrame
->r(proto
).jsValue();
3466 if (prototype
.isObject())
3467 structure
= asObject(prototype
)->inheritorID();
3469 structure
= callDataScopeChain
->globalObject
->emptyObjectStructure();
3470 JSObject
* newObject
= new (globalData
) JSObject(structure
);
3472 callFrame
->r(thisRegister
) = JSValue(newObject
); // "this" value
3474 CallFrame
* previousCallFrame
= callFrame
;
3476 callFrame
= slideRegisterWindowForCall(newCodeBlock
, registerFile
, callFrame
, registerOffset
, argCount
);
3477 if (UNLIKELY(!callFrame
)) {
3478 callFrame
= previousCallFrame
;
3479 exceptionValue
= createStackOverflowError(callFrame
);
3483 callFrame
->init(newCodeBlock
, vPC
+ 7, callDataScopeChain
, previousCallFrame
, dst
, argCount
, asFunction(v
));
3484 vPC
= newCodeBlock
->instructions().begin();
3486 #if ENABLE(OPCODE_STATS)
3487 OpcodeStats::resetLastInstruction();
3493 if (constructType
== ConstructTypeHost
) {
3494 ArgList
args(callFrame
->registers() + thisRegister
+ 1, argCount
- 1);
3496 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3497 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + registerOffset
);
3498 newCallFrame
->init(0, vPC
+ 7, scopeChain
, callFrame
, dst
, argCount
, 0);
3500 JSValue returnValue
;
3502 SamplingTool::HostCallRecord
callRecord(m_sampler
.get());
3503 returnValue
= constructData
.native
.function(newCallFrame
, asObject(v
), args
);
3505 CHECK_FOR_EXCEPTION();
3506 callFrame
->r(dst
) = JSValue(returnValue
);
3508 vPC
+= OPCODE_LENGTH(op_construct
);
3512 ASSERT(constructType
== ConstructTypeNone
);
3514 exceptionValue
= createNotAConstructorError(callFrame
, v
, vPC
- callFrame
->codeBlock()->instructions().begin(), callFrame
->codeBlock());
3517 DEFINE_OPCODE(op_construct_verify
) {
3518 /* construct_verify dst(r) override(r)
3520 Verifies that register dst holds an object. If not, moves
3521 the object in register override to register dst.
3524 int dst
= vPC
[1].u
.operand
;
3525 if (LIKELY(callFrame
->r(dst
).jsValue().isObject())) {
3526 vPC
+= OPCODE_LENGTH(op_construct_verify
);
3530 int override
= vPC
[2].u
.operand
;
3531 callFrame
->r(dst
) = callFrame
->r(override
);
3533 vPC
+= OPCODE_LENGTH(op_construct_verify
);
3536 DEFINE_OPCODE(op_strcat
) {
3537 int dst
= vPC
[1].u
.operand
;
3538 int src
= vPC
[2].u
.operand
;
3539 int count
= vPC
[3].u
.operand
;
3541 callFrame
->r(dst
) = jsString(callFrame
, &callFrame
->registers()[src
], count
);
3542 CHECK_FOR_EXCEPTION();
3543 vPC
+= OPCODE_LENGTH(op_strcat
);
3547 DEFINE_OPCODE(op_to_primitive
) {
3548 int dst
= vPC
[1].u
.operand
;
3549 int src
= vPC
[2].u
.operand
;
3551 callFrame
->r(dst
) = callFrame
->r(src
).jsValue().toPrimitive(callFrame
);
3552 vPC
+= OPCODE_LENGTH(op_to_primitive
);
3556 DEFINE_OPCODE(op_push_scope
) {
3557 /* push_scope scope(r)
3559 Converts register scope to object, and pushes it onto the top
3560 of the current scope chain. The contents of the register scope
3561 are replaced by the result of toObject conversion of the scope.
3563 int scope
= vPC
[1].u
.operand
;
3564 JSValue v
= callFrame
->r(scope
).jsValue();
3565 JSObject
* o
= v
.toObject(callFrame
);
3566 CHECK_FOR_EXCEPTION();
3568 callFrame
->r(scope
) = JSValue(o
);
3569 callFrame
->setScopeChain(callFrame
->scopeChain()->push(o
));
3571 vPC
+= OPCODE_LENGTH(op_push_scope
);
3574 DEFINE_OPCODE(op_pop_scope
) {
3577 Removes the top item from the current scope chain.
3579 callFrame
->setScopeChain(callFrame
->scopeChain()->pop());
3581 vPC
+= OPCODE_LENGTH(op_pop_scope
);
3584 DEFINE_OPCODE(op_get_pnames
) {
3585 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)
3587 Creates a property name list for register base and puts it
3588 in register dst, initializing i and size for iteration. If
3589 base is undefined or null, jumps to breakTarget.
3591 int dst
= vPC
[1].u
.operand
;
3592 int base
= vPC
[2].u
.operand
;
3593 int i
= vPC
[3].u
.operand
;
3594 int size
= vPC
[4].u
.operand
;
3595 int breakTarget
= vPC
[5].u
.operand
;
3597 JSValue v
= callFrame
->r(base
).jsValue();
3598 if (v
.isUndefinedOrNull()) {
3603 JSObject
* o
= v
.toObject(callFrame
);
3604 Structure
* structure
= o
->structure();
3605 JSPropertyNameIterator
* jsPropertyNameIterator
= structure
->enumerationCache();
3606 if (!jsPropertyNameIterator
|| jsPropertyNameIterator
->cachedPrototypeChain() != structure
->prototypeChain(callFrame
))
3607 jsPropertyNameIterator
= JSPropertyNameIterator::create(callFrame
, o
);
3609 callFrame
->r(dst
) = jsPropertyNameIterator
;
3610 callFrame
->r(base
) = JSValue(o
);
3611 callFrame
->r(i
) = Register::withInt(0);
3612 callFrame
->r(size
) = Register::withInt(jsPropertyNameIterator
->size());
3613 vPC
+= OPCODE_LENGTH(op_get_pnames
);
3616 DEFINE_OPCODE(op_next_pname
) {
3617 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)
3619 Copies the next name from the property name list in
3620 register iter to dst, then jumps to offset target. If there are no
3621 names left, invalidates the iterator and continues to the next
3624 int dst
= vPC
[1].u
.operand
;
3625 int base
= vPC
[2].u
.operand
;
3626 int i
= vPC
[3].u
.operand
;
3627 int size
= vPC
[4].u
.operand
;
3628 int iter
= vPC
[5].u
.operand
;
3629 int target
= vPC
[6].u
.operand
;
3631 JSPropertyNameIterator
* it
= callFrame
->r(iter
).propertyNameIterator();
3632 while (callFrame
->r(i
).i() != callFrame
->r(size
).i()) {
3633 JSValue key
= it
->get(callFrame
, asObject(callFrame
->r(base
).jsValue()), callFrame
->r(i
).i());
3634 callFrame
->r(i
) = Register::withInt(callFrame
->r(i
).i() + 1);
3636 CHECK_FOR_TIMEOUT();
3637 callFrame
->r(dst
) = key
;
3643 vPC
+= OPCODE_LENGTH(op_next_pname
);
3646 DEFINE_OPCODE(op_jmp_scopes
) {
3647 /* jmp_scopes count(n) target(offset)
3649 Removes the a number of items from the current scope chain
3650 specified by immediate number count, then jumps to offset
3653 int count
= vPC
[1].u
.operand
;
3654 int target
= vPC
[2].u
.operand
;
3656 ScopeChainNode
* tmp
= callFrame
->scopeChain();
3659 callFrame
->setScopeChain(tmp
);
3664 #if HAVE(COMPUTED_GOTO)
3666 goto *(&&skip_new_scope
);
3668 DEFINE_OPCODE(op_push_new_scope
) {
3669 /* new_scope dst(r) property(id) value(r)
3671 Constructs a new StaticScopeObject with property set to value. That scope
3672 object is then pushed onto the ScopeChain. The scope object is then stored
3675 callFrame
->setScopeChain(createExceptionScope(callFrame
, vPC
));
3677 vPC
+= OPCODE_LENGTH(op_push_new_scope
);
3680 #if HAVE(COMPUTED_GOTO)
3683 DEFINE_OPCODE(op_catch
) {
3686 Retrieves the VM's current exception and puts it in register
3687 ex. This is only valid after an exception has been raised,
3688 and usually forms the beginning of an exception handler.
3690 ASSERT(exceptionValue
);
3691 ASSERT(!globalData
->exception
);
3692 int ex
= vPC
[1].u
.operand
;
3693 callFrame
->r(ex
) = exceptionValue
;
3694 exceptionValue
= JSValue();
3696 vPC
+= OPCODE_LENGTH(op_catch
);
3699 DEFINE_OPCODE(op_throw
) {
3702 Throws register ex as an exception. This involves three
3703 steps: first, it is set as the current exception in the
3704 VM's internal state, then the stack is unwound until an
3705 exception handler or a native code boundary is found, and
3706 then control resumes at the exception handler if any or
3707 else the script returns control to the nearest native caller.
3710 int ex
= vPC
[1].u
.operand
;
3711 exceptionValue
= callFrame
->r(ex
).jsValue();
3713 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), true);
3715 *exception
= exceptionValue
;
3719 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3722 DEFINE_OPCODE(op_new_error
) {
3723 /* new_error dst(r) type(n) message(k)
3725 Constructs a new Error instance using the original
3726 constructor, using immediate number n as the type and
3727 constant message as the message string. The result is
3728 written to register dst.
3730 int dst
= vPC
[1].u
.operand
;
3731 int type
= vPC
[2].u
.operand
;
3732 int message
= vPC
[3].u
.operand
;
3734 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3735 callFrame
->r(dst
) = JSValue(Error::create(callFrame
, (ErrorType
)type
, callFrame
->r(message
).jsValue().toString(callFrame
), codeBlock
->lineNumberForBytecodeOffset(callFrame
, vPC
- codeBlock
->instructions().begin()), codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->sourceURL()));
3737 vPC
+= OPCODE_LENGTH(op_new_error
);
3740 DEFINE_OPCODE(op_end
) {
3743 Return register result as the value of a global or eval
3744 program. Return control to the calling native code.
3747 if (callFrame
->codeBlock()->needsFullScopeChain()) {
3748 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
3749 ASSERT(scopeChain
->refCount
> 1);
3750 scopeChain
->deref();
3752 int result
= vPC
[1].u
.operand
;
3753 return callFrame
->r(result
).jsValue();
3755 DEFINE_OPCODE(op_put_getter
) {
3756 /* put_getter base(r) property(id) function(r)
3758 Sets register function on register base as the getter named
3759 by identifier property. Base and function are assumed to be
3760 objects as this op should only be used for getters defined
3761 in object literal form.
3763 Unlike many opcodes, this one does not write any output to
3766 int base
= vPC
[1].u
.operand
;
3767 int property
= vPC
[2].u
.operand
;
3768 int function
= vPC
[3].u
.operand
;
3770 ASSERT(callFrame
->r(base
).jsValue().isObject());
3771 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3772 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3773 ASSERT(callFrame
->r(function
).jsValue().isObject());
3774 baseObj
->defineGetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()));
3776 vPC
+= OPCODE_LENGTH(op_put_getter
);
3779 DEFINE_OPCODE(op_put_setter
) {
3780 /* put_setter base(r) property(id) function(r)
3782 Sets register function on register base as the setter named
3783 by identifier property. Base and function are assumed to be
3784 objects as this op should only be used for setters defined
3785 in object literal form.
3787 Unlike many opcodes, this one does not write any output to
3790 int base
= vPC
[1].u
.operand
;
3791 int property
= vPC
[2].u
.operand
;
3792 int function
= vPC
[3].u
.operand
;
3794 ASSERT(callFrame
->r(base
).jsValue().isObject());
3795 JSObject
* baseObj
= asObject(callFrame
->r(base
).jsValue());
3796 Identifier
& ident
= callFrame
->codeBlock()->identifier(property
);
3797 ASSERT(callFrame
->r(function
).jsValue().isObject());
3798 baseObj
->defineSetter(callFrame
, ident
, asObject(callFrame
->r(function
).jsValue()), 0);
3800 vPC
+= OPCODE_LENGTH(op_put_setter
);
3803 DEFINE_OPCODE(op_method_check
) {
3807 DEFINE_OPCODE(op_jsr
) {
3808 /* jsr retAddrDst(r) target(offset)
3810 Places the address of the next instruction into the retAddrDst
3811 register and jumps to offset target from the current instruction.
3813 int retAddrDst
= vPC
[1].u
.operand
;
3814 int target
= vPC
[2].u
.operand
;
3815 callFrame
->r(retAddrDst
) = vPC
+ OPCODE_LENGTH(op_jsr
);
3820 DEFINE_OPCODE(op_sret
) {
3821 /* sret retAddrSrc(r)
3823 Jumps to the address stored in the retAddrSrc register. This
3824 differs from op_jmp because the target address is stored in a
3825 register, not as an immediate.
3827 int retAddrSrc
= vPC
[1].u
.operand
;
3828 vPC
= callFrame
->r(retAddrSrc
).vPC();
3831 DEFINE_OPCODE(op_debug
) {
3832 /* debug debugHookID(n) firstLine(n) lastLine(n)
3834 Notifies the debugger of the current state of execution. This opcode
3835 is only generated while the debugger is attached.
3837 int debugHookID
= vPC
[1].u
.operand
;
3838 int firstLine
= vPC
[2].u
.operand
;
3839 int lastLine
= vPC
[3].u
.operand
;
3841 debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
3843 vPC
+= OPCODE_LENGTH(op_debug
);
3846 DEFINE_OPCODE(op_profile_will_call
) {
3847 /* op_profile_will_call function(r)
3849 Notifies the profiler of the beginning of a function call. This opcode
3850 is only generated if developer tools are enabled.
3852 int function
= vPC
[1].u
.operand
;
3854 if (*enabledProfilerReference
)
3855 (*enabledProfilerReference
)->willExecute(callFrame
, callFrame
->r(function
).jsValue());
3857 vPC
+= OPCODE_LENGTH(op_profile_will_call
);
3860 DEFINE_OPCODE(op_profile_did_call
) {
3861 /* op_profile_did_call function(r)
3863 Notifies the profiler of the end of a function call. This opcode
3864 is only generated if developer tools are enabled.
3866 int function
= vPC
[1].u
.operand
;
3868 if (*enabledProfilerReference
)
3869 (*enabledProfilerReference
)->didExecute(callFrame
, callFrame
->r(function
).jsValue());
3871 vPC
+= OPCODE_LENGTH(op_profile_did_call
);
3875 globalData
->exception
= JSValue();
3877 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3878 // cannot fathom if we don't assign to the exceptionValue before branching)
3879 exceptionValue
= createInterruptedExecutionException(globalData
);
3881 handler
= throwException(callFrame
, exceptionValue
, vPC
- callFrame
->codeBlock()->instructions().begin(), false);
3883 *exception
= exceptionValue
;
3887 vPC
= callFrame
->codeBlock()->instructions().begin() + handler
->target
;
3891 #if !HAVE(COMPUTED_GOTO)
3892 } // iterator loop ends
3894 #endif // USE(INTERPRETER)
3895 #undef NEXT_INSTRUCTION
3896 #undef DEFINE_OPCODE
3897 #undef CHECK_FOR_EXCEPTION
3898 #undef CHECK_FOR_TIMEOUT
3901 JSValue
Interpreter::retrieveArguments(CallFrame
* callFrame
, JSFunction
* function
) const
3903 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3904 if (!functionCallFrame
)
3907 CodeBlock
* codeBlock
= functionCallFrame
->codeBlock();
3908 if (codeBlock
->usesArguments()) {
3909 ASSERT(codeBlock
->codeType() == FunctionCode
);
3910 SymbolTable
& symbolTable
= *codeBlock
->symbolTable();
3911 int argumentsIndex
= symbolTable
.get(functionCallFrame
->propertyNames().arguments
.ustring().rep()).getIndex();
3912 if (!functionCallFrame
->r(argumentsIndex
).jsValue()) {
3913 Arguments
* arguments
= new (callFrame
) Arguments(functionCallFrame
);
3914 functionCallFrame
->setCalleeArguments(arguments
);
3915 functionCallFrame
->r(RegisterFile::ArgumentsRegister
) = JSValue(arguments
);
3917 return functionCallFrame
->r(argumentsIndex
).jsValue();
3920 Arguments
* arguments
= functionCallFrame
->optionalCalleeArguments();
3922 arguments
= new (functionCallFrame
) Arguments(functionCallFrame
);
3923 arguments
->copyRegisters();
3924 callFrame
->setCalleeArguments(arguments
);
3930 JSValue
Interpreter::retrieveCaller(CallFrame
* callFrame
, InternalFunction
* function
) const
3932 CallFrame
* functionCallFrame
= findFunctionCallFrame(callFrame
, function
);
3933 if (!functionCallFrame
)
3936 CallFrame
* callerFrame
= functionCallFrame
->callerFrame();
3937 if (callerFrame
->hasHostCallFrameFlag())
3940 JSValue caller
= callerFrame
->callee();
3947 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, UString
& sourceURL
, JSValue
& function
) const
3949 function
= JSValue();
3951 sourceURL
= UString();
3953 CallFrame
* callerFrame
= callFrame
->callerFrame();
3954 if (callerFrame
->hasHostCallFrameFlag())
3957 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
3958 if (!callerCodeBlock
)
3961 unsigned bytecodeOffset
= bytecodeOffsetForPC(callerFrame
, callerCodeBlock
, callFrame
->returnPC());
3962 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(callerFrame
, bytecodeOffset
- 1);
3963 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
3964 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
3965 function
= callerFrame
->callee();
3968 CallFrame
* Interpreter::findFunctionCallFrame(CallFrame
* callFrame
, InternalFunction
* function
)
3970 for (CallFrame
* candidate
= callFrame
; candidate
; candidate
= candidate
->callerFrame()->removeHostCallFrameFlag()) {
3971 if (candidate
->callee() == function
)
3977 void Interpreter::enableSampler()
3979 #if ENABLE(OPCODE_SAMPLING)
3981 m_sampler
.set(new SamplingTool(this));
3986 void Interpreter::dumpSampleData(ExecState
* exec
)
3988 #if ENABLE(OPCODE_SAMPLING)
3990 m_sampler
->dump(exec
);
3995 void Interpreter::startSampling()
3997 #if ENABLE(SAMPLING_THREAD)
3998 if (!m_sampleEntryDepth
)
3999 SamplingThread::start();
4001 m_sampleEntryDepth
++;
4004 void Interpreter::stopSampling()
4006 #if ENABLE(SAMPLING_THREAD)
4007 m_sampleEntryDepth
--;
4008 if (!m_sampleEntryDepth
)
4009 SamplingThread::stop();