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

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

Reviewed by Geoff.

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