source: webkit/trunk/JavaScriptCore/VM/Machine.cpp@ 34067

Last change on this file since 34067 was 34067, checked in by [email protected], 17 years ago

Remove JAVASCRIPT_PROFILER define

RS=Kevin McCullough

File size: 83.5 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
17 *
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.
28 */
29
30#include "config.h"
31#include "Machine.h"
32
33#include "CodeBlock.h"
34#include "DebuggerCallFrame.h"
35#include "ExceptionHelpers.h"
36#include "ExecState.h"
37#include "JSActivation.h"
38#include "JSLock.h"
39#include "JSPropertyNameIterator.h"
40#include "Parser.h"
41#include "Profiler.h"
42#include "Register.h"
43#include "array_object.h"
44#include "debugger.h"
45#include "function.h"
46#include "internal.h"
47#include "object_object.h"
48#include "operations.h"
49#include "operations.h"
50#include "regexp_object.h"
51
52#if COMPILER(GCC)
53#define UNLIKELY(x) \
54 __builtin_expect ((x), 0)
55#else
56#define UNLIKELY(x) x
57#endif
58
59namespace KJS {
60
61#if HAVE(COMPUTED_GOTO)
62static void* op_throw_end_indirect;
63static void* op_call_indirect;
64#endif
65
66// Retrieves the offset of a calling function within the current register file.
67bool getCallerFunctionOffset(Register** registerBase, int callOffset, int& callerOffset)
68{
69 Register* callFrame = (*registerBase) + callOffset;
70
71 CodeBlock* callerCodeBlock = callFrame[Machine::CallerCodeBlock].u.codeBlock;
72 if (!callerCodeBlock) // test for top frame of re-entrant function call
73 return false;
74
75 callerOffset = callFrame[Machine::CallerRegisterOffset].u.i - callerCodeBlock->numLocals - Machine::CallFrameHeaderSize;
76 if (callerOffset < 0) // test for global frame
77 return false;
78
79 Register* callerCallFrame = (*registerBase) + callerOffset;
80 if (!callerCallFrame[Machine::CallerCodeBlock].u.codeBlock) // test for eval frame
81 return false;
82
83 return true;
84}
85
86// Returns the depth of the scope chain within a given call frame.
87static int depth(ScopeChain& sc)
88{
89 int scopeDepth = 0;
90 ScopeChainIterator iter = sc.begin();
91 ScopeChainIterator end = sc.end();
92 while (!(*iter)->isVariableObject()) {
93 ++iter;
94 ++scopeDepth;
95 }
96 return scopeDepth;
97}
98
99static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
100{
101 if (JSImmediate::areBothImmediateNumbers(v1, v2))
102 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
103
104 double n1;
105 double n2;
106 JSValue* p1;
107 JSValue* p2;
108 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
109 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
110
111 if (wasNotString1 | wasNotString2)
112 return n1 < n2;
113
114 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
115}
116
117static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
118{
119 double n1;
120 double n2;
121 JSValue* p1;
122 JSValue* p2;
123 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
124 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
125
126 if (wasNotString1 | wasNotString2)
127 return n1 <= n2;
128
129 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
130}
131
132static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
133{
134 // exception for the Date exception in defaultValue()
135 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
136 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
137
138 if (p1->isString() || p2->isString()) {
139 UString value = p1->toString(exec) + p2->toString(exec);
140 if (value.isNull())
141 return throwOutOfMemoryError(exec);
142 return jsString(value);
143 }
144
145 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
146}
147
148// Fast-path choices here are based on frequency data from SunSpider:
149// <times> Add case: <t1> <t2>
150// ---------------------------
151// 5627160 Add case: 1 1
152// 247427 Add case: 5 5
153// 20901 Add case: 5 6
154// 13978 Add case: 5 1
155// 4000 Add case: 1 5
156// 1 Add case: 3 5
157
158static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
159{
160 JSType t1 = v1->type();
161 JSType t2 = v2->type();
162 const unsigned bothTypes = (t1 << 3) | t2;
163
164 if (bothTypes == ((NumberType << 3) | NumberType))
165 return jsNumber(v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
166 if (bothTypes == ((StringType << 3) | StringType)) {
167 UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
168 if (value.isNull())
169 return throwOutOfMemoryError(exec);
170 return jsString(value);
171 }
172
173 // All other cases are pretty uncommon
174 return jsAddSlowCase(exec, v1, v2);
175}
176
177static JSValue* jsTypeStringForValue(JSValue* v)
178{
179 switch (v->type()) {
180 case UndefinedType:
181 return jsString("undefined");
182 case NullType:
183 return jsString("object");
184 case BooleanType:
185 return jsString("boolean");
186 case NumberType:
187 return jsString("number");
188 case StringType:
189 return jsString("string");
190 default:
191 if (v->isObject()) {
192 // Return "undefined" for objects that should be treated
193 // as null when doing comparisons.
194 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
195 return jsString("undefined");
196 else if (static_cast<JSObject*>(v)->implementsCall())
197 return jsString("function");
198 }
199
200 return jsString("object");
201 }
202}
203
204static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
205{
206 int dst = (vPC + 1)->u.operand;
207 int property = (vPC + 2)->u.operand;
208
209 ScopeChainIterator iter = scopeChain->begin();
210 ScopeChainIterator end = scopeChain->end();
211 ASSERT(iter != end);
212
213 PropertySlot slot;
214 Identifier& ident = codeBlock->identifiers[property];
215 do {
216 JSObject* o = *iter;
217 if (o->getPropertySlot(exec, ident, slot)) {
218 JSValue* result = slot.getValue(exec, o, ident);
219 exceptionValue = exec->exception();
220 if (exceptionValue)
221 return false;
222 r[dst].u.jsValue = result;
223 return true;
224 }
225 } while (++iter != end);
226 exceptionValue = createUndefinedVariableError(exec, ident);
227 return false;
228}
229
230static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
231{
232 int dst = (vPC + 1)->u.operand;
233 int property = (vPC + 2)->u.operand;
234 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
235
236 ScopeChainIterator iter = scopeChain->begin();
237 ScopeChainIterator end = scopeChain->end();
238 ASSERT(iter != end);
239 while (skip--) {
240 ++iter;
241 ASSERT(iter != end);
242 }
243 PropertySlot slot;
244 Identifier& ident = codeBlock->identifiers[property];
245 do {
246 JSObject* o = *iter;
247 if (o->getPropertySlot(exec, ident, slot)) {
248 JSValue* result = slot.getValue(exec, o, ident);
249 exceptionValue = exec->exception();
250 if (exceptionValue)
251 return false;
252 r[dst].u.jsValue = result;
253 return true;
254 }
255 } while (++iter != end);
256 exceptionValue = createUndefinedVariableError(exec, ident);
257 return false;
258}
259
260static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
261{
262 int dst = (vPC + 1)->u.operand;
263 int property = (vPC + 2)->u.operand;
264
265 ScopeChainIterator iter = scopeChain->begin();
266 ScopeChainIterator next = iter;
267 ++next;
268 ScopeChainIterator end = scopeChain->end();
269 ASSERT(iter != end);
270
271 PropertySlot slot;
272 Identifier& ident = codeBlock->identifiers[property];
273 JSObject* base;
274 while (true) {
275 base = *iter;
276 if (next == end || base->getPropertySlot(exec, ident, slot)) {
277 r[dst].u.jsValue = base;
278 return;
279 }
280 iter = next;
281 ++next;
282 }
283}
284
285static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
286{
287 int baseDst = (vPC + 1)->u.operand;
288 int propDst = (vPC + 2)->u.operand;
289 int property = (vPC + 3)->u.operand;
290
291 ScopeChainIterator iter = scopeChain->begin();
292 ScopeChainIterator end = scopeChain->end();
293
294 // FIXME: add scopeDepthIsZero optimization
295
296 ASSERT(iter != end);
297
298 PropertySlot slot;
299 Identifier& ident = codeBlock->identifiers[property];
300 JSObject* base;
301 do {
302 base = *iter;
303 if (base->getPropertySlot(exec, ident, slot)) {
304 JSValue* result = slot.getValue(exec, base, ident);
305 exceptionValue = exec->exception();
306 if (exceptionValue)
307 return false;
308 r[propDst].u.jsValue = result;
309 r[baseDst].u.jsValue = base;
310 return true;
311 }
312 ++iter;
313 } while (iter != end);
314
315 exceptionValue = createUndefinedVariableError(exec, ident);
316 return false;
317}
318
319static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
320{
321 int baseDst = (vPC + 1)->u.operand;
322 int funcDst = (vPC + 2)->u.operand;
323 int property = (vPC + 3)->u.operand;
324
325 ScopeChainIterator iter = scopeChain->begin();
326 ScopeChainIterator end = scopeChain->end();
327
328 // FIXME: add scopeDepthIsZero optimization
329
330 ASSERT(iter != end);
331
332 PropertySlot slot;
333 Identifier& ident = codeBlock->identifiers[property];
334 JSObject* base;
335 do {
336 base = *iter;
337 if (base->getPropertySlot(exec, ident, slot)) {
338 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
339 // However, section 10.2.3 says that in the case where the value provided
340 // by the caller is null, the global object should be used. It also says
341 // that the section does not apply to internal functions, but for simplicity
342 // of implementation we use the global object anyway here. This guarantees
343 // that in host objects you always get a valid object for this.
344 // We also handle wrapper substitution for the global object at the same time.
345 JSObject* thisObj = base->toThisObject(exec);
346 JSValue* result = slot.getValue(exec, base, ident);
347 exceptionValue = exec->exception();
348 if (exceptionValue)
349 return false;
350
351 r[baseDst].u.jsValue = thisObj;
352 r[funcDst].u.jsValue = result;
353 return true;
354 }
355 ++iter;
356 } while (iter != end);
357
358 exceptionValue = createUndefinedVariableError(exec, ident);
359 return false;
360}
361
362ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, int registerOffset, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
363{
364 callFrame[Machine::CallerCodeBlock].u.codeBlock = codeBlock;
365 callFrame[Machine::ReturnVPC].u.vPC = vPC + 1;
366 callFrame[Machine::CallerScopeChain].u.scopeChain = scopeChain;
367 callFrame[Machine::CallerRegisterOffset].u.i = registerOffset;
368 callFrame[Machine::ReturnValueRegister].u.i = returnValueRegister;
369 callFrame[Machine::ArgumentStartRegister].u.i = argv; // original argument vector (for the sake of the "arguments" object)
370 callFrame[Machine::ArgumentCount].u.i = argc; // original argument count (for the sake of the "arguments" object)
371 callFrame[Machine::CalledAsConstructor].u.i = calledAsConstructor;
372 callFrame[Machine::Callee].u.jsValue = function;
373 callFrame[Machine::OptionalCalleeActivation].u.jsValue = 0;
374}
375
376ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register** registerBase, int registerOffset, int argv, int argc, JSValue*& exceptionValue)
377{
378 Register* r = 0;
379 int oldOffset = registerOffset;
380 registerOffset += argv + newCodeBlock->numLocals;
381 size_t size = registerOffset + newCodeBlock->numTemporaries;
382
383 if (argc == newCodeBlock->numParameters) { // correct number of arguments
384 if (!registerFile->grow(size)) {
385 exceptionValue = createStackOverflowError(exec);
386 return *registerBase + oldOffset;
387 }
388 r = (*registerBase) + registerOffset;
389 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
390 if (!registerFile->grow(size)) {
391 exceptionValue = createStackOverflowError(exec);
392 return *registerBase + oldOffset;
393 }
394 r = (*registerBase) + registerOffset;
395
396 int omittedArgCount = newCodeBlock->numParameters - argc;
397 Register* endOfParams = r - newCodeBlock->numVars;
398 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
399 (*it).u.jsValue = jsUndefined();
400 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
401 int shift = argc + Machine::CallFrameHeaderSize;
402 registerOffset += shift;
403 size += shift;
404
405 if (!registerFile->grow(size)) {
406 exceptionValue = createStackOverflowError(exec);
407 return *registerBase + oldOffset;
408 }
409 r = (*registerBase) + registerOffset;
410
411 Register* it = r - newCodeBlock->numLocals - Machine::CallFrameHeaderSize - shift;
412 Register* end = it + Machine::CallFrameHeaderSize + newCodeBlock->numParameters;
413 for ( ; it != end; ++it)
414 *(it + shift) = *it;
415 }
416
417 return r;
418}
419
420ALWAYS_INLINE ScopeChainNode* scopeChainForCall(FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register** registerBase, Register* r)
421{
422 if (newCodeBlock->needsFullScopeChain) {
423 JSActivation* activation = new JSActivation(functionBodyNode, registerBase, r - (*registerBase));
424 r[Machine::OptionalCalleeActivation - Machine::CallFrameHeaderSize - newCodeBlock->numLocals].u.jsValue = activation;
425
426 return callDataScopeChain->copy()->push(activation);
427 }
428
429 return callDataScopeChain;
430}
431
432static NEVER_INLINE bool isNotObject(ExecState* exec, const Instruction*, CodeBlock*, JSValue* value, JSValue*& exceptionData)
433{
434 if (value->isObject())
435 return false;
436 exceptionData = createNotAnObjectError(exec, value, 0);
437 return true;
438}
439
440static NEVER_INLINE JSValue* callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
441{
442 Profiler** profiler = Profiler::enabledProfilerReference();
443 JSObject* evalFunction = scopeChain->globalObject()->evalFunction();
444 if (*profiler)
445 (*profiler)->willExecute(exec, evalFunction);
446
447 JSValue* x = argc >= 2 ? r[argv + 1].u.jsValue : jsUndefined();
448
449 if (!x->isString())
450 return x;
451
452 UString s = x->toString(exec);
453 if (exec->hadException()) {
454 exceptionValue = exec->exception();
455 exec->clearException();
456 return 0;
457 }
458
459 int sourceId;
460 int errLine;
461 UString errMsg;
462 RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(exec, UString(), 0, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);
463
464 if (!evalNode) {
465 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
466 return 0;
467 }
468
469 JSValue* result = machine().execute(evalNode.get(), exec, thisObj, registerFile, r - (*registerFile->basePointer()) + argv + argc, scopeChain, &exceptionValue);
470
471 if ((*profiler))
472 (*profiler)->didExecute(exec, evalFunction);
473
474 return result;
475}
476
477Machine& machine()
478{
479 ASSERT(JSLock::currentThreadIsHoldingLock());
480 static Machine machine;
481 return machine;
482}
483
484Machine::Machine()
485 : m_reentryDepth(0)
486{
487 privateExecute(InitializeAndReturn);
488}
489
490void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
491{
492 ScopeChain sc(scopeChain);
493 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(sc.bottom());
494 codeBlock->dump(globalObject->globalExec());
495 dumpRegisters(codeBlock, registerFile, r);
496}
497
498void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
499{
500 printf("Register frame: \n\n");
501 printf("----------------------------------------\n");
502 printf(" use | address | value \n");
503 printf("----------------------------------------\n");
504
505 const Register* it;
506 const Register* end;
507
508 if (isGlobalCallFrame(registerFile->basePointer(), r)) {
509 it = r - registerFile->numGlobalSlots();
510 end = r;
511 if (it != end) {
512 do {
513 printf("[global var] | %10p | %10p \n", it, (*it).u.jsValue);
514 ++it;
515 } while (it != end);
516 printf("----------------------------------------\n");
517 }
518 } else {
519 it = r - codeBlock->numLocals - CallFrameHeaderSize;
520 end = it + CallFrameHeaderSize;
521 if (it != end) {
522 do {
523 printf("[call frame] | %10p | %10p \n", it, (*it).u.jsValue);
524 ++it;
525 } while (it != end);
526 printf("----------------------------------------\n");
527 }
528
529 end = it + codeBlock->numParameters;
530 if (it != end) {
531 do {
532 printf("[param] | %10p | %10p \n", it, (*it).u.jsValue);
533 ++it;
534 } while (it != end);
535 printf("----------------------------------------\n");
536 }
537
538 end = it + codeBlock->numVars;
539 if (it != end) {
540 do {
541 printf("[var] | %10p | %10p \n", it, (*it).u.jsValue);
542 ++it;
543 } while (it != end);
544 printf("----------------------------------------\n");
545 }
546 }
547
548 end = it + codeBlock->numTemporaries;
549 if (it != end) {
550 do {
551 printf("[temp] | %10p | %10p \n", it, (*it).u.jsValue);
552 ++it;
553 } while (it != end);
554 }
555}
556
557bool Machine::isOpcode(Opcode opcode)
558{
559#if HAVE(COMPUTED_GOTO)
560 return opcode != HashTraits<Opcode>::emptyValue()
561 && !HashTraits<Opcode>::isDeletedValue(opcode)
562 && m_opcodeIDTable.contains(opcode);
563#else
564 return opcode >= 0 && opcode <= op_end;
565#endif
566}
567
568NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction*& vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
569{
570 CodeBlock* oldCodeBlock = codeBlock;
571
572 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
573 if (!isGlobalCallFrame(registerBase, r)) {
574 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
575 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
576 }
577 }
578
579 if (oldCodeBlock->needsFullScopeChain)
580 scopeChain->deref();
581
582 if (isGlobalCallFrame(registerBase, r))
583 return false;
584
585 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
586
587 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
588 if (!codeBlock)
589 return false;
590
591 // If this call frame created an activation, tear it off.
592 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
593 ASSERT(activation->isActivationObject());
594 activation->copyRegisters();
595 }
596
597 k = codeBlock->jsValues.data();
598 scopeChain = callFrame[CallerScopeChain].u.scopeChain;
599 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
600 r = (*registerBase) + callerRegisterOffset;
601 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
602 vPC = callFrame[ReturnVPC].u.vPC;
603
604 if (Profiler* profiler = *Profiler::enabledProfilerReference())
605 profiler->didExecute(exec, callFrame[Callee].u.jsObject);
606 return true;
607}
608
609NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, Register** registerBase, const Instruction* vPC, CodeBlock*& codeBlock, JSValue**& k, ScopeChainNode*& scopeChain, Register*& r)
610{
611 // Set up the exception object
612
613 if (exceptionValue->isObject()) {
614 JSObject* exception = static_cast<JSObject*>(exceptionValue);
615 if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
616 exception->put(exec, "line", jsNumber(codeBlock->lineNumberForVPC(vPC)));
617 exception->put(exec, "sourceURL", jsOwnedString(codeBlock->ownerNode->sourceURL()));
618 }
619 }
620
621 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
622 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, exceptionValue, registerBase, r - *registerBase);
623 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
624 }
625
626 // Calculate an exception handler vPC, unwinding call frames as necessary.
627
628 int scopeDepth;
629 Instruction* handlerVPC;
630
631 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth))
632 if (!unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r))
633 return 0;
634
635 // Now unwind the scope chain within the exception handler's call frame.
636
637 ScopeChain sc(scopeChain);
638 int scopeDelta = depth(sc) - scopeDepth;
639 ASSERT(scopeDelta >= 0);
640 while (scopeDelta--)
641 sc.pop();
642 setScopeChain(exec, scopeChain, sc.node());
643
644 return handlerVPC;
645}
646
647JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, RegisterFileStack* registerFileStack, JSValue** exception)
648{
649 if (m_reentryDepth >= MaxReentryDepth) {
650 *exception = createStackOverflowError(exec);
651 return 0;
652 }
653
654 RegisterFile* registerFile = registerFileStack->pushGlobalRegisterFile();
655 ASSERT(registerFile->numGlobalSlots());
656 CodeBlock* codeBlock = &programNode->code(scopeChain, !registerFileStack->inImplicitCall());
657 registerFile->addGlobalSlots(codeBlock->numVars);
658
659 registerFile->uncheckedGrow(codeBlock->numTemporaries);
660 Register* r = (*registerFile->basePointer());
661
662 r[ProgramCodeThisRegister].u.jsValue = thisObj;
663
664 if (codeBlock->needsFullScopeChain)
665 scopeChain = scopeChain->copy();
666
667 Profiler** profiler = Profiler::enabledProfilerReference();
668 if (*profiler)
669 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
670
671 ExecState newExec(exec, this, registerFile, scopeChain, -1);
672
673 m_reentryDepth++;
674 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
675 m_reentryDepth--;
676
677 registerFileStack->popGlobalRegisterFile();
678
679 if (*profiler)
680 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
681
682 return result;
683}
684
685JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, FunctionImp* function, JSObject* thisObj, const List& args, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
686{
687 if (m_reentryDepth >= MaxReentryDepth) {
688 *exception = createStackOverflowError(exec);
689 return 0;
690 }
691
692 RegisterFile* registerFile = registerFileStack->current();
693
694 int argv = CallFrameHeaderSize;
695 int argc = args.size() + 1; // implicit "this" parameter
696
697 size_t oldSize = registerFile->size();
698 if (!registerFile->grow(oldSize + CallFrameHeaderSize + argc)) {
699 *exception = createStackOverflowError(exec);
700 return 0;
701 }
702
703 Register** registerBase = registerFile->basePointer();
704 int registerOffset = oldSize;
705 int callFrameOffset = registerOffset;
706 Register* callFrame = (*registerBase) + callFrameOffset;
707
708 // put args in place, including "this"
709 Register* dst = callFrame + CallFrameHeaderSize;
710 (*dst).u.jsValue = thisObj;
711
712 List::const_iterator end = args.end();
713 for (List::const_iterator it = args.begin(); it != end; ++it)
714 (*++dst).u.jsValue = *it;
715
716 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
717 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, argv, argc, 0, function);
718
719 CodeBlock* newCodeBlock = &functionBodyNode->code(scopeChain);
720 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, *exception);
721 if (*exception) {
722 registerFile->shrink(oldSize);
723 return 0;
724 }
725
726 scopeChain = scopeChainForCall(functionBodyNode, newCodeBlock, scopeChain, registerBase, r);
727
728 ExecState newExec(exec, this, registerFile, scopeChain, callFrameOffset);
729
730 Profiler** profiler = Profiler::enabledProfilerReference();
731 if (*profiler)
732 (*profiler)->willExecute(exec, function);
733
734 m_reentryDepth++;
735 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, newCodeBlock, exception);
736 m_reentryDepth--;
737
738 if (*profiler)
739 (*profiler)->didExecute(exec, function);
740
741 registerFile->shrink(oldSize);
742 return result;
743}
744
745JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFile* registerFile, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
746{
747 if (m_reentryDepth >= MaxReentryDepth) {
748 *exception = createStackOverflowError(exec);
749 return 0;
750 }
751
752 EvalCodeBlock* codeBlock = &evalNode->code(scopeChain);
753
754 JSVariableObject* variableObject;
755 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
756 ASSERT(node);
757 if (node->object->isVariableObject()) {
758 variableObject = static_cast<JSVariableObject*>(node->object);
759 break;
760 }
761 }
762
763 for (Vector<Identifier>::const_iterator iter = codeBlock->declaredVariableNames.begin(); iter != codeBlock->declaredVariableNames.end(); ++iter) {
764 Identifier ident = *iter;
765
766 if (!variableObject->hasProperty(exec, ident))
767 variableObject->put(exec, ident, jsUndefined());
768 }
769
770 ASSERT(codeBlock->functions.size() == codeBlock->declaredFunctionNames.size());
771 for (size_t i = 0; i < codeBlock->functions.size(); ++i)
772 variableObject->put(exec, codeBlock->declaredFunctionNames[i], codeBlock->functions[i]->makeFunction(exec, scopeChain));
773
774 size_t oldSize = registerFile->size();
775 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + CallFrameHeaderSize;
776 if (!registerFile->grow(newSize)) {
777 *exception = createStackOverflowError(exec);
778 return 0;
779 }
780
781 Register* callFrame = *registerFile->basePointer() + registerOffset;
782
783 // put call frame in place, using a 0 codeBlock to indicate a built-in caller
784 initializeCallFrame(callFrame, 0, 0, 0, registerOffset, 0, 0, 0, 0, 0);
785
786 Register* r = callFrame + CallFrameHeaderSize + codeBlock->numVars;
787 r[ProgramCodeThisRegister].u.jsValue = thisObj;
788
789 if (codeBlock->needsFullScopeChain)
790 scopeChain = scopeChain->copy();
791
792 Profiler** profiler = Profiler::enabledProfilerReference();
793 if (*profiler)
794 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
795
796 ExecState newExec(exec, this, registerFile, scopeChain, -1);
797
798 m_reentryDepth++;
799 JSValue* result = privateExecute(Normal, &newExec, registerFile, r, scopeChain, codeBlock, exception);
800 m_reentryDepth--;
801
802 registerFile->shrink(oldSize);
803
804 if (*profiler)
805 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
806
807 return result;
808}
809
810JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, RegisterFileStack* registerFileStack, ScopeChainNode* scopeChain, JSValue** exception)
811{
812 RegisterFile* registerFile = registerFileStack->current();
813 if (registerFile->safeForReentry())
814 return Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
815 registerFile = registerFileStack->pushFunctionRegisterFile();
816 JSValue* result = Machine::execute(evalNode, exec, thisObj, registerFile, registerFile->size(), scopeChain, exception);
817 registerFileStack->popFunctionRegisterFile();
818 return result;
819}
820
821ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
822{
823 scopeChain = newScopeChain;
824 exec->m_scopeChain = newScopeChain;
825}
826
827NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register** registerBase, Register* r)
828{
829 int debugHookID = (++vPC)->u.operand;
830 int firstLine = (++vPC)->u.operand;
831 int lastLine = (++vPC)->u.operand;
832
833 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
834 if (!debugger)
835 return;
836
837 DebuggerCallFrame debuggerCallFrame(this, exec->dynamicGlobalObject(), codeBlock, scopeChain, 0, registerBase, r - *registerBase);
838
839 switch((DebugHookID)debugHookID) {
840 case DidEnterCallFrame: {
841 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
842 return;
843 }
844 case WillLeaveCallFrame: {
845 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
846 return;
847 }
848 case WillExecuteStatement: {
849 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
850 return;
851 }
852 }
853}
854
855JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
856{
857 // One-time initialization of our address tables. We have to put this code
858 // here because our labels are only in scope inside this function.
859 if (flag == InitializeAndReturn) {
860 #if HAVE(COMPUTED_GOTO)
861 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
862 FOR_EACH_OPCODE_ID(ADD_OPCODE);
863 #undef ADD_OPCODE
864
865 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
866 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
867 #undef ADD_OPCODE
868 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
869 op_throw_end_indirect = &&op_throw_end;
870 op_call_indirect = &&op_call;
871 #endif // HAVE(COMPUTED_GOTO)
872 return 0;
873 }
874
875 JSValue* exceptionValue = 0;
876 Instruction* handlerVPC = 0;
877
878 Register** registerBase = registerFile->basePointer();
879 Instruction* vPC = codeBlock->instructions.begin();
880 JSValue** k = codeBlock->jsValues.data();
881 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
882
883#if HAVE(COMPUTED_GOTO)
884 // Yet another hack around GCC's various foibles, in this case fetching the
885 // profiler reference results in a regression. Removing this indirection
886 // results in a 0.8% regression.
887 goto *(&&profilerFetchHack);
888 profilerFetchHack:
889#endif
890
891 registerFile->setSafeForReentry(false);
892#define VM_CHECK_EXCEPTION() \
893 do { \
894 if (UNLIKELY(exec->hadException())) { \
895 exceptionValue = exec->exception(); \
896 goto vm_throw; \
897 } \
898 } while (0)
899
900#if HAVE(COMPUTED_GOTO)
901 #define NEXT_OPCODE goto *vPC->u.opcode
902 #define BEGIN_OPCODE(opcode) opcode:
903 NEXT_OPCODE;
904#else
905 #define NEXT_OPCODE continue
906 #define BEGIN_OPCODE(opcode) case opcode:
907 while(1) // iterator loop begins
908 switch (vPC->u.opcode)
909#endif
910 {
911 BEGIN_OPCODE(op_load) {
912 /* load dst(r) src(k)
913
914 Copies constant src to register dst.
915 */
916 int dst = (++vPC)->u.operand;
917 int src = (++vPC)->u.operand;
918 r[dst].u.jsValue = k[src];
919
920 ++vPC;
921 NEXT_OPCODE;
922 }
923 BEGIN_OPCODE(op_new_object) {
924 /* new_object dst(r)
925
926 Constructs a new empty Object instance using the original
927 constructor, and puts the result in register dst.
928 */
929 int dst = (++vPC)->u.operand;
930 r[dst].u.jsValue = scopeChain->globalObject()->objectConstructor()->construct(exec, exec->emptyList());
931
932 ++vPC;
933 NEXT_OPCODE;
934 }
935 BEGIN_OPCODE(op_new_array) {
936 /* new_array dst(r)
937
938 Constructs a new empty Array instance using the original
939 constructor, and puts the result in register dst.
940 */
941 int dst = (++vPC)->u.operand;
942 r[dst].u.jsValue = scopeChain->globalObject()->arrayConstructor()->construct(exec, exec->emptyList());
943
944 ++vPC;
945 NEXT_OPCODE;
946 }
947 BEGIN_OPCODE(op_new_regexp) {
948 /* new_regexp dst(r) regExp(re)
949
950 Constructs a new RegExp instance using the original
951 constructor from regexp regExp, and puts the result in
952 register dst.
953 */
954 int dst = (++vPC)->u.operand;
955 int regExp = (++vPC)->u.operand;
956 r[dst].u.jsValue = new RegExpImp(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
957
958 ++vPC;
959 NEXT_OPCODE;
960 }
961 BEGIN_OPCODE(op_mov) {
962 /* mov dst(r) src(r)
963
964 Copies register src to register dst.
965 */
966 int dst = (++vPC)->u.operand;
967 int src = (++vPC)->u.operand;
968 r[dst] = r[src];
969
970 ++vPC;
971 NEXT_OPCODE;
972 }
973 BEGIN_OPCODE(op_eq) {
974 /* eq dst(r) src1(r) src2(r)
975
976 Checks whether register src1 and register src2 are equal,
977 as with the ECMAScript '==' operator, and puts the result
978 as a boolean in register dst.
979 */
980 int dst = (++vPC)->u.operand;
981 int src1 = (++vPC)->u.operand;
982 int src2 = (++vPC)->u.operand;
983 JSValue* result = jsBoolean(equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
984 VM_CHECK_EXCEPTION();
985 r[dst].u.jsValue = result;
986
987 ++vPC;
988 NEXT_OPCODE;
989 }
990 BEGIN_OPCODE(op_neq) {
991 /* neq dst(r) src1(r) src2(r)
992
993 Checks whether register src1 and register src2 are not
994 equal, as with the ECMAScript '!=' operator, and puts the
995 result as a boolean in register dst.
996 */
997 int dst = (++vPC)->u.operand;
998 int src1 = (++vPC)->u.operand;
999 int src2 = (++vPC)->u.operand;
1000 JSValue* result = jsBoolean(!equal(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1001 VM_CHECK_EXCEPTION();
1002 r[dst].u.jsValue = result;
1003
1004 ++vPC;
1005 NEXT_OPCODE;
1006 }
1007 BEGIN_OPCODE(op_stricteq) {
1008 /* stricteq dst(r) src1(r) src2(r)
1009
1010 Checks whether register src1 and register src2 are strictly
1011 equal, as with the ECMAScript '===' operator, and puts the
1012 result as a boolean in register dst.
1013 */
1014 int dst = (++vPC)->u.operand;
1015 int src1 = (++vPC)->u.operand;
1016 int src2 = (++vPC)->u.operand;
1017 r[dst].u.jsValue = jsBoolean(strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1018
1019 ++vPC;
1020 NEXT_OPCODE;
1021 }
1022 BEGIN_OPCODE(op_nstricteq) {
1023 /* nstricteq dst(r) src1(r) src2(r)
1024
1025 Checks whether register src1 and register src2 are not
1026 strictly equal, as with the ECMAScript '!==' operator, and
1027 puts the result as a boolean in register dst.
1028 */
1029 int dst = (++vPC)->u.operand;
1030 int src1 = (++vPC)->u.operand;
1031 int src2 = (++vPC)->u.operand;
1032 r[dst].u.jsValue = jsBoolean(!strictEqual(r[src1].u.jsValue, r[src2].u.jsValue));
1033
1034 ++vPC;
1035 NEXT_OPCODE;
1036 }
1037 BEGIN_OPCODE(op_less) {
1038 /* less dst(r) src1(r) src2(r)
1039
1040 Checks whether register src1 is less than register src2, as
1041 with the ECMAScript '<' operator, and puts the result as
1042 a boolean in register dst.
1043 */
1044 int dst = (++vPC)->u.operand;
1045 int src1 = (++vPC)->u.operand;
1046 int src2 = (++vPC)->u.operand;
1047 JSValue* result = jsBoolean(jsLess(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1048 VM_CHECK_EXCEPTION();
1049 r[dst].u.jsValue = result;
1050
1051 ++vPC;
1052 NEXT_OPCODE;
1053 }
1054 BEGIN_OPCODE(op_lesseq) {
1055 /* lesseq dst(r) src1(r) src2(r)
1056
1057 Checks whether register src1 is less than or equal to
1058 register src2, as with the ECMAScript '<=' operator, and
1059 puts the result as a boolean in register dst.
1060 */
1061 int dst = (++vPC)->u.operand;
1062 int src1 = (++vPC)->u.operand;
1063 int src2 = (++vPC)->u.operand;
1064 JSValue* result = jsBoolean(jsLessEq(exec, r[src1].u.jsValue, r[src2].u.jsValue));
1065 VM_CHECK_EXCEPTION();
1066 r[dst].u.jsValue = result;
1067
1068 ++vPC;
1069 NEXT_OPCODE;
1070 }
1071 BEGIN_OPCODE(op_pre_inc) {
1072 /* pre_inc srcDst(r)
1073
1074 Converts register srcDst to number, adds one, and puts the result
1075 back in register srcDst.
1076 */
1077 int srcDst = (++vPC)->u.operand;
1078 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) + 1);
1079 VM_CHECK_EXCEPTION();
1080 r[srcDst].u.jsValue = result;
1081
1082 ++vPC;
1083 NEXT_OPCODE;
1084 }
1085 BEGIN_OPCODE(op_pre_dec) {
1086 /* pre_dec srcDst(r)
1087
1088 Converts register srcDst to number, subtracts one, and puts the result
1089 back in register srcDst.
1090 */
1091 int srcDst = (++vPC)->u.operand;
1092 JSValue* result = jsNumber(r[srcDst].u.jsValue->toNumber(exec) - 1);
1093 VM_CHECK_EXCEPTION();
1094 r[srcDst].u.jsValue = result;
1095
1096 ++vPC;
1097 NEXT_OPCODE;
1098 }
1099 BEGIN_OPCODE(op_post_inc) {
1100 /* post_inc dst(r) srcDst(r)
1101
1102 Converts register srcDst to number. The number itself is
1103 written to register dst, and the number plus one is written
1104 back to register srcDst.
1105 */
1106 int dst = (++vPC)->u.operand;
1107 int srcDst = (++vPC)->u.operand;
1108 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1109 VM_CHECK_EXCEPTION();
1110
1111 r[dst].u.jsValue = number;
1112 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() + 1);
1113
1114 ++vPC;
1115 NEXT_OPCODE;
1116 }
1117 BEGIN_OPCODE(op_post_dec) {
1118 /* post_dec dst(r) srcDst(r)
1119
1120 Converts register srcDst to number. The number itself is
1121 written to register dst, and the number minus one is written
1122 back to register srcDst.
1123 */
1124 int dst = (++vPC)->u.operand;
1125 int srcDst = (++vPC)->u.operand;
1126 JSValue* number = r[srcDst].u.jsValue->toJSNumber(exec);
1127 VM_CHECK_EXCEPTION();
1128
1129 r[dst].u.jsValue = number;
1130 r[srcDst].u.jsValue = jsNumber(number->uncheckedGetNumber() - 1);
1131
1132 ++vPC;
1133 NEXT_OPCODE;
1134 }
1135 BEGIN_OPCODE(op_to_jsnumber) {
1136 /* to_jsnumber dst(r) src(r)
1137
1138 Converts register src to number, and puts the result
1139 in register dst.
1140 */
1141 int dst = (++vPC)->u.operand;
1142 int src = (++vPC)->u.operand;
1143 JSValue* result = r[src].u.jsValue->toJSNumber(exec);
1144 VM_CHECK_EXCEPTION();
1145
1146 r[dst].u.jsValue = result;
1147
1148 ++vPC;
1149 NEXT_OPCODE;
1150 }
1151 BEGIN_OPCODE(op_negate) {
1152 /* negate dst(r) src(r)
1153
1154 Converts register src to number, negates it, and puts the
1155 result in register dst.
1156 */
1157 int dst = (++vPC)->u.operand;
1158 int src = (++vPC)->u.operand;
1159 JSValue* result = jsNumber(-r[src].u.jsValue->toNumber(exec));
1160 VM_CHECK_EXCEPTION();
1161 r[dst].u.jsValue = result;
1162
1163 ++vPC;
1164 NEXT_OPCODE;
1165 }
1166 BEGIN_OPCODE(op_add) {
1167 /* add dst(r) src1(r) src2(r)
1168
1169 Adds register src1 and register src2, and puts the result
1170 in register dst. (JS add may be string concatenation or
1171 numeric add, depending on the types of the operands.)
1172 */
1173 int dst = (++vPC)->u.operand;
1174 int src1 = (++vPC)->u.operand;
1175 int src2 = (++vPC)->u.operand;
1176 JSValue* result = jsAdd(exec, r[src1].u.jsValue, r[src2].u.jsValue);
1177 VM_CHECK_EXCEPTION();
1178 r[dst].u.jsValue = result;
1179 ++vPC;
1180 NEXT_OPCODE;
1181 }
1182 BEGIN_OPCODE(op_mul) {
1183 /* mul dst(r) src1(r) src2(r)
1184
1185 Multiplies register src1 and register src2 (converted to
1186 numbers), and puts the product in register dst.
1187 */
1188 int dst = (++vPC)->u.operand;
1189 int src1 = (++vPC)->u.operand;
1190 int src2 = (++vPC)->u.operand;
1191 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) * r[src2].u.jsValue->toNumber(exec));
1192 VM_CHECK_EXCEPTION();
1193 r[dst].u.jsValue = result;
1194
1195 ++vPC;
1196 NEXT_OPCODE;
1197 }
1198 BEGIN_OPCODE(op_div) {
1199 /* div dst(r) dividend(r) divisor(r)
1200
1201 Divides register dividend (converted to number) by the
1202 register divisor (converted to number), and puts the
1203 quotient in register dst.
1204 */
1205 int dst = (++vPC)->u.operand;
1206 int dividend = (++vPC)->u.operand;
1207 int divisor = (++vPC)->u.operand;
1208 JSValue* result = jsNumber(r[dividend].u.jsValue->toNumber(exec) / r[divisor].u.jsValue->toNumber(exec));
1209 VM_CHECK_EXCEPTION();
1210 r[dst].u.jsValue = result;
1211 ++vPC;
1212 NEXT_OPCODE;
1213 }
1214 BEGIN_OPCODE(op_mod) {
1215 /* mod dst(r) dividend(r) divisor(r)
1216
1217 Divides register dividend (converted to number) by
1218 register divisor (converted to number), and puts the
1219 remainder in register dst.
1220 */
1221 int dst = (++vPC)->u.operand;
1222 int dividend = (++vPC)->u.operand;
1223 int divisor = (++vPC)->u.operand;
1224 double d = r[dividend].u.jsValue->toNumber(exec);
1225 JSValue* result = jsNumber(fmod(d, r[divisor].u.jsValue->toNumber(exec)));
1226 VM_CHECK_EXCEPTION();
1227 r[dst].u.jsValue = result;
1228 ++vPC;
1229 NEXT_OPCODE;
1230 }
1231 BEGIN_OPCODE(op_sub) {
1232 /* sub dst(r) src1(r) src2(r)
1233
1234 Subtracts register src2 (converted to number) from register
1235 src1 (converted to number), and puts the difference in
1236 register dst.
1237 */
1238 int dst = (++vPC)->u.operand;
1239 int src1 = (++vPC)->u.operand;
1240 int src2 = (++vPC)->u.operand;
1241 JSValue* result = jsNumber(r[src1].u.jsValue->toNumber(exec) - r[src2].u.jsValue->toNumber(exec));
1242 VM_CHECK_EXCEPTION();
1243 r[dst].u.jsValue = result;
1244 ++vPC;
1245 NEXT_OPCODE;
1246 }
1247 BEGIN_OPCODE(op_lshift) {
1248 /* lshift dst(r) val(r) shift(r)
1249
1250 Performs left shift of register val (converted to int32) by
1251 register shift (converted to uint32), and puts the result
1252 in register dst.
1253 */
1254 int dst = (++vPC)->u.operand;
1255 int val = (++vPC)->u.operand;
1256 int shift = (++vPC)->u.operand;
1257 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) << (r[shift].u.jsValue->toUInt32(exec)));
1258 VM_CHECK_EXCEPTION();
1259 r[dst].u.jsValue = result;
1260
1261 ++vPC;
1262 NEXT_OPCODE;
1263 }
1264 BEGIN_OPCODE(op_rshift) {
1265 /* rshift dst(r) val(r) shift(r)
1266
1267 Performs arithmetic right shift of register val (converted
1268 to int32) by register shift (converted to
1269 uint32), and puts the result in register dst.
1270 */
1271 int dst = (++vPC)->u.operand;
1272 int val = (++vPC)->u.operand;
1273 int shift = (++vPC)->u.operand;
1274 JSValue* result = jsNumber((r[val].u.jsValue->toInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1275 VM_CHECK_EXCEPTION();
1276 r[dst].u.jsValue = result;
1277
1278 ++vPC;
1279 NEXT_OPCODE;
1280 }
1281 BEGIN_OPCODE(op_urshift) {
1282 /* rshift dst(r) val(r) shift(r)
1283
1284 Performs logical right shift of register val (converted
1285 to uint32) by register shift (converted to
1286 uint32), and puts the result in register dst.
1287 */
1288 int dst = (++vPC)->u.operand;
1289 int val = (++vPC)->u.operand;
1290 int shift = (++vPC)->u.operand;
1291 JSValue* result = jsNumber((r[val].u.jsValue->toUInt32(exec)) >> (r[shift].u.jsValue->toUInt32(exec)));
1292 VM_CHECK_EXCEPTION();
1293 r[dst].u.jsValue = result;
1294
1295 ++vPC;
1296 NEXT_OPCODE;
1297 }
1298 BEGIN_OPCODE(op_bitand) {
1299 /* bitand dst(r) src1(r) src2(r)
1300
1301 Computes bitwise AND of register src1 (converted to int32)
1302 and register src2 (converted to int32), and puts the result
1303 in register dst.
1304 */
1305 int dst = (++vPC)->u.operand;
1306 int src1 = (++vPC)->u.operand;
1307 int src2 = (++vPC)->u.operand;
1308 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) & (r[src2].u.jsValue->toInt32(exec)));
1309 VM_CHECK_EXCEPTION();
1310 r[dst].u.jsValue = result;
1311
1312 ++vPC;
1313 NEXT_OPCODE;
1314 }
1315 BEGIN_OPCODE(op_bitxor) {
1316 /* bitxor dst(r) src1(r) src2(r)
1317
1318 Computes bitwise XOR of register src1 (converted to int32)
1319 and register src2 (converted to int32), and puts the result
1320 in register dst.
1321 */
1322 int dst = (++vPC)->u.operand;
1323 int src1 = (++vPC)->u.operand;
1324 int src2 = (++vPC)->u.operand;
1325 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) ^ (r[src2].u.jsValue->toInt32(exec)));
1326 VM_CHECK_EXCEPTION();
1327 r[dst].u.jsValue = result;
1328
1329 ++vPC;
1330 NEXT_OPCODE;
1331 }
1332 BEGIN_OPCODE(op_bitor) {
1333 /* bitor dst(r) src1(r) src2(r)
1334
1335 Computes bitwise OR of register src1 (converted to int32)
1336 and register src2 (converted to int32), and puts the
1337 result in register dst.
1338 */
1339 int dst = (++vPC)->u.operand;
1340 int src1 = (++vPC)->u.operand;
1341 int src2 = (++vPC)->u.operand;
1342 JSValue* result = jsNumber((r[src1].u.jsValue->toInt32(exec)) | (r[src2].u.jsValue->toInt32(exec)));
1343 VM_CHECK_EXCEPTION();
1344 r[dst].u.jsValue = result;
1345
1346 ++vPC;
1347 NEXT_OPCODE;
1348 }
1349 BEGIN_OPCODE(op_bitnot) {
1350 /* bitnot dst(r) src(r)
1351
1352 Computes bitwise NOT of register src1 (converted to int32),
1353 and puts the result in register dst.
1354 */
1355 int dst = (++vPC)->u.operand;
1356 int src = (++vPC)->u.operand;
1357 JSValue* result = jsNumber(~r[src].u.jsValue->toInt32(exec));
1358 VM_CHECK_EXCEPTION();
1359 r[dst].u.jsValue = result;
1360
1361 ++vPC;
1362 NEXT_OPCODE;
1363 }
1364 BEGIN_OPCODE(op_not) {
1365 /* not dst(r) src1(r) src2(r)
1366
1367 Computes logical NOT of register src1 (converted to
1368 boolean), and puts the result in register dst.
1369 */
1370 int dst = (++vPC)->u.operand;
1371 int src = (++vPC)->u.operand;
1372 JSValue* result = jsBoolean(!r[src].u.jsValue->toBoolean(exec));
1373 VM_CHECK_EXCEPTION();
1374 r[dst].u.jsValue = result;
1375
1376 ++vPC;
1377 NEXT_OPCODE;
1378 }
1379 BEGIN_OPCODE(op_instanceof) {
1380 /* instanceof dst(r) value(r) constructor(r)
1381
1382 Tests whether register value is an instance of register
1383 constructor, and puts the boolean result in register dst.
1384
1385 Raises an exception if register constructor is not an
1386 object.
1387 */
1388 int dst = (++vPC)->u.operand;
1389 int value = (++vPC)->u.operand;
1390 int base = (++vPC)->u.operand;
1391
1392 JSValue* baseVal = r[base].u.jsValue;
1393
1394 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1395 goto vm_throw;
1396
1397 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1398 r[dst].u.jsValue = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].u.jsValue) : false);
1399
1400 ++vPC;
1401 NEXT_OPCODE;
1402 }
1403 BEGIN_OPCODE(op_typeof) {
1404 /* typeof dst(r) src(r)
1405
1406 Determines the type string for src according to ECMAScript
1407 rules, and puts the result in register dst.
1408 */
1409 int dst = (++vPC)->u.operand;
1410 int src = (++vPC)->u.operand;
1411 r[dst].u.jsValue = jsTypeStringForValue(r[src].u.jsValue);
1412
1413 ++vPC;
1414 NEXT_OPCODE;
1415 }
1416 BEGIN_OPCODE(op_in) {
1417 /* in dst(r) property(r) base(r)
1418
1419 Tests whether register base has a property named register
1420 property, and puts the boolean result in register dst.
1421
1422 Raises an exception if register constructor is not an
1423 object.
1424 */
1425 int dst = (++vPC)->u.operand;
1426 int property = (++vPC)->u.operand;
1427 int base = (++vPC)->u.operand;
1428
1429 JSValue* baseVal = r[base].u.jsValue;
1430 if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
1431 goto vm_throw;
1432
1433 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1434
1435 JSValue* propName = r[property].u.jsValue;
1436
1437 uint32_t i;
1438 if (propName->getUInt32(i))
1439 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, i));
1440 else {
1441 Identifier property(propName->toString(exec));
1442 VM_CHECK_EXCEPTION();
1443 r[dst].u.jsValue = jsBoolean(baseObj->hasProperty(exec, property));
1444 }
1445
1446 ++vPC;
1447 NEXT_OPCODE;
1448 }
1449 BEGIN_OPCODE(op_resolve) {
1450 /* resolve dst(r) property(id)
1451
1452 Looks up the property named by identifier property in the
1453 scope chain, and writes the resulting value to register
1454 dst. If the property is not found, raises an exception.
1455 */
1456 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1457 goto vm_throw;
1458
1459 vPC += 3;
1460 NEXT_OPCODE;
1461 }
1462 BEGIN_OPCODE(op_resolve_skip) {
1463 /* resolve_skip dst(r) property(id) skip(n)
1464
1465 Looks up the property named by identifier property in the
1466 scope chain skipping the top 'skip' levels, and writes the resulting
1467 value to register dst. If the property is not found, raises an exception.
1468 */
1469 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1470 goto vm_throw;
1471
1472 vPC += 4;
1473
1474 NEXT_OPCODE;
1475 }
1476 BEGIN_OPCODE(op_get_scoped_var) {
1477 /* get_scoped_var dst(r) index(n) skip(n)
1478
1479 Loads the contents of the index-th local from the scope skip nodes from
1480 the top of the scope chain, and places it in register dst
1481 */
1482 int dst = (++vPC)->u.operand;
1483 int index = (++vPC)->u.operand;
1484 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1485
1486 ScopeChainIterator iter = scopeChain->begin();
1487 ScopeChainIterator end = scopeChain->end();
1488 ASSERT(iter != end);
1489 while (skip--) {
1490 ++iter;
1491 ASSERT(iter != end);
1492 }
1493
1494 ASSERT((*iter)->isVariableObject());
1495 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1496 r[dst].u.jsValue = scope->valueAt(index);
1497 ++vPC;
1498 NEXT_OPCODE;
1499 }
1500 BEGIN_OPCODE(op_put_scoped_var) {
1501 /* put_scoped_var index(n) skip(n) value(r)
1502
1503 */
1504 int index = (++vPC)->u.operand;
1505 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1506 int value = (++vPC)->u.operand;
1507
1508 ScopeChainIterator iter = scopeChain->begin();
1509 ScopeChainIterator end = scopeChain->end();
1510 ASSERT(iter != end);
1511 while (skip--) {
1512 ++iter;
1513 ASSERT(iter != end);
1514 }
1515
1516 ASSERT((*iter)->isVariableObject());
1517 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1518 scope->valueAt(index) = r[value].u.jsValue;
1519 ++vPC;
1520 NEXT_OPCODE;
1521 }
1522 BEGIN_OPCODE(op_resolve_base) {
1523 /* resolve_base dst(r) property(id)
1524
1525 Searches the scope chain for an object containing
1526 identifier property, and if one is found, writes it to
1527 register dst. If none is found, the outermost scope (which
1528 will be the global object) is stored in register dst.
1529 */
1530 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1531
1532 vPC += 3;
1533 NEXT_OPCODE;
1534 }
1535 BEGIN_OPCODE(op_resolve_with_base) {
1536 /* resolve_with_base baseDst(r) propDst(r) property(id)
1537
1538 Searches the scope chain for an object containing
1539 identifier property, and if one is found, writes it to
1540 register srcDst, and the retrieved property value to register
1541 propDst. If the property is not found, raises an exception.
1542
1543 This is more efficient than doing resolve_base followed by
1544 resolve, or resolve_base followed by get_by_id, as it
1545 avoids duplicate hash lookups.
1546 */
1547 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1548 goto vm_throw;
1549
1550 vPC += 4;
1551 NEXT_OPCODE;
1552 }
1553 BEGIN_OPCODE(op_resolve_func) {
1554 /* resolve_func baseDst(r) funcDst(r) property(id)
1555
1556 Searches the scope chain for an object containing
1557 identifier property, and if one is found, writes the
1558 appropriate object to use as "this" when calling its
1559 properties to register baseDst; and the retrieved property
1560 value to register propDst. If the property is not found,
1561 raises an exception.
1562
1563 This differs from resolve_with_base, because the
1564 global this value will be substituted for activations or
1565 the global object, which is the right behavior for function
1566 calls but not for other property lookup.
1567 */
1568 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1569 goto vm_throw;
1570
1571 vPC += 4;
1572 NEXT_OPCODE;
1573 }
1574 BEGIN_OPCODE(op_get_by_id) {
1575 /* get_by_id dst(r) base(r) property(id)
1576
1577 Converts register base to Object, gets the property
1578 named by identifier property from the object, and puts the
1579 result in register dst.
1580 */
1581 int dst = (++vPC)->u.operand;
1582 int base = (++vPC)->u.operand;
1583 int property = (++vPC)->u.operand;
1584#ifndef NDEBUG
1585 int registerOffset = r - (*registerBase);
1586#endif
1587 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1588
1589 Identifier& ident = codeBlock->identifiers[property];
1590 JSValue *result = baseObj->get(exec, ident);
1591 ASSERT(registerOffset == (r - (*registerBase)));
1592 VM_CHECK_EXCEPTION();
1593 r[dst].u.jsValue = result;
1594 ++vPC;
1595 NEXT_OPCODE;
1596 }
1597 BEGIN_OPCODE(op_put_by_id) {
1598 /* put_by_id base(r) property(id) value(r)
1599
1600 Sets register value on register base as the property named
1601 by identifier property. Base is converted to object first.
1602
1603 Unlike many opcodes, this one does not write any output to
1604 the register file.
1605 */
1606 int base = (++vPC)->u.operand;
1607 int property = (++vPC)->u.operand;
1608 int value = (++vPC)->u.operand;
1609#ifndef NDEBUG
1610 int registerOffset = r - (*registerBase);
1611#endif
1612
1613 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1614
1615 Identifier& ident = codeBlock->identifiers[property];
1616 baseObj->put(exec, ident, r[value].u.jsValue);
1617 ASSERT(registerOffset == (r - (*registerBase)));
1618
1619 VM_CHECK_EXCEPTION();
1620 ++vPC;
1621 NEXT_OPCODE;
1622 }
1623 BEGIN_OPCODE(op_del_by_id) {
1624 /* del_by_id dst(r) base(r) property(id)
1625
1626 Converts register base to Object, deletes the property
1627 named by identifier property from the object, and writes a
1628 boolean indicating success (if true) or failure (if false)
1629 to register dst.
1630 */
1631 int dst = (++vPC)->u.operand;
1632 int base = (++vPC)->u.operand;
1633 int property = (++vPC)->u.operand;
1634
1635 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1636
1637 Identifier& ident = codeBlock->identifiers[property];
1638 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1639 VM_CHECK_EXCEPTION();
1640 r[dst].u.jsValue = result;
1641 ++vPC;
1642 NEXT_OPCODE;
1643 }
1644 BEGIN_OPCODE(op_get_by_val) {
1645 /* get_by_val dst(r) base(r) property(r)
1646
1647 Converts register base to Object, gets the property named
1648 by register property from the object, and puts the result
1649 in register dst. property is nominally converted to string
1650 but numbers are treated more efficiently.
1651 */
1652 int dst = (++vPC)->u.operand;
1653 int base = (++vPC)->u.operand;
1654 int property = (++vPC)->u.operand;
1655
1656 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1657
1658 JSValue* subscript = r[property].u.jsValue;
1659 JSValue* result;
1660 uint32_t i;
1661 if (subscript->getUInt32(i))
1662 result = baseObj->get(exec, i);
1663 else {
1664 Identifier property;
1665 if (subscript->isObject()) {
1666 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1667 property = Identifier(subscript->toString(exec));
1668 } else
1669 property = Identifier(subscript->toString(exec));
1670
1671 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a getter after an exception is thrown
1672 result = baseObj->get(exec, property);
1673 }
1674
1675 VM_CHECK_EXCEPTION();
1676 r[dst].u.jsValue = result;
1677 ++vPC;
1678 NEXT_OPCODE;
1679 }
1680 BEGIN_OPCODE(op_put_by_val) {
1681 /* put_by_val base(r) property(r) value(r)
1682
1683 Sets register value on register base as the property named
1684 by register property. Base is converted to object
1685 first. register property is nominally converted to string
1686 but numbers are treated more efficiently.
1687
1688 Unlike many opcodes, this one does not write any output to
1689 the register file.
1690 */
1691 int base = (++vPC)->u.operand;
1692 int property = (++vPC)->u.operand;
1693 int value = (++vPC)->u.operand;
1694
1695 JSObject* baseObj = r[base].u.jsValue->toObject(exec);
1696
1697 JSValue* subscript = r[property].u.jsValue;
1698
1699 uint32_t i;
1700 if (subscript->getUInt32(i))
1701 baseObj->put(exec, i, r[value].u.jsValue);
1702 else {
1703 Identifier property;
1704 if (subscript->isObject()) {
1705 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1706 property = Identifier(subscript->toString(exec));
1707 } else
1708 property = Identifier(subscript->toString(exec));
1709
1710 VM_CHECK_EXCEPTION(); // This check is needed to prevent us from incorrectly calling a setter after an exception is thrown
1711 baseObj->put(exec, property, r[value].u.jsValue);
1712 }
1713
1714 VM_CHECK_EXCEPTION();
1715 ++vPC;
1716 NEXT_OPCODE;
1717 }
1718 BEGIN_OPCODE(op_del_by_val) {
1719 /* del_by_val dst(r) base(r) property(r)
1720
1721 Converts register base to Object, deletes the property
1722 named by register property from the object, and writes a
1723 boolean indicating success (if true) or failure (if false)
1724 to register dst.
1725 */
1726 int dst = (++vPC)->u.operand;
1727 int base = (++vPC)->u.operand;
1728 int property = (++vPC)->u.operand;
1729
1730 JSObject* baseObj = r[base].u.jsValue->toObject(exec); // may throw
1731
1732 JSValue* subscript = r[property].u.jsValue;
1733 JSValue* result;
1734 uint32_t i;
1735 if (subscript->getUInt32(i))
1736 result = jsBoolean(baseObj->deleteProperty(exec, i));
1737 else {
1738 VM_CHECK_EXCEPTION(); // If toObject threw, we must not call toString, which may execute arbitrary code
1739 Identifier property(subscript->toString(exec));
1740 VM_CHECK_EXCEPTION();
1741 result = jsBoolean(baseObj->deleteProperty(exec, property));
1742 }
1743
1744 VM_CHECK_EXCEPTION();
1745 r[dst].u.jsValue = result;
1746 ++vPC;
1747 NEXT_OPCODE;
1748 }
1749 BEGIN_OPCODE(op_put_by_index) {
1750 /* put_by_index base(r) property(n) value(r)
1751
1752 Sets register value on register base as the property named
1753 by the immediate number property. Base is converted to
1754 object first. register property is nominally converted to
1755 string but numbers are treated more efficiently.
1756
1757 Unlike many opcodes, this one does not write any output to
1758 the register file.
1759
1760 This opcode is mainly used to initialize array literals.
1761 */
1762 int base = (++vPC)->u.operand;
1763 unsigned property = (++vPC)->u.operand;
1764 int value = (++vPC)->u.operand;
1765
1766 r[base].u.jsObject->put(exec, property, r[value].u.jsValue);
1767
1768 ++vPC;
1769 NEXT_OPCODE;
1770 }
1771 BEGIN_OPCODE(op_jmp) {
1772 /* jmp target(offset)
1773
1774 Jumps unconditionally to offset target from the current
1775 instruction.
1776 */
1777 int target = (++vPC)->u.operand;
1778
1779 vPC += target;
1780 NEXT_OPCODE;
1781 }
1782 BEGIN_OPCODE(op_jtrue) {
1783 /* jtrue cond(r) target(offset)
1784
1785 Jumps to offset target from the current instruction, if and
1786 only if register cond converts to boolean as true.
1787 */
1788 int cond = (++vPC)->u.operand;
1789 int target = (++vPC)->u.operand;
1790 if (r[cond].u.jsValue->toBoolean(exec)) {
1791 vPC += target;
1792 NEXT_OPCODE;
1793 }
1794
1795 ++vPC;
1796 NEXT_OPCODE;
1797 }
1798 BEGIN_OPCODE(op_jfalse) {
1799 /* jfalse cond(r) target(offset)
1800
1801 Jumps to offset target from the current instruction, if and
1802 only if register cond converts to boolean as false.
1803 */
1804 int cond = (++vPC)->u.operand;
1805 int target = (++vPC)->u.operand;
1806 if (!r[cond].u.jsValue->toBoolean(exec)) {
1807 vPC += target;
1808 NEXT_OPCODE;
1809 }
1810
1811 ++vPC;
1812 NEXT_OPCODE;
1813 }
1814 BEGIN_OPCODE(op_new_func) {
1815 /* new_func dst(r) func(f)
1816
1817 Constructs a new Function instance from function func and
1818 the current scope chain using the original Function
1819 constructor, using the rules for function declarations, and
1820 puts the result in register dst.
1821 */
1822 int dst = (++vPC)->u.operand;
1823 int func = (++vPC)->u.operand;
1824
1825 r[dst].u.jsValue = codeBlock->functions[func]->makeFunction(exec, scopeChain);
1826
1827 ++vPC;
1828 NEXT_OPCODE;
1829 }
1830 BEGIN_OPCODE(op_new_func_exp) {
1831 /* new_func_exp dst(r) func(f)
1832
1833 Constructs a new Function instance from function func and
1834 the current scope chain using the original Function
1835 constructor, using the rules for function expressions, and
1836 puts the result in register dst.
1837 */
1838 int dst = (++vPC)->u.operand;
1839 int func = (++vPC)->u.operand;
1840
1841 r[dst].u.jsValue = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
1842
1843 ++vPC;
1844 NEXT_OPCODE;
1845 }
1846 BEGIN_OPCODE(op_call_eval) {
1847 int dst = (++vPC)->u.operand;
1848 int func = (++vPC)->u.operand;
1849 int base = (++vPC)->u.operand;
1850 int argv = (++vPC)->u.operand;
1851 int argc = (++vPC)->u.operand;
1852
1853 JSValue* funcVal = r[func].u.jsValue;
1854 JSValue* baseVal = r[base].u.jsValue;
1855
1856 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
1857 int registerOffset = r - (*registerBase);
1858
1859 JSObject* thisObject = r[codeBlock->thisRegister].u.jsObject;
1860
1861 registerFile->setSafeForReentry(true);
1862
1863 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, argv, argc, exceptionValue);
1864
1865 registerFile->setSafeForReentry(false);
1866 r = (*registerBase) + registerOffset;
1867
1868 if (exceptionValue)
1869 goto vm_throw;
1870
1871 r[dst].u.jsValue = result;
1872
1873 ++vPC;
1874 NEXT_OPCODE;
1875 }
1876
1877 // We didn't find the blessed version of eval, so reset vPC and process
1878 // this instruction as a normal function call, supplying the proper 'this'
1879 // value.
1880 vPC -= 5;
1881 r[base].u.jsValue = baseVal->toObject(exec)->toThisObject(exec);
1882
1883#if HAVE(COMPUTED_GOTO)
1884 // Hack around gcc performance quirk by performing an indirect goto
1885 // in order to set the vPC -- attempting to do so directly results in a
1886 // significant regression.
1887 goto *op_call_indirect; // indirect goto -> op_call
1888#endif
1889 // fall through to op_call
1890 }
1891 BEGIN_OPCODE(op_call) {
1892 int dst = (++vPC)->u.operand;
1893 int func = (++vPC)->u.operand;
1894 int base = (++vPC)->u.operand;
1895 int argv = (++vPC)->u.operand;
1896 int argc = (++vPC)->u.operand;
1897
1898 JSValue* v = r[func].u.jsValue;
1899
1900 CallData callData;
1901 CallType callType = v->getCallData(callData);
1902
1903 if (callType == CallTypeJS) {
1904 if (*enabledProfilerReference)
1905 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
1906 int registerOffset = r - (*registerBase);
1907 Register* callFrame = r + argv - CallFrameHeaderSize;
1908 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
1909
1910 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : r[base].u.jsValue; // "this" value
1911 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 0, v);
1912
1913 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
1914 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
1915
1916 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
1917 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
1918 if (UNLIKELY(exceptionValue != 0))
1919 goto vm_throw;
1920
1921 codeBlock = newCodeBlock;
1922 exec->m_callFrameOffset = callFrameOffset;
1923 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
1924 k = codeBlock->jsValues.data();
1925 vPC = codeBlock->instructions.begin();
1926
1927 NEXT_OPCODE;
1928 }
1929
1930 if (callType == CallTypeNative) {
1931 if (*enabledProfilerReference)
1932 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
1933 int registerOffset = r - (*registerBase);
1934
1935 r[argv].u.jsValue = base == missingThisObjectMarker() ? exec->globalThisValue() : (r[base].u.jsValue)->toObject(exec); // "this" value
1936 JSObject* thisObj = static_cast<JSObject*>(r[argv].u.jsValue);
1937
1938 List args(&r[argv + 1].u.jsValue, argc - 1);
1939
1940 registerFile->setSafeForReentry(true);
1941 JSValue* returnValue = static_cast<JSObject*>(v)->callAsFunction(exec, thisObj, args);
1942 registerFile->setSafeForReentry(false);
1943
1944 r = (*registerBase) + registerOffset;
1945 r[dst].u.jsValue = returnValue;
1946
1947 if (*enabledProfilerReference)
1948 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
1949 VM_CHECK_EXCEPTION();
1950
1951 ++vPC;
1952 NEXT_OPCODE;
1953 }
1954
1955 ASSERT(callType == CallTypeNone);
1956
1957 exceptionValue = createNotAFunctionError(exec, v, 0);
1958 goto vm_throw;
1959 }
1960 BEGIN_OPCODE(op_ret) {
1961 int r1 = (++vPC)->u.operand;
1962
1963 CodeBlock* oldCodeBlock = codeBlock;
1964
1965 Register* callFrame = r - oldCodeBlock->numLocals - CallFrameHeaderSize;
1966 JSValue* returnValue = r[r1].u.jsValue;
1967
1968 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue)) {
1969 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
1970 ASSERT(activation->isActivationObject());
1971 activation->copyRegisters();
1972 }
1973
1974 if (codeBlock->needsFullScopeChain)
1975 scopeChain->deref();
1976
1977 if (callFrame[CalledAsConstructor].u.i && !returnValue->isObject()) {
1978 JSValue* thisObject = callFrame[CallFrameHeaderSize].u.jsValue;
1979 returnValue = thisObject;
1980 }
1981
1982 codeBlock = callFrame[CallerCodeBlock].u.codeBlock;
1983 if (!codeBlock)
1984 return returnValue;
1985
1986 k = codeBlock->jsValues.data();
1987 vPC = callFrame[ReturnVPC].u.vPC;
1988 setScopeChain(exec, scopeChain, callFrame[CallerScopeChain].u.scopeChain);
1989 int callerRegisterOffset = callFrame[CallerRegisterOffset].u.i;
1990 r = (*registerBase) + callerRegisterOffset;
1991 exec->m_callFrameOffset = callerRegisterOffset - codeBlock->numLocals - CallFrameHeaderSize;
1992 int r0 = callFrame[ReturnValueRegister].u.i;
1993 r[r0].u.jsValue = returnValue;
1994
1995 if (*enabledProfilerReference)
1996 (*enabledProfilerReference)->didExecute(exec, callFrame[Callee].u.jsObject);
1997
1998 NEXT_OPCODE;
1999 }
2000 BEGIN_OPCODE(op_construct) {
2001 int dst = (++vPC)->u.operand;
2002 int func = (++vPC)->u.operand;
2003 int argv = (++vPC)->u.operand;
2004 int argc = (++vPC)->u.operand;
2005
2006 JSValue* funcVal = r[func].u.jsValue;
2007
2008 ConstructData constructData;
2009 ConstructType constructType = funcVal->getConstructData(constructData);
2010
2011 // Removing this line of code causes a measurable regression on squirrelfish.
2012 JSObject* constructor = static_cast<JSObject*>(funcVal);
2013
2014 if (constructType == ConstructTypeJS) {
2015 if (*enabledProfilerReference)
2016 (*enabledProfilerReference)->willExecute(exec, constructor);
2017
2018 int registerOffset = r - (*registerBase);
2019 Register* callFrame = r + argv - CallFrameHeaderSize;
2020 int callFrameOffset = registerOffset + argv - CallFrameHeaderSize;
2021
2022 JSObject* prototype;
2023 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2024 if (p->isObject())
2025 prototype = static_cast<JSObject*>(p);
2026 else
2027 prototype = scopeChain->globalObject()->objectPrototype();
2028 JSObject* newObject = new JSObject(prototype);
2029 r[argv].u.jsValue = newObject; // "this" value
2030
2031 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, registerOffset, dst, argv, argc, 1, constructor);
2032
2033 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2034 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2035
2036 CodeBlock* newCodeBlock = &functionBodyNode->code(callDataScopeChain);
2037 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, registerOffset, argv, argc, exceptionValue);
2038 if (exceptionValue)
2039 goto vm_throw;
2040
2041 codeBlock = newCodeBlock;
2042 exec->m_callFrameOffset = callFrameOffset;
2043 setScopeChain(exec, scopeChain, scopeChainForCall(functionBodyNode, codeBlock, callDataScopeChain, registerBase, r));
2044 k = codeBlock->jsValues.data();
2045 vPC = codeBlock->instructions.begin();
2046
2047 NEXT_OPCODE;
2048 }
2049
2050 if (constructType == ConstructTypeNative) {
2051 if (*enabledProfilerReference)
2052 (*enabledProfilerReference)->willExecute(exec, constructor);
2053
2054 int registerOffset = r - (*registerBase);
2055
2056 List args(&r[argv + 1].u.jsValue, argc - 1);
2057 registerFile->setSafeForReentry(true);
2058 JSValue* returnValue = constructor->construct(exec, args);
2059 registerFile->setSafeForReentry(false);
2060
2061 r = (*registerBase) + registerOffset;
2062 VM_CHECK_EXCEPTION();
2063 r[dst].u.jsValue = returnValue;
2064
2065 if (*enabledProfilerReference)
2066 (*enabledProfilerReference)->didExecute(exec, constructor);
2067
2068 ++vPC;
2069 NEXT_OPCODE;
2070 }
2071
2072 ASSERT(constructType == ConstructTypeNone);
2073
2074 exceptionValue = createNotAConstructorError(exec, funcVal, 0);
2075 goto vm_throw;
2076 }
2077 BEGIN_OPCODE(op_push_scope) {
2078 /* push_scope scope(r)
2079
2080 Converts register scope to object, and pushes it onto the top
2081 of the current scope chain.
2082 */
2083 int scope = (++vPC)->u.operand;
2084 JSValue* v = r[scope].u.jsValue;
2085 JSObject* o = v->toObject(exec);
2086 VM_CHECK_EXCEPTION();
2087
2088 setScopeChain(exec, scopeChain, scopeChain->push(o));
2089
2090 ++vPC;
2091 NEXT_OPCODE;
2092 }
2093 BEGIN_OPCODE(op_pop_scope) {
2094 /* pop_scope
2095
2096 Removes the top item from the current scope chain.
2097 */
2098 setScopeChain(exec, scopeChain, scopeChain->pop());
2099
2100 ++vPC;
2101 NEXT_OPCODE;
2102 }
2103 BEGIN_OPCODE(op_get_pnames) {
2104 /* get_pnames dst(r) base(r)
2105
2106 Creates a property name list for register base and puts it
2107 in register dst. This is not a true JavaScript value, just
2108 a synthetic value used to keep the iteration state in a
2109 register.
2110 */
2111 int dst = (++vPC)->u.operand;
2112 int base = (++vPC)->u.operand;
2113
2114 r[dst].u.jsPropertyNameIterator = JSPropertyNameIterator::create(exec, r[base].u.jsValue);
2115 ++vPC;
2116 NEXT_OPCODE;
2117 }
2118 BEGIN_OPCODE(op_next_pname) {
2119 /* next_pname dst(r) iter(r) target(offset)
2120
2121 Tries to copies the next name from property name list in
2122 register iter. If there are names left, then copies one to
2123 register dst, and jumps to offset target. If there are none
2124 left, invalidates the iterator and continues to the next
2125 instruction.
2126 */
2127 int dst = (++vPC)->u.operand;
2128 int iter = (++vPC)->u.operand;
2129 int target = (++vPC)->u.operand;
2130
2131 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator;
2132 if (JSValue* temp = it->next(exec)) {
2133 r[dst].u.jsValue = temp;
2134 vPC += target;
2135 NEXT_OPCODE;
2136 }
2137 it->invalidate();
2138
2139 ++vPC;
2140 NEXT_OPCODE;
2141 }
2142 BEGIN_OPCODE(op_jmp_scopes) {
2143 /* jmp_scopes count(n) target(offset)
2144
2145 Removes the a number of items from the current scope chain
2146 specified by immediate number count, then jumps to offset
2147 target.
2148 */
2149 int count = (++vPC)->u.operand;
2150 int target = (++vPC)->u.operand;
2151
2152 ScopeChainNode* tmp = scopeChain;
2153 while (count--)
2154 tmp = tmp->pop();
2155 setScopeChain(exec, scopeChain, tmp);
2156
2157 vPC += target;
2158 NEXT_OPCODE;
2159 }
2160 BEGIN_OPCODE(op_catch) {
2161 ASSERT(exceptionValue);
2162 ASSERT(!exec->hadException());
2163 int r0 = (++vPC)->u.operand;
2164 r[r0].u.jsValue = exceptionValue;
2165 exceptionValue = 0;
2166 ++vPC;
2167 NEXT_OPCODE;
2168 }
2169 BEGIN_OPCODE(op_throw) {
2170 int e = (++vPC)->u.operand;
2171 exceptionValue = r[e].u.jsValue;
2172 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2173 if (!handlerVPC) {
2174 *exception = exceptionValue;
2175 return jsNull();
2176 }
2177
2178#if HAVE(COMPUTED_GOTO)
2179 // Hack around gcc performance quirk by performing an indirect goto
2180 // in order to set the vPC -- attempting to do so directly results in a
2181 // significant regression.
2182 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2183 }
2184 op_throw_end: {
2185#endif
2186
2187 vPC = handlerVPC;
2188 NEXT_OPCODE;
2189 }
2190 BEGIN_OPCODE(op_new_error) {
2191 /* new_error dst(r) type(n) message(k)
2192
2193 Constructs a new Error instance using the original
2194 constructor, using immediate number n as the type and
2195 constant message as the message string. The result is
2196 written to register dst.
2197 */
2198 int dst = (++vPC)->u.operand;
2199 int type = (++vPC)->u.operand;
2200 int message = (++vPC)->u.operand;
2201
2202 r[dst].u.jsValue = Error::create(exec, (ErrorType)type, k[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2203
2204 ++vPC;
2205 NEXT_OPCODE;
2206 }
2207 BEGIN_OPCODE(op_end) {
2208 if (codeBlock->needsFullScopeChain) {
2209 ASSERT(scopeChain->refCount > 1);
2210 scopeChain->deref();
2211 }
2212 int r0 = (++vPC)->u.operand;
2213 return r[r0].u.jsValue;
2214 }
2215 BEGIN_OPCODE(op_put_getter) {
2216 /* put_getter base(r) property(id) function(r)
2217
2218 Sets register function on register base as the getter named
2219 by identifier property. Base and function are assumed to be
2220 objects as this op should only be used for getters defined
2221 in object literal form.
2222
2223 Unlike many opcodes, this one does not write any output to
2224 the register file.
2225 */
2226 int base = (++vPC)->u.operand;
2227 int property = (++vPC)->u.operand;
2228 int function = (++vPC)->u.operand;
2229
2230 ASSERT(r[base].u.jsValue->isObject());
2231 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2232 Identifier& ident = codeBlock->identifiers[property];
2233 ASSERT(r[function].u.jsValue->isObject());
2234 baseObj->defineGetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2235
2236 ++vPC;
2237 NEXT_OPCODE;
2238 }
2239 BEGIN_OPCODE(op_put_setter) {
2240 /* put_setter base(r) property(id) function(r)
2241
2242 Sets register function on register base as the setter named
2243 by identifier property. Base and function are assumed to be
2244 objects as this op should only be used for setters defined
2245 in object literal form.
2246
2247 Unlike many opcodes, this one does not write any output to
2248 the register file.
2249 */
2250 int base = (++vPC)->u.operand;
2251 int property = (++vPC)->u.operand;
2252 int function = (++vPC)->u.operand;
2253
2254 ASSERT(r[base].u.jsValue->isObject());
2255 JSObject* baseObj = static_cast<JSObject*>(r[base].u.jsValue);
2256 Identifier& ident = codeBlock->identifiers[property];
2257 ASSERT(r[function].u.jsValue->isObject());
2258 baseObj->defineSetter(exec, ident, static_cast<JSObject* >(r[function].u.jsValue));
2259
2260 ++vPC;
2261 NEXT_OPCODE;
2262 }
2263 BEGIN_OPCODE(op_jsr) {
2264 /* jsr retAddrDst(r) target(offset)
2265
2266 Places the address of the next instruction into the retAddrDst
2267 register and jumps to offset target from the current instruction.
2268 */
2269 int retAddrDst = (++vPC)->u.operand;
2270 int target = (++vPC)->u.operand;
2271 r[retAddrDst].u.vPC = vPC + 1;
2272
2273 vPC += target;
2274 NEXT_OPCODE;
2275 }
2276 BEGIN_OPCODE(op_sret) {
2277 /* sret retAddrSrc(r)
2278
2279 Jumps to the address stored in the retAddrSrc register. This
2280 differs from op_jmp because the target address is stored in a
2281 register, not as an immediate.
2282 */
2283 int retAddrSrc = (++vPC)->u.operand;
2284 vPC = r[retAddrSrc].u.vPC;
2285 NEXT_OPCODE;
2286 }
2287 BEGIN_OPCODE(op_debug) {
2288 /* debug debugHookID(n) firstLine(n) lastLine(n)
2289
2290 Notifies the debugger of the current state of execution:
2291 didEnterCallFrame; willLeaveCallFrame; or willExecuteStatement.
2292
2293 This opcode is only generated while the debugger is attached.
2294 */
2295
2296 int registerOffset = r - (*registerBase);
2297 registerFile->setSafeForReentry(true);
2298 debug(exec, vPC, codeBlock, scopeChain, registerBase, r);
2299 registerFile->setSafeForReentry(false);
2300 r = (*registerBase) + registerOffset;
2301
2302 vPC += 4;
2303 NEXT_OPCODE;
2304 }
2305 vm_throw: {
2306 exec->clearException();
2307 handlerVPC = throwException(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r);
2308 if (!handlerVPC) {
2309 *exception = exceptionValue;
2310 return jsNull();
2311 }
2312 vPC = handlerVPC;
2313 NEXT_OPCODE;
2314 }
2315 }
2316 #undef NEXT_OPCODE
2317 #undef BEGIN_OPCODE
2318 #undef VM_CHECK_EXCEPTION
2319}
2320
2321JSValue* Machine::retrieveArguments(ExecState* exec, FunctionImp* function) const
2322{
2323 Register** registerBase;
2324 int callFrameOffset;
2325
2326 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2327 return jsNull();
2328
2329 Register* callFrame = (*registerBase) + callFrameOffset;
2330 JSActivation* activation = static_cast<JSActivation*>(callFrame[OptionalCalleeActivation].u.jsValue);
2331 if (!activation) {
2332 CodeBlock* codeBlock = &function->body->generatedCode();
2333 activation = new JSActivation(function->body, registerBase, callFrameOffset + CallFrameHeaderSize + codeBlock->numLocals);
2334 callFrame[OptionalCalleeActivation].u.jsValue = activation;
2335 }
2336
2337 return activation->get(exec, exec->propertyNames().arguments);
2338}
2339
2340JSValue* Machine::retrieveCaller(ExecState* exec, FunctionImp* function) const
2341{
2342 Register** registerBase;
2343 int callFrameOffset;
2344
2345 if (!getCallFrame(exec, function, registerBase, callFrameOffset))
2346 return jsNull();
2347
2348 int callerFrameOffset;
2349 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callerFrameOffset))
2350 return jsNull();
2351
2352 Register* callerFrame = (*registerBase) + callerFrameOffset;
2353 ASSERT(callerFrame[Callee].u.jsValue);
2354 return callerFrame[Callee].u.jsValue;
2355}
2356
2357bool Machine::getCallFrame(ExecState* exec, FunctionImp* function, Register**& registerBase, int& callFrameOffset) const
2358{
2359 callFrameOffset = exec->m_callFrameOffset;
2360
2361 while (1) {
2362 while (callFrameOffset < 0) {
2363 exec = exec->m_prev;
2364 if (!exec)
2365 return false;
2366 callFrameOffset = exec->m_callFrameOffset;
2367 }
2368
2369 registerBase = exec->m_registerFile->basePointer();
2370 Register* callFrame = (*registerBase) + callFrameOffset;
2371 if (callFrame[Callee].u.jsValue == function)
2372 return true;
2373
2374 if (!getCallerFunctionOffset(registerBase, callFrameOffset, callFrameOffset))
2375 callFrameOffset = -1;
2376 }
2377}
2378
2379void Machine::getFunctionAndArguments(Register** registerBase, Register* callFrame, FunctionImp*& function, Register*& argv, int& argc)
2380{
2381 function = static_cast<FunctionImp*>(callFrame[Callee].u.jsValue);
2382 ASSERT(function->inherits(&FunctionImp::info));
2383
2384 argv = (*registerBase) + callFrame[CallerRegisterOffset].u.i + callFrame[ArgumentStartRegister].u.i + 1; // skip "this"
2385 argc = callFrame[ArgumentCount].u.i - 1; // skip "this"
2386}
2387
2388} // namespace KJS
Note: See TracBrowser for help on using the repository browser.