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

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

2008-06-30 Cameron Zwarich <[email protected]>

Rubber-stamped by Oliver.

Correct the documentation for op_put_by_index.

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