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

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

JavaScriptCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Splits FunctionConstructor out of FunctionPrototype.h/cpp
Splits NumberConstructor and NumberPrototype out of NumberObject.h/cpp
Rename object_object.h/cpp to ObjectPrototype.h/cpp and split out ObjectConstructor.

  • API/JSCallbackConstructor.cpp:
  • API/JSClassRef.cpp:
  • API/JSObjectRef.cpp:
  • DerivedSources.make:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • VM/Machine.cpp:
  • kjs/AllInOneFile.cpp:
  • kjs/ArrayConstructor.cpp:
  • kjs/ArrayConstructor.h:
  • kjs/FunctionConstructor.cpp: Copied from JavaScriptCore/kjs/FunctionPrototype.cpp.
  • kjs/FunctionConstructor.h: Copied from JavaScriptCore/kjs/FunctionPrototype.h.
  • kjs/FunctionPrototype.cpp:
  • kjs/FunctionPrototype.h:
  • kjs/JSFunction.cpp:
  • kjs/JSGlobalObject.cpp:
  • kjs/JSImmediate.cpp:
  • kjs/MathObject.h:
  • kjs/NumberConstructor.cpp: Copied from JavaScriptCore/kjs/NumberObject.cpp.
  • kjs/NumberConstructor.h: Copied from JavaScriptCore/kjs/NumberObject.h.
  • kjs/NumberObject.cpp:
  • kjs/NumberObject.h:
  • kjs/NumberPrototype.cpp: Copied from JavaScriptCore/kjs/NumberObject.cpp.
  • kjs/NumberPrototype.h: Copied from JavaScriptCore/kjs/NumberObject.h.
  • kjs/ObjectConstructor.cpp: Copied from JavaScriptCore/kjs/object_object.cpp.
  • kjs/ObjectConstructor.h: Copied from JavaScriptCore/kjs/object_object.h.
  • kjs/ObjectPrototype.cpp: Copied from JavaScriptCore/kjs/object_object.cpp.
  • kjs/ObjectPrototype.h: Copied from JavaScriptCore/kjs/object_object.h.
  • kjs/RegExpObject.h:
  • kjs/Shell.cpp:
  • kjs/error_object.h:
  • kjs/internal.cpp:
  • kjs/nodes.cpp:
  • kjs/object_object.cpp: Removed.
  • kjs/object_object.h: Removed.
  • kjs/string_object.h:

WebCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Oliver Hunt.

Update includes after remaming object_object.h to ObjectPrototype.h and
splitting FunctionConstructor out of FunctionPrototype.h

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