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

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

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

Rubber stamped by Oliver.

Roll out r34777 due to multiple assertion failures on tests.

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