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

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

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

Rubber-stamped by Oliver Hunt.

Splits ArrayConstructor out of ArrayPrototype.h/cpp
Splits BooleanConstructor and BooleanPrototype out of BooleanObject.h/cpp

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