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

Last change on this file since 35217 was 35217, checked in by Simon Hausmann, 17 years ago

2008-07-17 Ariya Hidayat <[email protected]>

Reviewed by Simon.

Fix the 32-bit gcc builds, conversion from "long int" to Register is
ambiguous. Explicitly choose the intptr_t constructor.

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