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

Last change on this file since 35310 was 35310, checked in by Adam Roben, 17 years ago

Windows build fixes

Build fix after r35293:

  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: Add API/ to the include path.

Build fix after r35305:

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