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

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

Bug 18774: SQUIRRELFISH: print meaningful error messages <https://bugs.webkit.org/show_bug.cgi?id=18774>
<rdar://problem/5769353> SQUIRRELFISH: JavaScript error messages are missing informative text

Reviewed by Cameron Zwarich

Add support for decent error messages in JavaScript. This patch achieves this by providing
ensuring the common errors and exceptions have messages that provide the text of expression
that trigger the exception. In addition it attaches a number of properties to the exception
object detailing where in the source the expression came from.

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