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

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

2008-07-23 Gavin Barraclough <[email protected]>

Reviewed by Geoff Garen.

Sampling tool to analyze cost of instruction execution and identify hot regions of JS code.
Enable Switches by setting SAMPLING_TOOL_ENABLED in Opcode.h.

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