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

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

<rdar://problem/6150322> In Gmail, a crash occurs at KJS::Machine::privateExecute() when applying list styling to text after a quote had been removed
<https://bugs.webkit.org/show_bug.cgi?id=20386>

Reviewed by Cameron Zwarich.

This crash was caused by "depth()" incorrectly determining the scope depth
of a 0 depth function without a full scope chain. Because such a function
would not have an activation the depth function would return the scope depth
of the parent frame, thus triggering an incorrect unwind. Any subsequent
look up that walked the scope chain would result in incorrect behaviour,
leading to a crash or incorrect variable resolution. This can only actually
happen in try...finally statements as that's the only path that can result in
the need to unwind the scope chain, but not force the function to need a
full scope chain.

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