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

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

<rdar://problem/6111648> JavaScript exceptions fail if the scope chain includes the global object

Reviewed by Alexey Proskuryakov.

In an attempt to remove the branch I just added to KJS::depth I
used the existence of a Variable Object at a point in the scope
chain as an indicator of function or global scope activation.
However this assumption results in incorrect behaviour if the
global object is injected into the scope chain with 'with'.

File size: 102.7 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 "GlobalEvalFunction.h"
38#include "JSActivation.h"
39#include "JSArray.h"
40#include "JSFunction.h"
41#include "JSNotAnObject.h"
42#include "JSPropertyNameIterator.h"
43#include "JSString.h"
44#include "ObjectPrototype.h"
45#include "Parser.h"
46#include "Profiler.h"
47#include "RegExpObject.h"
48#include "RegExpPrototype.h"
49#include "Register.h"
50#include "collector.h"
51#include "debugger.h"
52#include "operations.h"
53#include <stdio.h>
54
55#if HAVE(SYS_TIME_H)
56#include <sys/time.h>
57#endif
58
59#if PLATFORM(WIN_OS)
60#include <windows.h>
61#endif
62
63#if PLATFORM(QT)
64#include <QDateTime>
65#endif
66
67using namespace std;
68
69namespace KJS {
70
71// Default number of ticks before a timeout check should be done.
72static const int initialTickCountThreshold = 255;
73
74// Preferred number of milliseconds between each timeout check
75static const int preferredScriptCheckTimeInterval = 1000;
76
77#if HAVE(COMPUTED_GOTO)
78static void* op_throw_end_indirect;
79static void* op_call_indirect;
80#endif
81
82// Returns the depth of the scope chain within a given call frame.
83static int depth(ScopeChain& sc)
84{
85 int scopeDepth = 0;
86 ScopeChainIterator iter = sc.begin();
87 ScopeChainIterator end = sc.end();
88 while (!(*iter)->isActivationObject()) {
89 ++iter;
90 if (iter == end)
91 break;
92 ++scopeDepth;
93 }
94 return scopeDepth;
95}
96
97static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
98{
99 if (JSImmediate::areBothImmediateNumbers(v1, v2))
100 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
101
102 double n1;
103 double n2;
104 JSValue* p1;
105 JSValue* p2;
106 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
107 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
108
109 if (wasNotString1 | wasNotString2)
110 return n1 < n2;
111
112 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
113}
114
115static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
116{
117 if (JSImmediate::areBothImmediateNumbers(v1, v2))
118 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
119
120 double n1;
121 double n2;
122 JSValue* p1;
123 JSValue* p2;
124 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
125 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
126
127 if (wasNotString1 | wasNotString2)
128 return n1 <= n2;
129
130 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
131}
132
133static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
134{
135 // exception for the Date exception in defaultValue()
136 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
137 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
138
139 if (p1->isString() || p2->isString()) {
140 UString value = p1->toString(exec) + p2->toString(exec);
141 if (value.isNull())
142 return throwOutOfMemoryError(exec);
143 return jsString(exec, value);
144 }
145
146 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
147}
148
149// Fast-path choices here are based on frequency data from SunSpider:
150// <times> Add case: <t1> <t2>
151// ---------------------------
152// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
153// 247412 Add case: 5 5
154// 20900 Add case: 5 6
155// 13962 Add case: 5 3
156// 4000 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(exec, v1->uncheckedGetNumber() + v2->uncheckedGetNumber());
166 if (bothTypes == ((StringType << 3) | StringType)) {
167 UString value = static_cast<JSString*>(v1)->value() + static_cast<JSString*>(v2)->value();
168 if (value.isNull())
169 return throwOutOfMemoryError(exec);
170 return jsString(exec, value);
171 }
172
173 // All other cases are pretty uncommon
174 return jsAddSlowCase(exec, v1, v2);
175}
176
177static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
178{
179 switch (v->type()) {
180 case UndefinedType:
181 return jsString(exec, "undefined");
182 case NullType:
183 return jsString(exec, "object");
184 case BooleanType:
185 return jsString(exec, "boolean");
186 case NumberType:
187 return jsString(exec, "number");
188 case StringType:
189 return jsString(exec, "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(exec, "undefined");
196 CallData callData;
197 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
198 return jsString(exec, "function");
199 }
200
201 return jsString(exec, "object");
202 }
203}
204
205static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
206{
207 int dst = (vPC + 1)->u.operand;
208 int property = (vPC + 2)->u.operand;
209
210 ScopeChainIterator iter = scopeChain->begin();
211 ScopeChainIterator end = scopeChain->end();
212 ASSERT(iter != end);
213
214 Identifier& ident = codeBlock->identifiers[property];
215 do {
216 JSObject* o = *iter;
217 PropertySlot slot(o);
218 if (o->getPropertySlot(exec, ident, slot)) {
219 JSValue* result = slot.getValue(exec, ident);
220 exceptionValue = exec->exception();
221 if (exceptionValue)
222 return false;
223 r[dst] = result;
224 return true;
225 }
226 } while (++iter != end);
227 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
228 return false;
229}
230
231static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
232{
233 int dst = (vPC + 1)->u.operand;
234 int property = (vPC + 2)->u.operand;
235 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
236
237 ScopeChainIterator iter = scopeChain->begin();
238 ScopeChainIterator end = scopeChain->end();
239 ASSERT(iter != end);
240 while (skip--) {
241 ++iter;
242 ASSERT(iter != end);
243 }
244 Identifier& ident = codeBlock->identifiers[property];
245 do {
246 JSObject* o = *iter;
247 PropertySlot slot(o);
248 if (o->getPropertySlot(exec, ident, slot)) {
249 JSValue* result = slot.getValue(exec, ident);
250 exceptionValue = exec->exception();
251 if (exceptionValue)
252 return false;
253 r[dst] = result;
254 return true;
255 }
256 } while (++iter != end);
257 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
258 return false;
259}
260
261static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
262{
263 int dst = (vPC + 1)->u.operand;
264 int property = (vPC + 2)->u.operand;
265
266 ScopeChainIterator iter = scopeChain->begin();
267 ScopeChainIterator next = iter;
268 ++next;
269 ScopeChainIterator end = scopeChain->end();
270 ASSERT(iter != end);
271
272 PropertySlot slot;
273 Identifier& ident = codeBlock->identifiers[property];
274 JSObject* base;
275 while (true) {
276 base = *iter;
277 if (next == end || base->getPropertySlot(exec, ident, slot)) {
278 r[dst] = base;
279 return;
280 }
281 iter = next;
282 ++next;
283 }
284}
285
286static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
287{
288 int baseDst = (vPC + 1)->u.operand;
289 int propDst = (vPC + 2)->u.operand;
290 int property = (vPC + 3)->u.operand;
291
292 ScopeChainIterator iter = scopeChain->begin();
293 ScopeChainIterator end = scopeChain->end();
294
295 // FIXME: add scopeDepthIsZero optimization
296
297 ASSERT(iter != end);
298
299 Identifier& ident = codeBlock->identifiers[property];
300 JSObject* base;
301 do {
302 base = *iter;
303 PropertySlot slot(base);
304 if (base->getPropertySlot(exec, ident, slot)) {
305 JSValue* result = slot.getValue(exec, ident);
306 exceptionValue = exec->exception();
307 if (exceptionValue)
308 return false;
309 r[propDst] = result;
310 r[baseDst] = base;
311 return true;
312 }
313 ++iter;
314 } while (iter != end);
315
316 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
317 return false;
318}
319
320static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
321{
322 int baseDst = (vPC + 1)->u.operand;
323 int funcDst = (vPC + 2)->u.operand;
324 int property = (vPC + 3)->u.operand;
325
326 ScopeChainIterator iter = scopeChain->begin();
327 ScopeChainIterator end = scopeChain->end();
328
329 // FIXME: add scopeDepthIsZero optimization
330
331 ASSERT(iter != end);
332
333 Identifier& ident = codeBlock->identifiers[property];
334 JSObject* base;
335 do {
336 base = *iter;
337 PropertySlot slot(base);
338 if (base->getPropertySlot(exec, ident, slot)) {
339 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
340 // However, section 10.2.3 says that in the case where the value provided
341 // by the caller is null, the global object should be used. It also says
342 // that the section does not apply to internal functions, but for simplicity
343 // of implementation we use the global object anyway here. This guarantees
344 // that in host objects you always get a valid object for this.
345 // We also handle wrapper substitution for the global object at the same time.
346 JSObject* thisObj = base->toThisObject(exec);
347 JSValue* result = slot.getValue(exec, ident);
348 exceptionValue = exec->exception();
349 if (exceptionValue)
350 return false;
351
352 r[baseDst] = thisObj;
353 r[funcDst] = result;
354 return true;
355 }
356 ++iter;
357 } while (iter != end);
358
359 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
360 return false;
361}
362
363ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
364{
365 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
366 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
367 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
368 callFrame[RegisterFile::CallerRegisters] = r;
369 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
370 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
371 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
372 callFrame[RegisterFile::CalledAsConstructor] = calledAsConstructor;
373 callFrame[RegisterFile::Callee] = function;
374 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
375}
376
377ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
378{
379 size_t registerOffset = argv + newCodeBlock->numLocals;
380 size_t size = r - registerBase + registerOffset + newCodeBlock->numTemporaries;
381
382 if (argc == newCodeBlock->numParameters) { // correct number of arguments
383 if (!registerFile->grow(size)) {
384 exceptionValue = createStackOverflowError(exec);
385 return r;
386 }
387 r += registerOffset;
388 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
389 if (!registerFile->grow(size)) {
390 exceptionValue = createStackOverflowError(exec);
391 return r;
392 }
393 r += registerOffset;
394
395 int omittedArgCount = newCodeBlock->numParameters - argc;
396 Register* endOfParams = r - newCodeBlock->numVars;
397 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
398 (*it) = jsUndefined();
399 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
400 int shift = argc + RegisterFile::CallFrameHeaderSize;
401 registerOffset += shift;
402 size += shift;
403
404 if (!registerFile->grow(size)) {
405 exceptionValue = createStackOverflowError(exec);
406 return r;
407 }
408 r += registerOffset;
409
410 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
411 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
412 for ( ; it != end; ++it)
413 *(it + shift) = *it;
414 }
415
416 // initialize local variable slots
417 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
418 (*it) = jsUndefined();
419
420 return r;
421}
422
423ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
424{
425 if (newCodeBlock->needsFullScopeChain) {
426 JSActivation* activation = new (exec) JSActivation(functionBodyNode, r);
427 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
428
429 return callDataScopeChain->copy()->push(activation);
430 }
431
432 return callDataScopeChain;
433}
434
435static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
436{
437 if (value->isObject())
438 return false;
439 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
440 return true;
441}
442
443NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
444{
445 if (argc < 2)
446 return jsUndefined();
447
448 JSValue* program = r[argv + 1].jsValue(exec);
449
450 if (!program->isString())
451 return program;
452
453 Profiler** profiler = Profiler::enabledProfilerReference();
454 if (*profiler)
455 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
456
457 int sourceId;
458 int errLine;
459 UString errMsg;
460 RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(static_cast<JSString*>(program)->value()), &sourceId, &errLine, &errMsg);
461
462 if (!evalNode) {
463 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
464 if (*profiler)
465 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
466 return 0;
467 }
468
469 JSValue* result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
470
471 if (*profiler)
472 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
473
474 return result;
475}
476
477Machine::Machine()
478 :
479#if SAMPLING_TOOL_ENABLED
480 m_sampler(0),
481#else
482 m_reentryDepth(0)
483#endif
484 , m_timeoutTime(0)
485 , m_timeAtLastCheckTimeout(0)
486 , m_timeExecuting(0)
487 , m_timeoutCheckCount(0)
488 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
489{
490 privateExecute(InitializeAndReturn);
491
492 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
493 void* storage = fastMalloc(sizeof(CollectorBlock));
494
495 JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
496 m_jsArrayVptr = jsArray->vptr();
497 static_cast<JSCell*>(jsArray)->~JSCell();
498
499 JSString* jsString = new (storage) JSString("");
500 m_jsStringVptr = jsString->vptr();
501 static_cast<JSCell*>(jsString)->~JSCell();
502
503 fastFree(storage);
504}
505
506void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
507{
508 ScopeChain sc(scopeChain);
509 JSGlobalObject* globalObject = sc.globalObject();
510 codeBlock->dump(globalObject->globalExec());
511 dumpRegisters(codeBlock, registerFile, r);
512}
513
514void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
515{
516 printf("Register frame: \n\n");
517 printf("----------------------------------------------------\n");
518 printf(" use | address | value \n");
519 printf("----------------------------------------------------\n");
520
521 const Register* it;
522 const Register* end;
523
524 if (codeBlock->codeType == GlobalCode) {
525 it = registerFile->lastGlobal();
526 end = it + registerFile->numGlobals();
527 while (it != end) {
528 printf("[global var] | %10p | %10p \n", it, (*it).v());
529 ++it;
530 }
531 printf("----------------------------------------------------\n");
532 }
533
534 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
535 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
536 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
537 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
538 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
539 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
540 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
541 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
542 printf("[CalledAsConstructor] | %10p | %10p \n", it, (*it).v()); ++it;
543 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
544 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
545 printf("----------------------------------------------------\n");
546
547 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
548 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
549 if (it != end) {
550 do {
551 printf("[param] | %10p | %10p \n", it, (*it).v());
552 ++it;
553 } while (it != end);
554 }
555 printf("----------------------------------------------------\n");
556
557 if (codeBlock->codeType != GlobalCode) {
558 end = it + codeBlock->numVars;
559 if (it != end) {
560 do {
561 printf("[var] | %10p | %10p \n", it, (*it).v());
562 ++it;
563 } while (it != end);
564 printf("----------------------------------------------------\n");
565 }
566 }
567
568 end = it + codeBlock->numTemporaries;
569 if (it != end) {
570 do {
571 printf("[temp] | %10p | %10p \n", it, (*it).v());
572 ++it;
573 } while (it != end);
574 }
575}
576
577bool Machine::isOpcode(Opcode opcode)
578{
579#if HAVE(COMPUTED_GOTO)
580 return opcode != HashTraits<Opcode>::emptyValue()
581 && !HashTraits<Opcode>::isDeletedValue(opcode)
582 && m_opcodeIDTable.contains(opcode);
583#else
584 return opcode >= 0 && opcode <= op_end;
585#endif
586}
587
588NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, Register*& k, ScopeChainNode*& scopeChain, Register*& r)
589{
590 CodeBlock* oldCodeBlock = codeBlock;
591 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
592
593 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
594 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
595 if (callFrame[RegisterFile::Callee].jsValue(exec))
596 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
597 else
598 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
599 }
600
601 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
602 if (callFrame[RegisterFile::Callee].jsValue(exec))
603 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
604 else
605 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
606 }
607
608 if (oldCodeBlock->needsFullScopeChain)
609 scopeChain->deref();
610
611 // If this call frame created an activation, tear it off.
612 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
613 ASSERT(activation->isActivationObject());
614 activation->copyRegisters();
615 }
616
617 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
618 if (!codeBlock)
619 return false;
620
621 k = codeBlock->registers.data();
622 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
623 r = callFrame[RegisterFile::CallerRegisters].r();
624 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
625 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
626
627 return true;
628}
629
630NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, Register*& k, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
631{
632 // Set up the exception object
633
634 if (exceptionValue->isObject()) {
635 JSObject* exception = static_cast<JSObject*>(exceptionValue);
636 if (exception->isNotAnObjectErrorStub()) {
637 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
638 exceptionValue = exception;
639 } else {
640 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
641 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
642 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
643 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
644 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
645 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
646 if (explicitThrow) {
647 int startOffset = 0;
648 int endOffset = 0;
649 int divotPoint = 0;
650 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
651 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
652
653 // We only hit this path for error messages and throw statements, which don't have a specific failure position
654 // So we just give the full range of the error/throw statement.
655 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
656 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
657 } else
658 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
659 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
660 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
661 }
662
663 if (exception->isWatchdogException()) {
664 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r)) {
665 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
666 }
667 return 0;
668 }
669 }
670 }
671
672 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
673 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
674 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
675 }
676
677 // Calculate an exception handler vPC, unwinding call frames as necessary.
678
679 int scopeDepth;
680 Instruction* handlerVPC;
681
682 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
683 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r))
684 return 0;
685 }
686
687 // Now unwind the scope chain within the exception handler's call frame.
688
689 ScopeChain sc(scopeChain);
690 int scopeDelta = depth(sc) - scopeDepth;
691 ASSERT(scopeDelta >= 0);
692 while (scopeDelta--)
693 sc.pop();
694 setScopeChain(exec, scopeChain, sc.node());
695
696 return handlerVPC;
697}
698
699JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
700{
701 if (m_reentryDepth >= MaxReentryDepth) {
702 *exception = createStackOverflowError(exec);
703 return 0;
704 }
705
706 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
707
708 size_t oldSize = m_registerFile.size();
709 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numTemporaries;
710 if (!m_registerFile.grow(newSize)) {
711 *exception = createStackOverflowError(exec);
712 return 0;
713 }
714
715 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
716 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
717 globalObject->copyGlobalsTo(m_registerFile);
718
719 Register* callFrame = m_registerFile.base() + oldSize;
720
721 // a 0 codeBlock indicates a built-in caller
722 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
723
724 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
725 r[codeBlock->thisRegister] = thisObj;
726
727 if (codeBlock->needsFullScopeChain)
728 scopeChain = scopeChain->copy();
729
730 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
731
732 Profiler** profiler = Profiler::enabledProfilerReference();
733 if (*profiler)
734 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
735
736 m_reentryDepth++;
737 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
738 m_reentryDepth--;
739
740 MACHINE_SAMPLING_privateExecuteReturned();
741
742 if (*profiler) {
743 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
744 if (!m_reentryDepth)
745 (*profiler)->didFinishAllExecution(exec);
746 }
747
748 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
749 lastGlobalObject->copyGlobalsTo(m_registerFile);
750
751 m_registerFile.shrink(oldSize);
752 return result;
753}
754
755JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
756{
757 if (m_reentryDepth >= MaxReentryDepth) {
758 *exception = createStackOverflowError(exec);
759 return 0;
760 }
761
762 int argv = RegisterFile::CallFrameHeaderSize;
763 int argc = args.size() + 1; // implicit "this" parameter
764
765 size_t oldSize = m_registerFile.size();
766 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
767 *exception = createStackOverflowError(exec);
768 return 0;
769 }
770
771 Register* callFrame = m_registerFile.base() + oldSize;
772
773 // put args in place, including "this"
774 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
775 (*dst) = thisObj;
776
777 ArgList::const_iterator end = args.end();
778 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
779 (*++dst) = *it;
780
781 // a 0 codeBlock indicates a built-in caller
782 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
783
784 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
785 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
786 if (*exception) {
787 m_registerFile.shrink(oldSize);
788 return 0;
789 }
790
791 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
792
793 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
794
795 Profiler** profiler = Profiler::enabledProfilerReference();
796 if (*profiler)
797 (*profiler)->willExecute(exec, function);
798
799 m_reentryDepth++;
800 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
801 m_reentryDepth--;
802
803 MACHINE_SAMPLING_privateExecuteReturned();
804
805 if (*profiler && !m_reentryDepth)
806 (*profiler)->didFinishAllExecution(exec);
807
808 m_registerFile.shrink(oldSize);
809 return result;
810}
811
812JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
813{
814 if (m_reentryDepth >= MaxReentryDepth) {
815 *exception = createStackOverflowError(exec);
816 return 0;
817 }
818
819 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
820
821 JSVariableObject* variableObject;
822 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
823 ASSERT(node);
824 if (node->object->isVariableObject()) {
825 variableObject = static_cast<JSVariableObject*>(node->object);
826 break;
827 }
828 }
829
830 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
831 Node::VarStack::const_iterator varStackEnd = varStack.end();
832 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
833 const Identifier& ident = (*it).first;
834 if (!variableObject->hasProperty(exec, ident))
835 variableObject->put(exec, ident, jsUndefined());
836 }
837
838 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
839 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
840 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it)
841 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain));
842
843 size_t oldSize = m_registerFile.size();
844 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
845 if (!m_registerFile.grow(newSize)) {
846 *exception = createStackOverflowError(exec);
847 return 0;
848 }
849
850 Register* callFrame = m_registerFile.base() + registerOffset;
851
852 // a 0 codeBlock indicates a built-in caller
853 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
854
855 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
856 r[codeBlock->thisRegister] = thisObj;
857
858 if (codeBlock->needsFullScopeChain)
859 scopeChain = scopeChain->copy();
860
861 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
862
863 Profiler** profiler = Profiler::enabledProfilerReference();
864 if (*profiler)
865 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
866
867 m_reentryDepth++;
868 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
869 m_reentryDepth--;
870
871 MACHINE_SAMPLING_privateExecuteReturned();
872
873 if (*profiler) {
874 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
875 if (!m_reentryDepth)
876 (*profiler)->didFinishAllExecution(exec);
877 }
878
879 m_registerFile.shrink(oldSize);
880 return result;
881}
882
883ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
884{
885 scopeChain = newScopeChain;
886 exec->m_scopeChain = newScopeChain;
887}
888
889NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r)
890{
891 int debugHookID = (++vPC)->u.operand;
892 int firstLine = (++vPC)->u.operand;
893 int lastLine = (++vPC)->u.operand;
894
895 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
896 if (!debugger)
897 return;
898
899 DebuggerCallFrame debuggerCallFrame(exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
900
901 switch((DebugHookID)debugHookID) {
902 case DidEnterCallFrame: {
903 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
904 return;
905 }
906 case WillLeaveCallFrame: {
907 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
908 return;
909 }
910 case WillExecuteStatement: {
911 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
912 return;
913 }
914 case WillExecuteProgram: {
915 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
916 return;
917 }
918 case DidExecuteProgram: {
919 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
920 return;
921 }
922 case DidReachBreakpoint: {
923 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
924 return;
925 }
926 }
927}
928
929void Machine::resetTimeoutCheck()
930{
931 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
932 m_timeAtLastCheckTimeout = 0;
933 m_timeExecuting = 0;
934}
935
936// Returns the current time in milliseconds
937// It doesn't matter what "current time" is here, just as long as
938// it's possible to measure the time difference correctly.
939// In an ideal world this would just be getCurrentUTCTimeWithMicroseconds
940// from DateMath.h, but unfortunately there's a slowdown if we use tha.
941static inline unsigned getCurrentTime()
942{
943#if HAVE(SYS_TIME_H)
944 struct timeval tv;
945 gettimeofday(&tv, 0);
946 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
947#elif PLATFORM(QT)
948 QDateTime t = QDateTime::currentDateTime();
949 return t.toTime_t() * 1000 + t.time().msec();
950#elif PLATFORM(WIN_OS)
951 return timeGetTime();
952#else
953#error Platform does not have getCurrentTime function
954#endif
955}
956
957// We have to return a JSValue here, gcc seems to produce worse code if
958// we attempt to return a bool
959ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
960{
961 unsigned currentTime = getCurrentTime();
962
963 if (!m_timeAtLastCheckTimeout) {
964 // Suspicious amount of looping in a script -- start timing it
965 m_timeAtLastCheckTimeout = currentTime;
966 return 0;
967 }
968
969 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
970
971 if (timeDiff == 0)
972 timeDiff = 1;
973
974 m_timeExecuting += timeDiff;
975 m_timeAtLastCheckTimeout = currentTime;
976
977 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
978 // preferredScriptCheckTimeInterval
979 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
980 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
981 // preferred script check time interval.
982 if (m_ticksUntilNextTimeoutCheck == 0)
983 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
984
985 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
986 if (globalObject->shouldInterruptScript())
987 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
988
989 resetTimeoutCheck();
990 }
991
992 return 0;
993}
994
995static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {
996 StringJumpTable::const_iterator end = jumpTable.end();
997 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
998 StringJumpTable::const_iterator loc = jumpTable.find(value);
999 if (loc == end)
1000 return defaultOffset;
1001 return loc->second;
1002}
1003
1004JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1005{
1006 // One-time initialization of our address tables. We have to put this code
1007 // here because our labels are only in scope inside this function.
1008 if (flag == InitializeAndReturn) {
1009 #if HAVE(COMPUTED_GOTO)
1010 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1011 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1012 #undef ADD_OPCODE
1013
1014 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1015 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1016 #undef ADD_OPCODE
1017 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1018 op_throw_end_indirect = &&op_throw_end;
1019 op_call_indirect = &&op_call;
1020 #endif // HAVE(COMPUTED_GOTO)
1021 return 0;
1022 }
1023
1024 JSValue* exceptionValue = 0;
1025 Instruction* handlerVPC = 0;
1026
1027 Register* registerBase = registerFile->base();
1028 Instruction* vPC = codeBlock->instructions.begin();
1029 Register* k = codeBlock->registers.data();
1030 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1031 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1032
1033#define VM_CHECK_EXCEPTION() \
1034 do { \
1035 if (UNLIKELY(exec->hadException())) { \
1036 exceptionValue = exec->exception(); \
1037 goto vm_throw; \
1038 } \
1039 } while (0)
1040
1041#if DUMP_OPCODE_STATS
1042 OpcodeStats::resetLastInstruction();
1043#endif
1044
1045#define CHECK_FOR_TIMEOUT() \
1046 if (!--tickCount) { \
1047 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1048 goto vm_throw; \
1049 tickCount = m_ticksUntilNextTimeoutCheck; \
1050 }
1051
1052#if HAVE(COMPUTED_GOTO)
1053 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1054#if DUMP_OPCODE_STATS
1055 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1056#else
1057 #define BEGIN_OPCODE(opcode) opcode:
1058#endif
1059 NEXT_OPCODE;
1060#else
1061 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1062#if DUMP_OPCODE_STATS
1063 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1064#else
1065 #define BEGIN_OPCODE(opcode) case opcode:
1066#endif
1067 while (1) // iterator loop begins
1068 switch (vPC->u.opcode)
1069#endif
1070 {
1071 BEGIN_OPCODE(op_load) {
1072 /* load dst(r) src(k)
1073
1074 Copies constant src to register dst.
1075 */
1076 int dst = (++vPC)->u.operand;
1077 int src = (++vPC)->u.operand;
1078 r[dst] = k[src];
1079
1080 ++vPC;
1081 NEXT_OPCODE;
1082 }
1083 BEGIN_OPCODE(op_new_object) {
1084 /* new_object dst(r)
1085
1086 Constructs a new empty Object instance using the original
1087 constructor, and puts the result in register dst.
1088 */
1089 int dst = (++vPC)->u.operand;
1090 r[dst] = constructEmptyObject(exec);
1091
1092 ++vPC;
1093 NEXT_OPCODE;
1094 }
1095 BEGIN_OPCODE(op_new_array) {
1096 /* new_array dst(r) firstArg(r) argCount(n)
1097
1098 Constructs a new Array instance using the original
1099 constructor, and puts the result in register dst.
1100 The array will contain argCount elements with values
1101 taken from registers starting at register firstArg.
1102 */
1103 int dst = (++vPC)->u.operand;
1104 int firstArg = (++vPC)->u.operand;
1105 int argCount = (++vPC)->u.operand;
1106 ArgList args(r + firstArg, argCount);
1107 r[dst] = constructArray(exec, args);
1108
1109 ++vPC;
1110 NEXT_OPCODE;
1111 }
1112 BEGIN_OPCODE(op_new_regexp) {
1113 /* new_regexp dst(r) regExp(re)
1114
1115 Constructs a new RegExp instance using the original
1116 constructor from regexp regExp, and puts the result in
1117 register dst.
1118 */
1119 int dst = (++vPC)->u.operand;
1120 int regExp = (++vPC)->u.operand;
1121 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1122
1123 ++vPC;
1124 NEXT_OPCODE;
1125 }
1126 BEGIN_OPCODE(op_mov) {
1127 /* mov dst(r) src(r)
1128
1129 Copies register src to register dst.
1130 */
1131 int dst = (++vPC)->u.operand;
1132 int src = (++vPC)->u.operand;
1133 r[dst] = r[src];
1134
1135 ++vPC;
1136 NEXT_OPCODE;
1137 }
1138 BEGIN_OPCODE(op_eq) {
1139 /* eq dst(r) src1(r) src2(r)
1140
1141 Checks whether register src1 and register src2 are equal,
1142 as with the ECMAScript '==' operator, and puts the result
1143 as a boolean in register dst.
1144 */
1145 int dst = (++vPC)->u.operand;
1146 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1147 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1148 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1149 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1150 else {
1151 JSValue* result = jsBoolean(equal(exec, src1, src2));
1152 VM_CHECK_EXCEPTION();
1153 r[dst] = result;
1154 }
1155
1156 ++vPC;
1157 NEXT_OPCODE;
1158 }
1159 BEGIN_OPCODE(op_neq) {
1160 /* neq dst(r) src1(r) src2(r)
1161
1162 Checks whether register src1 and register src2 are not
1163 equal, as with the ECMAScript '!=' operator, and puts the
1164 result as a boolean in register dst.
1165 */
1166 int dst = (++vPC)->u.operand;
1167 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1168 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1169 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1170 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1171 else {
1172 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1173 VM_CHECK_EXCEPTION();
1174 r[dst] = result;
1175 }
1176
1177 ++vPC;
1178 NEXT_OPCODE;
1179 }
1180 BEGIN_OPCODE(op_stricteq) {
1181 /* stricteq dst(r) src1(r) src2(r)
1182
1183 Checks whether register src1 and register src2 are strictly
1184 equal, as with the ECMAScript '===' operator, and puts the
1185 result as a boolean in register dst.
1186 */
1187 int dst = (++vPC)->u.operand;
1188 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1189 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1190 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1191 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1192 else
1193 r[dst] = jsBoolean(strictEqual(src1, src2));
1194
1195 ++vPC;
1196 NEXT_OPCODE;
1197 }
1198 BEGIN_OPCODE(op_nstricteq) {
1199 /* nstricteq dst(r) src1(r) src2(r)
1200
1201 Checks whether register src1 and register src2 are not
1202 strictly equal, as with the ECMAScript '!==' operator, and
1203 puts the result as a boolean in register dst.
1204 */
1205 int dst = (++vPC)->u.operand;
1206 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1207 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1208 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1209 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1210 else
1211 r[dst] = jsBoolean(!strictEqual(src1, src2));
1212
1213 ++vPC;
1214 NEXT_OPCODE;
1215 }
1216 BEGIN_OPCODE(op_less) {
1217 /* less dst(r) src1(r) src2(r)
1218
1219 Checks whether register src1 is less than register src2, as
1220 with the ECMAScript '<' operator, and puts the result as
1221 a boolean in register dst.
1222 */
1223 int dst = (++vPC)->u.operand;
1224 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1225 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1226 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1227 VM_CHECK_EXCEPTION();
1228 r[dst] = result;
1229
1230 ++vPC;
1231 NEXT_OPCODE;
1232 }
1233 BEGIN_OPCODE(op_lesseq) {
1234 /* lesseq dst(r) src1(r) src2(r)
1235
1236 Checks whether register src1 is less than or equal to
1237 register src2, as with the ECMAScript '<=' operator, and
1238 puts the result as a boolean in register dst.
1239 */
1240 int dst = (++vPC)->u.operand;
1241 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1242 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1243 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1244 VM_CHECK_EXCEPTION();
1245 r[dst] = result;
1246
1247 ++vPC;
1248 NEXT_OPCODE;
1249 }
1250 BEGIN_OPCODE(op_pre_inc) {
1251 /* pre_inc srcDst(r)
1252
1253 Converts register srcDst to number, adds one, and puts the result
1254 back in register srcDst.
1255 */
1256 int srcDst = (++vPC)->u.operand;
1257 JSValue* v = r[srcDst].jsValue(exec);
1258 if (JSImmediate::canDoFastAdditiveOperations(v))
1259 r[srcDst] = JSImmediate::incImmediateNumber(v);
1260 else {
1261 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1262 VM_CHECK_EXCEPTION();
1263 r[srcDst] = result;
1264 }
1265
1266 ++vPC;
1267 NEXT_OPCODE;
1268 }
1269 BEGIN_OPCODE(op_pre_dec) {
1270 /* pre_dec srcDst(r)
1271
1272 Converts register srcDst to number, subtracts one, and puts the result
1273 back in register srcDst.
1274 */
1275 int srcDst = (++vPC)->u.operand;
1276 JSValue* v = r[srcDst].jsValue(exec);
1277 if (JSImmediate::canDoFastAdditiveOperations(v))
1278 r[srcDst] = JSImmediate::decImmediateNumber(v);
1279 else {
1280 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1281 VM_CHECK_EXCEPTION();
1282 r[srcDst] = result;
1283 }
1284
1285 ++vPC;
1286 NEXT_OPCODE;
1287 }
1288 BEGIN_OPCODE(op_post_inc) {
1289 /* post_inc dst(r) srcDst(r)
1290
1291 Converts register srcDst to number. The number itself is
1292 written to register dst, and the number plus one is written
1293 back to register srcDst.
1294 */
1295 int dst = (++vPC)->u.operand;
1296 int srcDst = (++vPC)->u.operand;
1297 JSValue* v = r[srcDst].jsValue(exec);
1298 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1299 r[dst] = v;
1300 r[srcDst] = JSImmediate::incImmediateNumber(v);
1301 } else {
1302 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1303 VM_CHECK_EXCEPTION();
1304 r[dst] = number;
1305 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1306 }
1307
1308 ++vPC;
1309 NEXT_OPCODE;
1310 }
1311 BEGIN_OPCODE(op_post_dec) {
1312 /* post_dec dst(r) srcDst(r)
1313
1314 Converts register srcDst to number. The number itself is
1315 written to register dst, and the number minus one is written
1316 back to register srcDst.
1317 */
1318 int dst = (++vPC)->u.operand;
1319 int srcDst = (++vPC)->u.operand;
1320 JSValue* v = r[srcDst].jsValue(exec);
1321 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1322 r[dst] = v;
1323 r[srcDst] = JSImmediate::decImmediateNumber(v);
1324 } else {
1325 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1326 VM_CHECK_EXCEPTION();
1327 r[dst] = number;
1328 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1329 }
1330
1331 ++vPC;
1332 NEXT_OPCODE;
1333 }
1334 BEGIN_OPCODE(op_to_jsnumber) {
1335 /* to_jsnumber dst(r) src(r)
1336
1337 Converts register src to number, and puts the result
1338 in register dst.
1339 */
1340 int dst = (++vPC)->u.operand;
1341 int src = (++vPC)->u.operand;
1342 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1343 VM_CHECK_EXCEPTION();
1344
1345 r[dst] = result;
1346
1347 ++vPC;
1348 NEXT_OPCODE;
1349 }
1350 BEGIN_OPCODE(op_negate) {
1351 /* negate dst(r) src(r)
1352
1353 Converts register src to number, negates it, and puts the
1354 result in register dst.
1355 */
1356 int dst = (++vPC)->u.operand;
1357 int src = (++vPC)->u.operand;
1358 JSValue* result = jsNumber(exec, -r[src].jsValue(exec)->toNumber(exec));
1359 VM_CHECK_EXCEPTION();
1360 r[dst] = result;
1361
1362 ++vPC;
1363 NEXT_OPCODE;
1364 }
1365 BEGIN_OPCODE(op_add) {
1366 /* add dst(r) src1(r) src2(r)
1367
1368 Adds register src1 and register src2, and puts the result
1369 in register dst. (JS add may be string concatenation or
1370 numeric add, depending on the types of the operands.)
1371 */
1372 int dst = (++vPC)->u.operand;
1373 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1374 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1375 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1376 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1377 else {
1378 JSValue* result = jsAdd(exec, src1, src2);
1379 VM_CHECK_EXCEPTION();
1380 r[dst] = result;
1381 }
1382 ++vPC;
1383 NEXT_OPCODE;
1384 }
1385 BEGIN_OPCODE(op_mul) {
1386 /* mul dst(r) src1(r) src2(r)
1387
1388 Multiplies register src1 and register src2 (converted to
1389 numbers), and puts the product in register dst.
1390 */
1391 int dst = (++vPC)->u.operand;
1392 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1393 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1394 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1395 VM_CHECK_EXCEPTION();
1396 r[dst] = result;
1397
1398 ++vPC;
1399 NEXT_OPCODE;
1400 }
1401 BEGIN_OPCODE(op_div) {
1402 /* div dst(r) dividend(r) divisor(r)
1403
1404 Divides register dividend (converted to number) by the
1405 register divisor (converted to number), and puts the
1406 quotient in register dst.
1407 */
1408 int dst = (++vPC)->u.operand;
1409 int dividend = (++vPC)->u.operand;
1410 int divisor = (++vPC)->u.operand;
1411 JSValue* result = jsNumber(exec, r[dividend].jsValue(exec)->toNumber(exec) / r[divisor].jsValue(exec)->toNumber(exec));
1412 VM_CHECK_EXCEPTION();
1413 r[dst] = result;
1414 ++vPC;
1415 NEXT_OPCODE;
1416 }
1417 BEGIN_OPCODE(op_mod) {
1418 /* mod dst(r) dividend(r) divisor(r)
1419
1420 Divides register dividend (converted to number) by
1421 register divisor (converted to number), and puts the
1422 remainder in register dst.
1423 */
1424 int dst = (++vPC)->u.operand;
1425 int dividend = (++vPC)->u.operand;
1426 int divisor = (++vPC)->u.operand;
1427 double d = r[dividend].jsValue(exec)->toNumber(exec);
1428 JSValue* result = jsNumber(exec, fmod(d, r[divisor].jsValue(exec)->toNumber(exec)));
1429 VM_CHECK_EXCEPTION();
1430 r[dst] = result;
1431 ++vPC;
1432 NEXT_OPCODE;
1433 }
1434 BEGIN_OPCODE(op_sub) {
1435 /* sub dst(r) src1(r) src2(r)
1436
1437 Subtracts register src2 (converted to number) from register
1438 src1 (converted to number), and puts the difference in
1439 register dst.
1440 */
1441 int dst = (++vPC)->u.operand;
1442 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1443 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1444 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1445 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1446 else {
1447 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1448 VM_CHECK_EXCEPTION();
1449 r[dst] = result;
1450 }
1451 ++vPC;
1452 NEXT_OPCODE;
1453 }
1454 BEGIN_OPCODE(op_lshift) {
1455 /* lshift dst(r) val(r) shift(r)
1456
1457 Performs left shift of register val (converted to int32) by
1458 register shift (converted to uint32), and puts the result
1459 in register dst.
1460 */
1461 int dst = (++vPC)->u.operand;
1462 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1463 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1464 if (JSImmediate::areBothImmediateNumbers(val, shift))
1465 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::toTruncatedUInt32(shift) & 0x1f));
1466 else {
1467 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1468 VM_CHECK_EXCEPTION();
1469 r[dst] = result;
1470 }
1471
1472 ++vPC;
1473 NEXT_OPCODE;
1474 }
1475 BEGIN_OPCODE(op_rshift) {
1476 /* rshift dst(r) val(r) shift(r)
1477
1478 Performs arithmetic right shift of register val (converted
1479 to int32) by register shift (converted to
1480 uint32), and puts the result in register dst.
1481 */
1482 int dst = (++vPC)->u.operand;
1483 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1484 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1485 if (JSImmediate::areBothImmediateNumbers(val, shift))
1486 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1487 else {
1488 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1489 VM_CHECK_EXCEPTION();
1490 r[dst] = result;
1491 }
1492
1493 ++vPC;
1494 NEXT_OPCODE;
1495 }
1496 BEGIN_OPCODE(op_urshift) {
1497 /* rshift dst(r) val(r) shift(r)
1498
1499 Performs logical right shift of register val (converted
1500 to uint32) by register shift (converted to
1501 uint32), and puts the result in register dst.
1502 */
1503 int dst = (++vPC)->u.operand;
1504 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1505 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1506 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1507 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1508 else {
1509 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1510 VM_CHECK_EXCEPTION();
1511 r[dst] = result;
1512 }
1513
1514 ++vPC;
1515 NEXT_OPCODE;
1516 }
1517 BEGIN_OPCODE(op_bitand) {
1518 /* bitand dst(r) src1(r) src2(r)
1519
1520 Computes bitwise AND of register src1 (converted to int32)
1521 and register src2 (converted to int32), and puts the result
1522 in register dst.
1523 */
1524 int dst = (++vPC)->u.operand;
1525 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1526 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1527 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1528 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1529 else {
1530 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1531 VM_CHECK_EXCEPTION();
1532 r[dst] = result;
1533 }
1534
1535 ++vPC;
1536 NEXT_OPCODE;
1537 }
1538 BEGIN_OPCODE(op_bitxor) {
1539 /* bitxor dst(r) src1(r) src2(r)
1540
1541 Computes bitwise XOR of register src1 (converted to int32)
1542 and register src2 (converted to int32), and puts the result
1543 in register dst.
1544 */
1545 int dst = (++vPC)->u.operand;
1546 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1547 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1548 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1549 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1550 else {
1551 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1552 VM_CHECK_EXCEPTION();
1553 r[dst] = result;
1554 }
1555
1556 ++vPC;
1557 NEXT_OPCODE;
1558 }
1559 BEGIN_OPCODE(op_bitor) {
1560 /* bitor dst(r) src1(r) src2(r)
1561
1562 Computes bitwise OR of register src1 (converted to int32)
1563 and register src2 (converted to int32), and puts the
1564 result in register dst.
1565 */
1566 int dst = (++vPC)->u.operand;
1567 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1568 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1569 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1570 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1571 else {
1572 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
1573 VM_CHECK_EXCEPTION();
1574 r[dst] = result;
1575 }
1576
1577 ++vPC;
1578 NEXT_OPCODE;
1579 }
1580 BEGIN_OPCODE(op_bitnot) {
1581 /* bitnot dst(r) src(r)
1582
1583 Computes bitwise NOT of register src1 (converted to int32),
1584 and puts the result in register dst.
1585 */
1586 int dst = (++vPC)->u.operand;
1587 int src = (++vPC)->u.operand;
1588 JSValue* result = jsNumber(exec, ~r[src].jsValue(exec)->toInt32(exec));
1589 VM_CHECK_EXCEPTION();
1590 r[dst] = result;
1591
1592 ++vPC;
1593 NEXT_OPCODE;
1594 }
1595 BEGIN_OPCODE(op_not) {
1596 /* not dst(r) src1(r) src2(r)
1597
1598 Computes logical NOT of register src1 (converted to
1599 boolean), and puts the result in register dst.
1600 */
1601 int dst = (++vPC)->u.operand;
1602 int src = (++vPC)->u.operand;
1603 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
1604 VM_CHECK_EXCEPTION();
1605 r[dst] = result;
1606
1607 ++vPC;
1608 NEXT_OPCODE;
1609 }
1610 BEGIN_OPCODE(op_instanceof) {
1611 /* instanceof dst(r) value(r) constructor(r)
1612
1613 Tests whether register value is an instance of register
1614 constructor, and puts the boolean result in register dst.
1615
1616 Raises an exception if register constructor is not an
1617 object.
1618 */
1619 int dst = (++vPC)->u.operand;
1620 int value = (++vPC)->u.operand;
1621 int base = (++vPC)->u.operand;
1622
1623 JSValue* baseVal = r[base].jsValue(exec);
1624
1625 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
1626 goto vm_throw;
1627
1628 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1629 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec)) : false);
1630
1631 ++vPC;
1632 NEXT_OPCODE;
1633 }
1634 BEGIN_OPCODE(op_typeof) {
1635 /* typeof dst(r) src(r)
1636
1637 Determines the type string for src according to ECMAScript
1638 rules, and puts the result in register dst.
1639 */
1640 int dst = (++vPC)->u.operand;
1641 int src = (++vPC)->u.operand;
1642 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
1643
1644 ++vPC;
1645 NEXT_OPCODE;
1646 }
1647 BEGIN_OPCODE(op_in) {
1648 /* in dst(r) property(r) base(r)
1649
1650 Tests whether register base has a property named register
1651 property, and puts the boolean result in register dst.
1652
1653 Raises an exception if register constructor is not an
1654 object.
1655 */
1656 int dst = (++vPC)->u.operand;
1657 int property = (++vPC)->u.operand;
1658 int base = (++vPC)->u.operand;
1659
1660 JSValue* baseVal = r[base].jsValue(exec);
1661 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
1662 goto vm_throw;
1663
1664 JSObject* baseObj = static_cast<JSObject*>(baseVal);
1665
1666 JSValue* propName = r[property].jsValue(exec);
1667
1668 uint32_t i;
1669 if (propName->getUInt32(i))
1670 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
1671 else {
1672 Identifier property(exec, propName->toString(exec));
1673 VM_CHECK_EXCEPTION();
1674 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
1675 }
1676
1677 ++vPC;
1678 NEXT_OPCODE;
1679 }
1680 BEGIN_OPCODE(op_resolve) {
1681 /* resolve dst(r) property(id)
1682
1683 Looks up the property named by identifier property in the
1684 scope chain, and writes the resulting value to register
1685 dst. If the property is not found, raises an exception.
1686 */
1687 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1688 goto vm_throw;
1689
1690 vPC += 3;
1691 NEXT_OPCODE;
1692 }
1693 BEGIN_OPCODE(op_resolve_skip) {
1694 /* resolve_skip dst(r) property(id) skip(n)
1695
1696 Looks up the property named by identifier property in the
1697 scope chain skipping the top 'skip' levels, and writes the resulting
1698 value to register dst. If the property is not found, raises an exception.
1699 */
1700 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1701 goto vm_throw;
1702
1703 vPC += 4;
1704
1705 NEXT_OPCODE;
1706 }
1707 BEGIN_OPCODE(op_get_scoped_var) {
1708 /* get_scoped_var dst(r) index(n) skip(n)
1709
1710 Loads the contents of the index-th local from the scope skip nodes from
1711 the top of the scope chain, and places it in register dst
1712 */
1713 int dst = (++vPC)->u.operand;
1714 int index = (++vPC)->u.operand;
1715 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1716
1717 ScopeChainIterator iter = scopeChain->begin();
1718 ScopeChainIterator end = scopeChain->end();
1719 ASSERT(iter != end);
1720 while (skip--) {
1721 ++iter;
1722 ASSERT(iter != end);
1723 }
1724
1725 ASSERT((*iter)->isVariableObject());
1726 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1727 r[dst] = scope->registerAt(index);
1728 ++vPC;
1729 NEXT_OPCODE;
1730 }
1731 BEGIN_OPCODE(op_put_scoped_var) {
1732 /* put_scoped_var index(n) skip(n) value(r)
1733
1734 */
1735 int index = (++vPC)->u.operand;
1736 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
1737 int value = (++vPC)->u.operand;
1738
1739 ScopeChainIterator iter = scopeChain->begin();
1740 ScopeChainIterator end = scopeChain->end();
1741 ASSERT(iter != end);
1742 while (skip--) {
1743 ++iter;
1744 ASSERT(iter != end);
1745 }
1746
1747 ASSERT((*iter)->isVariableObject());
1748 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
1749 scope->registerAt(index) = r[value].jsValue(exec);
1750 ++vPC;
1751 NEXT_OPCODE;
1752 }
1753 BEGIN_OPCODE(op_resolve_base) {
1754 /* resolve_base dst(r) property(id)
1755
1756 Searches the scope chain for an object containing
1757 identifier property, and if one is found, writes it to
1758 register dst. If none is found, the outermost scope (which
1759 will be the global object) is stored in register dst.
1760 */
1761 resolveBase(exec, vPC, r, scopeChain, codeBlock);
1762
1763 vPC += 3;
1764 NEXT_OPCODE;
1765 }
1766 BEGIN_OPCODE(op_resolve_with_base) {
1767 /* resolve_with_base baseDst(r) propDst(r) property(id)
1768
1769 Searches the scope chain for an object containing
1770 identifier property, and if one is found, writes it to
1771 register srcDst, and the retrieved property value to register
1772 propDst. If the property is not found, raises an exception.
1773
1774 This is more efficient than doing resolve_base followed by
1775 resolve, or resolve_base followed by get_by_id, as it
1776 avoids duplicate hash lookups.
1777 */
1778 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1779 goto vm_throw;
1780
1781 vPC += 4;
1782 NEXT_OPCODE;
1783 }
1784 BEGIN_OPCODE(op_resolve_func) {
1785 /* resolve_func baseDst(r) funcDst(r) property(id)
1786
1787 Searches the scope chain for an object containing
1788 identifier property, and if one is found, writes the
1789 appropriate object to use as "this" when calling its
1790 properties to register baseDst; and the retrieved property
1791 value to register propDst. If the property is not found,
1792 raises an exception.
1793
1794 This differs from resolve_with_base, because the
1795 global this value will be substituted for activations or
1796 the global object, which is the right behavior for function
1797 calls but not for other property lookup.
1798 */
1799 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
1800 goto vm_throw;
1801
1802 vPC += 4;
1803 NEXT_OPCODE;
1804 }
1805 BEGIN_OPCODE(op_get_by_id) {
1806 /* get_by_id dst(r) base(r) property(id)
1807
1808 Converts register base to Object, gets the property
1809 named by identifier property from the object, and puts the
1810 result in register dst.
1811 */
1812 int dst = (++vPC)->u.operand;
1813 int base = (++vPC)->u.operand;
1814 int property = (++vPC)->u.operand;
1815
1816 Identifier& ident = codeBlock->identifiers[property];
1817 JSValue *result = r[base].jsValue(exec)->get(exec, ident);
1818 VM_CHECK_EXCEPTION();
1819 r[dst] = result;
1820 ++vPC;
1821 NEXT_OPCODE;
1822 }
1823 BEGIN_OPCODE(op_put_by_id) {
1824 /* put_by_id base(r) property(id) value(r)
1825
1826 Sets register value on register base as the property named
1827 by identifier property. Base is converted to object first.
1828
1829 Unlike many opcodes, this one does not write any output to
1830 the register file.
1831 */
1832 int base = (++vPC)->u.operand;
1833 int property = (++vPC)->u.operand;
1834 int value = (++vPC)->u.operand;
1835
1836 Identifier& ident = codeBlock->identifiers[property];
1837 r[base].jsValue(exec)->put(exec, ident, r[value].jsValue(exec));
1838
1839 VM_CHECK_EXCEPTION();
1840 ++vPC;
1841 NEXT_OPCODE;
1842 }
1843 BEGIN_OPCODE(op_del_by_id) {
1844 /* del_by_id dst(r) base(r) property(id)
1845
1846 Converts register base to Object, deletes the property
1847 named by identifier property from the object, and writes a
1848 boolean indicating success (if true) or failure (if false)
1849 to register dst.
1850 */
1851 int dst = (++vPC)->u.operand;
1852 int base = (++vPC)->u.operand;
1853 int property = (++vPC)->u.operand;
1854
1855 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
1856
1857 Identifier& ident = codeBlock->identifiers[property];
1858 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
1859 VM_CHECK_EXCEPTION();
1860 r[dst] = result;
1861 ++vPC;
1862 NEXT_OPCODE;
1863 }
1864 BEGIN_OPCODE(op_get_by_val) {
1865 /* get_by_val dst(r) base(r) property(r)
1866
1867 Converts register base to Object, gets the property named
1868 by register property from the object, and puts the result
1869 in register dst. property is nominally converted to string
1870 but numbers are treated more efficiently.
1871 */
1872 int dst = (++vPC)->u.operand;
1873 int base = (++vPC)->u.operand;
1874 int property = (++vPC)->u.operand;
1875
1876 JSValue* baseValue = r[base].jsValue(exec);
1877 JSValue* subscript = r[property].jsValue(exec);
1878
1879 JSValue* result;
1880 unsigned i;
1881
1882 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
1883 if (LIKELY(isUInt32)) {
1884 if (isJSArray(baseValue)) {
1885 JSArray* jsArray = static_cast<JSArray*>(baseValue);
1886 if (jsArray->canGetIndex(i))
1887 result = jsArray->getIndex(i);
1888 else
1889 result = jsArray->JSArray::get(exec, i);
1890 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
1891 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
1892 else
1893 result = baseValue->get(exec, i);
1894 } else {
1895 Identifier property(exec, subscript->toString(exec));
1896 result = baseValue->get(exec, property);
1897 }
1898
1899 VM_CHECK_EXCEPTION();
1900 r[dst] = result;
1901 ++vPC;
1902 NEXT_OPCODE;
1903 }
1904 BEGIN_OPCODE(op_put_by_val) {
1905 /* put_by_val base(r) property(r) value(r)
1906
1907 Sets register value on register base as the property named
1908 by register property. Base is converted to object
1909 first. register property is nominally converted to string
1910 but numbers are treated more efficiently.
1911
1912 Unlike many opcodes, this one does not write any output to
1913 the register file.
1914 */
1915 int base = (++vPC)->u.operand;
1916 int property = (++vPC)->u.operand;
1917 int value = (++vPC)->u.operand;
1918
1919 JSValue* baseValue = r[base].jsValue(exec);
1920 JSValue* subscript = r[property].jsValue(exec);
1921
1922 unsigned i;
1923
1924 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
1925 if (LIKELY(isUInt32)) {
1926 if (isJSArray(baseValue)) {
1927 JSArray* jsArray = static_cast<JSArray*>(baseValue);
1928 if (jsArray->canSetIndex(i))
1929 jsArray->setIndex(i, r[value].jsValue(exec));
1930 else
1931 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
1932 } else
1933 baseValue->put(exec, i, r[value].jsValue(exec));
1934 } else {
1935 Identifier property(exec, subscript->toString(exec));
1936 if (!exec->hadException()) // Don't put to an object if toString threw an exception.
1937 baseValue->put(exec, property, r[value].jsValue(exec));
1938 }
1939
1940 VM_CHECK_EXCEPTION();
1941 ++vPC;
1942 NEXT_OPCODE;
1943 }
1944 BEGIN_OPCODE(op_del_by_val) {
1945 /* del_by_val dst(r) base(r) property(r)
1946
1947 Converts register base to Object, deletes the property
1948 named by register property from the object, and writes a
1949 boolean indicating success (if true) or failure (if false)
1950 to register dst.
1951 */
1952 int dst = (++vPC)->u.operand;
1953 int base = (++vPC)->u.operand;
1954 int property = (++vPC)->u.operand;
1955
1956 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
1957
1958 JSValue* subscript = r[property].jsValue(exec);
1959 JSValue* result;
1960 uint32_t i;
1961 if (subscript->getUInt32(i))
1962 result = jsBoolean(baseObj->deleteProperty(exec, i));
1963 else {
1964 VM_CHECK_EXCEPTION();
1965 Identifier property(exec, subscript->toString(exec));
1966 VM_CHECK_EXCEPTION();
1967 result = jsBoolean(baseObj->deleteProperty(exec, property));
1968 }
1969
1970 VM_CHECK_EXCEPTION();
1971 r[dst] = result;
1972 ++vPC;
1973 NEXT_OPCODE;
1974 }
1975 BEGIN_OPCODE(op_put_by_index) {
1976 /* put_by_index base(r) property(n) value(r)
1977
1978 Sets register value on register base as the property named
1979 by the immediate number property. Base is converted to
1980 object first.
1981
1982 Unlike many opcodes, this one does not write any output to
1983 the register file.
1984
1985 This opcode is mainly used to initialize array literals.
1986 */
1987 int base = (++vPC)->u.operand;
1988 unsigned property = (++vPC)->u.operand;
1989 int value = (++vPC)->u.operand;
1990
1991 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
1992
1993 ++vPC;
1994 NEXT_OPCODE;
1995 }
1996 BEGIN_OPCODE(op_loop) {
1997 /* loop target(offset)
1998
1999 Jumps unconditionally to offset target from the current
2000 instruction.
2001
2002 Additionally this loop instruction may terminate JS execution is
2003 the JS timeout is reached.
2004 */
2005#if DUMP_OPCODE_STATS
2006 OpcodeStats::resetLastInstruction();
2007#endif
2008 int target = (++vPC)->u.operand;
2009 CHECK_FOR_TIMEOUT();
2010 vPC += target;
2011 NEXT_OPCODE;
2012 }
2013 BEGIN_OPCODE(op_jmp) {
2014 /* jmp target(offset)
2015
2016 Jumps unconditionally to offset target from the current
2017 instruction.
2018 */
2019#if DUMP_OPCODE_STATS
2020 OpcodeStats::resetLastInstruction();
2021#endif
2022 int target = (++vPC)->u.operand;
2023
2024 vPC += target;
2025 NEXT_OPCODE;
2026 }
2027 BEGIN_OPCODE(op_loop_if_true) {
2028 /* loop_if_true cond(r) target(offset)
2029
2030 Jumps to offset target from the current instruction, if and
2031 only if register cond converts to boolean as true.
2032
2033 Additionally this loop instruction may terminate JS execution is
2034 the JS timeout is reached.
2035 */
2036 int cond = (++vPC)->u.operand;
2037 int target = (++vPC)->u.operand;
2038 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2039 vPC += target;
2040 CHECK_FOR_TIMEOUT();
2041 NEXT_OPCODE;
2042 }
2043
2044 ++vPC;
2045 NEXT_OPCODE;
2046 }
2047 BEGIN_OPCODE(op_jtrue) {
2048 /* jtrue cond(r) target(offset)
2049
2050 Jumps to offset target from the current instruction, if and
2051 only if register cond converts to boolean as true.
2052 */
2053 int cond = (++vPC)->u.operand;
2054 int target = (++vPC)->u.operand;
2055 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2056 vPC += target;
2057 NEXT_OPCODE;
2058 }
2059
2060 ++vPC;
2061 NEXT_OPCODE;
2062 }
2063 BEGIN_OPCODE(op_jfalse) {
2064 /* jfalse cond(r) target(offset)
2065
2066 Jumps to offset target from the current instruction, if and
2067 only if register cond converts to boolean as false.
2068 */
2069 int cond = (++vPC)->u.operand;
2070 int target = (++vPC)->u.operand;
2071 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2072 vPC += target;
2073 NEXT_OPCODE;
2074 }
2075
2076 ++vPC;
2077 NEXT_OPCODE;
2078 }
2079 BEGIN_OPCODE(op_loop_if_less) {
2080 /* loop_if_less src1(r) src2(r) target(offset)
2081
2082 Checks whether register src1 is less than register src2, as
2083 with the ECMAScript '<' operator, and then jumps to offset
2084 target from the current instruction, if and only if the
2085 result of the comparison is true.
2086
2087 Additionally this loop instruction may terminate JS execution is
2088 the JS timeout is reached.
2089 */
2090 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2091 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2092 int target = (++vPC)->u.operand;
2093
2094 bool result = jsLess(exec, src1, src2);
2095 VM_CHECK_EXCEPTION();
2096
2097 if (result) {
2098 vPC += target;
2099 CHECK_FOR_TIMEOUT();
2100 NEXT_OPCODE;
2101 }
2102
2103 ++vPC;
2104 NEXT_OPCODE;
2105 }
2106 BEGIN_OPCODE(op_jless) {
2107 /* jless src1(r) src2(r) target(offset)
2108
2109 Checks whether register src1 is less than register src2, as
2110 with the ECMAScript '<' operator, and then jumps to offset
2111 target from the current instruction, if and only if the
2112 result of the comparison is true.
2113 */
2114 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2115 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2116 int target = (++vPC)->u.operand;
2117
2118 bool result = jsLess(exec, src1, src2);
2119 VM_CHECK_EXCEPTION();
2120
2121 if (result) {
2122 vPC += target;
2123 NEXT_OPCODE;
2124 }
2125
2126 ++vPC;
2127 NEXT_OPCODE;
2128 }
2129 BEGIN_OPCODE(op_jnless) {
2130 /* jnless src1(r) src2(r) target(offset)
2131
2132 Checks whether register src1 is less than register src2, as
2133 with the ECMAScript '<' operator, and then jumps to offset
2134 target from the current instruction, if and only if the
2135 result of the comparison is false.
2136 */
2137 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2138 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2139 int target = (++vPC)->u.operand;
2140
2141 bool result = jsLess(exec, src1, src2);
2142 VM_CHECK_EXCEPTION();
2143
2144 if (!result) {
2145 vPC += target;
2146 NEXT_OPCODE;
2147 }
2148
2149 ++vPC;
2150 NEXT_OPCODE;
2151 }
2152 BEGIN_OPCODE(op_switch_imm) {
2153 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2154
2155 Performs a range checked switch on the scrutinee value, using
2156 the tableIndex-th immediate switch jump table. If the scrutinee value
2157 is an immediate number in the range covered by the referenced jump
2158 table, and the value at jumpTable[scrutinee value] is non-zero, then
2159 that value is used as the jump offset, otherwise defaultOffset is used.
2160 */
2161 int tableIndex = (++vPC)->u.operand;
2162 int defaultOffset = (++vPC)->u.operand;
2163 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2164 if (!JSImmediate::isNumber(scrutinee))
2165 vPC += defaultOffset;
2166 else {
2167 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
2168 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
2169 }
2170 NEXT_OPCODE;
2171 }
2172 BEGIN_OPCODE(op_switch_char) {
2173 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2174
2175 Performs a range checked switch on the scrutinee value, using
2176 the tableIndex-th character switch jump table. If the scrutinee value
2177 is a single character string in the range covered by the referenced jump
2178 table, and the value at jumpTable[scrutinee value] is non-zero, then
2179 that value is used as the jump offset, otherwise defaultOffset is used.
2180 */
2181 int tableIndex = (++vPC)->u.operand;
2182 int defaultOffset = (++vPC)->u.operand;
2183 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2184 if (scrutinee->type() != StringType)
2185 vPC += defaultOffset;
2186 else {
2187 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
2188 if (value->size() != 1)
2189 vPC += defaultOffset;
2190 else
2191 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
2192 }
2193 NEXT_OPCODE;
2194 }
2195 BEGIN_OPCODE(op_switch_string) {
2196 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2197
2198 Performs a sparse hashmap based switch on the value in the scrutinee
2199 register, using the tableIndex-th string switch jump table. If the
2200 scrutinee value is a string that exists as a key in the referenced
2201 jump table, then the value associated with the string is used as the
2202 jump offset, otherwise defaultOffset is used.
2203 */
2204 int tableIndex = (++vPC)->u.operand;
2205 int defaultOffset = (++vPC)->u.operand;
2206 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
2207 if (scrutinee->type() != StringType)
2208 vPC += defaultOffset;
2209 else
2210 vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);
2211 NEXT_OPCODE;
2212 }
2213 BEGIN_OPCODE(op_new_func) {
2214 /* new_func dst(r) func(f)
2215
2216 Constructs a new Function instance from function func and
2217 the current scope chain using the original Function
2218 constructor, using the rules for function declarations, and
2219 puts the result in register dst.
2220 */
2221 int dst = (++vPC)->u.operand;
2222 int func = (++vPC)->u.operand;
2223
2224 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
2225
2226 ++vPC;
2227 NEXT_OPCODE;
2228 }
2229 BEGIN_OPCODE(op_new_func_exp) {
2230 /* new_func_exp dst(r) func(f)
2231
2232 Constructs a new Function instance from function func and
2233 the current scope chain using the original Function
2234 constructor, using the rules for function expressions, and
2235 puts the result in register dst.
2236 */
2237 int dst = (++vPC)->u.operand;
2238 int func = (++vPC)->u.operand;
2239
2240 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
2241
2242 ++vPC;
2243 NEXT_OPCODE;
2244 }
2245 BEGIN_OPCODE(op_call_eval) {
2246 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2247
2248 Call a function named "eval" with no explicit "this" value
2249 (which may therefore be the eval operator). If register
2250 thisVal is the global object, and register func contains
2251 that global object's original global eval function, then
2252 perform the eval operator in local scope (interpreting
2253 the argument registers as for the "call"
2254 opcode). Otherwise, act exactly as the "call" opcode would.
2255 */
2256
2257 int dst = (++vPC)->u.operand;
2258 int func = (++vPC)->u.operand;
2259 int thisVal = (++vPC)->u.operand;
2260 int firstArg = (++vPC)->u.operand;
2261 int argCount = (++vPC)->u.operand;
2262
2263 JSValue* funcVal = r[func].jsValue(exec);
2264 JSValue* baseVal = r[thisVal].jsValue(exec);
2265
2266 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
2267 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
2268 JSValue* result = callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
2269 if (exceptionValue)
2270 goto vm_throw;
2271
2272 r[dst] = result;
2273
2274 ++vPC;
2275 NEXT_OPCODE;
2276 }
2277
2278 // We didn't find the blessed version of eval, so reset vPC and process
2279 // this instruction as a normal function call, supplying the proper 'this'
2280 // value.
2281 vPC -= 5;
2282 r[thisVal] = baseVal->toThisObject(exec);
2283
2284#if HAVE(COMPUTED_GOTO)
2285 // Hack around gcc performance quirk by performing an indirect goto
2286 // in order to set the vPC -- attempting to do so directly results in a
2287 // significant regression.
2288 goto *op_call_indirect; // indirect goto -> op_call
2289#endif
2290 // fall through to op_call
2291 }
2292 BEGIN_OPCODE(op_call) {
2293 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
2294
2295 Perform a function call. Specifically, call register func
2296 with a "this" value of register thisVal, and put the result
2297 in register dst.
2298
2299 The arguments start at register firstArg and go up to
2300 argCount, but the "this" value is considered an implicit
2301 first argument, so the argCount should be one greater than
2302 the number of explicit arguments passed, and the register
2303 after firstArg should contain the actual first
2304 argument. This opcode will copy from the thisVal register
2305 to the firstArg register, unless the register index of
2306 thisVal is the special missing this object marker, which is
2307 2^31-1; in that case, the global object will be used as the
2308 "this" value.
2309
2310 If func is a native code function, then this opcode calls
2311 it and returns the value immediately.
2312
2313 But if it is a JS function, then the current scope chain
2314 and code block is set to the function's, and we slide the
2315 register window so that the arguments would form the first
2316 few local registers of the called function's register
2317 window. In addition, a call frame header is written
2318 immediately before the arguments; see the call frame
2319 documentation for an explanation of how many registers a
2320 call frame takes and what they contain. That many registers
2321 before the firstArg register will be overwritten by the
2322 call. In addition, any registers higher than firstArg +
2323 argCount may be overwritten. Once this setup is complete,
2324 execution continues from the called function's first
2325 argument, and does not return until a "ret" opcode is
2326 encountered.
2327 */
2328
2329 int dst = (++vPC)->u.operand;
2330 int func = (++vPC)->u.operand;
2331 int thisVal = (++vPC)->u.operand;
2332 int firstArg = (++vPC)->u.operand;
2333 int argCount = (++vPC)->u.operand;
2334
2335 JSValue* v = r[func].jsValue(exec);
2336
2337 CallData callData;
2338 CallType callType = v->getCallData(callData);
2339
2340 if (callType == CallTypeJS) {
2341 if (*enabledProfilerReference)
2342 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2343
2344 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
2345 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
2346 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2347
2348 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2349
2350 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2351 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
2352 exec->m_callFrame = callFrame;
2353
2354 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2355 if (UNLIKELY(exceptionValue != 0))
2356 goto vm_throw;
2357
2358 codeBlock = newCodeBlock;
2359 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2360 k = codeBlock->registers.data();
2361 vPC = codeBlock->instructions.begin();
2362
2363#if DUMP_OPCODE_STATS
2364 OpcodeStats::resetLastInstruction();
2365#endif
2366
2367 NEXT_OPCODE;
2368 }
2369
2370 if (callType == CallTypeHost) {
2371 if (*enabledProfilerReference)
2372 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
2373
2374 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
2375 ArgList args(r + firstArg + 1, argCount - 1);
2376
2377 MACHINE_SAMPLING_callingNativeFunction();
2378
2379 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
2380 VM_CHECK_EXCEPTION();
2381
2382 r[dst] = returnValue;
2383
2384 if (*enabledProfilerReference)
2385 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
2386
2387 ++vPC;
2388 NEXT_OPCODE;
2389 }
2390
2391 ASSERT(callType == CallTypeNone);
2392
2393 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
2394 goto vm_throw;
2395 }
2396 BEGIN_OPCODE(op_ret) {
2397 /* ret result(r)
2398
2399 Return register result as the return value of the current
2400 function call, writing it into the caller's expected return
2401 value register. In addition, unwind one call frame and
2402 restore the scope chain, code block instruction pointer and
2403 register base to those of the calling function.
2404 */
2405
2406 int result = (++vPC)->u.operand;
2407
2408 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2409 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
2410 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
2411 ASSERT(activation->isActivationObject());
2412 activation->copyRegisters();
2413 }
2414
2415 if (*enabledProfilerReference)
2416 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
2417
2418 if (codeBlock->needsFullScopeChain)
2419 scopeChain->deref();
2420
2421 JSValue* returnValue = r[result].jsValue(exec);
2422 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
2423 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
2424 returnValue = thisObject;
2425 }
2426
2427 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2428 if (!codeBlock)
2429 return returnValue;
2430
2431 k = codeBlock->registers.data();
2432 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
2433 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
2434 r = callFrame[RegisterFile::CallerRegisters].r();
2435 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2436 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
2437 r[dst] = returnValue;
2438
2439 NEXT_OPCODE;
2440 }
2441 BEGIN_OPCODE(op_construct) {
2442 /* construct dst(r) constr(r) firstArg(r) argCount(n)
2443
2444 Invoke register "constr" as a constructor. For JS
2445 functions, the calling convention is exactly as for the
2446 "call" opcode, except that the "this" value is a newly
2447 created Object. For native constructors, a null "this"
2448 value is passed. In either case, the firstArg and argCount
2449 registers are interpreted as for the "call" opcode.
2450 */
2451
2452 int dst = (++vPC)->u.operand;
2453 int constr = (++vPC)->u.operand;
2454 int firstArg = (++vPC)->u.operand;
2455 int argCount = (++vPC)->u.operand;
2456
2457 JSValue* constrVal = r[constr].jsValue(exec);
2458
2459 ConstructData constructData;
2460 ConstructType constructType = constrVal->getConstructData(constructData);
2461
2462 // Removing this line of code causes a measurable regression on squirrelfish.
2463 JSObject* constructor = static_cast<JSObject*>(constrVal);
2464
2465 if (constructType == ConstructTypeJS) {
2466 if (*enabledProfilerReference)
2467 (*enabledProfilerReference)->willExecute(exec, constructor);
2468
2469 JSObject* prototype;
2470 JSValue* p = constructor->get(exec, exec->propertyNames().prototype);
2471 if (p->isObject())
2472 prototype = static_cast<JSObject*>(p);
2473 else
2474 prototype = scopeChain->globalObject()->objectPrototype();
2475 JSObject* newObject = new (exec) JSObject(prototype);
2476
2477 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
2478 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
2479 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
2480
2481 r[firstArg] = newObject; // "this" value
2482
2483 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
2484 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 1, constructor);
2485 exec->m_callFrame = callFrame;
2486
2487 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
2488 if (exceptionValue)
2489 goto vm_throw;
2490
2491 codeBlock = newCodeBlock;
2492 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
2493 k = codeBlock->registers.data();
2494 vPC = codeBlock->instructions.begin();
2495
2496 NEXT_OPCODE;
2497 }
2498
2499 if (constructType == ConstructTypeHost) {
2500 if (*enabledProfilerReference)
2501 (*enabledProfilerReference)->willExecute(exec, constructor);
2502
2503 ArgList args(r + firstArg + 1, argCount - 1);
2504 JSValue* returnValue = constructData.native.function(exec, constructor, args);
2505
2506 VM_CHECK_EXCEPTION();
2507 r[dst] = returnValue;
2508
2509 if (*enabledProfilerReference)
2510 (*enabledProfilerReference)->didExecute(exec, constructor);
2511
2512 ++vPC;
2513 NEXT_OPCODE;
2514 }
2515
2516 ASSERT(constructType == ConstructTypeNone);
2517
2518 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
2519 goto vm_throw;
2520 }
2521 BEGIN_OPCODE(op_push_scope) {
2522 /* push_scope scope(r)
2523
2524 Converts register scope to object, and pushes it onto the top
2525 of the current scope chain.
2526 */
2527 int scope = (++vPC)->u.operand;
2528 JSValue* v = r[scope].jsValue(exec);
2529 JSObject* o = v->toObject(exec);
2530 VM_CHECK_EXCEPTION();
2531
2532 setScopeChain(exec, scopeChain, scopeChain->push(o));
2533
2534 ++vPC;
2535 NEXT_OPCODE;
2536 }
2537 BEGIN_OPCODE(op_pop_scope) {
2538 /* pop_scope
2539
2540 Removes the top item from the current scope chain.
2541 */
2542 setScopeChain(exec, scopeChain, scopeChain->pop());
2543
2544 ++vPC;
2545 NEXT_OPCODE;
2546 }
2547 BEGIN_OPCODE(op_get_pnames) {
2548 /* get_pnames dst(r) base(r)
2549
2550 Creates a property name list for register base and puts it
2551 in register dst. This is not a true JavaScript value, just
2552 a synthetic value used to keep the iteration state in a
2553 register.
2554 */
2555 int dst = (++vPC)->u.operand;
2556 int base = (++vPC)->u.operand;
2557
2558 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
2559 ++vPC;
2560 NEXT_OPCODE;
2561 }
2562 BEGIN_OPCODE(op_next_pname) {
2563 /* next_pname dst(r) iter(r) target(offset)
2564
2565 Tries to copies the next name from property name list in
2566 register iter. If there are names left, then copies one to
2567 register dst, and jumps to offset target. If there are none
2568 left, invalidates the iterator and continues to the next
2569 instruction.
2570 */
2571 int dst = (++vPC)->u.operand;
2572 int iter = (++vPC)->u.operand;
2573 int target = (++vPC)->u.operand;
2574
2575 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
2576 if (JSValue* temp = it->next(exec)) {
2577 CHECK_FOR_TIMEOUT();
2578 r[dst] = temp;
2579 vPC += target;
2580 NEXT_OPCODE;
2581 }
2582 it->invalidate();
2583
2584 ++vPC;
2585 NEXT_OPCODE;
2586 }
2587 BEGIN_OPCODE(op_jmp_scopes) {
2588 /* jmp_scopes count(n) target(offset)
2589
2590 Removes the a number of items from the current scope chain
2591 specified by immediate number count, then jumps to offset
2592 target.
2593 */
2594 int count = (++vPC)->u.operand;
2595 int target = (++vPC)->u.operand;
2596
2597 ScopeChainNode* tmp = scopeChain;
2598 while (count--)
2599 tmp = tmp->pop();
2600 setScopeChain(exec, scopeChain, tmp);
2601
2602 vPC += target;
2603 NEXT_OPCODE;
2604 }
2605 BEGIN_OPCODE(op_catch) {
2606 /* catch ex(r)
2607
2608 Retrieves the VMs current exception and puts it in register
2609 ex. This is only valid after an exception has been raised,
2610 and usually forms the beginning of an exception handler.
2611 */
2612 ASSERT(exceptionValue);
2613 ASSERT(!exec->hadException());
2614 int ex = (++vPC)->u.operand;
2615 r[ex] = exceptionValue;
2616 exceptionValue = 0;
2617
2618 ++vPC;
2619 NEXT_OPCODE;
2620 }
2621 BEGIN_OPCODE(op_throw) {
2622 /* throw ex(r)
2623
2624 Throws register ex as an exception. This involves three
2625 steps: first, it is set as the current exception in the
2626 VM's internal state, then the stack is unwound until an
2627 exception handler or a native code boundary is found, and
2628 then control resumes at the exception handler if any or
2629 else the script returns control to the nearest native caller.
2630 */
2631
2632 int ex = (++vPC)->u.operand;
2633 exceptionValue = r[ex].jsValue(exec);
2634
2635 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r, true);
2636 if (!handlerVPC) {
2637 *exception = exceptionValue;
2638 return jsNull();
2639 }
2640
2641#if HAVE(COMPUTED_GOTO)
2642 // Hack around gcc performance quirk by performing an indirect goto
2643 // in order to set the vPC -- attempting to do so directly results in a
2644 // significant regression.
2645 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
2646 }
2647 op_throw_end: {
2648#endif
2649
2650 vPC = handlerVPC;
2651 NEXT_OPCODE;
2652 }
2653 BEGIN_OPCODE(op_new_error) {
2654 /* new_error dst(r) type(n) message(k)
2655
2656 Constructs a new Error instance using the original
2657 constructor, using immediate number n as the type and
2658 constant message as the message string. The result is
2659 written to register dst.
2660 */
2661 int dst = (++vPC)->u.operand;
2662 int type = (++vPC)->u.operand;
2663 int message = (++vPC)->u.operand;
2664
2665 r[dst] = Error::create(exec, (ErrorType)type, k[message].jsValue(exec)->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
2666
2667 ++vPC;
2668 NEXT_OPCODE;
2669 }
2670 BEGIN_OPCODE(op_end) {
2671 /* end result(r)
2672
2673 Return register result as the value of a global or eval
2674 program. Return control to the calling native code.
2675 */
2676
2677 if (codeBlock->needsFullScopeChain) {
2678 ASSERT(scopeChain->refCount > 1);
2679 scopeChain->deref();
2680 }
2681 int result = (++vPC)->u.operand;
2682 return r[result].jsValue(exec);
2683 }
2684 BEGIN_OPCODE(op_put_getter) {
2685 /* put_getter base(r) property(id) function(r)
2686
2687 Sets register function on register base as the getter named
2688 by identifier property. Base and function are assumed to be
2689 objects as this op should only be used for getters defined
2690 in object literal form.
2691
2692 Unlike many opcodes, this one does not write any output to
2693 the register file.
2694 */
2695 int base = (++vPC)->u.operand;
2696 int property = (++vPC)->u.operand;
2697 int function = (++vPC)->u.operand;
2698
2699 ASSERT(r[base].jsValue(exec)->isObject());
2700 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2701 Identifier& ident = codeBlock->identifiers[property];
2702 ASSERT(r[function].jsValue(exec)->isObject());
2703 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2704
2705 ++vPC;
2706 NEXT_OPCODE;
2707 }
2708 BEGIN_OPCODE(op_put_setter) {
2709 /* put_setter base(r) property(id) function(r)
2710
2711 Sets register function on register base as the setter named
2712 by identifier property. Base and function are assumed to be
2713 objects as this op should only be used for setters defined
2714 in object literal form.
2715
2716 Unlike many opcodes, this one does not write any output to
2717 the register file.
2718 */
2719 int base = (++vPC)->u.operand;
2720 int property = (++vPC)->u.operand;
2721 int function = (++vPC)->u.operand;
2722
2723 ASSERT(r[base].jsValue(exec)->isObject());
2724 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
2725 Identifier& ident = codeBlock->identifiers[property];
2726 ASSERT(r[function].jsValue(exec)->isObject());
2727 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
2728
2729 ++vPC;
2730 NEXT_OPCODE;
2731 }
2732 BEGIN_OPCODE(op_jsr) {
2733 /* jsr retAddrDst(r) target(offset)
2734
2735 Places the address of the next instruction into the retAddrDst
2736 register and jumps to offset target from the current instruction.
2737 */
2738 int retAddrDst = (++vPC)->u.operand;
2739 int target = (++vPC)->u.operand;
2740 r[retAddrDst] = vPC + 1;
2741
2742 vPC += target;
2743 NEXT_OPCODE;
2744 }
2745 BEGIN_OPCODE(op_sret) {
2746 /* sret retAddrSrc(r)
2747
2748 Jumps to the address stored in the retAddrSrc register. This
2749 differs from op_jmp because the target address is stored in a
2750 register, not as an immediate.
2751 */
2752 int retAddrSrc = (++vPC)->u.operand;
2753 vPC = r[retAddrSrc].vPC();
2754 NEXT_OPCODE;
2755 }
2756 BEGIN_OPCODE(op_debug) {
2757 /* debug debugHookID(n) firstLine(n) lastLine(n)
2758
2759 Notifies the debugger of the current state of execution. This opcode
2760 is only generated while the debugger is attached.
2761 */
2762
2763 debug(exec, vPC, codeBlock, scopeChain, r);
2764
2765 vPC += 4;
2766 NEXT_OPCODE;
2767 }
2768 vm_throw: {
2769 exec->clearException();
2770 if (!tickCount) {
2771 // The exceptionValue is a lie! (GCC produces bad code for reasons I
2772 // cannot fathom if we don't assign to the exceptionValue before branching)
2773 exceptionValue = createInterruptedExecutionException(exec);
2774 }
2775 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r, false);
2776 if (!handlerVPC) {
2777 *exception = exceptionValue;
2778 return jsNull();
2779 }
2780 vPC = handlerVPC;
2781 NEXT_OPCODE;
2782 }
2783 }
2784 #undef NEXT_OPCODE
2785 #undef BEGIN_OPCODE
2786 #undef VM_CHECK_EXCEPTION
2787}
2788
2789JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
2790{
2791 Register* callFrame = this->callFrame(exec, function);
2792 if (!callFrame)
2793 return jsNull();
2794
2795 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
2796 if (!activation) {
2797 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
2798 activation = new (exec) JSActivation(function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
2799 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
2800 }
2801
2802 return activation->get(exec, exec->propertyNames().arguments);
2803}
2804
2805JSValue* Machine::retrieveCaller(ExecState* exec, JSFunction* function) const
2806{
2807 Register* callFrame = this->callFrame(exec, function);
2808 if (!callFrame)
2809 return jsNull();
2810
2811 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2812 if (!callerCodeBlock)
2813 return jsNull();
2814
2815 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2816 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
2817 return caller;
2818
2819 return jsNull();
2820}
2821
2822Register* Machine::callFrame(ExecState* exec, JSFunction* function) const
2823{
2824 Register* callFrame = exec->m_callFrame;
2825
2826 while (1) {
2827 while (!callFrame) {
2828 exec = exec->m_prev;
2829 if (!exec)
2830 return 0;
2831 callFrame = exec->m_callFrame;
2832 }
2833
2834 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
2835 return callFrame;
2836
2837 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
2838 if (!callerCodeBlock) {
2839 callFrame = 0;
2840 continue;
2841 }
2842
2843 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
2844 }
2845}
2846
2847void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
2848{
2849 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
2850 ASSERT(function->inherits(&JSFunction::info));
2851
2852 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
2853 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
2854}
2855
2856} // namespace KJS
Note: See TracBrowser for help on using the repository browser.