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

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

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

Rubber-stamped by Darin Adler.

Splits RegExpConstructor and RegExpPrototype out of RegExpObject.h/cpp

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