2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "CodeBlock.h"
34 #include "DebuggerCallFrame.h"
35 #include "ExceptionHelpers.h"
36 #include "ExecState.h"
37 #include "GlobalEvalFunction.h"
38 #include "JSActivation.h"
40 #include "JSFunction.h"
41 #include "JSNotAnObject.h"
42 #include "JSPropertyNameIterator.h"
43 #include "JSStaticScopeObject.h"
45 #include "ObjectPrototype.h"
48 #include "RegExpObject.h"
49 #include "RegExpPrototype.h"
51 #include "collector.h"
53 #include "operations.h"
54 #include "SamplingTool.h"
58 #include <mach/mach.h>
77 // Default number of ticks before a timeout check should be done.
78 static const int initialTickCountThreshold
= 255;
80 // Preferred number of milliseconds between each timeout check
81 static const int preferredScriptCheckTimeInterval
= 1000;
83 #if HAVE(COMPUTED_GOTO)
84 static void* op_throw_end_indirect
;
85 static void* op_call_indirect
;
88 // Returns the depth of the scope chain within a given call frame.
89 static int depth(CodeBlock
* codeBlock
, ScopeChain
& sc
)
91 if (!codeBlock
->needsFullScopeChain
)
94 ScopeChainIterator iter
= sc
.begin();
95 ScopeChainIterator end
= sc
.end();
96 while (!(*iter
)->isActivationObject()) {
105 // FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
106 // FIXME: There's no need to have a "slow" version of this. All versions should be fast.
107 static bool fastIsNumber(JSValue
* value
, double& arg
)
109 if (JSImmediate::isNumber(value
))
110 arg
= JSImmediate::getTruncatedInt32(value
);
111 else if (Heap::isNumber(static_cast<JSCell
*>(value
)))
112 arg
= static_cast<JSNumberCell
*>(value
)->value();
118 // FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
119 static bool fastToInt32(JSValue
* value
, int32_t& arg
)
121 if (JSImmediate::isNumber(value
))
122 arg
= JSImmediate::getTruncatedInt32(value
);
123 else if (Heap::isNumber(static_cast<JSCell
*>(value
)))
124 arg
= static_cast<JSNumberCell
*>(value
)->toInt32();
130 static ALWAYS_INLINE
bool fastToUInt32(JSValue
* value
, uint32_t& arg
)
132 if (JSImmediate::isNumber(value
)) {
133 if (JSImmediate::getTruncatedUInt32(value
, arg
))
136 arg
= JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value
), scratch
);
138 } else if (Heap::isNumber(static_cast<JSCell
*>(value
)))
139 arg
= static_cast<JSNumberCell
*>(value
)->toUInt32();
145 static inline bool jsLess(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
147 if (JSImmediate::areBothImmediateNumbers(v1
, v2
))
148 return JSImmediate::getTruncatedInt32(v1
) < JSImmediate::getTruncatedInt32(v2
);
152 if (fastIsNumber(v1
, n1
) && fastIsNumber(v2
, n2
))
157 bool wasNotString1
= v1
->getPrimitiveNumber(exec
, n1
, p1
);
158 bool wasNotString2
= v2
->getPrimitiveNumber(exec
, n2
, p2
);
160 if (wasNotString1
| wasNotString2
)
163 return static_cast<const JSString
*>(p1
)->value() < static_cast<const JSString
*>(p2
)->value();
166 static inline bool jsLessEq(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
168 if (JSImmediate::areBothImmediateNumbers(v1
, v2
))
169 return JSImmediate::getTruncatedInt32(v1
) <= JSImmediate::getTruncatedInt32(v2
);
173 if (fastIsNumber(v1
, n1
) && fastIsNumber(v2
, n2
))
178 bool wasNotString1
= v1
->getPrimitiveNumber(exec
, n1
, p1
);
179 bool wasNotString2
= v2
->getPrimitiveNumber(exec
, n2
, p2
);
181 if (wasNotString1
| wasNotString2
)
184 return !(static_cast<const JSString
*>(p2
)->value() < static_cast<const JSString
*>(p1
)->value());
187 static JSValue
* jsAddSlowCase(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
189 // exception for the Date exception in defaultValue()
190 JSValue
* p1
= v1
->toPrimitive(exec
);
191 JSValue
* p2
= v2
->toPrimitive(exec
);
193 if (p1
->isString() || p2
->isString()) {
194 UString value
= p1
->toString(exec
) + p2
->toString(exec
);
196 return throwOutOfMemoryError(exec
);
197 return jsString(exec
, value
);
200 return jsNumber(exec
, p1
->toNumber(exec
) + p2
->toNumber(exec
));
203 // Fast-path choices here are based on frequency data from SunSpider:
204 // <times> Add case: <t1> <t2>
205 // ---------------------------
206 // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
207 // 247412 Add case: 5 5
208 // 20900 Add case: 5 6
209 // 13962 Add case: 5 3
210 // 4000 Add case: 3 5
212 static inline JSValue
* jsAdd(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
216 if (fastIsNumber(v1
, left
) && fastIsNumber(v2
, right
))
217 return jsNumber(exec
, left
+ right
);
219 if (v1
->isString() && v2
->isString()) {
220 UString value
= static_cast<JSString
*>(v1
)->value() + static_cast<JSString
*>(v2
)->value();
222 return throwOutOfMemoryError(exec
);
223 return jsString(exec
, value
);
226 // All other cases are pretty uncommon
227 return jsAddSlowCase(exec
, v1
, v2
);
230 static JSValue
* jsTypeStringForValue(ExecState
* exec
, JSValue
* v
)
232 if (v
->isUndefined())
233 return jsString(exec
, "undefined");
235 return jsString(exec
, "boolean");
237 return jsString(exec
, "number");
239 return jsString(exec
, "string");
241 // Return "undefined" for objects that should be treated
242 // as null when doing comparisons.
243 if (static_cast<JSObject
*>(v
)->masqueradeAsUndefined())
244 return jsString(exec
, "undefined");
246 if (static_cast<JSObject
*>(v
)->getCallData(callData
) != CallTypeNone
)
247 return jsString(exec
, "function");
249 return jsString(exec
, "object");
252 static bool NEVER_INLINE
resolve(ExecState
* exec
, Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
, JSValue
*& exceptionValue
)
254 int dst
= (vPC
+ 1)->u
.operand
;
255 int property
= (vPC
+ 2)->u
.operand
;
257 ScopeChainIterator iter
= scopeChain
->begin();
258 ScopeChainIterator end
= scopeChain
->end();
261 Identifier
& ident
= codeBlock
->identifiers
[property
];
264 PropertySlot
slot(o
);
265 if (o
->getPropertySlot(exec
, ident
, slot
)) {
266 JSValue
* result
= slot
.getValue(exec
, ident
);
267 exceptionValue
= exec
->exception();
273 } while (++iter
!= end
);
274 exceptionValue
= createUndefinedVariableError(exec
, ident
, vPC
, codeBlock
);
278 static bool NEVER_INLINE
resolve_skip(ExecState
* exec
, Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
, JSValue
*& exceptionValue
)
280 int dst
= (vPC
+ 1)->u
.operand
;
281 int property
= (vPC
+ 2)->u
.operand
;
282 int skip
= (vPC
+ 3)->u
.operand
+ codeBlock
->needsFullScopeChain
;
284 ScopeChainIterator iter
= scopeChain
->begin();
285 ScopeChainIterator end
= scopeChain
->end();
291 Identifier
& ident
= codeBlock
->identifiers
[property
];
294 PropertySlot
slot(o
);
295 if (o
->getPropertySlot(exec
, ident
, slot
)) {
296 JSValue
* result
= slot
.getValue(exec
, ident
);
297 exceptionValue
= exec
->exception();
303 } while (++iter
!= end
);
304 exceptionValue
= createUndefinedVariableError(exec
, ident
, vPC
, codeBlock
);
308 static void NEVER_INLINE
resolveBase(ExecState
* exec
, Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
)
310 int dst
= (vPC
+ 1)->u
.operand
;
311 int property
= (vPC
+ 2)->u
.operand
;
313 ScopeChainIterator iter
= scopeChain
->begin();
314 ScopeChainIterator next
= iter
;
316 ScopeChainIterator end
= scopeChain
->end();
320 Identifier
& ident
= codeBlock
->identifiers
[property
];
324 if (next
== end
|| base
->getPropertySlot(exec
, ident
, slot
)) {
333 static bool NEVER_INLINE
resolveBaseAndProperty(ExecState
* exec
, Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
, JSValue
*& exceptionValue
)
335 int baseDst
= (vPC
+ 1)->u
.operand
;
336 int propDst
= (vPC
+ 2)->u
.operand
;
337 int property
= (vPC
+ 3)->u
.operand
;
339 ScopeChainIterator iter
= scopeChain
->begin();
340 ScopeChainIterator end
= scopeChain
->end();
342 // FIXME: add scopeDepthIsZero optimization
346 Identifier
& ident
= codeBlock
->identifiers
[property
];
350 PropertySlot
slot(base
);
351 if (base
->getPropertySlot(exec
, ident
, slot
)) {
352 JSValue
* result
= slot
.getValue(exec
, ident
);
353 exceptionValue
= exec
->exception();
361 } while (iter
!= end
);
363 exceptionValue
= createUndefinedVariableError(exec
, ident
, vPC
, codeBlock
);
367 static bool NEVER_INLINE
resolveBaseAndFunc(ExecState
* exec
, Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
, JSValue
*& exceptionValue
)
369 int baseDst
= (vPC
+ 1)->u
.operand
;
370 int funcDst
= (vPC
+ 2)->u
.operand
;
371 int property
= (vPC
+ 3)->u
.operand
;
373 ScopeChainIterator iter
= scopeChain
->begin();
374 ScopeChainIterator end
= scopeChain
->end();
376 // FIXME: add scopeDepthIsZero optimization
380 Identifier
& ident
= codeBlock
->identifiers
[property
];
384 PropertySlot
slot(base
);
385 if (base
->getPropertySlot(exec
, ident
, slot
)) {
386 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
387 // However, section 10.2.3 says that in the case where the value provided
388 // by the caller is null, the global object should be used. It also says
389 // that the section does not apply to internal functions, but for simplicity
390 // of implementation we use the global object anyway here. This guarantees
391 // that in host objects you always get a valid object for this.
392 // We also handle wrapper substitution for the global object at the same time.
393 JSObject
* thisObj
= base
->toThisObject(exec
);
394 JSValue
* result
= slot
.getValue(exec
, ident
);
395 exceptionValue
= exec
->exception();
399 r
[baseDst
] = thisObj
;
404 } while (iter
!= end
);
406 exceptionValue
= createUndefinedVariableError(exec
, ident
, vPC
, codeBlock
);
410 ALWAYS_INLINE
void Machine::initializeCallFrame(Register
* callFrame
, CodeBlock
* codeBlock
, Instruction
* vPC
, ScopeChainNode
* scopeChain
, Register
* r
, int returnValueRegister
, int argv
, int argc
, int calledAsConstructor
, JSValue
* function
)
412 callFrame
[RegisterFile::CallerCodeBlock
] = codeBlock
;
413 callFrame
[RegisterFile::ReturnVPC
] = vPC
+ 1;
414 callFrame
[RegisterFile::CallerScopeChain
] = scopeChain
;
415 callFrame
[RegisterFile::CallerRegisters
] = r
;
416 callFrame
[RegisterFile::ReturnValueRegister
] = returnValueRegister
;
417 callFrame
[RegisterFile::ArgumentStartRegister
] = argv
; // original argument vector (for the sake of the "arguments" object)
418 callFrame
[RegisterFile::ArgumentCount
] = argc
; // original argument count (for the sake of the "arguments" object)
419 callFrame
[RegisterFile::CalledAsConstructor
] = calledAsConstructor
;
420 callFrame
[RegisterFile::Callee
] = function
;
421 callFrame
[RegisterFile::OptionalCalleeActivation
] = nullJSValue
;
424 ALWAYS_INLINE Register
* slideRegisterWindowForCall(ExecState
* exec
, CodeBlock
* newCodeBlock
, RegisterFile
* registerFile
, Register
* registerBase
, Register
* r
, int argv
, int argc
, JSValue
*& exceptionValue
)
426 size_t registerOffset
= argv
+ newCodeBlock
->numLocals
;
427 size_t size
= r
- registerBase
+ registerOffset
+ newCodeBlock
->numConstants
+ newCodeBlock
->numTemporaries
;
429 if (argc
== newCodeBlock
->numParameters
) { // correct number of arguments
430 if (!registerFile
->grow(size
)) {
431 exceptionValue
= createStackOverflowError(exec
);
435 } else if (argc
< newCodeBlock
->numParameters
) { // too few arguments -- fill in the blanks
436 if (!registerFile
->grow(size
)) {
437 exceptionValue
= createStackOverflowError(exec
);
442 int omittedArgCount
= newCodeBlock
->numParameters
- argc
;
443 Register
* endOfParams
= r
- newCodeBlock
->numVars
;
444 for (Register
* it
= endOfParams
- omittedArgCount
; it
!= endOfParams
; ++it
)
445 (*it
) = jsUndefined();
446 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
447 int shift
= argc
+ RegisterFile::CallFrameHeaderSize
;
448 registerOffset
+= shift
;
451 if (!registerFile
->grow(size
)) {
452 exceptionValue
= createStackOverflowError(exec
);
457 Register
* it
= r
- newCodeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
- shift
;
458 Register
* end
= it
+ RegisterFile::CallFrameHeaderSize
+ newCodeBlock
->numParameters
;
459 for ( ; it
!= end
; ++it
)
463 // initialize local variable slots
464 for (Register
* it
= r
- newCodeBlock
->numVars
; it
!= r
; ++it
)
465 (*it
) = jsUndefined();
468 for (size_t i
= 0; i
< newCodeBlock
->constantRegisters
.size(); ++i
)
469 r
[i
] = newCodeBlock
->constantRegisters
[i
];
474 ALWAYS_INLINE ScopeChainNode
* scopeChainForCall(ExecState
* exec
, FunctionBodyNode
* functionBodyNode
, CodeBlock
* newCodeBlock
, ScopeChainNode
* callDataScopeChain
, Register
* r
)
476 if (newCodeBlock
->needsFullScopeChain
) {
477 JSActivation
* activation
= new (exec
) JSActivation(functionBodyNode
, r
);
478 r
[RegisterFile::OptionalCalleeActivation
- RegisterFile::CallFrameHeaderSize
- newCodeBlock
->numLocals
] = activation
;
480 return callDataScopeChain
->copy()->push(activation
);
483 return callDataScopeChain
;
486 static NEVER_INLINE
bool isNotObject(ExecState
* exec
, bool forInstanceOf
, CodeBlock
* codeBlock
, const Instruction
* vPC
, JSValue
* value
, JSValue
*& exceptionData
)
488 if (value
->isObject())
490 exceptionData
= createInvalidParamError(exec
, forInstanceOf
? "instanceof" : "in" , value
, vPC
, codeBlock
);
494 NEVER_INLINE JSValue
* Machine::callEval(ExecState
* exec
, JSObject
* thisObj
, ScopeChainNode
* scopeChain
, RegisterFile
* registerFile
, Register
* r
, int argv
, int argc
, JSValue
*& exceptionValue
)
497 return jsUndefined();
499 JSValue
* program
= r
[argv
+ 1].jsValue(exec
);
501 if (!program
->isString())
504 Profiler
** profiler
= Profiler::enabledProfilerReference();
506 (*profiler
)->willExecute(exec
, scopeChain
->globalObject()->evalFunction());
511 RefPtr
<EvalNode
> evalNode
= exec
->parser()->parse
<EvalNode
>(exec
, UString(), 1, UStringSourceProvider::create(static_cast<JSString
*>(program
)->value()), &sourceId
, &errLine
, &errMsg
);
514 exceptionValue
= Error::create(exec
, SyntaxError
, errMsg
, errLine
, sourceId
, NULL
);
516 (*profiler
)->didExecute(exec
, scopeChain
->globalObject()->evalFunction());
520 JSValue
* result
= exec
->globalData().machine
->execute(evalNode
.get(), exec
, thisObj
, r
- registerFile
->base() + argv
+ argc
, scopeChain
, &exceptionValue
);
523 (*profiler
)->didExecute(exec
, scopeChain
->globalObject()->evalFunction());
532 , m_timeAtLastCheckTimeout(0)
534 , m_timeoutCheckCount(0)
535 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold
)
537 privateExecute(InitializeAndReturn
);
539 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
540 void* storage
= fastMalloc(sizeof(CollectorBlock
));
542 JSArray
* jsArray
= new (storage
) JSArray(jsNull(), 0);
543 m_jsArrayVptr
= jsArray
->vptr();
544 static_cast<JSCell
*>(jsArray
)->~JSCell();
546 JSString
* jsString
= new (storage
) JSString("");
547 m_jsStringVptr
= jsString
->vptr();
548 static_cast<JSCell
*>(jsString
)->~JSCell();
555 void Machine::dumpCallFrame(const CodeBlock
* codeBlock
, ScopeChainNode
* scopeChain
, RegisterFile
* registerFile
, const Register
* r
)
557 ScopeChain
sc(scopeChain
);
558 JSGlobalObject
* globalObject
= sc
.globalObject();
559 codeBlock
->dump(globalObject
->globalExec());
560 dumpRegisters(codeBlock
, registerFile
, r
);
563 void Machine::dumpRegisters(const CodeBlock
* codeBlock
, RegisterFile
* registerFile
, const Register
* r
)
565 printf("Register frame: \n\n");
566 printf("----------------------------------------------------\n");
567 printf(" use | address | value \n");
568 printf("----------------------------------------------------\n");
573 if (codeBlock
->codeType
== GlobalCode
) {
574 it
= registerFile
->lastGlobal();
575 end
= it
+ registerFile
->numGlobals();
577 printf("[global var] | %10p | %10p \n", it
, (*it
).v());
580 printf("----------------------------------------------------\n");
583 it
= r
- codeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
584 printf("[CallerCodeBlock] | %10p | %10p \n", it
, (*it
).v()); ++it
;
585 printf("[ReturnVPC] | %10p | %10p \n", it
, (*it
).v()); ++it
;
586 printf("[CallerScopeChain] | %10p | %10p \n", it
, (*it
).v()); ++it
;
587 printf("[CallerRegisterOffset] | %10p | %10p \n", it
, (*it
).v()); ++it
;
588 printf("[ReturnValueRegister] | %10p | %10p \n", it
, (*it
).v()); ++it
;
589 printf("[ArgumentStartRegister] | %10p | %10p \n", it
, (*it
).v()); ++it
;
590 printf("[ArgumentCount] | %10p | %10p \n", it
, (*it
).v()); ++it
;
591 printf("[CalledAsConstructor] | %10p | %10p \n", it
, (*it
).v()); ++it
;
592 printf("[Callee] | %10p | %10p \n", it
, (*it
).v()); ++it
;
593 printf("[OptionalCalleeActivation] | %10p | %10p \n", it
, (*it
).v()); ++it
;
594 printf("----------------------------------------------------\n");
596 printf("[this] | %10p | %10p \n", it
, (*it
).v()); ++it
;
597 end
= it
+ max(codeBlock
->numParameters
- 1, 0); // - 1 to skip "this"
600 printf("[param] | %10p | %10p \n", it
, (*it
).v());
604 printf("----------------------------------------------------\n");
606 if (codeBlock
->codeType
!= GlobalCode
) {
607 end
= it
+ codeBlock
->numVars
;
610 printf("[var] | %10p | %10p \n", it
, (*it
).v());
613 printf("----------------------------------------------------\n");
617 end
= it
+ codeBlock
->numTemporaries
;
620 printf("[temp] | %10p | %10p \n", it
, (*it
).v());
628 #if !defined(NDEBUG) || HAVE(SAMPLING_TOOL)
630 bool Machine::isOpcode(Opcode opcode
)
632 #if HAVE(COMPUTED_GOTO)
633 return opcode
!= HashTraits
<Opcode
>::emptyValue()
634 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
635 && m_opcodeIDTable
.contains(opcode
);
637 return opcode
>= 0 && opcode
<= op_end
;
643 NEVER_INLINE
bool Machine::unwindCallFrame(ExecState
* exec
, JSValue
* exceptionValue
, const Instruction
*& vPC
, CodeBlock
*& codeBlock
, ScopeChainNode
*& scopeChain
, Register
*& r
)
645 CodeBlock
* oldCodeBlock
= codeBlock
;
646 Register
* callFrame
= r
- oldCodeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
648 if (Debugger
* debugger
= exec
->dynamicGlobalObject()->debugger()) {
649 DebuggerCallFrame
debuggerCallFrame(exec
, exec
->dynamicGlobalObject(), codeBlock
, scopeChain
, r
, exceptionValue
);
650 if (callFrame
[RegisterFile::Callee
].jsValue(exec
))
651 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), codeBlock
->ownerNode
->lastLine());
653 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), codeBlock
->ownerNode
->lastLine());
656 if (Profiler
* profiler
= *Profiler::enabledProfilerReference()) {
657 if (callFrame
[RegisterFile::Callee
].jsValue(exec
))
658 profiler
->didExecute(exec
, static_cast<JSObject
*>(callFrame
[RegisterFile::Callee
].jsValue(exec
)));
660 profiler
->didExecute(exec
, codeBlock
->ownerNode
->sourceURL(), codeBlock
->ownerNode
->lineNo());
663 if (oldCodeBlock
->needsFullScopeChain
)
666 // If this call frame created an activation, tear it off.
667 if (JSActivation
* activation
= static_cast<JSActivation
*>(callFrame
[RegisterFile::OptionalCalleeActivation
].jsValue(exec
))) {
668 ASSERT(activation
->isActivationObject());
669 activation
->copyRegisters();
672 codeBlock
= callFrame
[RegisterFile::CallerCodeBlock
].codeBlock();
676 scopeChain
= callFrame
[RegisterFile::CallerScopeChain
].scopeChain();
677 r
= callFrame
[RegisterFile::CallerRegisters
].r();
678 exec
->m_callFrame
= r
- oldCodeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
679 vPC
= callFrame
[RegisterFile::ReturnVPC
].vPC();
684 NEVER_INLINE Instruction
* Machine::throwException(ExecState
* exec
, JSValue
*& exceptionValue
, const Instruction
* vPC
, CodeBlock
*& codeBlock
, ScopeChainNode
*& scopeChain
, Register
*& r
, bool explicitThrow
)
686 // Set up the exception object
688 if (exceptionValue
->isObject()) {
689 JSObject
* exception
= static_cast<JSObject
*>(exceptionValue
);
690 if (exception
->isNotAnObjectErrorStub()) {
691 exception
= createNotAnObjectError(exec
, static_cast<JSNotAnObjectErrorStub
*>(exception
), vPC
, codeBlock
);
692 exceptionValue
= exception
;
694 if (!exception
->hasProperty(exec
, Identifier(exec
, "line")) &&
695 !exception
->hasProperty(exec
, Identifier(exec
, "sourceId")) &&
696 !exception
->hasProperty(exec
, Identifier(exec
, "sourceURL")) &&
697 !exception
->hasProperty(exec
, Identifier(exec
, expressionBeginOffsetPropertyName
)) &&
698 !exception
->hasProperty(exec
, Identifier(exec
, expressionCaretOffsetPropertyName
)) &&
699 !exception
->hasProperty(exec
, Identifier(exec
, expressionEndOffsetPropertyName
))) {
704 int line
= codeBlock
->expressionRangeForVPC(vPC
, divotPoint
, startOffset
, endOffset
);
705 exception
->putWithAttributes(exec
, Identifier(exec
, "line"), jsNumber(exec
, line
), ReadOnly
| DontDelete
);
707 // We only hit this path for error messages and throw statements, which don't have a specific failure position
708 // So we just give the full range of the error/throw statement.
709 exception
->putWithAttributes(exec
, Identifier(exec
, expressionBeginOffsetPropertyName
), jsNumber(exec
, divotPoint
- startOffset
), ReadOnly
| DontDelete
);
710 exception
->putWithAttributes(exec
, Identifier(exec
, expressionEndOffsetPropertyName
), jsNumber(exec
, divotPoint
+ endOffset
), ReadOnly
| DontDelete
);
712 exception
->putWithAttributes(exec
, Identifier(exec
, "line"), jsNumber(exec
, codeBlock
->lineNumberForVPC(vPC
)), ReadOnly
| DontDelete
);
713 exception
->putWithAttributes(exec
, Identifier(exec
, "sourceId"), jsNumber(exec
, codeBlock
->ownerNode
->sourceId()), ReadOnly
| DontDelete
);
714 exception
->putWithAttributes(exec
, Identifier(exec
, "sourceURL"), jsOwnedString(exec
, codeBlock
->ownerNode
->sourceURL()), ReadOnly
| DontDelete
);
717 if (exception
->isWatchdogException()) {
718 while (unwindCallFrame(exec
, exceptionValue
, vPC
, codeBlock
, scopeChain
, r
)) {
719 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
726 if (Debugger
* debugger
= exec
->dynamicGlobalObject()->debugger()) {
727 DebuggerCallFrame
debuggerCallFrame(exec
, exec
->dynamicGlobalObject(), codeBlock
, scopeChain
, r
, exceptionValue
);
728 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), codeBlock
->lineNumberForVPC(vPC
));
731 // Calculate an exception handler vPC, unwinding call frames as necessary.
734 Instruction
* handlerVPC
;
736 while (!codeBlock
->getHandlerForVPC(vPC
, handlerVPC
, scopeDepth
)) {
737 if (!unwindCallFrame(exec
, exceptionValue
, vPC
, codeBlock
, scopeChain
, r
))
741 // Now unwind the scope chain within the exception handler's call frame.
743 ScopeChain
sc(scopeChain
);
744 int scopeDelta
= depth(codeBlock
, sc
) - scopeDepth
;
745 ASSERT(scopeDelta
>= 0);
748 setScopeChain(exec
, scopeChain
, sc
.node());
753 JSValue
* Machine::execute(ProgramNode
* programNode
, ExecState
* exec
, ScopeChainNode
* scopeChain
, JSObject
* thisObj
, JSValue
** exception
)
755 if (m_reentryDepth
>= MaxReentryDepth
) {
756 *exception
= createStackOverflowError(exec
);
760 CodeBlock
* codeBlock
= &programNode
->byteCode(scopeChain
);
762 size_t oldSize
= m_registerFile
.size();
763 size_t newSize
= oldSize
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->numVars
+ codeBlock
->numConstants
+ codeBlock
->numTemporaries
;
764 if (!m_registerFile
.grow(newSize
)) {
765 *exception
= createStackOverflowError(exec
);
769 JSGlobalObject
* lastGlobalObject
= m_registerFile
.globalObject();
770 JSGlobalObject
* globalObject
= exec
->dynamicGlobalObject();
771 globalObject
->copyGlobalsTo(m_registerFile
);
773 Register
* callFrame
= m_registerFile
.base() + oldSize
;
775 // a 0 codeBlock indicates a built-in caller
776 initializeCallFrame(callFrame
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
778 Register
* r
= callFrame
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->numVars
;
779 r
[codeBlock
->thisRegister
] = thisObj
;
781 for (size_t i
= 0; i
< codeBlock
->constantRegisters
.size(); ++i
)
782 r
[i
] = codeBlock
->constantRegisters
[i
];
784 if (codeBlock
->needsFullScopeChain
)
785 scopeChain
= scopeChain
->copy();
787 ExecState
newExec(exec
, &m_registerFile
, scopeChain
, 0);
789 Profiler
** profiler
= Profiler::enabledProfilerReference();
791 (*profiler
)->willExecute(exec
, programNode
->sourceURL(), programNode
->lineNo());
794 JSValue
* result
= privateExecute(Normal
, &newExec
, &m_registerFile
, r
, scopeChain
, codeBlock
, exception
);
797 MACHINE_SAMPLING_privateExecuteReturned();
800 (*profiler
)->didExecute(exec
, programNode
->sourceURL(), programNode
->lineNo());
802 (*profiler
)->didFinishAllExecution(exec
);
805 if (m_reentryDepth
&& lastGlobalObject
&& globalObject
!= lastGlobalObject
)
806 lastGlobalObject
->copyGlobalsTo(m_registerFile
);
808 m_registerFile
.shrink(oldSize
);
812 JSValue
* Machine::execute(FunctionBodyNode
* functionBodyNode
, ExecState
* exec
, JSFunction
* function
, JSObject
* thisObj
, const ArgList
& args
, ScopeChainNode
* scopeChain
, JSValue
** exception
)
814 if (m_reentryDepth
>= MaxReentryDepth
) {
815 *exception
= createStackOverflowError(exec
);
819 int argv
= RegisterFile::CallFrameHeaderSize
;
820 int argc
= args
.size() + 1; // implicit "this" parameter
822 size_t oldSize
= m_registerFile
.size();
823 if (!m_registerFile
.grow(oldSize
+ RegisterFile::CallFrameHeaderSize
+ argc
)) {
824 *exception
= createStackOverflowError(exec
);
828 Register
* callFrame
= m_registerFile
.base() + oldSize
;
830 // put args in place, including "this"
831 Register
* dst
= callFrame
+ RegisterFile::CallFrameHeaderSize
;
834 ArgList::const_iterator end
= args
.end();
835 for (ArgList::const_iterator it
= args
.begin(); it
!= end
; ++it
)
838 // a 0 codeBlock indicates a built-in caller
839 initializeCallFrame(callFrame
, 0, 0, 0, callFrame
, 0, argv
, argc
, 0, function
);
841 CodeBlock
* newCodeBlock
= &functionBodyNode
->byteCode(scopeChain
);
842 Register
* r
= slideRegisterWindowForCall(exec
, newCodeBlock
, &m_registerFile
, m_registerFile
.base(), callFrame
, argv
, argc
, *exception
);
844 m_registerFile
.shrink(oldSize
);
848 scopeChain
= scopeChainForCall(exec
, functionBodyNode
, newCodeBlock
, scopeChain
, r
);
850 ExecState
newExec(exec
, &m_registerFile
, scopeChain
, callFrame
);
852 Profiler
** profiler
= Profiler::enabledProfilerReference();
854 (*profiler
)->willExecute(exec
, function
);
857 JSValue
* result
= privateExecute(Normal
, &newExec
, &m_registerFile
, r
, scopeChain
, newCodeBlock
, exception
);
860 MACHINE_SAMPLING_privateExecuteReturned();
862 if (*profiler
&& !m_reentryDepth
)
863 (*profiler
)->didFinishAllExecution(exec
);
865 m_registerFile
.shrink(oldSize
);
869 JSValue
* Machine::execute(EvalNode
* evalNode
, ExecState
* exec
, JSObject
* thisObj
, int registerOffset
, ScopeChainNode
* scopeChain
, JSValue
** exception
)
871 if (m_reentryDepth
>= MaxReentryDepth
) {
872 *exception
= createStackOverflowError(exec
);
876 EvalCodeBlock
* codeBlock
= &evalNode
->byteCode(scopeChain
);
878 JSVariableObject
* variableObject
;
879 for (ScopeChainNode
* node
= scopeChain
; ; node
= node
->next
) {
881 if (node
->object
->isVariableObject()) {
882 variableObject
= static_cast<JSVariableObject
*>(node
->object
);
887 const Node::VarStack
& varStack
= codeBlock
->ownerNode
->varStack();
888 Node::VarStack::const_iterator varStackEnd
= varStack
.end();
889 for (Node::VarStack::const_iterator it
= varStack
.begin(); it
!= varStackEnd
; ++it
) {
890 const Identifier
& ident
= (*it
).first
;
891 if (!variableObject
->hasProperty(exec
, ident
))
892 variableObject
->put(exec
, ident
, jsUndefined());
895 const Node::FunctionStack
& functionStack
= codeBlock
->ownerNode
->functionStack();
896 Node::FunctionStack::const_iterator functionStackEnd
= functionStack
.end();
897 for (Node::FunctionStack::const_iterator it
= functionStack
.begin(); it
!= functionStackEnd
; ++it
)
898 variableObject
->put(exec
, (*it
)->m_ident
, (*it
)->makeFunction(exec
, scopeChain
));
900 size_t oldSize
= m_registerFile
.size();
901 size_t newSize
= registerOffset
+ codeBlock
->numVars
+ codeBlock
->numConstants
+ codeBlock
->numTemporaries
+ RegisterFile::CallFrameHeaderSize
;
902 if (!m_registerFile
.grow(newSize
)) {
903 *exception
= createStackOverflowError(exec
);
907 Register
* callFrame
= m_registerFile
.base() + registerOffset
;
909 // a 0 codeBlock indicates a built-in caller
910 initializeCallFrame(callFrame
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
912 Register
* r
= callFrame
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->numVars
;
913 r
[codeBlock
->thisRegister
] = thisObj
;
915 for (size_t i
= 0; i
< codeBlock
->constantRegisters
.size(); ++i
)
916 r
[i
] = codeBlock
->constantRegisters
[i
];
918 if (codeBlock
->needsFullScopeChain
)
919 scopeChain
= scopeChain
->copy();
921 ExecState
newExec(exec
, &m_registerFile
, scopeChain
, 0);
923 Profiler
** profiler
= Profiler::enabledProfilerReference();
925 (*profiler
)->willExecute(exec
, evalNode
->sourceURL(), evalNode
->lineNo());
928 JSValue
* result
= privateExecute(Normal
, &newExec
, &m_registerFile
, r
, scopeChain
, codeBlock
, exception
);
931 MACHINE_SAMPLING_privateExecuteReturned();
934 (*profiler
)->didExecute(exec
, evalNode
->sourceURL(), evalNode
->lineNo());
936 (*profiler
)->didFinishAllExecution(exec
);
939 m_registerFile
.shrink(oldSize
);
943 ALWAYS_INLINE
void Machine::setScopeChain(ExecState
* exec
, ScopeChainNode
*& scopeChain
, ScopeChainNode
* newScopeChain
)
945 scopeChain
= newScopeChain
;
946 exec
->m_scopeChain
= newScopeChain
;
949 NEVER_INLINE
void Machine::debug(ExecState
* exec
, const Instruction
* vPC
, const CodeBlock
* codeBlock
, ScopeChainNode
* scopeChain
, Register
* r
)
951 int debugHookID
= (++vPC
)->u
.operand
;
952 int firstLine
= (++vPC
)->u
.operand
;
953 int lastLine
= (++vPC
)->u
.operand
;
955 Debugger
* debugger
= exec
->dynamicGlobalObject()->debugger();
959 DebuggerCallFrame
debuggerCallFrame(exec
, exec
->dynamicGlobalObject(), codeBlock
, scopeChain
, r
, 0);
961 switch((DebugHookID
)debugHookID
) {
962 case DidEnterCallFrame
: {
963 debugger
->callEvent(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), firstLine
);
966 case WillLeaveCallFrame
: {
967 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), lastLine
);
970 case WillExecuteStatement
: {
971 debugger
->atStatement(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), firstLine
);
974 case WillExecuteProgram
: {
975 debugger
->willExecuteProgram(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), firstLine
);
978 case DidExecuteProgram
: {
979 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), lastLine
);
982 case DidReachBreakpoint
: {
983 debugger
->didReachBreakpoint(debuggerCallFrame
, codeBlock
->ownerNode
->sourceId(), lastLine
);
989 void Machine::resetTimeoutCheck()
991 m_ticksUntilNextTimeoutCheck
= initialTickCountThreshold
;
992 m_timeAtLastCheckTimeout
= 0;
996 // Returns the time the current thread has spent executing, in milliseconds.
997 static inline unsigned getCPUTime()
1000 mach_msg_type_number_t infoCount
= THREAD_BASIC_INFO_COUNT
;
1001 thread_basic_info_data_t info
;
1003 // Get thread information
1004 thread_info(mach_thread_self(), THREAD_BASIC_INFO
, reinterpret_cast<thread_info_t
>(&info
), &infoCount
);
1006 unsigned time
= info
.user_time
.seconds
* 1000 + info
.user_time
.microseconds
/ 1000;
1007 time
+= info
.system_time
.seconds
* 1000 + info
.system_time
.microseconds
/ 1000;
1010 #elif HAVE(SYS_TIME_H)
1011 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1013 gettimeofday(&tv
, 0);
1014 return tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
1016 QDateTime t
= QDateTime::currentDateTime();
1017 return t
.toTime_t() * 1000 + t
.time().msec();
1018 #elif PLATFORM(WIN_OS)
1021 unsigned long long fileTimeAsLong
;
1022 } userTime
, kernelTime
;
1024 // GetThreadTimes won't accept NULL arguments so we pass these even though
1025 // they're not used.
1026 FILETIME creationTime
, exitTime
;
1028 GetThreadTimes(GetCurrentThread(), &creationTime
, &exitTime
, &kernelTime
.fileTime
, &userTime
.fileTime
);
1030 return userTime
.fileTimeAsLong
/ 10000 + kernelTime
.fileTimeAsLong
/ 10000;
1032 #error Platform does not have getCurrentTime function
1036 // We have to return a JSValue here, gcc seems to produce worse code if
1037 // we attempt to return a bool
1038 ALWAYS_INLINE JSValue
* Machine::checkTimeout(JSGlobalObject
* globalObject
)
1040 unsigned currentTime
= getCPUTime();
1042 if (!m_timeAtLastCheckTimeout
) {
1043 // Suspicious amount of looping in a script -- start timing it
1044 m_timeAtLastCheckTimeout
= currentTime
;
1048 unsigned timeDiff
= currentTime
- m_timeAtLastCheckTimeout
;
1053 m_timeExecuting
+= timeDiff
;
1054 m_timeAtLastCheckTimeout
= currentTime
;
1056 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1057 // preferredScriptCheckTimeInterval
1058 m_ticksUntilNextTimeoutCheck
= static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval
) / timeDiff
) * m_ticksUntilNextTimeoutCheck
);
1059 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1060 // preferred script check time interval.
1061 if (m_ticksUntilNextTimeoutCheck
== 0)
1062 m_ticksUntilNextTimeoutCheck
= initialTickCountThreshold
;
1064 if (m_timeoutTime
&& m_timeExecuting
> m_timeoutTime
) {
1065 if (globalObject
->shouldInterruptScript())
1066 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1068 resetTimeoutCheck();
1074 static int32_t offsetForStringSwitch(StringJumpTable
& jumpTable
, JSValue
* scrutinee
, int32_t defaultOffset
) {
1075 StringJumpTable::const_iterator end
= jumpTable
.end();
1076 UString::Rep
* value
= static_cast<JSString
*>(scrutinee
)->value().rep();
1077 StringJumpTable::const_iterator loc
= jumpTable
.find(value
);
1079 return defaultOffset
;
1083 static NEVER_INLINE ScopeChainNode
* createExceptionScope(ExecState
* exec
, CodeBlock
* codeBlock
, const Instruction
* vPC
, Register
* r
, ScopeChainNode
* scopeChain
)
1085 int dst
= (++vPC
)->u
.operand
;
1086 Identifier
& property
= codeBlock
->identifiers
[(++vPC
)->u
.operand
];
1087 JSValue
* value
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1088 JSObject
* scope
= new (exec
) JSStaticScopeObject(property
, value
, DontDelete
);
1090 return scopeChain
->push(scope
);
1093 JSValue
* Machine::privateExecute(ExecutionFlag flag
, ExecState
* exec
, RegisterFile
* registerFile
, Register
* r
, ScopeChainNode
* scopeChain
, CodeBlock
* codeBlock
, JSValue
** exception
)
1095 // One-time initialization of our address tables. We have to put this code
1096 // here because our labels are only in scope inside this function.
1097 if (flag
== InitializeAndReturn
) {
1098 #if HAVE(COMPUTED_GOTO)
1099 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1100 FOR_EACH_OPCODE_ID(ADD_OPCODE
);
1103 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1104 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID
);
1105 #undef ADD_OPCODE_ID
1106 ASSERT(m_opcodeIDTable
.size() == numOpcodeIDs
);
1107 op_throw_end_indirect
= &&op_throw_end
;
1108 op_call_indirect
= &&op_call
;
1109 #endif // HAVE(COMPUTED_GOTO)
1113 JSValue
* exceptionValue
= 0;
1114 Instruction
* handlerVPC
= 0;
1116 Register
* registerBase
= registerFile
->base();
1117 Instruction
* vPC
= codeBlock
->instructions
.begin();
1118 Profiler
** enabledProfilerReference
= Profiler::enabledProfilerReference();
1119 unsigned tickCount
= m_ticksUntilNextTimeoutCheck
+ 1;
1121 #define VM_CHECK_EXCEPTION() \
1123 if (UNLIKELY(exec->hadException())) { \
1124 exceptionValue = exec->exception(); \
1129 #if DUMP_OPCODE_STATS
1130 OpcodeStats::resetLastInstruction();
1133 #define CHECK_FOR_TIMEOUT() \
1134 if (!--tickCount) { \
1135 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1137 tickCount = m_ticksUntilNextTimeoutCheck; \
1140 #if HAVE(COMPUTED_GOTO)
1141 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1142 #if DUMP_OPCODE_STATS
1143 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1145 #define BEGIN_OPCODE(opcode) opcode:
1149 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1150 #if DUMP_OPCODE_STATS
1151 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1153 #define BEGIN_OPCODE(opcode) case opcode:
1155 while (1) // iterator loop begins
1156 switch (vPC
->u
.opcode
)
1159 BEGIN_OPCODE(op_new_object
) {
1160 /* new_object dst(r)
1162 Constructs a new empty Object instance using the original
1163 constructor, and puts the result in register dst.
1165 int dst
= (++vPC
)->u
.operand
;
1166 r
[dst
] = constructEmptyObject(exec
);
1171 BEGIN_OPCODE(op_new_array
) {
1172 /* new_array dst(r) firstArg(r) argCount(n)
1174 Constructs a new Array instance using the original
1175 constructor, and puts the result in register dst.
1176 The array will contain argCount elements with values
1177 taken from registers starting at register firstArg.
1179 int dst
= (++vPC
)->u
.operand
;
1180 int firstArg
= (++vPC
)->u
.operand
;
1181 int argCount
= (++vPC
)->u
.operand
;
1182 ArgList
args(r
+ firstArg
, argCount
);
1183 r
[dst
] = constructArray(exec
, args
);
1188 BEGIN_OPCODE(op_new_regexp
) {
1189 /* new_regexp dst(r) regExp(re)
1191 Constructs a new RegExp instance using the original
1192 constructor from regexp regExp, and puts the result in
1195 int dst
= (++vPC
)->u
.operand
;
1196 int regExp
= (++vPC
)->u
.operand
;
1197 r
[dst
] = new (exec
) RegExpObject(scopeChain
->globalObject()->regExpPrototype(), codeBlock
->regexps
[regExp
]);
1202 BEGIN_OPCODE(op_mov
) {
1203 /* mov dst(r) src(r)
1205 Copies register src to register dst.
1207 int dst
= (++vPC
)->u
.operand
;
1208 int src
= (++vPC
)->u
.operand
;
1214 BEGIN_OPCODE(op_eq
) {
1215 /* eq dst(r) src1(r) src2(r)
1217 Checks whether register src1 and register src2 are equal,
1218 as with the ECMAScript '==' operator, and puts the result
1219 as a boolean in register dst.
1221 int dst
= (++vPC
)->u
.operand
;
1222 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1223 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1224 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1225 r
[dst
] = jsBoolean(reinterpret_cast<intptr_t>(src1
) == reinterpret_cast<intptr_t>(src2
));
1227 JSValue
* result
= jsBoolean(equal(exec
, src1
, src2
));
1228 VM_CHECK_EXCEPTION();
1235 BEGIN_OPCODE(op_neq
) {
1236 /* neq dst(r) src1(r) src2(r)
1238 Checks whether register src1 and register src2 are not
1239 equal, as with the ECMAScript '!=' operator, and puts the
1240 result as a boolean in register dst.
1242 int dst
= (++vPC
)->u
.operand
;
1243 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1244 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1245 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1246 r
[dst
] = jsBoolean(reinterpret_cast<intptr_t>(src1
) != reinterpret_cast<intptr_t>(src2
));
1248 JSValue
* result
= jsBoolean(!equal(exec
, src1
, src2
));
1249 VM_CHECK_EXCEPTION();
1256 BEGIN_OPCODE(op_stricteq
) {
1257 /* stricteq dst(r) src1(r) src2(r)
1259 Checks whether register src1 and register src2 are strictly
1260 equal, as with the ECMAScript '===' operator, and puts the
1261 result as a boolean in register dst.
1263 int dst
= (++vPC
)->u
.operand
;
1264 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1265 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1266 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1267 r
[dst
] = jsBoolean(reinterpret_cast<intptr_t>(src1
) == reinterpret_cast<intptr_t>(src2
));
1269 r
[dst
] = jsBoolean(strictEqual(src1
, src2
));
1274 BEGIN_OPCODE(op_nstricteq
) {
1275 /* nstricteq dst(r) src1(r) src2(r)
1277 Checks whether register src1 and register src2 are not
1278 strictly equal, as with the ECMAScript '!==' operator, and
1279 puts the result as a boolean in register dst.
1281 int dst
= (++vPC
)->u
.operand
;
1282 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1283 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1284 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1285 r
[dst
] = jsBoolean(reinterpret_cast<intptr_t>(src1
) != reinterpret_cast<intptr_t>(src2
));
1287 r
[dst
] = jsBoolean(!strictEqual(src1
, src2
));
1292 BEGIN_OPCODE(op_less
) {
1293 /* less dst(r) src1(r) src2(r)
1295 Checks whether register src1 is less than register src2, as
1296 with the ECMAScript '<' operator, and puts the result as
1297 a boolean in register dst.
1299 int dst
= (++vPC
)->u
.operand
;
1300 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1301 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1302 JSValue
* result
= jsBoolean(jsLess(exec
, src1
, src2
));
1303 VM_CHECK_EXCEPTION();
1309 BEGIN_OPCODE(op_lesseq
) {
1310 /* lesseq dst(r) src1(r) src2(r)
1312 Checks whether register src1 is less than or equal to
1313 register src2, as with the ECMAScript '<=' operator, and
1314 puts the result as a boolean in register dst.
1316 int dst
= (++vPC
)->u
.operand
;
1317 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1318 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1319 JSValue
* result
= jsBoolean(jsLessEq(exec
, src1
, src2
));
1320 VM_CHECK_EXCEPTION();
1326 BEGIN_OPCODE(op_pre_inc
) {
1327 /* pre_inc srcDst(r)
1329 Converts register srcDst to number, adds one, and puts the result
1330 back in register srcDst.
1332 int srcDst
= (++vPC
)->u
.operand
;
1333 JSValue
* v
= r
[srcDst
].jsValue(exec
);
1334 if (JSImmediate::canDoFastAdditiveOperations(v
))
1335 r
[srcDst
] = JSImmediate::incImmediateNumber(v
);
1337 JSValue
* result
= jsNumber(exec
, v
->toNumber(exec
) + 1);
1338 VM_CHECK_EXCEPTION();
1345 BEGIN_OPCODE(op_pre_dec
) {
1346 /* pre_dec srcDst(r)
1348 Converts register srcDst to number, subtracts one, and puts the result
1349 back in register srcDst.
1351 int srcDst
= (++vPC
)->u
.operand
;
1352 JSValue
* v
= r
[srcDst
].jsValue(exec
);
1353 if (JSImmediate::canDoFastAdditiveOperations(v
))
1354 r
[srcDst
] = JSImmediate::decImmediateNumber(v
);
1356 JSValue
* result
= jsNumber(exec
, v
->toNumber(exec
) - 1);
1357 VM_CHECK_EXCEPTION();
1364 BEGIN_OPCODE(op_post_inc
) {
1365 /* post_inc dst(r) srcDst(r)
1367 Converts register srcDst to number. The number itself is
1368 written to register dst, and the number plus one is written
1369 back to register srcDst.
1371 int dst
= (++vPC
)->u
.operand
;
1372 int srcDst
= (++vPC
)->u
.operand
;
1373 JSValue
* v
= r
[srcDst
].jsValue(exec
);
1374 if (JSImmediate::canDoFastAdditiveOperations(v
)) {
1376 r
[srcDst
] = JSImmediate::incImmediateNumber(v
);
1378 JSValue
* number
= r
[srcDst
].jsValue(exec
)->toJSNumber(exec
);
1379 VM_CHECK_EXCEPTION();
1381 r
[srcDst
] = jsNumber(exec
, number
->uncheckedGetNumber() + 1);
1387 BEGIN_OPCODE(op_post_dec
) {
1388 /* post_dec dst(r) srcDst(r)
1390 Converts register srcDst to number. The number itself is
1391 written to register dst, and the number minus one is written
1392 back to register srcDst.
1394 int dst
= (++vPC
)->u
.operand
;
1395 int srcDst
= (++vPC
)->u
.operand
;
1396 JSValue
* v
= r
[srcDst
].jsValue(exec
);
1397 if (JSImmediate::canDoFastAdditiveOperations(v
)) {
1399 r
[srcDst
] = JSImmediate::decImmediateNumber(v
);
1401 JSValue
* number
= r
[srcDst
].jsValue(exec
)->toJSNumber(exec
);
1402 VM_CHECK_EXCEPTION();
1404 r
[srcDst
] = jsNumber(exec
, number
->uncheckedGetNumber() - 1);
1410 BEGIN_OPCODE(op_to_jsnumber
) {
1411 /* to_jsnumber dst(r) src(r)
1413 Converts register src to number, and puts the result
1416 int dst
= (++vPC
)->u
.operand
;
1417 int src
= (++vPC
)->u
.operand
;
1418 JSValue
* result
= r
[src
].jsValue(exec
)->toJSNumber(exec
);
1419 VM_CHECK_EXCEPTION();
1426 BEGIN_OPCODE(op_negate
) {
1427 /* negate dst(r) src(r)
1429 Converts register src to number, negates it, and puts the
1430 result in register dst.
1432 int dst
= (++vPC
)->u
.operand
;
1433 JSValue
* src
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1435 if (fastIsNumber(src
, v
))
1436 r
[dst
] = jsNumber(exec
, -v
);
1438 JSValue
* result
= jsNumber(exec
, -src
->toNumber(exec
));
1439 VM_CHECK_EXCEPTION();
1446 BEGIN_OPCODE(op_add
) {
1447 /* add dst(r) src1(r) src2(r)
1449 Adds register src1 and register src2, and puts the result
1450 in register dst. (JS add may be string concatenation or
1451 numeric add, depending on the types of the operands.)
1453 int dst
= (++vPC
)->u
.operand
;
1454 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1455 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1456 if (JSImmediate::canDoFastAdditiveOperations(src1
) && JSImmediate::canDoFastAdditiveOperations(src2
))
1457 r
[dst
] = JSImmediate::addImmediateNumbers(src1
, src2
);
1459 JSValue
* result
= jsAdd(exec
, src1
, src2
);
1460 VM_CHECK_EXCEPTION();
1466 BEGIN_OPCODE(op_mul
) {
1467 /* mul dst(r) src1(r) src2(r)
1469 Multiplies register src1 and register src2 (converted to
1470 numbers), and puts the product in register dst.
1472 int dst
= (++vPC
)->u
.operand
;
1473 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1474 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1477 if (fastIsNumber(src1
, left
) && fastIsNumber(src2
, right
))
1478 r
[dst
] = jsNumber(exec
, left
* right
);
1480 JSValue
* result
= jsNumber(exec
, src1
->toNumber(exec
) * src2
->toNumber(exec
));
1481 VM_CHECK_EXCEPTION();
1488 BEGIN_OPCODE(op_div
) {
1489 /* div dst(r) dividend(r) divisor(r)
1491 Divides register dividend (converted to number) by the
1492 register divisor (converted to number), and puts the
1493 quotient in register dst.
1495 int dst
= (++vPC
)->u
.operand
;
1496 JSValue
* dividend
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1497 JSValue
* divisor
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1500 if (fastIsNumber(dividend
, left
) && fastIsNumber(divisor
, right
))
1501 r
[dst
] = jsNumber(exec
, left
/ right
);
1503 JSValue
* result
= jsNumber(exec
, dividend
->toNumber(exec
) / divisor
->toNumber(exec
));
1504 VM_CHECK_EXCEPTION();
1510 BEGIN_OPCODE(op_mod
) {
1511 /* mod dst(r) dividend(r) divisor(r)
1513 Divides register dividend (converted to number) by
1514 register divisor (converted to number), and puts the
1515 remainder in register dst.
1517 int dst
= (++vPC
)->u
.operand
;
1518 int dividend
= (++vPC
)->u
.operand
;
1519 int divisor
= (++vPC
)->u
.operand
;
1521 JSValue
* dividendValue
= r
[dividend
].jsValue(exec
);
1522 JSValue
* divisorValue
= r
[divisor
].jsValue(exec
);
1524 if (JSImmediate::areBothImmediateNumbers(dividendValue
, divisorValue
) && divisorValue
!= JSImmediate::from(0)) {
1525 r
[dst
] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue
) % JSImmediate::getTruncatedInt32(divisorValue
));
1530 double d
= dividendValue
->toNumber(exec
);
1531 JSValue
* result
= jsNumber(exec
, fmod(d
, divisorValue
->toNumber(exec
)));
1532 VM_CHECK_EXCEPTION();
1537 BEGIN_OPCODE(op_sub
) {
1538 /* sub dst(r) src1(r) src2(r)
1540 Subtracts register src2 (converted to number) from register
1541 src1 (converted to number), and puts the difference in
1544 int dst
= (++vPC
)->u
.operand
;
1545 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1546 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1549 if (JSImmediate::canDoFastAdditiveOperations(src1
) && JSImmediate::canDoFastAdditiveOperations(src2
))
1550 r
[dst
] = JSImmediate::subImmediateNumbers(src1
, src2
);
1551 else if (fastIsNumber(src1
, left
) && fastIsNumber(src2
, right
))
1552 r
[dst
] = jsNumber(exec
, left
- right
);
1554 JSValue
* result
= jsNumber(exec
, src1
->toNumber(exec
) - src2
->toNumber(exec
));
1555 VM_CHECK_EXCEPTION();
1561 BEGIN_OPCODE(op_lshift
) {
1562 /* lshift dst(r) val(r) shift(r)
1564 Performs left shift of register val (converted to int32) by
1565 register shift (converted to uint32), and puts the result
1568 int dst
= (++vPC
)->u
.operand
;
1569 JSValue
* val
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1570 JSValue
* shift
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1573 if (JSImmediate::areBothImmediateNumbers(val
, shift
))
1574 r
[dst
] = jsNumber(exec
, JSImmediate::getTruncatedInt32(val
) << (JSImmediate::getTruncatedUInt32(shift
) & 0x1f));
1575 else if (fastToInt32(val
, left
) && fastToUInt32(shift
, right
))
1576 r
[dst
] = jsNumber(exec
, left
<< (right
& 0x1f));
1578 JSValue
* result
= jsNumber(exec
, (val
->toInt32(exec
)) << (shift
->toUInt32(exec
) & 0x1f));
1579 VM_CHECK_EXCEPTION();
1586 BEGIN_OPCODE(op_rshift
) {
1587 /* rshift dst(r) val(r) shift(r)
1589 Performs arithmetic right shift of register val (converted
1590 to int32) by register shift (converted to
1591 uint32), and puts the result in register dst.
1593 int dst
= (++vPC
)->u
.operand
;
1594 JSValue
* val
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1595 JSValue
* shift
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1598 if (JSImmediate::areBothImmediateNumbers(val
, shift
))
1599 r
[dst
] = JSImmediate::rightShiftImmediateNumbers(val
, shift
);
1600 else if (fastToInt32(val
, left
) && fastToUInt32(shift
, right
))
1601 r
[dst
] = jsNumber(exec
, left
>> (right
& 0x1f));
1603 JSValue
* result
= jsNumber(exec
, (val
->toInt32(exec
)) >> (shift
->toUInt32(exec
) & 0x1f));
1604 VM_CHECK_EXCEPTION();
1611 BEGIN_OPCODE(op_urshift
) {
1612 /* rshift dst(r) val(r) shift(r)
1614 Performs logical right shift of register val (converted
1615 to uint32) by register shift (converted to
1616 uint32), and puts the result in register dst.
1618 int dst
= (++vPC
)->u
.operand
;
1619 JSValue
* val
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1620 JSValue
* shift
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1621 if (JSImmediate::areBothImmediateNumbers(val
, shift
) && !JSImmediate::isNegative(val
))
1622 r
[dst
] = JSImmediate::rightShiftImmediateNumbers(val
, shift
);
1624 JSValue
* result
= jsNumber(exec
, (val
->toUInt32(exec
)) >> (shift
->toUInt32(exec
) & 0x1f));
1625 VM_CHECK_EXCEPTION();
1632 BEGIN_OPCODE(op_bitand
) {
1633 /* bitand dst(r) src1(r) src2(r)
1635 Computes bitwise AND of register src1 (converted to int32)
1636 and register src2 (converted to int32), and puts the result
1639 int dst
= (++vPC
)->u
.operand
;
1640 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1641 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1644 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1645 r
[dst
] = JSImmediate::andImmediateNumbers(src1
, src2
);
1646 else if (fastToInt32(src1
, left
) && fastToInt32(src2
, right
))
1647 r
[dst
] = jsNumber(exec
, left
& right
);
1649 JSValue
* result
= jsNumber(exec
, src1
->toInt32(exec
) & src2
->toInt32(exec
));
1650 VM_CHECK_EXCEPTION();
1657 BEGIN_OPCODE(op_bitxor
) {
1658 /* bitxor dst(r) src1(r) src2(r)
1660 Computes bitwise XOR of register src1 (converted to int32)
1661 and register src2 (converted to int32), and puts the result
1664 int dst
= (++vPC
)->u
.operand
;
1665 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1666 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1669 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1670 r
[dst
] = JSImmediate::xorImmediateNumbers(src1
, src2
);
1671 else if (fastToInt32(src1
, left
) && fastToInt32(src2
, right
))
1672 r
[dst
] = jsNumber(exec
, left
^ right
);
1674 JSValue
* result
= jsNumber(exec
, src1
->toInt32(exec
) ^ src2
->toInt32(exec
));
1675 VM_CHECK_EXCEPTION();
1682 BEGIN_OPCODE(op_bitor
) {
1683 /* bitor dst(r) src1(r) src2(r)
1685 Computes bitwise OR of register src1 (converted to int32)
1686 and register src2 (converted to int32), and puts the
1687 result in register dst.
1689 int dst
= (++vPC
)->u
.operand
;
1690 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1691 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1694 if (JSImmediate::areBothImmediateNumbers(src1
, src2
))
1695 r
[dst
] = JSImmediate::orImmediateNumbers(src1
, src2
);
1696 else if (fastToInt32(src1
, left
) && fastToInt32(src2
, right
))
1697 r
[dst
] = jsNumber(exec
, left
| right
);
1699 JSValue
* result
= jsNumber(exec
, src1
->toInt32(exec
) | src2
->toInt32(exec
));
1700 VM_CHECK_EXCEPTION();
1707 BEGIN_OPCODE(op_bitnot
) {
1708 /* bitnot dst(r) src(r)
1710 Computes bitwise NOT of register src1 (converted to int32),
1711 and puts the result in register dst.
1713 int dst
= (++vPC
)->u
.operand
;
1714 JSValue
* src
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
1716 if (fastToInt32(src
, value
))
1717 r
[dst
] = jsNumber(exec
, ~value
);
1719 JSValue
* result
= jsNumber(exec
, ~src
->toInt32(exec
));
1720 VM_CHECK_EXCEPTION();
1726 BEGIN_OPCODE(op_not
) {
1727 /* not dst(r) src(r)
1729 Computes logical NOT of register src (converted to
1730 boolean), and puts the result in register dst.
1732 int dst
= (++vPC
)->u
.operand
;
1733 int src
= (++vPC
)->u
.operand
;
1734 JSValue
* result
= jsBoolean(!r
[src
].jsValue(exec
)->toBoolean(exec
));
1735 VM_CHECK_EXCEPTION();
1741 BEGIN_OPCODE(op_instanceof
) {
1742 /* instanceof dst(r) value(r) constructor(r)
1744 Tests whether register value is an instance of register
1745 constructor, and puts the boolean result in register dst.
1747 Raises an exception if register constructor is not an
1750 int dst
= (++vPC
)->u
.operand
;
1751 int value
= (++vPC
)->u
.operand
;
1752 int base
= (++vPC
)->u
.operand
;
1754 JSValue
* baseVal
= r
[base
].jsValue(exec
);
1756 if (isNotObject(exec
, true, codeBlock
, vPC
, baseVal
, exceptionValue
))
1759 JSObject
* baseObj
= static_cast<JSObject
*>(baseVal
);
1760 r
[dst
] = jsBoolean(baseObj
->implementsHasInstance() ? baseObj
->hasInstance(exec
, r
[value
].jsValue(exec
)) : false);
1765 BEGIN_OPCODE(op_typeof
) {
1766 /* typeof dst(r) src(r)
1768 Determines the type string for src according to ECMAScript
1769 rules, and puts the result in register dst.
1771 int dst
= (++vPC
)->u
.operand
;
1772 int src
= (++vPC
)->u
.operand
;
1773 r
[dst
] = jsTypeStringForValue(exec
, r
[src
].jsValue(exec
));
1778 BEGIN_OPCODE(op_in
) {
1779 /* in dst(r) property(r) base(r)
1781 Tests whether register base has a property named register
1782 property, and puts the boolean result in register dst.
1784 Raises an exception if register constructor is not an
1787 int dst
= (++vPC
)->u
.operand
;
1788 int property
= (++vPC
)->u
.operand
;
1789 int base
= (++vPC
)->u
.operand
;
1791 JSValue
* baseVal
= r
[base
].jsValue(exec
);
1792 if (isNotObject(exec
, false, codeBlock
, vPC
, baseVal
, exceptionValue
))
1795 JSObject
* baseObj
= static_cast<JSObject
*>(baseVal
);
1797 JSValue
* propName
= r
[property
].jsValue(exec
);
1800 if (propName
->getUInt32(i
))
1801 r
[dst
] = jsBoolean(baseObj
->hasProperty(exec
, i
));
1803 Identifier
property(exec
, propName
->toString(exec
));
1804 VM_CHECK_EXCEPTION();
1805 r
[dst
] = jsBoolean(baseObj
->hasProperty(exec
, property
));
1811 BEGIN_OPCODE(op_resolve
) {
1812 /* resolve dst(r) property(id)
1814 Looks up the property named by identifier property in the
1815 scope chain, and writes the resulting value to register
1816 dst. If the property is not found, raises an exception.
1818 if (UNLIKELY(!resolve(exec
, vPC
, r
, scopeChain
, codeBlock
, exceptionValue
)))
1824 BEGIN_OPCODE(op_resolve_skip
) {
1825 /* resolve_skip dst(r) property(id) skip(n)
1827 Looks up the property named by identifier property in the
1828 scope chain skipping the top 'skip' levels, and writes the resulting
1829 value to register dst. If the property is not found, raises an exception.
1831 if (UNLIKELY(!resolve_skip(exec
, vPC
, r
, scopeChain
, codeBlock
, exceptionValue
)))
1838 BEGIN_OPCODE(op_get_scoped_var
) {
1839 /* get_scoped_var dst(r) index(n) skip(n)
1841 Loads the contents of the index-th local from the scope skip nodes from
1842 the top of the scope chain, and places it in register dst
1844 int dst
= (++vPC
)->u
.operand
;
1845 int index
= (++vPC
)->u
.operand
;
1846 int skip
= (++vPC
)->u
.operand
+ codeBlock
->needsFullScopeChain
;
1848 ScopeChainIterator iter
= scopeChain
->begin();
1849 ScopeChainIterator end
= scopeChain
->end();
1850 ASSERT(iter
!= end
);
1853 ASSERT(iter
!= end
);
1856 ASSERT((*iter
)->isVariableObject());
1857 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
1858 r
[dst
] = scope
->registerAt(index
);
1862 BEGIN_OPCODE(op_put_scoped_var
) {
1863 /* put_scoped_var index(n) skip(n) value(r)
1866 int index
= (++vPC
)->u
.operand
;
1867 int skip
= (++vPC
)->u
.operand
+ codeBlock
->needsFullScopeChain
;
1868 int value
= (++vPC
)->u
.operand
;
1870 ScopeChainIterator iter
= scopeChain
->begin();
1871 ScopeChainIterator end
= scopeChain
->end();
1872 ASSERT(iter
!= end
);
1875 ASSERT(iter
!= end
);
1878 ASSERT((*iter
)->isVariableObject());
1879 JSVariableObject
* scope
= static_cast<JSVariableObject
*>(*iter
);
1880 scope
->registerAt(index
) = r
[value
].jsValue(exec
);
1884 BEGIN_OPCODE(op_resolve_base
) {
1885 /* resolve_base dst(r) property(id)
1887 Searches the scope chain for an object containing
1888 identifier property, and if one is found, writes it to
1889 register dst. If none is found, the outermost scope (which
1890 will be the global object) is stored in register dst.
1892 resolveBase(exec
, vPC
, r
, scopeChain
, codeBlock
);
1897 BEGIN_OPCODE(op_resolve_with_base
) {
1898 /* resolve_with_base baseDst(r) propDst(r) property(id)
1900 Searches the scope chain for an object containing
1901 identifier property, and if one is found, writes it to
1902 register srcDst, and the retrieved property value to register
1903 propDst. If the property is not found, raises an exception.
1905 This is more efficient than doing resolve_base followed by
1906 resolve, or resolve_base followed by get_by_id, as it
1907 avoids duplicate hash lookups.
1909 if (UNLIKELY(!resolveBaseAndProperty(exec
, vPC
, r
, scopeChain
, codeBlock
, exceptionValue
)))
1915 BEGIN_OPCODE(op_resolve_func
) {
1916 /* resolve_func baseDst(r) funcDst(r) property(id)
1918 Searches the scope chain for an object containing
1919 identifier property, and if one is found, writes the
1920 appropriate object to use as "this" when calling its
1921 properties to register baseDst; and the retrieved property
1922 value to register propDst. If the property is not found,
1923 raises an exception.
1925 This differs from resolve_with_base, because the
1926 global this value will be substituted for activations or
1927 the global object, which is the right behavior for function
1928 calls but not for other property lookup.
1930 if (UNLIKELY(!resolveBaseAndFunc(exec
, vPC
, r
, scopeChain
, codeBlock
, exceptionValue
)))
1936 BEGIN_OPCODE(op_get_by_id
) {
1937 /* get_by_id dst(r) base(r) property(id)
1939 Converts register base to Object, gets the property
1940 named by identifier property from the object, and puts the
1941 result in register dst.
1943 int dst
= (++vPC
)->u
.operand
;
1944 int base
= (++vPC
)->u
.operand
;
1945 int property
= (++vPC
)->u
.operand
;
1947 Identifier
& ident
= codeBlock
->identifiers
[property
];
1948 JSValue
* result
= r
[base
].jsValue(exec
)->get(exec
, ident
);
1949 VM_CHECK_EXCEPTION();
1954 BEGIN_OPCODE(op_put_by_id
) {
1955 /* put_by_id base(r) property(id) value(r)
1957 Sets register value on register base as the property named
1958 by identifier property. Base is converted to object first.
1960 Unlike many opcodes, this one does not write any output to
1963 int base
= (++vPC
)->u
.operand
;
1964 int property
= (++vPC
)->u
.operand
;
1965 int value
= (++vPC
)->u
.operand
;
1967 Identifier
& ident
= codeBlock
->identifiers
[property
];
1968 r
[base
].jsValue(exec
)->put(exec
, ident
, r
[value
].jsValue(exec
));
1970 VM_CHECK_EXCEPTION();
1974 BEGIN_OPCODE(op_del_by_id
) {
1975 /* del_by_id dst(r) base(r) property(id)
1977 Converts register base to Object, deletes the property
1978 named by identifier property from the object, and writes a
1979 boolean indicating success (if true) or failure (if false)
1982 int dst
= (++vPC
)->u
.operand
;
1983 int base
= (++vPC
)->u
.operand
;
1984 int property
= (++vPC
)->u
.operand
;
1986 JSObject
* baseObj
= r
[base
].jsValue(exec
)->toObject(exec
);
1988 Identifier
& ident
= codeBlock
->identifiers
[property
];
1989 JSValue
* result
= jsBoolean(baseObj
->deleteProperty(exec
, ident
));
1990 VM_CHECK_EXCEPTION();
1995 BEGIN_OPCODE(op_get_by_val
) {
1996 /* get_by_val dst(r) base(r) property(r)
1998 Converts register base to Object, gets the property named
1999 by register property from the object, and puts the result
2000 in register dst. property is nominally converted to string
2001 but numbers are treated more efficiently.
2003 int dst
= (++vPC
)->u
.operand
;
2004 int base
= (++vPC
)->u
.operand
;
2005 int property
= (++vPC
)->u
.operand
;
2007 JSValue
* baseValue
= r
[base
].jsValue(exec
);
2008 JSValue
* subscript
= r
[property
].jsValue(exec
);
2013 bool isUInt32
= JSImmediate::getUInt32(subscript
, i
);
2014 if (LIKELY(isUInt32
)) {
2015 if (isJSArray(baseValue
)) {
2016 JSArray
* jsArray
= static_cast<JSArray
*>(baseValue
);
2017 if (jsArray
->canGetIndex(i
))
2018 result
= jsArray
->getIndex(i
);
2020 result
= jsArray
->JSArray::get(exec
, i
);
2021 } else if (isJSString(baseValue
) && static_cast<JSString
*>(baseValue
)->canGetIndex(i
))
2022 result
= static_cast<JSString
*>(baseValue
)->getIndex(exec
, i
);
2024 result
= baseValue
->get(exec
, i
);
2026 Identifier
property(exec
, subscript
->toString(exec
));
2027 result
= baseValue
->get(exec
, property
);
2030 VM_CHECK_EXCEPTION();
2035 BEGIN_OPCODE(op_put_by_val
) {
2036 /* put_by_val base(r) property(r) value(r)
2038 Sets register value on register base as the property named
2039 by register property. Base is converted to object
2040 first. register property is nominally converted to string
2041 but numbers are treated more efficiently.
2043 Unlike many opcodes, this one does not write any output to
2046 int base
= (++vPC
)->u
.operand
;
2047 int property
= (++vPC
)->u
.operand
;
2048 int value
= (++vPC
)->u
.operand
;
2050 JSValue
* baseValue
= r
[base
].jsValue(exec
);
2051 JSValue
* subscript
= r
[property
].jsValue(exec
);
2055 bool isUInt32
= JSImmediate::getUInt32(subscript
, i
);
2056 if (LIKELY(isUInt32
)) {
2057 if (isJSArray(baseValue
)) {
2058 JSArray
* jsArray
= static_cast<JSArray
*>(baseValue
);
2059 if (jsArray
->canSetIndex(i
))
2060 jsArray
->setIndex(i
, r
[value
].jsValue(exec
));
2062 jsArray
->JSArray::put(exec
, i
, r
[value
].jsValue(exec
));
2064 baseValue
->put(exec
, i
, r
[value
].jsValue(exec
));
2066 Identifier
property(exec
, subscript
->toString(exec
));
2067 if (!exec
->hadException()) // Don't put to an object if toString threw an exception.
2068 baseValue
->put(exec
, property
, r
[value
].jsValue(exec
));
2071 VM_CHECK_EXCEPTION();
2075 BEGIN_OPCODE(op_del_by_val
) {
2076 /* del_by_val dst(r) base(r) property(r)
2078 Converts register base to Object, deletes the property
2079 named by register property from the object, and writes a
2080 boolean indicating success (if true) or failure (if false)
2083 int dst
= (++vPC
)->u
.operand
;
2084 int base
= (++vPC
)->u
.operand
;
2085 int property
= (++vPC
)->u
.operand
;
2087 JSObject
* baseObj
= r
[base
].jsValue(exec
)->toObject(exec
); // may throw
2089 JSValue
* subscript
= r
[property
].jsValue(exec
);
2092 if (subscript
->getUInt32(i
))
2093 result
= jsBoolean(baseObj
->deleteProperty(exec
, i
));
2095 VM_CHECK_EXCEPTION();
2096 Identifier
property(exec
, subscript
->toString(exec
));
2097 VM_CHECK_EXCEPTION();
2098 result
= jsBoolean(baseObj
->deleteProperty(exec
, property
));
2101 VM_CHECK_EXCEPTION();
2106 BEGIN_OPCODE(op_put_by_index
) {
2107 /* put_by_index base(r) property(n) value(r)
2109 Sets register value on register base as the property named
2110 by the immediate number property. Base is converted to
2113 Unlike many opcodes, this one does not write any output to
2116 This opcode is mainly used to initialize array literals.
2118 int base
= (++vPC
)->u
.operand
;
2119 unsigned property
= (++vPC
)->u
.operand
;
2120 int value
= (++vPC
)->u
.operand
;
2122 r
[base
].jsValue(exec
)->put(exec
, property
, r
[value
].jsValue(exec
));
2127 BEGIN_OPCODE(op_loop
) {
2128 /* loop target(offset)
2130 Jumps unconditionally to offset target from the current
2133 Additionally this loop instruction may terminate JS execution is
2134 the JS timeout is reached.
2136 #if DUMP_OPCODE_STATS
2137 OpcodeStats::resetLastInstruction();
2139 int target
= (++vPC
)->u
.operand
;
2140 CHECK_FOR_TIMEOUT();
2144 BEGIN_OPCODE(op_jmp
) {
2145 /* jmp target(offset)
2147 Jumps unconditionally to offset target from the current
2150 #if DUMP_OPCODE_STATS
2151 OpcodeStats::resetLastInstruction();
2153 int target
= (++vPC
)->u
.operand
;
2158 BEGIN_OPCODE(op_loop_if_true
) {
2159 /* loop_if_true cond(r) target(offset)
2161 Jumps to offset target from the current instruction, if and
2162 only if register cond converts to boolean as true.
2164 Additionally this loop instruction may terminate JS execution is
2165 the JS timeout is reached.
2167 int cond
= (++vPC
)->u
.operand
;
2168 int target
= (++vPC
)->u
.operand
;
2169 if (r
[cond
].jsValue(exec
)->toBoolean(exec
)) {
2171 CHECK_FOR_TIMEOUT();
2178 BEGIN_OPCODE(op_jtrue
) {
2179 /* jtrue cond(r) target(offset)
2181 Jumps to offset target from the current instruction, if and
2182 only if register cond converts to boolean as true.
2184 int cond
= (++vPC
)->u
.operand
;
2185 int target
= (++vPC
)->u
.operand
;
2186 if (r
[cond
].jsValue(exec
)->toBoolean(exec
)) {
2194 BEGIN_OPCODE(op_jfalse
) {
2195 /* jfalse cond(r) target(offset)
2197 Jumps to offset target from the current instruction, if and
2198 only if register cond converts to boolean as false.
2200 int cond
= (++vPC
)->u
.operand
;
2201 int target
= (++vPC
)->u
.operand
;
2202 if (!r
[cond
].jsValue(exec
)->toBoolean(exec
)) {
2210 BEGIN_OPCODE(op_loop_if_less
) {
2211 /* loop_if_less src1(r) src2(r) target(offset)
2213 Checks whether register src1 is less than register src2, as
2214 with the ECMAScript '<' operator, and then jumps to offset
2215 target from the current instruction, if and only if the
2216 result of the comparison is true.
2218 Additionally this loop instruction may terminate JS execution is
2219 the JS timeout is reached.
2221 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2222 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2223 int target
= (++vPC
)->u
.operand
;
2225 bool result
= jsLess(exec
, src1
, src2
);
2226 VM_CHECK_EXCEPTION();
2230 CHECK_FOR_TIMEOUT();
2237 BEGIN_OPCODE(op_jnless
) {
2238 /* jnless src1(r) src2(r) target(offset)
2240 Checks whether register src1 is less than register src2, as
2241 with the ECMAScript '<' operator, and then jumps to offset
2242 target from the current instruction, if and only if the
2243 result of the comparison is false.
2245 JSValue
* src1
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2246 JSValue
* src2
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2247 int target
= (++vPC
)->u
.operand
;
2249 bool result
= jsLess(exec
, src1
, src2
);
2250 VM_CHECK_EXCEPTION();
2260 BEGIN_OPCODE(op_switch_imm
) {
2261 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2263 Performs a range checked switch on the scrutinee value, using
2264 the tableIndex-th immediate switch jump table. If the scrutinee value
2265 is an immediate number in the range covered by the referenced jump
2266 table, and the value at jumpTable[scrutinee value] is non-zero, then
2267 that value is used as the jump offset, otherwise defaultOffset is used.
2269 int tableIndex
= (++vPC
)->u
.operand
;
2270 int defaultOffset
= (++vPC
)->u
.operand
;
2271 JSValue
* scrutinee
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2272 if (!JSImmediate::isNumber(scrutinee
))
2273 vPC
+= defaultOffset
;
2275 int32_t value
= JSImmediate::getTruncatedInt32(scrutinee
);
2276 vPC
+= codeBlock
->immediateSwitchJumpTables
[tableIndex
].offsetForValue(value
, defaultOffset
);
2280 BEGIN_OPCODE(op_switch_char
) {
2281 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2283 Performs a range checked switch on the scrutinee value, using
2284 the tableIndex-th character switch jump table. If the scrutinee value
2285 is a single character string in the range covered by the referenced jump
2286 table, and the value at jumpTable[scrutinee value] is non-zero, then
2287 that value is used as the jump offset, otherwise defaultOffset is used.
2289 int tableIndex
= (++vPC
)->u
.operand
;
2290 int defaultOffset
= (++vPC
)->u
.operand
;
2291 JSValue
* scrutinee
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2292 if (!scrutinee
->isString())
2293 vPC
+= defaultOffset
;
2295 UString::Rep
* value
= static_cast<JSString
*>(scrutinee
)->value().rep();
2296 if (value
->size() != 1)
2297 vPC
+= defaultOffset
;
2299 vPC
+= codeBlock
->characterSwitchJumpTables
[tableIndex
].offsetForValue(value
->data()[0], defaultOffset
);
2303 BEGIN_OPCODE(op_switch_string
) {
2304 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2306 Performs a sparse hashmap based switch on the value in the scrutinee
2307 register, using the tableIndex-th string switch jump table. If the
2308 scrutinee value is a string that exists as a key in the referenced
2309 jump table, then the value associated with the string is used as the
2310 jump offset, otherwise defaultOffset is used.
2312 int tableIndex
= (++vPC
)->u
.operand
;
2313 int defaultOffset
= (++vPC
)->u
.operand
;
2314 JSValue
* scrutinee
= r
[(++vPC
)->u
.operand
].jsValue(exec
);
2315 if (!scrutinee
->isString())
2316 vPC
+= defaultOffset
;
2318 vPC
+= offsetForStringSwitch(codeBlock
->stringSwitchJumpTables
[tableIndex
], scrutinee
, defaultOffset
);
2321 BEGIN_OPCODE(op_new_func
) {
2322 /* new_func dst(r) func(f)
2324 Constructs a new Function instance from function func and
2325 the current scope chain using the original Function
2326 constructor, using the rules for function declarations, and
2327 puts the result in register dst.
2329 int dst
= (++vPC
)->u
.operand
;
2330 int func
= (++vPC
)->u
.operand
;
2332 r
[dst
] = codeBlock
->functions
[func
]->makeFunction(exec
, scopeChain
);
2337 BEGIN_OPCODE(op_new_func_exp
) {
2338 /* new_func_exp dst(r) func(f)
2340 Constructs a new Function instance from function func and
2341 the current scope chain using the original Function
2342 constructor, using the rules for function expressions, and
2343 puts the result in register dst.
2345 int dst
= (++vPC
)->u
.operand
;
2346 int func
= (++vPC
)->u
.operand
;
2348 r
[dst
] = codeBlock
->functionExpressions
[func
]->makeFunction(exec
, scopeChain
);
2353 BEGIN_OPCODE(op_call_eval
) {
2354 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2356 Call a function named "eval" with no explicit "this" value
2357 (which may therefore be the eval operator). If register
2358 thisVal is the global object, and register func contains
2359 that global object's original global eval function, then
2360 perform the eval operator in local scope (interpreting
2361 the argument registers as for the "call"
2362 opcode). Otherwise, act exactly as the "call" opcode would.
2365 int dst
= (++vPC
)->u
.operand
;
2366 int func
= (++vPC
)->u
.operand
;
2367 int thisVal
= (++vPC
)->u
.operand
;
2368 int firstArg
= (++vPC
)->u
.operand
;
2369 int argCount
= (++vPC
)->u
.operand
;
2371 JSValue
* funcVal
= r
[func
].jsValue(exec
);
2372 JSValue
* baseVal
= r
[thisVal
].jsValue(exec
);
2374 if (baseVal
== scopeChain
->globalObject() && funcVal
== scopeChain
->globalObject()->evalFunction()) {
2375 JSObject
* thisObject
= static_cast<JSObject
*>(r
[codeBlock
->thisRegister
].jsValue(exec
));
2376 JSValue
* result
= callEval(exec
, thisObject
, scopeChain
, registerFile
, r
, firstArg
, argCount
, exceptionValue
);
2386 // We didn't find the blessed version of eval, so reset vPC and process
2387 // this instruction as a normal function call, supplying the proper 'this'
2390 r
[thisVal
] = baseVal
->toThisObject(exec
);
2392 #if HAVE(COMPUTED_GOTO)
2393 // Hack around gcc performance quirk by performing an indirect goto
2394 // in order to set the vPC -- attempting to do so directly results in a
2395 // significant regression.
2396 goto *op_call_indirect
; // indirect goto -> op_call
2398 // fall through to op_call
2400 BEGIN_OPCODE(op_call
) {
2401 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2403 Perform a function call. Specifically, call register func
2404 with a "this" value of register thisVal, and put the result
2407 The arguments start at register firstArg and go up to
2408 argCount, but the "this" value is considered an implicit
2409 first argument, so the argCount should be one greater than
2410 the number of explicit arguments passed, and the register
2411 after firstArg should contain the actual first
2412 argument. This opcode will copy from the thisVal register
2413 to the firstArg register, unless the register index of
2414 thisVal is the special missing this object marker, which is
2415 2^31-1; in that case, the global object will be used as the
2418 If func is a native code function, then this opcode calls
2419 it and returns the value immediately.
2421 But if it is a JS function, then the current scope chain
2422 and code block is set to the function's, and we slide the
2423 register window so that the arguments would form the first
2424 few local registers of the called function's register
2425 window. In addition, a call frame header is written
2426 immediately before the arguments; see the call frame
2427 documentation for an explanation of how many registers a
2428 call frame takes and what they contain. That many registers
2429 before the firstArg register will be overwritten by the
2430 call. In addition, any registers higher than firstArg +
2431 argCount may be overwritten. Once this setup is complete,
2432 execution continues from the called function's first
2433 argument, and does not return until a "ret" opcode is
2437 int dst
= (++vPC
)->u
.operand
;
2438 int func
= (++vPC
)->u
.operand
;
2439 int thisVal
= (++vPC
)->u
.operand
;
2440 int firstArg
= (++vPC
)->u
.operand
;
2441 int argCount
= (++vPC
)->u
.operand
;
2443 JSValue
* v
= r
[func
].jsValue(exec
);
2446 CallType callType
= v
->getCallData(callData
);
2448 if (*enabledProfilerReference
)
2449 (*enabledProfilerReference
)->willExecute(exec
, static_cast<JSObject
*>(v
));
2451 Register
* callFrame
= r
+ firstArg
- RegisterFile::CallFrameHeaderSize
;
2452 initializeCallFrame(callFrame
, codeBlock
, vPC
, scopeChain
, r
, dst
, firstArg
, argCount
, 0, v
);
2453 exec
->m_callFrame
= callFrame
;
2455 if (callType
== CallTypeJS
) {
2457 ScopeChainNode
* callDataScopeChain
= callData
.js
.scopeChain
;
2458 FunctionBodyNode
* functionBodyNode
= callData
.js
.functionBody
;
2459 CodeBlock
* newCodeBlock
= &functionBodyNode
->byteCode(callDataScopeChain
);
2461 r
[firstArg
] = thisVal
== missingThisObjectMarker() ? exec
->globalThisValue() : r
[thisVal
].jsValue(exec
);
2463 r
= slideRegisterWindowForCall(exec
, newCodeBlock
, registerFile
, registerBase
, r
, firstArg
, argCount
, exceptionValue
);
2464 if (UNLIKELY(exceptionValue
!= 0))
2467 codeBlock
= newCodeBlock
;
2468 setScopeChain(exec
, scopeChain
, scopeChainForCall(exec
, functionBodyNode
, codeBlock
, callDataScopeChain
, r
));
2469 vPC
= codeBlock
->instructions
.begin();
2471 #if DUMP_OPCODE_STATS
2472 OpcodeStats::resetLastInstruction();
2478 if (callType
== CallTypeHost
) {
2479 JSValue
* thisValue
= thisVal
== missingThisObjectMarker() ? exec
->globalThisValue() : r
[thisVal
].jsValue(exec
);
2480 ArgList
args(r
+ firstArg
+ 1, argCount
- 1);
2482 MACHINE_SAMPLING_callingHostFunction();
2484 JSValue
* returnValue
= callData
.native
.function(exec
, static_cast<JSObject
*>(v
), thisValue
, args
);
2485 exec
->m_callFrame
= r
- codeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
2486 VM_CHECK_EXCEPTION();
2488 r
[dst
] = returnValue
;
2490 if (*enabledProfilerReference
)
2491 (*enabledProfilerReference
)->didExecute(exec
, static_cast<JSObject
*>(v
));
2497 ASSERT(callType
== CallTypeNone
);
2499 exceptionValue
= createNotAFunctionError(exec
, v
, vPC
, codeBlock
);
2500 exec
->m_callFrame
= r
- codeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
2503 BEGIN_OPCODE(op_ret
) {
2506 Return register result as the return value of the current
2507 function call, writing it into the caller's expected return
2508 value register. In addition, unwind one call frame and
2509 restore the scope chain, code block instruction pointer and
2510 register base to those of the calling function.
2513 int result
= (++vPC
)->u
.operand
;
2515 Register
* callFrame
= r
- codeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
2516 if (JSActivation
* activation
= static_cast<JSActivation
*>(callFrame
[RegisterFile::OptionalCalleeActivation
].jsValue(exec
))) {
2517 ASSERT(!codeBlock
->needsFullScopeChain
|| scopeChain
->object
== activation
);
2518 ASSERT(activation
->isActivationObject());
2519 activation
->copyRegisters();
2522 if (*enabledProfilerReference
)
2523 (*enabledProfilerReference
)->didExecute(exec
, static_cast<JSObject
*>(callFrame
[RegisterFile::Callee
].jsValue(exec
)));
2525 if (codeBlock
->needsFullScopeChain
)
2526 scopeChain
->deref();
2528 JSValue
* returnValue
= r
[result
].jsValue(exec
);
2529 if (callFrame
[RegisterFile::CalledAsConstructor
].i() && !returnValue
->isObject()) {
2530 JSValue
* thisObject
= callFrame
[RegisterFile::CallFrameHeaderSize
].jsValue(exec
);
2531 returnValue
= thisObject
;
2534 codeBlock
= callFrame
[RegisterFile::CallerCodeBlock
].codeBlock();
2538 vPC
= callFrame
[RegisterFile::ReturnVPC
].vPC();
2539 setScopeChain(exec
, scopeChain
, callFrame
[RegisterFile::CallerScopeChain
].scopeChain());
2540 r
= callFrame
[RegisterFile::CallerRegisters
].r();
2541 exec
->m_callFrame
= r
- codeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
2542 int dst
= callFrame
[RegisterFile::ReturnValueRegister
].i();
2543 r
[dst
] = returnValue
;
2547 BEGIN_OPCODE(op_construct
) {
2548 /* construct dst(r) constr(r) firstArg(r) argCount(n)
2550 Invoke register "constr" as a constructor. For JS
2551 functions, the calling convention is exactly as for the
2552 "call" opcode, except that the "this" value is a newly
2553 created Object. For native constructors, a null "this"
2554 value is passed. In either case, the firstArg and argCount
2555 registers are interpreted as for the "call" opcode.
2558 int dst
= (++vPC
)->u
.operand
;
2559 int constr
= (++vPC
)->u
.operand
;
2560 int firstArg
= (++vPC
)->u
.operand
;
2561 int argCount
= (++vPC
)->u
.operand
;
2563 JSValue
* constrVal
= r
[constr
].jsValue(exec
);
2565 ConstructData constructData
;
2566 ConstructType constructType
= constrVal
->getConstructData(constructData
);
2568 // Removing this line of code causes a measurable regression on squirrelfish.
2569 JSObject
* constructor
= static_cast<JSObject
*>(constrVal
);
2571 if (constructType
== ConstructTypeJS
) {
2572 if (*enabledProfilerReference
)
2573 (*enabledProfilerReference
)->willExecute(exec
, constructor
);
2575 JSObject
* prototype
;
2576 JSValue
* p
= constructor
->get(exec
, exec
->propertyNames().prototype
);
2578 prototype
= static_cast<JSObject
*>(p
);
2580 prototype
= scopeChain
->globalObject()->objectPrototype();
2581 JSObject
* newObject
= new (exec
) JSObject(prototype
);
2583 ScopeChainNode
* callDataScopeChain
= constructData
.js
.scopeChain
;
2584 FunctionBodyNode
* functionBodyNode
= constructData
.js
.functionBody
;
2585 CodeBlock
* newCodeBlock
= &functionBodyNode
->byteCode(callDataScopeChain
);
2587 r
[firstArg
] = newObject
; // "this" value
2589 Register
* callFrame
= r
+ firstArg
- RegisterFile::CallFrameHeaderSize
;
2590 initializeCallFrame(callFrame
, codeBlock
, vPC
, scopeChain
, r
, dst
, firstArg
, argCount
, 1, constructor
);
2591 exec
->m_callFrame
= callFrame
;
2593 r
= slideRegisterWindowForCall(exec
, newCodeBlock
, registerFile
, registerBase
, r
, firstArg
, argCount
, exceptionValue
);
2597 codeBlock
= newCodeBlock
;
2598 setScopeChain(exec
, scopeChain
, scopeChainForCall(exec
, functionBodyNode
, codeBlock
, callDataScopeChain
, r
));
2599 vPC
= codeBlock
->instructions
.begin();
2604 if (constructType
== ConstructTypeHost
) {
2605 if (*enabledProfilerReference
)
2606 (*enabledProfilerReference
)->willExecute(exec
, constructor
);
2608 ArgList
args(r
+ firstArg
+ 1, argCount
- 1);
2610 MACHINE_SAMPLING_callingHostFunction();
2612 JSValue
* returnValue
= constructData
.native
.function(exec
, constructor
, args
);
2614 VM_CHECK_EXCEPTION();
2615 r
[dst
] = returnValue
;
2617 if (*enabledProfilerReference
)
2618 (*enabledProfilerReference
)->didExecute(exec
, constructor
);
2624 ASSERT(constructType
== ConstructTypeNone
);
2626 exceptionValue
= createNotAConstructorError(exec
, constrVal
, vPC
, codeBlock
);
2629 BEGIN_OPCODE(op_push_scope
) {
2630 /* push_scope scope(r)
2632 Converts register scope to object, and pushes it onto the top
2633 of the current scope chain.
2635 int scope
= (++vPC
)->u
.operand
;
2636 JSValue
* v
= r
[scope
].jsValue(exec
);
2637 JSObject
* o
= v
->toObject(exec
);
2638 VM_CHECK_EXCEPTION();
2640 setScopeChain(exec
, scopeChain
, scopeChain
->push(o
));
2645 BEGIN_OPCODE(op_pop_scope
) {
2648 Removes the top item from the current scope chain.
2650 setScopeChain(exec
, scopeChain
, scopeChain
->pop());
2655 BEGIN_OPCODE(op_get_pnames
) {
2656 /* get_pnames dst(r) base(r)
2658 Creates a property name list for register base and puts it
2659 in register dst. This is not a true JavaScript value, just
2660 a synthetic value used to keep the iteration state in a
2663 int dst
= (++vPC
)->u
.operand
;
2664 int base
= (++vPC
)->u
.operand
;
2666 r
[dst
] = JSPropertyNameIterator::create(exec
, r
[base
].jsValue(exec
));
2670 BEGIN_OPCODE(op_next_pname
) {
2671 /* next_pname dst(r) iter(r) target(offset)
2673 Tries to copies the next name from property name list in
2674 register iter. If there are names left, then copies one to
2675 register dst, and jumps to offset target. If there are none
2676 left, invalidates the iterator and continues to the next
2679 int dst
= (++vPC
)->u
.operand
;
2680 int iter
= (++vPC
)->u
.operand
;
2681 int target
= (++vPC
)->u
.operand
;
2683 JSPropertyNameIterator
* it
= r
[iter
].jsPropertyNameIterator();
2684 if (JSValue
* temp
= it
->next(exec
)) {
2685 CHECK_FOR_TIMEOUT();
2695 BEGIN_OPCODE(op_jmp_scopes
) {
2696 /* jmp_scopes count(n) target(offset)
2698 Removes the a number of items from the current scope chain
2699 specified by immediate number count, then jumps to offset
2702 int count
= (++vPC
)->u
.operand
;
2703 int target
= (++vPC
)->u
.operand
;
2705 ScopeChainNode
* tmp
= scopeChain
;
2708 setScopeChain(exec
, scopeChain
, tmp
);
2713 #if HAVE(COMPUTED_GOTO)
2715 goto *(&&skip_new_scope
);
2717 BEGIN_OPCODE(op_push_new_scope
) {
2718 /* new_scope dst(r) property(id) value(r)
2720 Constructs a new StaticScopeObject with property set to value. That scope
2721 object is then pushed onto the ScopeChain. The scope object is then stored
2724 setScopeChain(exec
, scopeChain
, createExceptionScope(exec
, codeBlock
, vPC
, r
, scopeChain
));
2728 #if HAVE(COMPUTED_GOTO)
2731 BEGIN_OPCODE(op_catch
) {
2734 Retrieves the VMs current exception and puts it in register
2735 ex. This is only valid after an exception has been raised,
2736 and usually forms the beginning of an exception handler.
2738 ASSERT(exceptionValue
);
2739 ASSERT(!exec
->hadException());
2740 int ex
= (++vPC
)->u
.operand
;
2741 r
[ex
] = exceptionValue
;
2747 BEGIN_OPCODE(op_throw
) {
2750 Throws register ex as an exception. This involves three
2751 steps: first, it is set as the current exception in the
2752 VM's internal state, then the stack is unwound until an
2753 exception handler or a native code boundary is found, and
2754 then control resumes at the exception handler if any or
2755 else the script returns control to the nearest native caller.
2758 int ex
= (++vPC
)->u
.operand
;
2759 exceptionValue
= r
[ex
].jsValue(exec
);
2761 handlerVPC
= throwException(exec
, exceptionValue
, vPC
, codeBlock
, scopeChain
, r
, true);
2763 *exception
= exceptionValue
;
2767 #if HAVE(COMPUTED_GOTO)
2768 // Hack around gcc performance quirk by performing an indirect goto
2769 // in order to set the vPC -- attempting to do so directly results in a
2770 // significant regression.
2771 goto *op_throw_end_indirect
; // indirect goto -> op_throw_end
2779 BEGIN_OPCODE(op_unexpected_load
) {
2780 /* unexpected_load load dst(r) src(k)
2782 Copies constant src to register dst.
2784 int dst
= (++vPC
)->u
.operand
;
2785 int src
= (++vPC
)->u
.operand
;
2786 r
[dst
] = codeBlock
->unexpectedConstants
[src
];
2791 BEGIN_OPCODE(op_new_error
) {
2792 /* new_error dst(r) type(n) message(k)
2794 Constructs a new Error instance using the original
2795 constructor, using immediate number n as the type and
2796 constant message as the message string. The result is
2797 written to register dst.
2799 int dst
= (++vPC
)->u
.operand
;
2800 int type
= (++vPC
)->u
.operand
;
2801 int message
= (++vPC
)->u
.operand
;
2803 r
[dst
] = Error::create(exec
, (ErrorType
)type
, codeBlock
->unexpectedConstants
[message
]->toString(exec
), codeBlock
->lineNumberForVPC(vPC
), codeBlock
->ownerNode
->sourceId(), codeBlock
->ownerNode
->sourceURL());
2808 BEGIN_OPCODE(op_end
) {
2811 Return register result as the value of a global or eval
2812 program. Return control to the calling native code.
2815 if (codeBlock
->needsFullScopeChain
) {
2816 ASSERT(scopeChain
->refCount
> 1);
2817 scopeChain
->deref();
2819 int result
= (++vPC
)->u
.operand
;
2820 return r
[result
].jsValue(exec
);
2822 BEGIN_OPCODE(op_put_getter
) {
2823 /* put_getter base(r) property(id) function(r)
2825 Sets register function on register base as the getter named
2826 by identifier property. Base and function are assumed to be
2827 objects as this op should only be used for getters defined
2828 in object literal form.
2830 Unlike many opcodes, this one does not write any output to
2833 int base
= (++vPC
)->u
.operand
;
2834 int property
= (++vPC
)->u
.operand
;
2835 int function
= (++vPC
)->u
.operand
;
2837 ASSERT(r
[base
].jsValue(exec
)->isObject());
2838 JSObject
* baseObj
= static_cast<JSObject
*>(r
[base
].jsValue(exec
));
2839 Identifier
& ident
= codeBlock
->identifiers
[property
];
2840 ASSERT(r
[function
].jsValue(exec
)->isObject());
2841 baseObj
->defineGetter(exec
, ident
, static_cast<JSObject
*>(r
[function
].jsValue(exec
)));
2846 BEGIN_OPCODE(op_put_setter
) {
2847 /* put_setter base(r) property(id) function(r)
2849 Sets register function on register base as the setter named
2850 by identifier property. Base and function are assumed to be
2851 objects as this op should only be used for setters defined
2852 in object literal form.
2854 Unlike many opcodes, this one does not write any output to
2857 int base
= (++vPC
)->u
.operand
;
2858 int property
= (++vPC
)->u
.operand
;
2859 int function
= (++vPC
)->u
.operand
;
2861 ASSERT(r
[base
].jsValue(exec
)->isObject());
2862 JSObject
* baseObj
= static_cast<JSObject
*>(r
[base
].jsValue(exec
));
2863 Identifier
& ident
= codeBlock
->identifiers
[property
];
2864 ASSERT(r
[function
].jsValue(exec
)->isObject());
2865 baseObj
->defineSetter(exec
, ident
, static_cast<JSObject
*>(r
[function
].jsValue(exec
)));
2870 BEGIN_OPCODE(op_jsr
) {
2871 /* jsr retAddrDst(r) target(offset)
2873 Places the address of the next instruction into the retAddrDst
2874 register and jumps to offset target from the current instruction.
2876 int retAddrDst
= (++vPC
)->u
.operand
;
2877 int target
= (++vPC
)->u
.operand
;
2878 r
[retAddrDst
] = vPC
+ 1;
2883 BEGIN_OPCODE(op_sret
) {
2884 /* sret retAddrSrc(r)
2886 Jumps to the address stored in the retAddrSrc register. This
2887 differs from op_jmp because the target address is stored in a
2888 register, not as an immediate.
2890 int retAddrSrc
= (++vPC
)->u
.operand
;
2891 vPC
= r
[retAddrSrc
].vPC();
2894 BEGIN_OPCODE(op_debug
) {
2895 /* debug debugHookID(n) firstLine(n) lastLine(n)
2897 Notifies the debugger of the current state of execution. This opcode
2898 is only generated while the debugger is attached.
2901 debug(exec
, vPC
, codeBlock
, scopeChain
, r
);
2907 exec
->clearException();
2909 // The exceptionValue is a lie! (GCC produces bad code for reasons I
2910 // cannot fathom if we don't assign to the exceptionValue before branching)
2911 exceptionValue
= createInterruptedExecutionException(exec
);
2913 handlerVPC
= throwException(exec
, exceptionValue
, vPC
, codeBlock
, scopeChain
, r
, false);
2915 *exception
= exceptionValue
;
2924 #undef VM_CHECK_EXCEPTION
2927 JSValue
* Machine::retrieveArguments(ExecState
* exec
, JSFunction
* function
) const
2929 Register
* callFrame
= this->callFrame(exec
, function
);
2933 JSActivation
* activation
= static_cast<JSActivation
*>(callFrame
[RegisterFile::OptionalCalleeActivation
].jsValue(exec
));
2935 CodeBlock
* codeBlock
= &function
->m_body
->generatedByteCode();
2936 activation
= new (exec
) JSActivation(function
->m_body
, callFrame
+ RegisterFile::CallFrameHeaderSize
+ codeBlock
->numLocals
);
2937 callFrame
[RegisterFile::OptionalCalleeActivation
] = activation
;
2940 return activation
->get(exec
, exec
->propertyNames().arguments
);
2943 JSValue
* Machine::retrieveCaller(ExecState
* exec
, JSFunction
* function
) const
2945 Register
* callFrame
= this->callFrame(exec
, function
);
2949 CodeBlock
* callerCodeBlock
= callFrame
[RegisterFile::CallerCodeBlock
].codeBlock();
2950 if (!callerCodeBlock
)
2953 Register
* callerCallFrame
= callFrame
[RegisterFile::CallerRegisters
].r() - callerCodeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
2954 if (JSValue
* caller
= callerCallFrame
[RegisterFile::Callee
].jsValue(exec
))
2960 void Machine::retrieveLastCaller(ExecState
* exec
, int& lineNumber
, int& sourceId
, UString
& sourceURL
) const
2963 sourceURL
= UString();
2965 Register
* callFrame
= exec
->m_callFrame
;
2969 CodeBlock
* callerCodeBlock
= callFrame
[RegisterFile::CallerCodeBlock
].codeBlock();
2970 if (!callerCodeBlock
)
2973 Instruction
* vPC
= callFrame
[RegisterFile::ReturnVPC
].vPC();
2974 lineNumber
= callerCodeBlock
->lineNumberForVPC(vPC
- 1);
2975 sourceId
= callerCodeBlock
->ownerNode
->sourceId();
2976 sourceURL
= callerCodeBlock
->ownerNode
->sourceURL();
2979 Register
* Machine::callFrame(ExecState
* exec
, JSFunction
* function
) const
2981 Register
* callFrame
= exec
->m_callFrame
;
2984 while (!callFrame
) {
2985 exec
= exec
->m_prev
;
2988 callFrame
= exec
->m_callFrame
;
2991 if (callFrame
[RegisterFile::Callee
].jsValue(exec
) == function
)
2994 CodeBlock
* callerCodeBlock
= callFrame
[RegisterFile::CallerCodeBlock
].codeBlock();
2995 if (!callerCodeBlock
) {
3000 callFrame
= callFrame
[RegisterFile::CallerRegisters
].r() - callerCodeBlock
->numLocals
- RegisterFile::CallFrameHeaderSize
;
3004 void Machine::getArgumentsData(Register
* callFrame
, JSFunction
*& function
, Register
*& argv
, int& argc
)
3006 function
= static_cast<JSFunction
*>(callFrame
[RegisterFile::Callee
].getJSValue());
3007 ASSERT(function
->inherits(&JSFunction::info
));
3009 argv
= callFrame
[RegisterFile::CallerRegisters
].r() + callFrame
[RegisterFile::ArgumentStartRegister
].i() + 1; // + 1 to skip "this"
3010 argc
= callFrame
[RegisterFile::ArgumentCount
].i() - 1; // - 1 to skip "this"