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

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

2008-09-15 Geoffrey Garen <[email protected]>

Reviewed by Maciej Stachowiak.


Fixed a typo in op_get_by_id_chain that caused it to miss every time
in the interpreter.


Also, a little cleanup.

  • VM/Machine.cpp: (JSC::Machine::privateExecute): Set up baseObject before entering the loop, so we compare against the right values.
File size: 185.6 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 "BatchedTransitionOptimizer.h"
34#include "CodeBlock.h"
35#include "DebuggerCallFrame.h"
36#include "ExceptionHelpers.h"
37#include "ExecState.h"
38#include "GlobalEvalFunction.h"
39#include "JSActivation.h"
40#include "JSArray.h"
41#include "JSFunction.h"
42#include "JSNotAnObject.h"
43#include "JSPropertyNameIterator.h"
44#include "JSStaticScopeObject.h"
45#include "JSString.h"
46#include "ObjectPrototype.h"
47#include "Parser.h"
48#include "Profiler.h"
49#include "RegExpObject.h"
50#include "RegExpPrototype.h"
51#include "Register.h"
52#include "collector.h"
53#include "debugger.h"
54#include "operations.h"
55#include "SamplingTool.h"
56#include "StringObjectThatMasqueradesAsUndefined.h"
57#include <stdio.h>
58
59#if PLATFORM(DARWIN)
60#include <mach/mach.h>
61#endif
62
63#if HAVE(SYS_TIME_H)
64#include <sys/time.h>
65#endif
66
67#if PLATFORM(WIN_OS)
68#include <windows.h>
69#endif
70
71#if PLATFORM(QT)
72#include <QDateTime>
73#endif
74
75using namespace std;
76
77namespace JSC {
78
79// Preferred number of milliseconds between each timeout check
80static const int preferredScriptCheckTimeInterval = 1000;
81
82#if HAVE(COMPUTED_GOTO)
83static void* op_throw_end_indirect;
84static void* op_call_indirect;
85#endif
86
87// Returns the depth of the scope chain within a given call frame.
88static int depth(CodeBlock* codeBlock, ScopeChain& sc)
89{
90 if (!codeBlock->needsFullScopeChain)
91 return 0;
92 int scopeDepth = 0;
93 ScopeChainIterator iter = sc.begin();
94 ScopeChainIterator end = sc.end();
95 while (!(*iter)->isActivationObject()) {
96 ++iter;
97 if (iter == end)
98 break;
99 ++scopeDepth;
100 }
101 return scopeDepth;
102}
103
104// FIXME: This operation should be called "getNumber", not "isNumber" (as it is in JSValue.h).
105// FIXME: There's no need to have a "slow" version of this. All versions should be fast.
106static bool fastIsNumber(JSValue* value, double& arg)
107{
108 if (JSImmediate::isNumber(value))
109 arg = JSImmediate::getTruncatedInt32(value);
110 else if (Heap::isNumber(static_cast<JSCell*>(value)))
111 arg = static_cast<JSNumberCell*>(value)->value();
112 else
113 return false;
114 return true;
115}
116
117// FIXME: Why doesn't JSValue::toInt32 have the Heap::isNumber optimization?
118static bool fastToInt32(JSValue* value, int32_t& arg)
119{
120 if (JSImmediate::isNumber(value))
121 arg = JSImmediate::getTruncatedInt32(value);
122 else if (Heap::isNumber(static_cast<JSCell*>(value)))
123 arg = static_cast<JSNumberCell*>(value)->toInt32();
124 else
125 return false;
126 return true;
127}
128
129static ALWAYS_INLINE bool fastToUInt32(JSValue* value, uint32_t& arg)
130{
131 if (JSImmediate::isNumber(value)) {
132 if (JSImmediate::getTruncatedUInt32(value, arg))
133 return true;
134 bool scratch;
135 arg = JSValue::toUInt32SlowCase(JSImmediate::getTruncatedInt32(value), scratch);
136 return true;
137 } else if (Heap::isNumber(static_cast<JSCell*>(value)))
138 arg = static_cast<JSNumberCell*>(value)->toUInt32();
139 else
140 return false;
141 return true;
142}
143
144static inline bool jsLess(ExecState* exec, JSValue* v1, JSValue* v2)
145{
146 if (JSImmediate::areBothImmediateNumbers(v1, v2))
147 return JSImmediate::getTruncatedInt32(v1) < JSImmediate::getTruncatedInt32(v2);
148
149 double n1;
150 double n2;
151 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
152 return n1 < n2;
153
154 JSValue* p1;
155 JSValue* p2;
156 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
157 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
158
159 if (wasNotString1 | wasNotString2)
160 return n1 < n2;
161
162 return static_cast<const JSString*>(p1)->value() < static_cast<const JSString*>(p2)->value();
163}
164
165static inline bool jsLessEq(ExecState* exec, JSValue* v1, JSValue* v2)
166{
167 if (JSImmediate::areBothImmediateNumbers(v1, v2))
168 return JSImmediate::getTruncatedInt32(v1) <= JSImmediate::getTruncatedInt32(v2);
169
170 double n1;
171 double n2;
172 if (fastIsNumber(v1, n1) && fastIsNumber(v2, n2))
173 return n1 <= n2;
174
175 JSValue* p1;
176 JSValue* p2;
177 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
178 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
179
180 if (wasNotString1 | wasNotString2)
181 return n1 <= n2;
182
183 return !(static_cast<const JSString*>(p2)->value() < static_cast<const JSString*>(p1)->value());
184}
185
186static JSValue* jsAddSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
187{
188 // exception for the Date exception in defaultValue()
189 JSValue* p1 = v1->toPrimitive(exec);
190 JSValue* p2 = v2->toPrimitive(exec);
191
192 if (p1->isString() || p2->isString()) {
193 RefPtr<UString::Rep> value = concatenate(p1->toString(exec).rep(), p2->toString(exec).rep());
194 if (!value)
195 return throwOutOfMemoryError(exec);
196 return jsString(exec, value.release());
197 }
198
199 return jsNumber(exec, p1->toNumber(exec) + p2->toNumber(exec));
200}
201
202// Fast-path choices here are based on frequency data from SunSpider:
203// <times> Add case: <t1> <t2>
204// ---------------------------
205// 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
206// 247412 Add case: 5 5
207// 20900 Add case: 5 6
208// 13962 Add case: 5 3
209// 4000 Add case: 3 5
210
211static inline JSValue* jsAdd(ExecState* exec, JSValue* v1, JSValue* v2)
212{
213 double left;
214 double right;
215 if (fastIsNumber(v1, left) && fastIsNumber(v2, right))
216 return jsNumber(exec, left + right);
217
218 if (v1->isString() && v2->isString()) {
219 RefPtr<UString::Rep> value = concatenate(static_cast<JSString*>(v1)->value().rep(), static_cast<JSString*>(v2)->value().rep());
220 if (!value)
221 return throwOutOfMemoryError(exec);
222 return jsString(exec, value.release());
223 }
224
225 // All other cases are pretty uncommon
226 return jsAddSlowCase(exec, v1, v2);
227}
228
229static JSValue* jsTypeStringForValue(ExecState* exec, JSValue* v)
230{
231 if (v->isUndefined())
232 return jsNontrivialString(exec, "undefined");
233 if (v->isBoolean())
234 return jsNontrivialString(exec, "boolean");
235 if (v->isNumber())
236 return jsNontrivialString(exec, "number");
237 if (v->isString())
238 return jsNontrivialString(exec, "string");
239 if (v->isObject()) {
240 // Return "undefined" for objects that should be treated
241 // as null when doing comparisons.
242 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
243 return jsNontrivialString(exec, "undefined");
244 CallData callData;
245 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
246 return jsNontrivialString(exec, "function");
247 }
248 return jsNontrivialString(exec, "object");
249}
250
251static bool jsIsObjectType(JSValue* v)
252{
253 if (JSImmediate::isImmediate(v))
254 return v->isNull();
255
256 JSType type = static_cast<JSCell*>(v)->structureID()->type();
257 if (type == NumberType || type == StringType)
258 return false;
259 if (type == ObjectType) {
260 if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
261 return false;
262 CallData callData;
263 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
264 return false;
265 }
266 return true;
267}
268
269static bool jsIsFunctionType(JSValue* v)
270{
271 if (v->isObject()) {
272 CallData callData;
273 if (static_cast<JSObject*>(v)->getCallData(callData) != CallTypeNone)
274 return true;
275 }
276 return false;
277}
278
279static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
280{
281 int dst = (vPC + 1)->u.operand;
282 int property = (vPC + 2)->u.operand;
283
284 ScopeChainIterator iter = scopeChain->begin();
285 ScopeChainIterator end = scopeChain->end();
286 ASSERT(iter != end);
287
288 Identifier& ident = codeBlock->identifiers[property];
289 do {
290 JSObject* o = *iter;
291 PropertySlot slot(o);
292 if (o->getPropertySlot(exec, ident, slot)) {
293 JSValue* result = slot.getValue(exec, ident);
294 exceptionValue = exec->exception();
295 if (exceptionValue)
296 return false;
297 r[dst] = result;
298 return true;
299 }
300 } while (++iter != end);
301 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
302 return false;
303}
304
305static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
306{
307 int dst = (vPC + 1)->u.operand;
308 int property = (vPC + 2)->u.operand;
309 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain;
310
311 ScopeChainIterator iter = scopeChain->begin();
312 ScopeChainIterator end = scopeChain->end();
313 ASSERT(iter != end);
314 while (skip--) {
315 ++iter;
316 ASSERT(iter != end);
317 }
318 Identifier& ident = codeBlock->identifiers[property];
319 do {
320 JSObject* o = *iter;
321 PropertySlot slot(o);
322 if (o->getPropertySlot(exec, ident, slot)) {
323 JSValue* result = slot.getValue(exec, ident);
324 exceptionValue = exec->exception();
325 if (exceptionValue)
326 return false;
327 r[dst] = result;
328 return true;
329 }
330 } while (++iter != end);
331 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
332 return false;
333}
334
335ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain)
336{
337 ScopeChainIterator iter = scopeChain->begin();
338 ScopeChainIterator next = iter;
339 ++next;
340 ScopeChainIterator end = scopeChain->end();
341 ASSERT(iter != end);
342
343 PropertySlot slot;
344 JSObject* base;
345 while (true) {
346 base = *iter;
347 if (next == end || base->getPropertySlot(exec, property, slot))
348 return base;
349
350 iter = next;
351 ++next;
352 }
353
354 ASSERT_NOT_REACHED();
355 return 0;
356}
357
358NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock)
359{
360 int dst = (vPC + 1)->u.operand;
361 int property = (vPC + 2)->u.operand;
362 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain);
363}
364
365static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
366{
367 int baseDst = (vPC + 1)->u.operand;
368 int propDst = (vPC + 2)->u.operand;
369 int property = (vPC + 3)->u.operand;
370
371 ScopeChainIterator iter = scopeChain->begin();
372 ScopeChainIterator end = scopeChain->end();
373
374 // FIXME: add scopeDepthIsZero optimization
375
376 ASSERT(iter != end);
377
378 Identifier& ident = codeBlock->identifiers[property];
379 JSObject* base;
380 do {
381 base = *iter;
382 PropertySlot slot(base);
383 if (base->getPropertySlot(exec, ident, slot)) {
384 JSValue* result = slot.getValue(exec, ident);
385 exceptionValue = exec->exception();
386 if (exceptionValue)
387 return false;
388 r[propDst] = result;
389 r[baseDst] = base;
390 return true;
391 }
392 ++iter;
393 } while (iter != end);
394
395 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
396 return false;
397}
398
399static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue*& exceptionValue)
400{
401 int baseDst = (vPC + 1)->u.operand;
402 int funcDst = (vPC + 2)->u.operand;
403 int property = (vPC + 3)->u.operand;
404
405 ScopeChainIterator iter = scopeChain->begin();
406 ScopeChainIterator end = scopeChain->end();
407
408 // FIXME: add scopeDepthIsZero optimization
409
410 ASSERT(iter != end);
411
412 Identifier& ident = codeBlock->identifiers[property];
413 JSObject* base;
414 do {
415 base = *iter;
416 PropertySlot slot(base);
417 if (base->getPropertySlot(exec, ident, slot)) {
418 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
419 // However, section 10.2.3 says that in the case where the value provided
420 // by the caller is null, the global object should be used. It also says
421 // that the section does not apply to internal functions, but for simplicity
422 // of implementation we use the global object anyway here. This guarantees
423 // that in host objects you always get a valid object for this.
424 // We also handle wrapper substitution for the global object at the same time.
425 JSObject* thisObj = base->toThisObject(exec);
426 JSValue* result = slot.getValue(exec, ident);
427 exceptionValue = exec->exception();
428 if (exceptionValue)
429 return false;
430
431 r[baseDst] = thisObj;
432 r[funcDst] = result;
433 return true;
434 }
435 ++iter;
436 } while (iter != end);
437
438 exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
439 return false;
440}
441
442ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
443{
444 callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
445 callFrame[RegisterFile::ReturnVPC] = vPC + 1;
446 callFrame[RegisterFile::CallerScopeChain] = scopeChain;
447 callFrame[RegisterFile::CallerRegisters] = r;
448 callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
449 callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
450 callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
451 callFrame[RegisterFile::Callee] = function;
452 callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
453}
454
455ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
456{
457 size_t registerOffset = argv + newCodeBlock->numLocals;
458 size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
459
460 if (argc == newCodeBlock->numParameters) { // correct number of arguments
461 if (!registerFile->grow(size)) {
462 exceptionValue = createStackOverflowError(exec);
463 return r;
464 }
465 r += registerOffset;
466 } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
467 if (!registerFile->grow(size)) {
468 exceptionValue = createStackOverflowError(exec);
469 return r;
470 }
471 r += registerOffset;
472
473 int omittedArgCount = newCodeBlock->numParameters - argc;
474 Register* endOfParams = r - newCodeBlock->numVars;
475 for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
476 (*it) = jsUndefined();
477 } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
478 int shift = argc + RegisterFile::CallFrameHeaderSize;
479 registerOffset += shift;
480 size += shift;
481
482 if (!registerFile->grow(size)) {
483 exceptionValue = createStackOverflowError(exec);
484 return r;
485 }
486 r += registerOffset;
487
488 Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
489 Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
490 for ( ; it != end; ++it)
491 *(it + shift) = *it;
492 }
493
494 // initialize local variable slots
495 for (Register* it = r - newCodeBlock->numVars; it != r; ++it)
496 (*it) = jsUndefined();
497
498 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i)
499 r[i] = newCodeBlock->constantRegisters[i];
500
501 return r;
502}
503
504ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNode* functionBodyNode, CodeBlock* newCodeBlock, ScopeChainNode* callDataScopeChain, Register* r)
505{
506 if (newCodeBlock->needsFullScopeChain) {
507 JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
508 r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
509
510 return callDataScopeChain->copy()->push(activation);
511 }
512
513 return callDataScopeChain;
514}
515
516static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
517{
518 if (value->isObject())
519 return false;
520 exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
521 return true;
522}
523
524NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, Register* r, int argv, int argc, JSValue*& exceptionValue)
525{
526 if (argc < 2)
527 return jsUndefined();
528
529 JSValue* program = r[argv + 1].jsValue(exec);
530
531 if (!program->isString())
532 return program;
533
534 Profiler** profiler = Profiler::enabledProfilerReference();
535 if (*profiler)
536 (*profiler)->willExecute(exec, scopeChain->globalObject()->evalFunction());
537
538 UString programSource = static_cast<JSString*>(program)->value();
539
540 RefPtr<EvalNode> evalNode = callingCodeBlock->evalCodeCache.get(exec, programSource, scopeChain, exceptionValue);
541
542 JSValue* result = 0;
543 if (evalNode)
544 result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
545
546 if (*profiler)
547 (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
548
549 return result;
550}
551
552Machine::Machine()
553 : m_sampler(0)
554#if ENABLE(CTI)
555 , m_ctiArrayLengthTrampoline(0)
556 , m_ctiStringLengthTrampoline(0)
557 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024))
558#endif
559 , m_reentryDepth(0)
560 , m_timeoutTime(0)
561 , m_timeAtLastCheckTimeout(0)
562 , m_timeExecuting(0)
563 , m_timeoutCheckCount(0)
564 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
565{
566 privateExecute(InitializeAndReturn);
567
568 // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
569 void* storage = fastMalloc(sizeof(CollectorBlock));
570
571 JSArray* jsArray = new (storage) JSArray(StructureID::create(jsNull()));
572 m_jsArrayVptr = jsArray->vptr();
573 static_cast<JSCell*>(jsArray)->~JSCell();
574
575 StringObjectThatMasqueradesAsUndefined* jsStringObjectThatMasqueradesAsUndefined = new (storage) StringObjectThatMasqueradesAsUndefined(StringObjectThatMasqueradesAsUndefined::VPtrStealingHack);
576 m_jsStringObjectThatMasqueradesAsUndefinedVptr = jsStringObjectThatMasqueradesAsUndefined->vptr();
577 static_cast<JSCell*>(jsStringObjectThatMasqueradesAsUndefined)->~JSCell();
578
579 JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
580 m_jsStringVptr = jsString->vptr();
581 static_cast<JSCell*>(jsString)->~JSCell();
582
583 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull()));
584 m_jsFunctionVptr = jsFunction->vptr();
585 static_cast<JSCell*>(jsFunction)->~JSCell();
586
587 fastFree(storage);
588}
589
590Machine::~Machine()
591{
592#if ENABLE(CTI)
593 if (m_ctiArrayLengthTrampoline)
594 fastFree(m_ctiArrayLengthTrampoline);
595 if (m_ctiStringLengthTrampoline)
596 fastFree(m_ctiStringLengthTrampoline);
597#endif
598}
599
600#ifndef NDEBUG
601
602void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
603{
604 ScopeChain sc(scopeChain);
605 JSGlobalObject* globalObject = sc.globalObject();
606 codeBlock->dump(globalObject->globalExec());
607 dumpRegisters(codeBlock, registerFile, r);
608}
609
610void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFile, const Register* r)
611{
612 printf("Register frame: \n\n");
613 printf("----------------------------------------------------\n");
614 printf(" use | address | value \n");
615 printf("----------------------------------------------------\n");
616
617 const Register* it;
618 const Register* end;
619
620 if (codeBlock->codeType == GlobalCode) {
621 it = registerFile->lastGlobal();
622 end = it + registerFile->numGlobals();
623 while (it != end) {
624 printf("[global var] | %10p | %10p \n", it, (*it).v());
625 ++it;
626 }
627 printf("----------------------------------------------------\n");
628 }
629
630 it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
631 printf("[CallerCodeBlock] | %10p | %10p \n", it, (*it).v()); ++it;
632 printf("[ReturnVPC] | %10p | %10p \n", it, (*it).v()); ++it;
633 printf("[CallerScopeChain] | %10p | %10p \n", it, (*it).v()); ++it;
634 printf("[CallerRegisterOffset] | %10p | %10p \n", it, (*it).v()); ++it;
635 printf("[ReturnValueRegister] | %10p | %10p \n", it, (*it).v()); ++it;
636 printf("[ArgumentStartRegister] | %10p | %10p \n", it, (*it).v()); ++it;
637 printf("[ArgumentCount] | %10p | %10p \n", it, (*it).v()); ++it;
638 printf("[Callee] | %10p | %10p \n", it, (*it).v()); ++it;
639 printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
640 printf("----------------------------------------------------\n");
641
642 printf("[this] | %10p | %10p \n", it, (*it).v()); ++it;
643 end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
644 if (it != end) {
645 do {
646 printf("[param] | %10p | %10p \n", it, (*it).v());
647 ++it;
648 } while (it != end);
649 }
650 printf("----------------------------------------------------\n");
651
652 if (codeBlock->codeType != GlobalCode) {
653 end = it + codeBlock->numVars;
654 if (it != end) {
655 do {
656 printf("[var] | %10p | %10p \n", it, (*it).v());
657 ++it;
658 } while (it != end);
659 printf("----------------------------------------------------\n");
660 }
661 }
662
663 end = it + codeBlock->numTemporaries;
664 if (it != end) {
665 do {
666 printf("[temp] | %10p | %10p \n", it, (*it).v());
667 ++it;
668 } while (it != end);
669 }
670}
671
672#endif
673
674//#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
675
676bool Machine::isOpcode(Opcode opcode)
677{
678#if HAVE(COMPUTED_GOTO)
679 return opcode != HashTraits<Opcode>::emptyValue()
680 && !HashTraits<Opcode>::isDeletedValue(opcode)
681 && m_opcodeIDTable.contains(opcode);
682#else
683 return opcode >= 0 && opcode <= op_end;
684#endif
685}
686
687//#endif
688
689NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
690{
691 CodeBlock* oldCodeBlock = codeBlock;
692 Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
693
694 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
695 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
696 if (callFrame[RegisterFile::Callee].jsValue(exec))
697 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
698 else
699 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
700 }
701
702 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
703 if (callFrame[RegisterFile::Callee].jsValue(exec))
704 profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
705 else
706 profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
707 }
708
709 if (oldCodeBlock->needsFullScopeChain)
710 scopeChain->deref();
711
712 // If this call frame created an activation, tear it off.
713 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
714 ASSERT(activation->isActivationObject());
715 activation->copyRegisters();
716 }
717
718 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
719 if (!codeBlock)
720 return false;
721
722 scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
723 r = callFrame[RegisterFile::CallerRegisters].r();
724 exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
725 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
726
727 return true;
728}
729
730NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
731{
732 // Set up the exception object
733
734 if (exceptionValue->isObject()) {
735 JSObject* exception = static_cast<JSObject*>(exceptionValue);
736 if (exception->isNotAnObjectErrorStub()) {
737 exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
738 exceptionValue = exception;
739 } else {
740 if (!exception->hasProperty(exec, Identifier(exec, "line")) &&
741 !exception->hasProperty(exec, Identifier(exec, "sourceId")) &&
742 !exception->hasProperty(exec, Identifier(exec, "sourceURL")) &&
743 !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) &&
744 !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) &&
745 !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
746 if (explicitThrow) {
747 int startOffset = 0;
748 int endOffset = 0;
749 int divotPoint = 0;
750 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
751 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
752
753 // We only hit this path for error messages and throw statements, which don't have a specific failure position
754 // So we just give the full range of the error/throw statement.
755 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
756 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
757 } else
758 exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
759 exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
760 exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
761 }
762
763 if (exception->isWatchdogException()) {
764 while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r)) {
765 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
766 }
767 return 0;
768 }
769 }
770 }
771
772 if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
773 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
774 debugger->exception(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->lineNumberForVPC(vPC));
775 }
776
777 // Calculate an exception handler vPC, unwinding call frames as necessary.
778
779 int scopeDepth;
780 Instruction* handlerVPC;
781
782 while (!codeBlock->getHandlerForVPC(vPC, handlerVPC, scopeDepth)) {
783 if (!unwindCallFrame(exec, exceptionValue, vPC, codeBlock, scopeChain, r))
784 return 0;
785 }
786
787 // Now unwind the scope chain within the exception handler's call frame.
788
789 ScopeChain sc(scopeChain);
790 int scopeDelta = depth(codeBlock, sc) - scopeDepth;
791 ASSERT(scopeDelta >= 0);
792 while (scopeDelta--)
793 sc.pop();
794 setScopeChain(exec, scopeChain, sc.node());
795
796 return handlerVPC;
797}
798
799JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue** exception)
800{
801 if (m_reentryDepth >= MaxReentryDepth) {
802 *exception = createStackOverflowError(exec);
803 return 0;
804 }
805
806 CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
807
808 size_t oldSize = m_registerFile.size();
809 size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
810 if (!m_registerFile.grow(newSize)) {
811 *exception = createStackOverflowError(exec);
812 return 0;
813 }
814
815 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
816 JSGlobalObject* globalObject = exec->dynamicGlobalObject();
817 globalObject->copyGlobalsTo(m_registerFile);
818
819 Register* callFrame = m_registerFile.base() + oldSize;
820
821 // a 0 codeBlock indicates a built-in caller
822 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
823
824 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
825 r[codeBlock->thisRegister] = thisObj;
826
827 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
828 r[i] = codeBlock->constantRegisters[i];
829
830 if (codeBlock->needsFullScopeChain)
831 scopeChain = scopeChain->copy();
832
833 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
834
835 Profiler** profiler = Profiler::enabledProfilerReference();
836 if (*profiler)
837 (*profiler)->willExecute(exec, programNode->sourceURL(), programNode->lineNo());
838
839 m_reentryDepth++;
840#if ENABLE(CTI)
841 if (!codeBlock->ctiCode)
842 CTI::compile(this, exec, codeBlock);
843 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
844#else
845 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
846#endif
847 m_reentryDepth--;
848
849 MACHINE_SAMPLING_privateExecuteReturned();
850
851 if (*profiler)
852 (*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
853
854 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
855 lastGlobalObject->copyGlobalsTo(m_registerFile);
856
857 m_registerFile.shrink(oldSize);
858 return result;
859}
860
861JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue** exception)
862{
863 if (m_reentryDepth >= MaxReentryDepth) {
864 *exception = createStackOverflowError(exec);
865 return 0;
866 }
867
868 int argv = RegisterFile::CallFrameHeaderSize;
869 int argc = args.size() + 1; // implicit "this" parameter
870
871 size_t oldSize = m_registerFile.size();
872 if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
873 *exception = createStackOverflowError(exec);
874 return 0;
875 }
876
877 Register* callFrame = m_registerFile.base() + oldSize;
878
879 // put args in place, including "this"
880 Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
881 (*dst) = thisObj;
882
883 ArgList::const_iterator end = args.end();
884 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
885 (*++dst) = *it;
886
887 // a 0 codeBlock indicates a built-in caller
888 initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
889
890 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
891 Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
892 if (*exception) {
893 m_registerFile.shrink(oldSize);
894 return 0;
895 }
896
897 scopeChain = scopeChainForCall(exec, functionBodyNode, newCodeBlock, scopeChain, r);
898
899 ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
900
901 Profiler** profiler = Profiler::enabledProfilerReference();
902 if (*profiler)
903 (*profiler)->willExecute(exec, function);
904
905 m_reentryDepth++;
906#if ENABLE(CTI)
907 if (!newCodeBlock->ctiCode)
908 CTI::compile(this, exec, newCodeBlock);
909 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
910#else
911 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
912#endif
913 m_reentryDepth--;
914
915 MACHINE_SAMPLING_privateExecuteReturned();
916
917 m_registerFile.shrink(oldSize);
918 return result;
919}
920
921JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
922{
923 if (m_reentryDepth >= MaxReentryDepth) {
924 *exception = createStackOverflowError(exec);
925 return 0;
926 }
927
928 EvalCodeBlock* codeBlock = &evalNode->byteCode(scopeChain);
929
930 JSVariableObject* variableObject;
931 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
932 ASSERT(node);
933 if (node->object->isVariableObject()) {
934 variableObject = static_cast<JSVariableObject*>(node->object);
935 break;
936 }
937 }
938
939 { // Scope for BatchedTransitionOptimizer
940
941 BatchedTransitionOptimizer optimizer(variableObject);
942
943 const Node::VarStack& varStack = codeBlock->ownerNode->varStack();
944 Node::VarStack::const_iterator varStackEnd = varStack.end();
945 for (Node::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
946 const Identifier& ident = (*it).first;
947 if (!variableObject->hasProperty(exec, ident)) {
948 PutPropertySlot slot;
949 variableObject->put(exec, ident, jsUndefined(), slot);
950 }
951 }
952
953 const Node::FunctionStack& functionStack = codeBlock->ownerNode->functionStack();
954 Node::FunctionStack::const_iterator functionStackEnd = functionStack.end();
955 for (Node::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
956 PutPropertySlot slot;
957 variableObject->put(exec, (*it)->m_ident, (*it)->makeFunction(exec, scopeChain), slot);
958 }
959
960 }
961
962 size_t oldSize = m_registerFile.size();
963 size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
964 if (!m_registerFile.grow(newSize)) {
965 *exception = createStackOverflowError(exec);
966 return 0;
967 }
968
969 Register* callFrame = m_registerFile.base() + registerOffset;
970
971 // a 0 codeBlock indicates a built-in caller
972 initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
973
974 Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
975 r[codeBlock->thisRegister] = thisObj;
976
977 for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
978 r[i] = codeBlock->constantRegisters[i];
979
980 if (codeBlock->needsFullScopeChain)
981 scopeChain = scopeChain->copy();
982
983 ExecState newExec(exec, &m_registerFile, scopeChain, 0);
984
985 Profiler** profiler = Profiler::enabledProfilerReference();
986 if (*profiler)
987 (*profiler)->willExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
988
989 m_reentryDepth++;
990#if ENABLE(CTI)
991 if (!codeBlock->ctiCode)
992 CTI::compile(this, exec, codeBlock);
993 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
994#else
995 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
996#endif
997 m_reentryDepth--;
998
999 MACHINE_SAMPLING_privateExecuteReturned();
1000
1001 if (*profiler)
1002 (*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
1003
1004 m_registerFile.shrink(oldSize);
1005 return result;
1006}
1007
1008ALWAYS_INLINE void Machine::setScopeChain(ExecState* exec, ScopeChainNode*& scopeChain, ScopeChainNode* newScopeChain)
1009{
1010 scopeChain = newScopeChain;
1011 exec->m_scopeChain = newScopeChain;
1012}
1013
1014NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine)
1015{
1016 Debugger* debugger = exec->dynamicGlobalObject()->debugger();
1017 if (!debugger)
1018 return;
1019
1020 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0);
1021
1022 switch (debugHookID) {
1023 case DidEnterCallFrame:
1024 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1025 return;
1026 case WillLeaveCallFrame:
1027 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1028 return;
1029 case WillExecuteStatement:
1030 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1031 return;
1032 case WillExecuteProgram:
1033 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine);
1034 return;
1035 case DidExecuteProgram:
1036 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1037 return;
1038 case DidReachBreakpoint:
1039 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine);
1040 return;
1041 }
1042}
1043
1044void Machine::resetTimeoutCheck()
1045{
1046 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1047 m_timeAtLastCheckTimeout = 0;
1048 m_timeExecuting = 0;
1049}
1050
1051// Returns the time the current thread has spent executing, in milliseconds.
1052static inline unsigned getCPUTime()
1053{
1054#if PLATFORM(DARWIN)
1055 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
1056 thread_basic_info_data_t info;
1057
1058 // Get thread information
1059 thread_info(mach_thread_self(), THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
1060
1061 unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
1062 time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
1063
1064 return time;
1065#elif HAVE(SYS_TIME_H)
1066 // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag.
1067 struct timeval tv;
1068 gettimeofday(&tv, 0);
1069 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
1070#elif PLATFORM(QT)
1071 QDateTime t = QDateTime::currentDateTime();
1072 return t.toTime_t() * 1000 + t.time().msec();
1073#elif PLATFORM(WIN_OS)
1074 union {
1075 FILETIME fileTime;
1076 unsigned long long fileTimeAsLong;
1077 } userTime, kernelTime;
1078
1079 // GetThreadTimes won't accept NULL arguments so we pass these even though
1080 // they're not used.
1081 FILETIME creationTime, exitTime;
1082
1083 GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
1084
1085 return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
1086#else
1087#error Platform does not have getCurrentTime function
1088#endif
1089}
1090
1091// We have to return a JSValue here, gcc seems to produce worse code if
1092// we attempt to return a bool
1093ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject)
1094{
1095 unsigned currentTime = getCPUTime();
1096
1097 if (!m_timeAtLastCheckTimeout) {
1098 // Suspicious amount of looping in a script -- start timing it
1099 m_timeAtLastCheckTimeout = currentTime;
1100 return 0;
1101 }
1102
1103 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout;
1104
1105 if (timeDiff == 0)
1106 timeDiff = 1;
1107
1108 m_timeExecuting += timeDiff;
1109 m_timeAtLastCheckTimeout = currentTime;
1110
1111 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
1112 // preferredScriptCheckTimeInterval
1113 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck);
1114 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
1115 // preferred script check time interval.
1116 if (m_ticksUntilNextTimeoutCheck == 0)
1117 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold;
1118
1119 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) {
1120 if (globalObject->shouldInterruptScript())
1121 return jsNull(); // Appeasing GCC, all we need is a non-null js value.
1122
1123 resetTimeoutCheck();
1124 }
1125
1126 return 0;
1127}
1128
1129static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain)
1130{
1131 int dst = (++vPC)->u.operand;
1132 Identifier& property = codeBlock->identifiers[(++vPC)->u.operand];
1133 JSValue* value = r[(++vPC)->u.operand].jsValue(exec);
1134 JSObject* scope = new (exec) JSStaticScopeObject(exec, property, value, DontDelete);
1135 r[dst] = scope;
1136 return scopeChain->push(scope);
1137}
1138
1139static StructureIDChain* cachePrototypeChain(ExecState* exec, StructureID* structureID)
1140{
1141 JSValue* prototype = structureID->prototypeForLookup(exec);
1142 if (JSImmediate::isImmediate(prototype))
1143 return 0;
1144 RefPtr<StructureIDChain> chain = StructureIDChain::create(static_cast<JSObject*>(prototype)->structureID());
1145 structureID->setCachedPrototypeChain(chain.release());
1146 return structureID->cachedPrototypeChain();
1147}
1148
1149NEVER_INLINE void Machine::tryCachePutByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const PutPropertySlot& slot)
1150{
1151 // Recursive invocation may already have specialized this instruction.
1152 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
1153 return;
1154
1155 if (JSImmediate::isImmediate(baseValue))
1156 return;
1157
1158 // Uncacheable: give up.
1159 if (!slot.isCacheable()) {
1160 vPC[0] = getOpcode(op_put_by_id_generic);
1161 return;
1162 }
1163
1164 JSCell* baseCell = static_cast<JSCell*>(baseValue);
1165 StructureID* structureID = baseCell->structureID();
1166
1167 if (structureID->isDictionary()) {
1168 vPC[0] = getOpcode(op_put_by_id_generic);
1169 return;
1170 }
1171
1172 // Cache miss: record StructureID to compare against next time.
1173 StructureID* lastStructureID = vPC[4].u.structureID;
1174 if (structureID != lastStructureID) {
1175 // First miss: record StructureID to compare against next time.
1176 if (!lastStructureID) {
1177 vPC[4] = structureID;
1178 return;
1179 }
1180
1181 // Second miss: give up.
1182 vPC[0] = getOpcode(op_put_by_id_generic);
1183 return;
1184 }
1185
1186 // Cache hit: Specialize instruction and ref StructureIDs.
1187
1188 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
1189 if (baseCell != slot.base()) {
1190 vPC[0] = getOpcode(op_put_by_id_generic);
1191 return;
1192 }
1193
1194 // StructureID transition, cache transition info
1195 if (slot.type() == PutPropertySlot::NewProperty) {
1196 vPC[0] = getOpcode(op_put_by_id_transition);
1197 vPC[4] = structureID->previousID();
1198 vPC[5] = structureID;
1199 StructureIDChain* chain = structureID->cachedPrototypeChain();
1200 if (!chain) {
1201 chain = cachePrototypeChain(exec, structureID);
1202 if (!chain) {
1203 // This happens if someone has manually inserted null into the prototype chain
1204 vPC[0] = getOpcode(op_put_by_id_generic);
1205 return;
1206 }
1207 }
1208 vPC[6] = chain;
1209 vPC[7] = slot.cachedOffset();
1210 codeBlock->refStructureIDs(vPC);
1211 return;
1212 }
1213
1214 vPC[0] = getOpcode(op_put_by_id_replace);
1215 vPC[5] = slot.cachedOffset();
1216 codeBlock->refStructureIDs(vPC);
1217}
1218
1219NEVER_INLINE void Machine::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1220{
1221 codeBlock->derefStructureIDs(vPC);
1222 vPC[0] = getOpcode(op_put_by_id);
1223 vPC[4] = 0;
1224}
1225
1226NEVER_INLINE void Machine::tryCacheGetByID(ExecState* exec, CodeBlock* codeBlock, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
1227{
1228 // Recursive invocation may already have specialized this instruction.
1229 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1230 return;
1231
1232 // FIXME: Cache property access for immediates.
1233 if (JSImmediate::isImmediate(baseValue)) {
1234 vPC[0] = getOpcode(op_get_by_id_generic);
1235 return;
1236 }
1237
1238 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
1239 vPC[0] = getOpcode(op_get_array_length);
1240 return;
1241 }
1242
1243 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
1244 vPC[0] = getOpcode(op_get_string_length);
1245 return;
1246 }
1247
1248 // Uncacheable: give up.
1249 if (!slot.isCacheable()) {
1250 vPC[0] = getOpcode(op_get_by_id_generic);
1251 return;
1252 }
1253
1254 StructureID* structureID = static_cast<JSCell*>(baseValue)->structureID();
1255
1256 if (structureID->isDictionary()) {
1257 vPC[0] = getOpcode(op_get_by_id_generic);
1258 return;
1259 }
1260
1261 // Cache miss
1262 StructureID* lastStructureID = vPC[4].u.structureID;
1263 if (structureID != lastStructureID) {
1264 // First miss: record StructureID to compare against next time.
1265 if (!lastStructureID) {
1266 vPC[4] = structureID;
1267 return;
1268 }
1269
1270 // Second miss: give up.
1271 vPC[0] = getOpcode(op_get_by_id_generic);
1272 return;
1273 }
1274
1275 // Cache hit: Specialize instruction and ref StructureIDs.
1276
1277 if (slot.slotBase() == baseValue) {
1278 vPC[0] = getOpcode(op_get_by_id_self);
1279 vPC[5] = slot.cachedOffset();
1280
1281 codeBlock->refStructureIDs(vPC);
1282 return;
1283 }
1284
1285 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
1286 ASSERT(slot.slotBase()->isObject());
1287
1288 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase());
1289
1290 // Heavy access to a prototype is a good indication that it's not being
1291 // used as a dictionary.
1292 if (baseObject->structureID()->isDictionary()) {
1293 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID());
1294 baseObject->setStructureID(transition.release());
1295 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1296 }
1297
1298 vPC[0] = getOpcode(op_get_by_id_proto);
1299 vPC[5] = baseObject->structureID();
1300 vPC[6] = slot.cachedOffset();
1301
1302 codeBlock->refStructureIDs(vPC);
1303 return;
1304 }
1305
1306 size_t count = 0;
1307 JSObject* o = static_cast<JSObject*>(baseValue);
1308 while (slot.slotBase() != o) {
1309 JSValue* v = o->structureID()->prototypeForLookup(exec);
1310
1311 // If we didn't find base in baseValue's prototype chain, then baseValue
1312 // must be a proxy for another object.
1313 if (v->isNull()) {
1314 vPC[0] = getOpcode(op_get_by_id_generic);
1315 return;
1316 }
1317
1318 o = static_cast<JSObject*>(v);
1319
1320 // Heavy access to a prototype is a good indication that it's not being
1321 // used as a dictionary.
1322 if (o->structureID()->isDictionary()) {
1323 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
1324 o->setStructureID(transition.release());
1325 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
1326 }
1327
1328 ++count;
1329 }
1330
1331 StructureIDChain* chain = structureID->cachedPrototypeChain();
1332 if (!chain)
1333 chain = cachePrototypeChain(exec, structureID);
1334 ASSERT(chain);
1335
1336 vPC[0] = getOpcode(op_get_by_id_chain);
1337 vPC[4] = structureID;
1338 vPC[5] = chain;
1339 vPC[6] = count;
1340 vPC[7] = slot.cachedOffset();
1341 codeBlock->refStructureIDs(vPC);
1342}
1343
1344NEVER_INLINE void Machine::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1345{
1346 codeBlock->derefStructureIDs(vPC);
1347 vPC[0] = getOpcode(op_get_by_id);
1348 vPC[4] = 0;
1349}
1350
1351JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception)
1352{
1353 // One-time initialization of our address tables. We have to put this code
1354 // here because our labels are only in scope inside this function.
1355 if (flag == InitializeAndReturn) {
1356 #if HAVE(COMPUTED_GOTO)
1357 #define ADD_OPCODE(id) m_opcodeTable[id] = &&id;
1358 FOR_EACH_OPCODE_ID(ADD_OPCODE);
1359 #undef ADD_OPCODE
1360
1361 #define ADD_OPCODE_ID(id) m_opcodeIDTable.add(&&id, id);
1362 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1363 #undef ADD_OPCODE_ID
1364 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1365 op_throw_end_indirect = &&op_throw_end;
1366 op_call_indirect = &&op_call;
1367 #endif // HAVE(COMPUTED_GOTO)
1368 return 0;
1369 }
1370
1371#if ENABLE(CTI)
1372 // Currently with CTI enabled we never interpret functions
1373 ASSERT_NOT_REACHED();
1374#endif
1375
1376 JSValue* exceptionValue = 0;
1377 Instruction* handlerVPC = 0;
1378
1379 Register* registerBase = registerFile->base();
1380 Instruction* vPC = codeBlock->instructions.begin();
1381 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1382 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1;
1383
1384#define VM_CHECK_EXCEPTION() \
1385 do { \
1386 if (UNLIKELY(exec->hadException())) { \
1387 exceptionValue = exec->exception(); \
1388 goto vm_throw; \
1389 } \
1390 } while (0)
1391
1392#if DUMP_OPCODE_STATS
1393 OpcodeStats::resetLastInstruction();
1394#endif
1395
1396#define CHECK_FOR_TIMEOUT() \
1397 if (!--tickCount) { \
1398 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \
1399 goto vm_throw; \
1400 tickCount = m_ticksUntilNextTimeoutCheck; \
1401 }
1402
1403#if HAVE(COMPUTED_GOTO)
1404 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
1405#if DUMP_OPCODE_STATS
1406 #define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1407#else
1408 #define BEGIN_OPCODE(opcode) opcode:
1409#endif
1410 NEXT_OPCODE;
1411#else
1412 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
1413#if DUMP_OPCODE_STATS
1414 #define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1415#else
1416 #define BEGIN_OPCODE(opcode) case opcode:
1417#endif
1418 while (1) // iterator loop begins
1419 switch (vPC->u.opcode)
1420#endif
1421 {
1422 BEGIN_OPCODE(op_new_object) {
1423 /* new_object dst(r)
1424
1425 Constructs a new empty Object instance using the original
1426 constructor, and puts the result in register dst.
1427 */
1428 int dst = (++vPC)->u.operand;
1429 r[dst] = constructEmptyObject(exec);
1430
1431 ++vPC;
1432 NEXT_OPCODE;
1433 }
1434 BEGIN_OPCODE(op_new_array) {
1435 /* new_array dst(r) firstArg(r) argCount(n)
1436
1437 Constructs a new Array instance using the original
1438 constructor, and puts the result in register dst.
1439 The array will contain argCount elements with values
1440 taken from registers starting at register firstArg.
1441 */
1442 int dst = (++vPC)->u.operand;
1443 int firstArg = (++vPC)->u.operand;
1444 int argCount = (++vPC)->u.operand;
1445 ArgList args(r + firstArg, argCount);
1446 r[dst] = constructArray(exec, args);
1447
1448 ++vPC;
1449 NEXT_OPCODE;
1450 }
1451 BEGIN_OPCODE(op_new_regexp) {
1452 /* new_regexp dst(r) regExp(re)
1453
1454 Constructs a new RegExp instance using the original
1455 constructor from regexp regExp, and puts the result in
1456 register dst.
1457 */
1458 int dst = (++vPC)->u.operand;
1459 int regExp = (++vPC)->u.operand;
1460 r[dst] = new (exec) RegExpObject(scopeChain->globalObject()->regExpPrototype(), codeBlock->regexps[regExp]);
1461
1462 ++vPC;
1463 NEXT_OPCODE;
1464 }
1465 BEGIN_OPCODE(op_mov) {
1466 /* mov dst(r) src(r)
1467
1468 Copies register src to register dst.
1469 */
1470 int dst = (++vPC)->u.operand;
1471 int src = (++vPC)->u.operand;
1472 r[dst] = r[src];
1473
1474 ++vPC;
1475 NEXT_OPCODE;
1476 }
1477 BEGIN_OPCODE(op_eq) {
1478 /* eq dst(r) src1(r) src2(r)
1479
1480 Checks whether register src1 and register src2 are equal,
1481 as with the ECMAScript '==' operator, and puts the result
1482 as a boolean in register dst.
1483 */
1484 int dst = (++vPC)->u.operand;
1485 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1486 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1487 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1488 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1489 else {
1490 JSValue* result = jsBoolean(equal(exec, src1, src2));
1491 VM_CHECK_EXCEPTION();
1492 r[dst] = result;
1493 }
1494
1495 ++vPC;
1496 NEXT_OPCODE;
1497 }
1498 BEGIN_OPCODE(op_eq_null) {
1499 /* neq dst(r) src(r)
1500
1501 Checks whether register src is null, as with the ECMAScript '!='
1502 operator, and puts the result as a boolean in register dst.
1503 */
1504 int dst = (++vPC)->u.operand;
1505 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1506
1507 if (src->isUndefinedOrNull()) {
1508 r[dst] = jsBoolean(true);
1509 ++vPC;
1510 NEXT_OPCODE;
1511 }
1512
1513 r[dst] = jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
1514 ++vPC;
1515 NEXT_OPCODE;
1516 }
1517 BEGIN_OPCODE(op_neq) {
1518 /* neq dst(r) src1(r) src2(r)
1519
1520 Checks whether register src1 and register src2 are not
1521 equal, as with the ECMAScript '!=' operator, and puts the
1522 result as a boolean in register dst.
1523 */
1524 int dst = (++vPC)->u.operand;
1525 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1526 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1527 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1528 r[dst] = jsBoolean(src1 != src2);
1529 else {
1530 JSValue* result = jsBoolean(!equal(exec, src1, src2));
1531 VM_CHECK_EXCEPTION();
1532 r[dst] = result;
1533 }
1534
1535 ++vPC;
1536 NEXT_OPCODE;
1537 }
1538 BEGIN_OPCODE(op_neq_null) {
1539 /* neq dst(r) src(r)
1540
1541 Checks whether register src is not null, as with the ECMAScript '!='
1542 operator, and puts the result as a boolean in register dst.
1543 */
1544 int dst = (++vPC)->u.operand;
1545 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1546
1547 if (src->isUndefinedOrNull()) {
1548 r[dst] = jsBoolean(false);
1549 ++vPC;
1550 NEXT_OPCODE;
1551 }
1552
1553 r[dst] = jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
1554 ++vPC;
1555 NEXT_OPCODE;
1556 }
1557 BEGIN_OPCODE(op_stricteq) {
1558 /* stricteq dst(r) src1(r) src2(r)
1559
1560 Checks whether register src1 and register src2 are strictly
1561 equal, as with the ECMAScript '===' operator, and puts the
1562 result as a boolean in register dst.
1563 */
1564 int dst = (++vPC)->u.operand;
1565 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1566 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1567 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1568 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
1569 else
1570 r[dst] = jsBoolean(strictEqual(src1, src2));
1571
1572 ++vPC;
1573 NEXT_OPCODE;
1574 }
1575 BEGIN_OPCODE(op_nstricteq) {
1576 /* nstricteq dst(r) src1(r) src2(r)
1577
1578 Checks whether register src1 and register src2 are not
1579 strictly equal, as with the ECMAScript '!==' operator, and
1580 puts the result as a boolean in register dst.
1581 */
1582 int dst = (++vPC)->u.operand;
1583 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1584 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1585 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1586 r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
1587 else
1588 r[dst] = jsBoolean(!strictEqual(src1, src2));
1589
1590 ++vPC;
1591 NEXT_OPCODE;
1592 }
1593 BEGIN_OPCODE(op_less) {
1594 /* less dst(r) src1(r) src2(r)
1595
1596 Checks whether register src1 is less than register src2, as
1597 with the ECMAScript '<' operator, and puts the result as
1598 a boolean in register dst.
1599 */
1600 int dst = (++vPC)->u.operand;
1601 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1602 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1603 JSValue* result = jsBoolean(jsLess(exec, src1, src2));
1604 VM_CHECK_EXCEPTION();
1605 r[dst] = result;
1606
1607 ++vPC;
1608 NEXT_OPCODE;
1609 }
1610 BEGIN_OPCODE(op_lesseq) {
1611 /* lesseq dst(r) src1(r) src2(r)
1612
1613 Checks whether register src1 is less than or equal to
1614 register src2, as with the ECMAScript '<=' operator, and
1615 puts the result as a boolean in register dst.
1616 */
1617 int dst = (++vPC)->u.operand;
1618 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1619 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1620 JSValue* result = jsBoolean(jsLessEq(exec, src1, src2));
1621 VM_CHECK_EXCEPTION();
1622 r[dst] = result;
1623
1624 ++vPC;
1625 NEXT_OPCODE;
1626 }
1627 BEGIN_OPCODE(op_pre_inc) {
1628 /* pre_inc srcDst(r)
1629
1630 Converts register srcDst to number, adds one, and puts the result
1631 back in register srcDst.
1632 */
1633 int srcDst = (++vPC)->u.operand;
1634 JSValue* v = r[srcDst].jsValue(exec);
1635 if (JSImmediate::canDoFastAdditiveOperations(v))
1636 r[srcDst] = JSImmediate::incImmediateNumber(v);
1637 else {
1638 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
1639 VM_CHECK_EXCEPTION();
1640 r[srcDst] = result;
1641 }
1642
1643 ++vPC;
1644 NEXT_OPCODE;
1645 }
1646 BEGIN_OPCODE(op_pre_dec) {
1647 /* pre_dec srcDst(r)
1648
1649 Converts register srcDst to number, subtracts one, and puts the result
1650 back in register srcDst.
1651 */
1652 int srcDst = (++vPC)->u.operand;
1653 JSValue* v = r[srcDst].jsValue(exec);
1654 if (JSImmediate::canDoFastAdditiveOperations(v))
1655 r[srcDst] = JSImmediate::decImmediateNumber(v);
1656 else {
1657 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
1658 VM_CHECK_EXCEPTION();
1659 r[srcDst] = result;
1660 }
1661
1662 ++vPC;
1663 NEXT_OPCODE;
1664 }
1665 BEGIN_OPCODE(op_post_inc) {
1666 /* post_inc dst(r) srcDst(r)
1667
1668 Converts register srcDst to number. The number itself is
1669 written to register dst, and the number plus one is written
1670 back to register srcDst.
1671 */
1672 int dst = (++vPC)->u.operand;
1673 int srcDst = (++vPC)->u.operand;
1674 JSValue* v = r[srcDst].jsValue(exec);
1675 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1676 r[dst] = v;
1677 r[srcDst] = JSImmediate::incImmediateNumber(v);
1678 } else {
1679 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1680 VM_CHECK_EXCEPTION();
1681 r[dst] = number;
1682 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() + 1);
1683 }
1684
1685 ++vPC;
1686 NEXT_OPCODE;
1687 }
1688 BEGIN_OPCODE(op_post_dec) {
1689 /* post_dec dst(r) srcDst(r)
1690
1691 Converts register srcDst to number. The number itself is
1692 written to register dst, and the number minus one is written
1693 back to register srcDst.
1694 */
1695 int dst = (++vPC)->u.operand;
1696 int srcDst = (++vPC)->u.operand;
1697 JSValue* v = r[srcDst].jsValue(exec);
1698 if (JSImmediate::canDoFastAdditiveOperations(v)) {
1699 r[dst] = v;
1700 r[srcDst] = JSImmediate::decImmediateNumber(v);
1701 } else {
1702 JSValue* number = r[srcDst].jsValue(exec)->toJSNumber(exec);
1703 VM_CHECK_EXCEPTION();
1704 r[dst] = number;
1705 r[srcDst] = jsNumber(exec, number->uncheckedGetNumber() - 1);
1706 }
1707
1708 ++vPC;
1709 NEXT_OPCODE;
1710 }
1711 BEGIN_OPCODE(op_to_jsnumber) {
1712 /* to_jsnumber dst(r) src(r)
1713
1714 Converts register src to number, and puts the result
1715 in register dst.
1716 */
1717 int dst = (++vPC)->u.operand;
1718 int src = (++vPC)->u.operand;
1719 JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
1720 VM_CHECK_EXCEPTION();
1721
1722 r[dst] = result;
1723
1724 ++vPC;
1725 NEXT_OPCODE;
1726 }
1727 BEGIN_OPCODE(op_negate) {
1728 /* negate dst(r) src(r)
1729
1730 Converts register src to number, negates it, and puts the
1731 result in register dst.
1732 */
1733 int dst = (++vPC)->u.operand;
1734 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
1735 double v;
1736 if (fastIsNumber(src, v))
1737 r[dst] = jsNumber(exec, -v);
1738 else {
1739 JSValue* result = jsNumber(exec, -src->toNumber(exec));
1740 VM_CHECK_EXCEPTION();
1741 r[dst] = result;
1742 }
1743
1744 ++vPC;
1745 NEXT_OPCODE;
1746 }
1747 BEGIN_OPCODE(op_add) {
1748 /* add dst(r) src1(r) src2(r)
1749
1750 Adds register src1 and register src2, and puts the result
1751 in register dst. (JS add may be string concatenation or
1752 numeric add, depending on the types of the operands.)
1753 */
1754 int dst = (++vPC)->u.operand;
1755 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1756 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1757 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1758 r[dst] = JSImmediate::addImmediateNumbers(src1, src2);
1759 else {
1760 JSValue* result = jsAdd(exec, src1, src2);
1761 VM_CHECK_EXCEPTION();
1762 r[dst] = result;
1763 }
1764 ++vPC;
1765 NEXT_OPCODE;
1766 }
1767 BEGIN_OPCODE(op_mul) {
1768 /* mul dst(r) src1(r) src2(r)
1769
1770 Multiplies register src1 and register src2 (converted to
1771 numbers), and puts the product in register dst.
1772 */
1773 int dst = (++vPC)->u.operand;
1774 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1775 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1776 double left;
1777 double right;
1778 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1779 r[dst] = jsNumber(exec, left * right);
1780 else {
1781 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
1782 VM_CHECK_EXCEPTION();
1783 r[dst] = result;
1784 }
1785
1786 ++vPC;
1787 NEXT_OPCODE;
1788 }
1789 BEGIN_OPCODE(op_div) {
1790 /* div dst(r) dividend(r) divisor(r)
1791
1792 Divides register dividend (converted to number) by the
1793 register divisor (converted to number), and puts the
1794 quotient in register dst.
1795 */
1796 int dst = (++vPC)->u.operand;
1797 JSValue* dividend = r[(++vPC)->u.operand].jsValue(exec);
1798 JSValue* divisor = r[(++vPC)->u.operand].jsValue(exec);
1799 double left;
1800 double right;
1801 if (fastIsNumber(dividend, left) && fastIsNumber(divisor, right))
1802 r[dst] = jsNumber(exec, left / right);
1803 else {
1804 JSValue* result = jsNumber(exec, dividend->toNumber(exec) / divisor->toNumber(exec));
1805 VM_CHECK_EXCEPTION();
1806 r[dst] = result;
1807 }
1808 ++vPC;
1809 NEXT_OPCODE;
1810 }
1811 BEGIN_OPCODE(op_mod) {
1812 /* mod dst(r) dividend(r) divisor(r)
1813
1814 Divides register dividend (converted to number) by
1815 register divisor (converted to number), and puts the
1816 remainder in register dst.
1817 */
1818 int dst = (++vPC)->u.operand;
1819 int dividend = (++vPC)->u.operand;
1820 int divisor = (++vPC)->u.operand;
1821
1822 JSValue* dividendValue = r[dividend].jsValue(exec);
1823 JSValue* divisorValue = r[divisor].jsValue(exec);
1824
1825 if (JSImmediate::areBothImmediateNumbers(dividendValue, divisorValue) && divisorValue != JSImmediate::from(0)) {
1826 r[dst] = JSImmediate::from(JSImmediate::getTruncatedInt32(dividendValue) % JSImmediate::getTruncatedInt32(divisorValue));
1827 ++vPC;
1828 NEXT_OPCODE;
1829 }
1830
1831 double d = dividendValue->toNumber(exec);
1832 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
1833 VM_CHECK_EXCEPTION();
1834 r[dst] = result;
1835 ++vPC;
1836 NEXT_OPCODE;
1837 }
1838 BEGIN_OPCODE(op_sub) {
1839 /* sub dst(r) src1(r) src2(r)
1840
1841 Subtracts register src2 (converted to number) from register
1842 src1 (converted to number), and puts the difference in
1843 register dst.
1844 */
1845 int dst = (++vPC)->u.operand;
1846 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1847 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1848 double left;
1849 double right;
1850 if (JSImmediate::canDoFastAdditiveOperations(src1) && JSImmediate::canDoFastAdditiveOperations(src2))
1851 r[dst] = JSImmediate::subImmediateNumbers(src1, src2);
1852 else if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
1853 r[dst] = jsNumber(exec, left - right);
1854 else {
1855 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
1856 VM_CHECK_EXCEPTION();
1857 r[dst] = result;
1858 }
1859 ++vPC;
1860 NEXT_OPCODE;
1861 }
1862 BEGIN_OPCODE(op_lshift) {
1863 /* lshift dst(r) val(r) shift(r)
1864
1865 Performs left shift of register val (converted to int32) by
1866 register shift (converted to uint32), and puts the result
1867 in register dst.
1868 */
1869 int dst = (++vPC)->u.operand;
1870 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1871 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1872 int32_t left;
1873 uint32_t right;
1874 if (JSImmediate::areBothImmediateNumbers(val, shift))
1875 r[dst] = jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
1876 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1877 r[dst] = jsNumber(exec, left << (right & 0x1f));
1878 else {
1879 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
1880 VM_CHECK_EXCEPTION();
1881 r[dst] = result;
1882 }
1883
1884 ++vPC;
1885 NEXT_OPCODE;
1886 }
1887 BEGIN_OPCODE(op_rshift) {
1888 /* rshift dst(r) val(r) shift(r)
1889
1890 Performs arithmetic right shift of register val (converted
1891 to int32) by register shift (converted to
1892 uint32), and puts the result in register dst.
1893 */
1894 int dst = (++vPC)->u.operand;
1895 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1896 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1897 int32_t left;
1898 uint32_t right;
1899 if (JSImmediate::areBothImmediateNumbers(val, shift))
1900 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1901 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
1902 r[dst] = jsNumber(exec, left >> (right & 0x1f));
1903 else {
1904 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1905 VM_CHECK_EXCEPTION();
1906 r[dst] = result;
1907 }
1908
1909 ++vPC;
1910 NEXT_OPCODE;
1911 }
1912 BEGIN_OPCODE(op_urshift) {
1913 /* rshift dst(r) val(r) shift(r)
1914
1915 Performs logical right shift of register val (converted
1916 to uint32) by register shift (converted to
1917 uint32), and puts the result in register dst.
1918 */
1919 int dst = (++vPC)->u.operand;
1920 JSValue* val = r[(++vPC)->u.operand].jsValue(exec);
1921 JSValue* shift = r[(++vPC)->u.operand].jsValue(exec);
1922 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
1923 r[dst] = JSImmediate::rightShiftImmediateNumbers(val, shift);
1924 else {
1925 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
1926 VM_CHECK_EXCEPTION();
1927 r[dst] = result;
1928 }
1929
1930 ++vPC;
1931 NEXT_OPCODE;
1932 }
1933 BEGIN_OPCODE(op_bitand) {
1934 /* bitand dst(r) src1(r) src2(r)
1935
1936 Computes bitwise AND of register src1 (converted to int32)
1937 and register src2 (converted to int32), and puts the result
1938 in register dst.
1939 */
1940 int dst = (++vPC)->u.operand;
1941 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1942 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1943 int32_t left;
1944 int32_t right;
1945 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1946 r[dst] = JSImmediate::andImmediateNumbers(src1, src2);
1947 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1948 r[dst] = jsNumber(exec, left & right);
1949 else {
1950 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
1951 VM_CHECK_EXCEPTION();
1952 r[dst] = result;
1953 }
1954
1955 ++vPC;
1956 NEXT_OPCODE;
1957 }
1958 BEGIN_OPCODE(op_bitxor) {
1959 /* bitxor dst(r) src1(r) src2(r)
1960
1961 Computes bitwise XOR of register src1 (converted to int32)
1962 and register src2 (converted to int32), and puts the result
1963 in register dst.
1964 */
1965 int dst = (++vPC)->u.operand;
1966 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1967 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1968 int32_t left;
1969 int32_t right;
1970 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1971 r[dst] = JSImmediate::xorImmediateNumbers(src1, src2);
1972 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1973 r[dst] = jsNumber(exec, left ^ right);
1974 else {
1975 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
1976 VM_CHECK_EXCEPTION();
1977 r[dst] = result;
1978 }
1979
1980 ++vPC;
1981 NEXT_OPCODE;
1982 }
1983 BEGIN_OPCODE(op_bitor) {
1984 /* bitor dst(r) src1(r) src2(r)
1985
1986 Computes bitwise OR of register src1 (converted to int32)
1987 and register src2 (converted to int32), and puts the
1988 result in register dst.
1989 */
1990 int dst = (++vPC)->u.operand;
1991 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
1992 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
1993 int32_t left;
1994 int32_t right;
1995 if (JSImmediate::areBothImmediateNumbers(src1, src2))
1996 r[dst] = JSImmediate::orImmediateNumbers(src1, src2);
1997 else if (fastToInt32(src1, left) && fastToInt32(src2, right))
1998 r[dst] = jsNumber(exec, left | right);
1999 else {
2000 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
2001 VM_CHECK_EXCEPTION();
2002 r[dst] = result;
2003 }
2004
2005 ++vPC;
2006 NEXT_OPCODE;
2007 }
2008 BEGIN_OPCODE(op_bitnot) {
2009 /* bitnot dst(r) src(r)
2010
2011 Computes bitwise NOT of register src1 (converted to int32),
2012 and puts the result in register dst.
2013 */
2014 int dst = (++vPC)->u.operand;
2015 JSValue* src = r[(++vPC)->u.operand].jsValue(exec);
2016 int32_t value;
2017 if (fastToInt32(src, value))
2018 r[dst] = jsNumber(exec, ~value);
2019 else {
2020 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
2021 VM_CHECK_EXCEPTION();
2022 r[dst] = result;
2023 }
2024 ++vPC;
2025 NEXT_OPCODE;
2026 }
2027 BEGIN_OPCODE(op_not) {
2028 /* not dst(r) src(r)
2029
2030 Computes logical NOT of register src (converted to
2031 boolean), and puts the result in register dst.
2032 */
2033 int dst = (++vPC)->u.operand;
2034 int src = (++vPC)->u.operand;
2035 JSValue* result = jsBoolean(!r[src].jsValue(exec)->toBoolean(exec));
2036 VM_CHECK_EXCEPTION();
2037 r[dst] = result;
2038
2039 ++vPC;
2040 NEXT_OPCODE;
2041 }
2042 BEGIN_OPCODE(op_instanceof) {
2043 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
2044
2045 Tests whether register value is an instance of register
2046 constructor, and puts the boolean result in register
2047 dst. Register constructorProto must contain the "prototype"
2048 property (not the actual prototype) of the object in
2049 register constructor. This lookup is separated so that
2050 polymorphic inline caching can apply.
2051
2052 Raises an exception if register constructor is not an
2053 object.
2054 */
2055 int dst = (++vPC)->u.operand;
2056 int value = (++vPC)->u.operand;
2057 int base = (++vPC)->u.operand;
2058 int baseProto = (++vPC)->u.operand;
2059
2060 JSValue* baseVal = r[base].jsValue(exec);
2061
2062 if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
2063 goto vm_throw;
2064
2065 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2066 r[dst] = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, r[value].jsValue(exec), r[baseProto].jsValue(exec)) : false);
2067
2068 ++vPC;
2069 NEXT_OPCODE;
2070 }
2071 BEGIN_OPCODE(op_typeof) {
2072 /* typeof dst(r) src(r)
2073
2074 Determines the type string for src according to ECMAScript
2075 rules, and puts the result in register dst.
2076 */
2077 int dst = (++vPC)->u.operand;
2078 int src = (++vPC)->u.operand;
2079 r[dst] = jsTypeStringForValue(exec, r[src].jsValue(exec));
2080
2081 ++vPC;
2082 NEXT_OPCODE;
2083 }
2084 BEGIN_OPCODE(op_is_undefined) {
2085 /* is_undefined dst(r) src(r)
2086
2087 Determines whether the type string for src according to
2088 the ECMAScript rules is "undefined", and puts the result
2089 in register dst.
2090 */
2091 int dst = (++vPC)->u.operand;
2092 int src = (++vPC)->u.operand;
2093 JSValue* v = r[src].jsValue(exec);
2094 r[dst] = jsBoolean(v->isUndefined() || (v->isObject() && static_cast<JSObject*>(v)->masqueradeAsUndefined()));
2095
2096 ++vPC;
2097 NEXT_OPCODE;
2098 }
2099 BEGIN_OPCODE(op_is_boolean) {
2100 /* is_boolean dst(r) src(r)
2101
2102 Determines whether the type string for src according to
2103 the ECMAScript rules is "boolean", and puts the result
2104 in register dst.
2105 */
2106 int dst = (++vPC)->u.operand;
2107 int src = (++vPC)->u.operand;
2108 r[dst] = jsBoolean(r[src].jsValue(exec)->isBoolean());
2109
2110 ++vPC;
2111 NEXT_OPCODE;
2112 }
2113 BEGIN_OPCODE(op_is_number) {
2114 /* is_number dst(r) src(r)
2115
2116 Determines whether the type string for src according to
2117 the ECMAScript rules is "number", and puts the result
2118 in register dst.
2119 */
2120 int dst = (++vPC)->u.operand;
2121 int src = (++vPC)->u.operand;
2122 r[dst] = jsBoolean(r[src].jsValue(exec)->isNumber());
2123
2124 ++vPC;
2125 NEXT_OPCODE;
2126 }
2127 BEGIN_OPCODE(op_is_string) {
2128 /* is_string dst(r) src(r)
2129
2130 Determines whether the type string for src according to
2131 the ECMAScript rules is "string", and puts the result
2132 in register dst.
2133 */
2134 int dst = (++vPC)->u.operand;
2135 int src = (++vPC)->u.operand;
2136 r[dst] = jsBoolean(r[src].jsValue(exec)->isString());
2137
2138 ++vPC;
2139 NEXT_OPCODE;
2140 }
2141 BEGIN_OPCODE(op_is_object) {
2142 /* is_object dst(r) src(r)
2143
2144 Determines whether the type string for src according to
2145 the ECMAScript rules is "object", and puts the result
2146 in register dst.
2147 */
2148 int dst = (++vPC)->u.operand;
2149 int src = (++vPC)->u.operand;
2150 r[dst] = jsBoolean(jsIsObjectType(r[src].jsValue(exec)));
2151
2152 ++vPC;
2153 NEXT_OPCODE;
2154 }
2155 BEGIN_OPCODE(op_is_function) {
2156 /* is_function dst(r) src(r)
2157
2158 Determines whether the type string for src according to
2159 the ECMAScript rules is "function", and puts the result
2160 in register dst.
2161 */
2162 int dst = (++vPC)->u.operand;
2163 int src = (++vPC)->u.operand;
2164 r[dst] = jsBoolean(jsIsFunctionType(r[src].jsValue(exec)));
2165
2166 ++vPC;
2167 NEXT_OPCODE;
2168 }
2169 BEGIN_OPCODE(op_in) {
2170 /* in dst(r) property(r) base(r)
2171
2172 Tests whether register base has a property named register
2173 property, and puts the boolean result in register dst.
2174
2175 Raises an exception if register constructor is not an
2176 object.
2177 */
2178 int dst = (++vPC)->u.operand;
2179 int property = (++vPC)->u.operand;
2180 int base = (++vPC)->u.operand;
2181
2182 JSValue* baseVal = r[base].jsValue(exec);
2183 if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
2184 goto vm_throw;
2185
2186 JSObject* baseObj = static_cast<JSObject*>(baseVal);
2187
2188 JSValue* propName = r[property].jsValue(exec);
2189
2190 uint32_t i;
2191 if (propName->getUInt32(i))
2192 r[dst] = jsBoolean(baseObj->hasProperty(exec, i));
2193 else {
2194 Identifier property(exec, propName->toString(exec));
2195 VM_CHECK_EXCEPTION();
2196 r[dst] = jsBoolean(baseObj->hasProperty(exec, property));
2197 }
2198
2199 ++vPC;
2200 NEXT_OPCODE;
2201 }
2202 BEGIN_OPCODE(op_resolve) {
2203 /* resolve dst(r) property(id)
2204
2205 Looks up the property named by identifier property in the
2206 scope chain, and writes the resulting value to register
2207 dst. If the property is not found, raises an exception.
2208 */
2209 if (UNLIKELY(!resolve(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2210 goto vm_throw;
2211
2212 vPC += 3;
2213 NEXT_OPCODE;
2214 }
2215 BEGIN_OPCODE(op_resolve_skip) {
2216 /* resolve_skip dst(r) property(id) skip(n)
2217
2218 Looks up the property named by identifier property in the
2219 scope chain skipping the top 'skip' levels, and writes the resulting
2220 value to register dst. If the property is not found, raises an exception.
2221 */
2222 if (UNLIKELY(!resolve_skip(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2223 goto vm_throw;
2224
2225 vPC += 4;
2226
2227 NEXT_OPCODE;
2228 }
2229 BEGIN_OPCODE(op_get_global_var) {
2230 /* get_global_var dst(r) index(n)
2231
2232 Gets the global var at global slot index and places it in register dst.
2233 */
2234 int dst = (++vPC)->u.operand;
2235 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2236 ASSERT(scope->isGlobalObject());
2237 int index = (++vPC)->u.operand;
2238
2239 r[dst] = scope->registerAt(index);
2240 ++vPC;
2241 NEXT_OPCODE;
2242 }
2243 BEGIN_OPCODE(op_put_global_var) {
2244 /* put_global_var globalObject(c) index(n) value(r)
2245
2246 Puts value into global slot index.
2247 */
2248 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2249 ASSERT(scope->isGlobalObject());
2250 int index = (++vPC)->u.operand;
2251 int value = (++vPC)->u.operand;
2252
2253 scope->registerAt(index) = r[value].jsValue(exec);
2254 ++vPC;
2255 NEXT_OPCODE;
2256 }
2257 BEGIN_OPCODE(op_get_scoped_var) {
2258 /* get_scoped_var dst(r) index(n) skip(n)
2259
2260 Loads the contents of the index-th local from the scope skip nodes from
2261 the top of the scope chain, and places it in register dst
2262 */
2263 int dst = (++vPC)->u.operand;
2264 int index = (++vPC)->u.operand;
2265 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2266
2267 ScopeChainIterator iter = scopeChain->begin();
2268 ScopeChainIterator end = scopeChain->end();
2269 ASSERT(iter != end);
2270 while (skip--) {
2271 ++iter;
2272 ASSERT(iter != end);
2273 }
2274
2275 ASSERT((*iter)->isVariableObject());
2276 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2277 r[dst] = scope->registerAt(index);
2278 ++vPC;
2279 NEXT_OPCODE;
2280 }
2281 BEGIN_OPCODE(op_put_scoped_var) {
2282 /* put_scoped_var index(n) skip(n) value(r)
2283
2284 */
2285 int index = (++vPC)->u.operand;
2286 int skip = (++vPC)->u.operand + codeBlock->needsFullScopeChain;
2287 int value = (++vPC)->u.operand;
2288
2289 ScopeChainIterator iter = scopeChain->begin();
2290 ScopeChainIterator end = scopeChain->end();
2291 ASSERT(iter != end);
2292 while (skip--) {
2293 ++iter;
2294 ASSERT(iter != end);
2295 }
2296
2297 ASSERT((*iter)->isVariableObject());
2298 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2299 scope->registerAt(index) = r[value].jsValue(exec);
2300 ++vPC;
2301 NEXT_OPCODE;
2302 }
2303 BEGIN_OPCODE(op_resolve_base) {
2304 /* resolve_base dst(r) property(id)
2305
2306 Searches the scope chain for an object containing
2307 identifier property, and if one is found, writes it to
2308 register dst. If none is found, the outermost scope (which
2309 will be the global object) is stored in register dst.
2310 */
2311 resolveBase(exec, vPC, r, scopeChain, codeBlock);
2312
2313 vPC += 3;
2314 NEXT_OPCODE;
2315 }
2316 BEGIN_OPCODE(op_resolve_with_base) {
2317 /* resolve_with_base baseDst(r) propDst(r) property(id)
2318
2319 Searches the scope chain for an object containing
2320 identifier property, and if one is found, writes it to
2321 register srcDst, and the retrieved property value to register
2322 propDst. If the property is not found, raises an exception.
2323
2324 This is more efficient than doing resolve_base followed by
2325 resolve, or resolve_base followed by get_by_id, as it
2326 avoids duplicate hash lookups.
2327 */
2328 if (UNLIKELY(!resolveBaseAndProperty(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2329 goto vm_throw;
2330
2331 vPC += 4;
2332 NEXT_OPCODE;
2333 }
2334 BEGIN_OPCODE(op_resolve_func) {
2335 /* resolve_func baseDst(r) funcDst(r) property(id)
2336
2337 Searches the scope chain for an object containing
2338 identifier property, and if one is found, writes the
2339 appropriate object to use as "this" when calling its
2340 properties to register baseDst; and the retrieved property
2341 value to register propDst. If the property is not found,
2342 raises an exception.
2343
2344 This differs from resolve_with_base, because the
2345 global this value will be substituted for activations or
2346 the global object, which is the right behavior for function
2347 calls but not for other property lookup.
2348 */
2349 if (UNLIKELY(!resolveBaseAndFunc(exec, vPC, r, scopeChain, codeBlock, exceptionValue)))
2350 goto vm_throw;
2351
2352 vPC += 4;
2353 NEXT_OPCODE;
2354 }
2355 BEGIN_OPCODE(op_get_by_id) {
2356 /* get_by_id dst(r) base(r) property(id) structureID(sID) nop(n) nop(n) nop(n)
2357
2358 Generic property access: Gets the property named by identifier
2359 property from the value base, and puts the result in register dst.
2360 */
2361 int dst = vPC[1].u.operand;
2362 int base = vPC[2].u.operand;
2363 int property = vPC[3].u.operand;
2364
2365 Identifier& ident = codeBlock->identifiers[property];
2366 JSValue* baseValue = r[base].jsValue(exec);
2367 PropertySlot slot(baseValue);
2368 JSValue* result = baseValue->get(exec, ident, slot);
2369 VM_CHECK_EXCEPTION();
2370
2371 tryCacheGetByID(exec, codeBlock, vPC, baseValue, ident, slot);
2372
2373 r[dst] = result;
2374 vPC += 8;
2375 NEXT_OPCODE;
2376 }
2377 BEGIN_OPCODE(op_get_by_id_self) {
2378 /* op_get_by_id_self dst(r) base(r) property(id) structureID(sID) offset(n) nop(n) nop(n)
2379
2380 Cached property access: Attempts to get a cached property from the
2381 value base. If the cache misses, op_get_by_id_self reverts to
2382 op_get_by_id.
2383 */
2384 int base = vPC[2].u.operand;
2385 JSValue* baseValue = r[base].jsValue(exec);
2386
2387 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2388 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2389 StructureID* structureID = vPC[4].u.structureID;
2390
2391 if (LIKELY(baseCell->structureID() == structureID)) {
2392 ASSERT(baseCell->isObject());
2393 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2394 int dst = vPC[1].u.operand;
2395 int offset = vPC[5].u.operand;
2396
2397 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2398 r[dst] = baseObject->getDirectOffset(offset);
2399
2400 vPC += 8;
2401 NEXT_OPCODE;
2402 }
2403 }
2404
2405 uncacheGetByID(codeBlock, vPC);
2406 NEXT_OPCODE;
2407 }
2408 BEGIN_OPCODE(op_get_by_id_proto) {
2409 /* op_get_by_id_proto dst(r) base(r) property(id) structureID(sID) protoStructureID(sID) offset(n) nop(n)
2410
2411 Cached property access: Attempts to get a cached property from the
2412 value base's prototype. If the cache misses, op_get_by_id_proto
2413 reverts to op_get_by_id.
2414 */
2415 int base = vPC[2].u.operand;
2416 JSValue* baseValue = r[base].jsValue(exec);
2417
2418 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2419 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2420 StructureID* structureID = vPC[4].u.structureID;
2421
2422 if (LIKELY(baseCell->structureID() == structureID)) {
2423 ASSERT(structureID->prototypeForLookup(exec)->isObject());
2424 JSObject* protoObject = static_cast<JSObject*>(structureID->prototypeForLookup(exec));
2425 StructureID* protoStructureID = vPC[5].u.structureID;
2426
2427 if (LIKELY(protoObject->structureID() == protoStructureID)) {
2428 int dst = vPC[1].u.operand;
2429 int offset = vPC[6].u.operand;
2430
2431 ASSERT(protoObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == protoObject->getDirectOffset(offset));
2432 r[dst] = protoObject->getDirectOffset(offset);
2433
2434 vPC += 8;
2435 NEXT_OPCODE;
2436 }
2437 }
2438 }
2439
2440 uncacheGetByID(codeBlock, vPC);
2441 NEXT_OPCODE;
2442 }
2443 BEGIN_OPCODE(op_get_by_id_chain) {
2444 /* op_get_by_id_chain dst(r) base(r) property(id) structureID(sID) structureIDChain(sIDc) count(n) offset(n)
2445
2446 Cached property access: Attempts to get a cached property from the
2447 value base's prototype chain. If the cache misses, op_get_by_id_chain
2448 reverts to op_get_by_id.
2449 */
2450 int base = vPC[2].u.operand;
2451 JSValue* baseValue = r[base].jsValue(exec);
2452
2453 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2454 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2455 StructureID* structureID = vPC[4].u.structureID;
2456
2457 if (LIKELY(baseCell->structureID() == structureID)) {
2458 RefPtr<StructureID>* it = vPC[5].u.structureIDChain->head();
2459 size_t count = vPC[6].u.operand;
2460 RefPtr<StructureID>* end = it + count;
2461
2462 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2463 while (1) {
2464 baseObject = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2465 if (UNLIKELY(baseObject->structureID() != (*it).get()))
2466 break;
2467
2468 if (++it == end) {
2469 int dst = vPC[1].u.operand;
2470 int offset = vPC[7].u.operand;
2471
2472 ASSERT(baseObject->get(exec, codeBlock->identifiers[vPC[3].u.operand]) == baseObject->getDirectOffset(offset));
2473 r[dst] = baseObject->getDirectOffset(offset);
2474
2475 vPC += 8;
2476 NEXT_OPCODE;
2477 }
2478 }
2479 }
2480 }
2481
2482 uncacheGetByID(codeBlock, vPC);
2483 NEXT_OPCODE;
2484 }
2485 BEGIN_OPCODE(op_get_by_id_generic) {
2486 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2487
2488 Generic property access: Gets the property named by identifier
2489 property from the value base, and puts the result in register dst.
2490 */
2491 int dst = vPC[1].u.operand;
2492 int base = vPC[2].u.operand;
2493 int property = vPC[3].u.operand;
2494
2495 Identifier& ident = codeBlock->identifiers[property];
2496
2497 JSValue* baseValue = r[base].jsValue(exec);
2498 PropertySlot slot(baseValue);
2499 JSValue* result = baseValue->get(exec, ident, slot);
2500 VM_CHECK_EXCEPTION();
2501
2502 r[dst] = result;
2503 vPC += 8;
2504 NEXT_OPCODE;
2505 }
2506 BEGIN_OPCODE(op_get_array_length) {
2507 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2508
2509 Cached property access: Gets the length of the array in register base,
2510 and puts the result in register dst. If register base does not hold
2511 an array, op_get_array_length reverts to op_get_by_id.
2512 */
2513
2514 int base = vPC[2].u.operand;
2515 JSValue* baseValue = r[base].jsValue(exec);
2516 if (LIKELY(isJSArray(baseValue))) {
2517 int dst = vPC[1].u.operand;
2518 r[dst] = jsNumber(exec, static_cast<JSArray*>(baseValue)->length());
2519 vPC += 8;
2520 NEXT_OPCODE;
2521 }
2522
2523 uncacheGetByID(codeBlock, vPC);
2524 NEXT_OPCODE;
2525 }
2526 BEGIN_OPCODE(op_get_string_length) {
2527 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2528
2529 Cached property access: Gets the length of the string in register base,
2530 and puts the result in register dst. If register base does not hold
2531 a string, op_get_string_length reverts to op_get_by_id.
2532 */
2533
2534 int base = vPC[2].u.operand;
2535 JSValue* baseValue = r[base].jsValue(exec);
2536 if (LIKELY(isJSString(baseValue))) {
2537 int dst = vPC[1].u.operand;
2538 r[dst] = jsNumber(exec, static_cast<JSString*>(baseValue)->value().size());
2539 vPC += 8;
2540 NEXT_OPCODE;
2541 }
2542
2543 uncacheGetByID(codeBlock, vPC);
2544 NEXT_OPCODE;
2545 }
2546 BEGIN_OPCODE(op_put_by_id) {
2547 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2548
2549 Generic property access: Sets the property named by identifier
2550 property, belonging to register base, to register value.
2551
2552 Unlike many opcodes, this one does not write any output to
2553 the register file.
2554 */
2555
2556 int base = vPC[1].u.operand;
2557 int property = vPC[2].u.operand;
2558 int value = vPC[3].u.operand;
2559
2560 JSValue* baseValue = r[base].jsValue(exec);
2561
2562 PutPropertySlot slot;
2563 Identifier& ident = codeBlock->identifiers[property];
2564 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2565 VM_CHECK_EXCEPTION();
2566
2567 tryCachePutByID(exec, codeBlock, vPC, baseValue, slot);
2568
2569 vPC += 8;
2570 NEXT_OPCODE;
2571 }
2572 BEGIN_OPCODE(op_put_by_id_transition) {
2573 /* op_put_by_id_transition base(r) property(id) value(r) oldStructureID(sID) newStructureID(sID) structureIDChain(sIDc) offset(n)
2574
2575 Cached property access: Attempts to set a new property with a cached transition
2576 property named by identifier property, belonging to register base,
2577 to register value. If the cache misses, op_put_by_id_transition
2578 reverts to op_put_by_id_generic.
2579
2580 Unlike many opcodes, this one does not write any output to
2581 the register file.
2582 */
2583 int base = vPC[1].u.operand;
2584 JSValue* baseValue = r[base].jsValue(exec);
2585
2586 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2587 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2588 StructureID* oldStructureID = vPC[4].u.structureID;
2589 StructureID* newStructureID = vPC[5].u.structureID;
2590
2591 if (LIKELY(baseCell->structureID() == oldStructureID)) {
2592 ASSERT(baseCell->isObject());
2593 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2594
2595 RefPtr<StructureID>* it = vPC[6].u.structureIDChain->head();
2596
2597 JSObject* proto = static_cast<JSObject*>(baseObject->structureID()->prototypeForLookup(exec));
2598 while (!proto->isNull()) {
2599 if (UNLIKELY(proto->structureID() != (*it).get())) {
2600 uncachePutByID(codeBlock, vPC);
2601 NEXT_OPCODE;
2602 }
2603 ++it;
2604 proto = static_cast<JSObject*>(proto->structureID()->prototypeForLookup(exec));
2605 }
2606
2607 baseObject->transitionTo(newStructureID);
2608 if (oldStructureID->propertyMap().storageSize() == JSObject::inlineStorageCapacity)
2609 baseObject->allocatePropertyStorage(oldStructureID->propertyMap().storageSize(), oldStructureID->propertyMap().size());
2610
2611 int value = vPC[3].u.operand;
2612 unsigned offset = vPC[7].u.operand;
2613 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2614 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2615
2616 vPC += 8;
2617 NEXT_OPCODE;
2618 }
2619 }
2620
2621 uncachePutByID(codeBlock, vPC);
2622 NEXT_OPCODE;
2623 }
2624 BEGIN_OPCODE(op_put_by_id_replace) {
2625 /* op_put_by_id_replace base(r) property(id) value(r) structureID(sID) offset(n) nop(n) nop(n)
2626
2627 Cached property access: Attempts to set a pre-existing, cached
2628 property named by identifier property, belonging to register base,
2629 to register value. If the cache misses, op_put_by_id_replace
2630 reverts to op_put_by_id.
2631
2632 Unlike many opcodes, this one does not write any output to
2633 the register file.
2634 */
2635 int base = vPC[1].u.operand;
2636 JSValue* baseValue = r[base].jsValue(exec);
2637
2638 if (LIKELY(!JSImmediate::isImmediate(baseValue))) {
2639 JSCell* baseCell = static_cast<JSCell*>(baseValue);
2640 StructureID* structureID = vPC[4].u.structureID;
2641
2642 if (LIKELY(baseCell->structureID() == structureID)) {
2643 ASSERT(baseCell->isObject());
2644 JSObject* baseObject = static_cast<JSObject*>(baseCell);
2645 int value = vPC[3].u.operand;
2646 unsigned offset = vPC[5].u.operand;
2647
2648 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(codeBlock->identifiers[vPC[2].u.operand])) == offset);
2649 baseObject->putDirectOffset(offset, r[value].jsValue(exec));
2650
2651 vPC += 8;
2652 NEXT_OPCODE;
2653 }
2654 }
2655
2656 uncachePutByID(codeBlock, vPC);
2657 NEXT_OPCODE;
2658 }
2659 BEGIN_OPCODE(op_put_by_id_generic) {
2660 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2661
2662 Generic property access: Sets the property named by identifier
2663 property, belonging to register base, to register value.
2664
2665 Unlike many opcodes, this one does not write any output to
2666 the register file.
2667 */
2668 int base = vPC[1].u.operand;
2669 int property = vPC[2].u.operand;
2670 int value = vPC[3].u.operand;
2671
2672 JSValue* baseValue = r[base].jsValue(exec);
2673
2674 PutPropertySlot slot;
2675 Identifier& ident = codeBlock->identifiers[property];
2676 baseValue->put(exec, ident, r[value].jsValue(exec), slot);
2677 VM_CHECK_EXCEPTION();
2678
2679 vPC += 8;
2680 NEXT_OPCODE;
2681 }
2682 BEGIN_OPCODE(op_del_by_id) {
2683 /* del_by_id dst(r) base(r) property(id)
2684
2685 Converts register base to Object, deletes the property
2686 named by identifier property from the object, and writes a
2687 boolean indicating success (if true) or failure (if false)
2688 to register dst.
2689 */
2690 int dst = (++vPC)->u.operand;
2691 int base = (++vPC)->u.operand;
2692 int property = (++vPC)->u.operand;
2693
2694 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec);
2695
2696 Identifier& ident = codeBlock->identifiers[property];
2697 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
2698 VM_CHECK_EXCEPTION();
2699 r[dst] = result;
2700 ++vPC;
2701 NEXT_OPCODE;
2702 }
2703 BEGIN_OPCODE(op_get_by_val) {
2704 /* get_by_val dst(r) base(r) property(r)
2705
2706 Converts register base to Object, gets the property named
2707 by register property from the object, and puts the result
2708 in register dst. property is nominally converted to string
2709 but numbers are treated more efficiently.
2710 */
2711 int dst = (++vPC)->u.operand;
2712 int base = (++vPC)->u.operand;
2713 int property = (++vPC)->u.operand;
2714
2715 JSValue* baseValue = r[base].jsValue(exec);
2716 JSValue* subscript = r[property].jsValue(exec);
2717
2718 JSValue* result;
2719 unsigned i;
2720
2721 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2722 if (LIKELY(isUInt32)) {
2723 if (isJSArray(baseValue)) {
2724 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2725 if (jsArray->canGetIndex(i))
2726 result = jsArray->getIndex(i);
2727 else
2728 result = jsArray->JSArray::get(exec, i);
2729 } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
2730 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
2731 else
2732 result = baseValue->get(exec, i);
2733 } else {
2734 Identifier property(exec, subscript->toString(exec));
2735 result = baseValue->get(exec, property);
2736 }
2737
2738 VM_CHECK_EXCEPTION();
2739 r[dst] = result;
2740 ++vPC;
2741 NEXT_OPCODE;
2742 }
2743 BEGIN_OPCODE(op_put_by_val) {
2744 /* put_by_val base(r) property(r) value(r)
2745
2746 Sets register value on register base as the property named
2747 by register property. Base is converted to object
2748 first. register property is nominally converted to string
2749 but numbers are treated more efficiently.
2750
2751 Unlike many opcodes, this one does not write any output to
2752 the register file.
2753 */
2754 int base = (++vPC)->u.operand;
2755 int property = (++vPC)->u.operand;
2756 int value = (++vPC)->u.operand;
2757
2758 JSValue* baseValue = r[base].jsValue(exec);
2759 JSValue* subscript = r[property].jsValue(exec);
2760
2761 unsigned i;
2762
2763 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
2764 if (LIKELY(isUInt32)) {
2765 if (isJSArray(baseValue)) {
2766 JSArray* jsArray = static_cast<JSArray*>(baseValue);
2767 if (jsArray->canSetIndex(i))
2768 jsArray->setIndex(i, r[value].jsValue(exec));
2769 else
2770 jsArray->JSArray::put(exec, i, r[value].jsValue(exec));
2771 } else
2772 baseValue->put(exec, i, r[value].jsValue(exec));
2773 } else {
2774 Identifier property(exec, subscript->toString(exec));
2775 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
2776 PutPropertySlot slot;
2777 baseValue->put(exec, property, r[value].jsValue(exec), slot);
2778 }
2779 }
2780
2781 VM_CHECK_EXCEPTION();
2782 ++vPC;
2783 NEXT_OPCODE;
2784 }
2785 BEGIN_OPCODE(op_del_by_val) {
2786 /* del_by_val dst(r) base(r) property(r)
2787
2788 Converts register base to Object, deletes the property
2789 named by register property from the object, and writes a
2790 boolean indicating success (if true) or failure (if false)
2791 to register dst.
2792 */
2793 int dst = (++vPC)->u.operand;
2794 int base = (++vPC)->u.operand;
2795 int property = (++vPC)->u.operand;
2796
2797 JSObject* baseObj = r[base].jsValue(exec)->toObject(exec); // may throw
2798
2799 JSValue* subscript = r[property].jsValue(exec);
2800 JSValue* result;
2801 uint32_t i;
2802 if (subscript->getUInt32(i))
2803 result = jsBoolean(baseObj->deleteProperty(exec, i));
2804 else {
2805 VM_CHECK_EXCEPTION();
2806 Identifier property(exec, subscript->toString(exec));
2807 VM_CHECK_EXCEPTION();
2808 result = jsBoolean(baseObj->deleteProperty(exec, property));
2809 }
2810
2811 VM_CHECK_EXCEPTION();
2812 r[dst] = result;
2813 ++vPC;
2814 NEXT_OPCODE;
2815 }
2816 BEGIN_OPCODE(op_put_by_index) {
2817 /* put_by_index base(r) property(n) value(r)
2818
2819 Sets register value on register base as the property named
2820 by the immediate number property. Base is converted to
2821 object first.
2822
2823 Unlike many opcodes, this one does not write any output to
2824 the register file.
2825
2826 This opcode is mainly used to initialize array literals.
2827 */
2828 int base = (++vPC)->u.operand;
2829 unsigned property = (++vPC)->u.operand;
2830 int value = (++vPC)->u.operand;
2831
2832 r[base].jsValue(exec)->put(exec, property, r[value].jsValue(exec));
2833
2834 ++vPC;
2835 NEXT_OPCODE;
2836 }
2837 BEGIN_OPCODE(op_loop) {
2838 /* loop target(offset)
2839
2840 Jumps unconditionally to offset target from the current
2841 instruction.
2842
2843 Additionally this loop instruction may terminate JS execution is
2844 the JS timeout is reached.
2845 */
2846#if DUMP_OPCODE_STATS
2847 OpcodeStats::resetLastInstruction();
2848#endif
2849 int target = (++vPC)->u.operand;
2850 CHECK_FOR_TIMEOUT();
2851 vPC += target;
2852 NEXT_OPCODE;
2853 }
2854 BEGIN_OPCODE(op_jmp) {
2855 /* jmp target(offset)
2856
2857 Jumps unconditionally to offset target from the current
2858 instruction.
2859 */
2860#if DUMP_OPCODE_STATS
2861 OpcodeStats::resetLastInstruction();
2862#endif
2863 int target = (++vPC)->u.operand;
2864
2865 vPC += target;
2866 NEXT_OPCODE;
2867 }
2868 BEGIN_OPCODE(op_loop_if_true) {
2869 /* loop_if_true cond(r) target(offset)
2870
2871 Jumps to offset target from the current instruction, if and
2872 only if register cond converts to boolean as true.
2873
2874 Additionally this loop instruction may terminate JS execution is
2875 the JS timeout is reached.
2876 */
2877 int cond = (++vPC)->u.operand;
2878 int target = (++vPC)->u.operand;
2879 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2880 vPC += target;
2881 CHECK_FOR_TIMEOUT();
2882 NEXT_OPCODE;
2883 }
2884
2885 ++vPC;
2886 NEXT_OPCODE;
2887 }
2888 BEGIN_OPCODE(op_jtrue) {
2889 /* jtrue cond(r) target(offset)
2890
2891 Jumps to offset target from the current instruction, if and
2892 only if register cond converts to boolean as true.
2893 */
2894 int cond = (++vPC)->u.operand;
2895 int target = (++vPC)->u.operand;
2896 if (r[cond].jsValue(exec)->toBoolean(exec)) {
2897 vPC += target;
2898 NEXT_OPCODE;
2899 }
2900
2901 ++vPC;
2902 NEXT_OPCODE;
2903 }
2904 BEGIN_OPCODE(op_jfalse) {
2905 /* jfalse cond(r) target(offset)
2906
2907 Jumps to offset target from the current instruction, if and
2908 only if register cond converts to boolean as false.
2909 */
2910 int cond = (++vPC)->u.operand;
2911 int target = (++vPC)->u.operand;
2912 if (!r[cond].jsValue(exec)->toBoolean(exec)) {
2913 vPC += target;
2914 NEXT_OPCODE;
2915 }
2916
2917 ++vPC;
2918 NEXT_OPCODE;
2919 }
2920 BEGIN_OPCODE(op_loop_if_less) {
2921 /* loop_if_less src1(r) src2(r) target(offset)
2922
2923 Checks whether register src1 is less than register src2, as
2924 with the ECMAScript '<' operator, and then jumps to offset
2925 target from the current instruction, if and only if the
2926 result of the comparison is true.
2927
2928 Additionally this loop instruction may terminate JS execution is
2929 the JS timeout is reached.
2930 */
2931 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2932 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2933 int target = (++vPC)->u.operand;
2934
2935 bool result = jsLess(exec, src1, src2);
2936 VM_CHECK_EXCEPTION();
2937
2938 if (result) {
2939 vPC += target;
2940 CHECK_FOR_TIMEOUT();
2941 NEXT_OPCODE;
2942 }
2943
2944 ++vPC;
2945 NEXT_OPCODE;
2946 }
2947 BEGIN_OPCODE(op_loop_if_lesseq) {
2948 /* loop_if_lesseq src1(r) src2(r) target(offset)
2949
2950 Checks whether register src1 is less than or equal to register
2951 src2, as with the ECMAScript '<=' operator, and then jumps to
2952 offset target from the current instruction, if and only if the
2953 result of the comparison is true.
2954
2955 Additionally this loop instruction may terminate JS execution is
2956 the JS timeout is reached.
2957 */
2958 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2959 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2960 int target = (++vPC)->u.operand;
2961
2962 bool result = jsLessEq(exec, src1, src2);
2963 VM_CHECK_EXCEPTION();
2964
2965 if (result) {
2966 vPC += target;
2967 CHECK_FOR_TIMEOUT();
2968 NEXT_OPCODE;
2969 }
2970
2971 ++vPC;
2972 NEXT_OPCODE;
2973 }
2974 BEGIN_OPCODE(op_jnless) {
2975 /* jnless src1(r) src2(r) target(offset)
2976
2977 Checks whether register src1 is less than register src2, as
2978 with the ECMAScript '<' operator, and then jumps to offset
2979 target from the current instruction, if and only if the
2980 result of the comparison is false.
2981 */
2982 JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
2983 JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
2984 int target = (++vPC)->u.operand;
2985
2986 bool result = jsLess(exec, src1, src2);
2987 VM_CHECK_EXCEPTION();
2988
2989 if (!result) {
2990 vPC += target;
2991 NEXT_OPCODE;
2992 }
2993
2994 ++vPC;
2995 NEXT_OPCODE;
2996 }
2997 BEGIN_OPCODE(op_switch_imm) {
2998 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2999
3000 Performs a range checked switch on the scrutinee value, using
3001 the tableIndex-th immediate switch jump table. If the scrutinee value
3002 is an immediate number in the range covered by the referenced jump
3003 table, and the value at jumpTable[scrutinee value] is non-zero, then
3004 that value is used as the jump offset, otherwise defaultOffset is used.
3005 */
3006 int tableIndex = (++vPC)->u.operand;
3007 int defaultOffset = (++vPC)->u.operand;
3008 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3009 if (!JSImmediate::isNumber(scrutinee))
3010 vPC += defaultOffset;
3011 else {
3012 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
3013 vPC += codeBlock->immediateSwitchJumpTables[tableIndex].offsetForValue(value, defaultOffset);
3014 }
3015 NEXT_OPCODE;
3016 }
3017 BEGIN_OPCODE(op_switch_char) {
3018 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
3019
3020 Performs a range checked switch on the scrutinee value, using
3021 the tableIndex-th character switch jump table. If the scrutinee value
3022 is a single character string in the range covered by the referenced jump
3023 table, and the value at jumpTable[scrutinee value] is non-zero, then
3024 that value is used as the jump offset, otherwise defaultOffset is used.
3025 */
3026 int tableIndex = (++vPC)->u.operand;
3027 int defaultOffset = (++vPC)->u.operand;
3028 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3029 if (!scrutinee->isString())
3030 vPC += defaultOffset;
3031 else {
3032 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
3033 if (value->size() != 1)
3034 vPC += defaultOffset;
3035 else
3036 vPC += codeBlock->characterSwitchJumpTables[tableIndex].offsetForValue(value->data()[0], defaultOffset);
3037 }
3038 NEXT_OPCODE;
3039 }
3040 BEGIN_OPCODE(op_switch_string) {
3041 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
3042
3043 Performs a sparse hashmap based switch on the value in the scrutinee
3044 register, using the tableIndex-th string switch jump table. If the
3045 scrutinee value is a string that exists as a key in the referenced
3046 jump table, then the value associated with the string is used as the
3047 jump offset, otherwise defaultOffset is used.
3048 */
3049 int tableIndex = (++vPC)->u.operand;
3050 int defaultOffset = (++vPC)->u.operand;
3051 JSValue* scrutinee = r[(++vPC)->u.operand].jsValue(exec);
3052 if (!scrutinee->isString())
3053 vPC += defaultOffset;
3054 else
3055 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset);
3056 NEXT_OPCODE;
3057 }
3058 BEGIN_OPCODE(op_new_func) {
3059 /* new_func dst(r) func(f)
3060
3061 Constructs a new Function instance from function func and
3062 the current scope chain using the original Function
3063 constructor, using the rules for function declarations, and
3064 puts the result in register dst.
3065 */
3066 int dst = (++vPC)->u.operand;
3067 int func = (++vPC)->u.operand;
3068
3069 r[dst] = codeBlock->functions[func]->makeFunction(exec, scopeChain);
3070
3071 ++vPC;
3072 NEXT_OPCODE;
3073 }
3074 BEGIN_OPCODE(op_new_func_exp) {
3075 /* new_func_exp dst(r) func(f)
3076
3077 Constructs a new Function instance from function func and
3078 the current scope chain using the original Function
3079 constructor, using the rules for function expressions, and
3080 puts the result in register dst.
3081 */
3082 int dst = (++vPC)->u.operand;
3083 int func = (++vPC)->u.operand;
3084
3085 r[dst] = codeBlock->functionExpressions[func]->makeFunction(exec, scopeChain);
3086
3087 ++vPC;
3088 NEXT_OPCODE;
3089 }
3090 BEGIN_OPCODE(op_call_eval) {
3091 /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3092
3093 Call a function named "eval" with no explicit "this" value
3094 (which may therefore be the eval operator). If register
3095 thisVal is the global object, and register func contains
3096 that global object's original global eval function, then
3097 perform the eval operator in local scope (interpreting
3098 the argument registers as for the "call"
3099 opcode). Otherwise, act exactly as the "call" opcode would.
3100 */
3101
3102 int dst = (++vPC)->u.operand;
3103 int func = (++vPC)->u.operand;
3104 int thisVal = (++vPC)->u.operand;
3105 int firstArg = (++vPC)->u.operand;
3106 int argCount = (++vPC)->u.operand;
3107
3108 JSValue* funcVal = r[func].jsValue(exec);
3109 JSValue* baseVal = r[thisVal].jsValue(exec);
3110
3111 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
3112 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
3113 JSValue* result = callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
3114 if (exceptionValue)
3115 goto vm_throw;
3116
3117 r[dst] = result;
3118
3119 ++vPC;
3120 NEXT_OPCODE;
3121 }
3122
3123 // We didn't find the blessed version of eval, so reset vPC and process
3124 // this instruction as a normal function call, supplying the proper 'this'
3125 // value.
3126 vPC -= 5;
3127 r[thisVal] = baseVal->toThisObject(exec);
3128
3129#if HAVE(COMPUTED_GOTO)
3130 // Hack around gcc performance quirk by performing an indirect goto
3131 // in order to set the vPC -- attempting to do so directly results in a
3132 // significant regression.
3133 goto *op_call_indirect; // indirect goto -> op_call
3134#endif
3135 // fall through to op_call
3136 }
3137 BEGIN_OPCODE(op_call) {
3138 /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
3139
3140 Perform a function call. Specifically, call register func
3141 with a "this" value of register thisVal, and put the result
3142 in register dst.
3143
3144 The arguments start at register firstArg and go up to
3145 argCount, but the "this" value is considered an implicit
3146 first argument, so the argCount should be one greater than
3147 the number of explicit arguments passed, and the register
3148 after firstArg should contain the actual first
3149 argument. This opcode will copy from the thisVal register
3150 to the firstArg register, unless the register index of
3151 thisVal is the special missing this object marker, which is
3152 2^31-1; in that case, the global object will be used as the
3153 "this" value.
3154
3155 If func is a native code function, then this opcode calls
3156 it and returns the value immediately.
3157
3158 But if it is a JS function, then the current scope chain
3159 and code block is set to the function's, and we slide the
3160 register window so that the arguments would form the first
3161 few local registers of the called function's register
3162 window. In addition, a call frame header is written
3163 immediately before the arguments; see the call frame
3164 documentation for an explanation of how many registers a
3165 call frame takes and what they contain. That many registers
3166 before the firstArg register will be overwritten by the
3167 call. In addition, any registers higher than firstArg +
3168 argCount may be overwritten. Once this setup is complete,
3169 execution continues from the called function's first
3170 argument, and does not return until a "ret" opcode is
3171 encountered.
3172 */
3173
3174 int dst = (++vPC)->u.operand;
3175 int func = (++vPC)->u.operand;
3176 int thisVal = (++vPC)->u.operand;
3177 int firstArg = (++vPC)->u.operand;
3178 int argCount = (++vPC)->u.operand;
3179
3180 JSValue* v = r[func].jsValue(exec);
3181
3182 CallData callData;
3183 CallType callType = v->getCallData(callData);
3184
3185 if (*enabledProfilerReference)
3186 (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
3187
3188 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3189 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
3190 exec->m_callFrame = callFrame;
3191
3192 if (callType == CallTypeJS) {
3193
3194 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3195 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3196 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3197
3198 r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3199
3200 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3201 if (UNLIKELY(exceptionValue != 0))
3202 goto vm_throw;
3203
3204 codeBlock = newCodeBlock;
3205 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3206 vPC = codeBlock->instructions.begin();
3207
3208#if DUMP_OPCODE_STATS
3209 OpcodeStats::resetLastInstruction();
3210#endif
3211
3212 NEXT_OPCODE;
3213 }
3214
3215 if (callType == CallTypeHost) {
3216 JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
3217 ArgList args(r + firstArg + 1, argCount - 1);
3218
3219 MACHINE_SAMPLING_callingHostFunction();
3220
3221 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
3222 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3223 VM_CHECK_EXCEPTION();
3224
3225 r[dst] = returnValue;
3226
3227 if (*enabledProfilerReference)
3228 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
3229
3230 ++vPC;
3231 NEXT_OPCODE;
3232 }
3233
3234 ASSERT(callType == CallTypeNone);
3235
3236 exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
3237 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3238 goto vm_throw;
3239 }
3240 BEGIN_OPCODE(op_ret) {
3241 /* ret result(r)
3242
3243 Return register result as the return value of the current
3244 function call, writing it into the caller's expected return
3245 value register. In addition, unwind one call frame and
3246 restore the scope chain, code block instruction pointer and
3247 register base to those of the calling function.
3248 */
3249
3250 int result = (++vPC)->u.operand;
3251
3252 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3253 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
3254 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
3255 ASSERT(activation->isActivationObject());
3256 activation->copyRegisters();
3257 }
3258
3259 if (*enabledProfilerReference)
3260 (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
3261
3262 if (codeBlock->needsFullScopeChain)
3263 scopeChain->deref();
3264
3265 JSValue* returnValue = r[result].jsValue(exec);
3266
3267 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3268 if (!codeBlock)
3269 return returnValue;
3270
3271 vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3272 setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
3273 r = callFrame[RegisterFile::CallerRegisters].r();
3274 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3275 int dst = callFrame[RegisterFile::ReturnValueRegister].i();
3276 r[dst] = returnValue;
3277
3278 NEXT_OPCODE;
3279 }
3280 BEGIN_OPCODE(op_construct) {
3281 /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
3282
3283 Invoke register "constr" as a constructor. For JS
3284 functions, the calling convention is exactly as for the
3285 "call" opcode, except that the "this" value is a newly
3286 created Object. For native constructors, a null "this"
3287 value is passed. In either case, the firstArg and argCount
3288 registers are interpreted as for the "call" opcode.
3289
3290 Register constrProto must contain the prototype property of
3291 register constsr. This is to enable polymorphic inline
3292 caching of this lookup.
3293 */
3294
3295 int dst = (++vPC)->u.operand;
3296 int constr = (++vPC)->u.operand;
3297 int constrProto = (++vPC)->u.operand;
3298 int firstArg = (++vPC)->u.operand;
3299 int argCount = (++vPC)->u.operand;
3300
3301 JSValue* constrVal = r[constr].jsValue(exec);
3302
3303 ConstructData constructData;
3304 ConstructType constructType = constrVal->getConstructData(constructData);
3305
3306 // Removing this line of code causes a measurable regression on squirrelfish.
3307 JSObject* constructor = static_cast<JSObject*>(constrVal);
3308
3309 if (constructType == ConstructTypeJS) {
3310 if (*enabledProfilerReference)
3311 (*enabledProfilerReference)->willExecute(exec, constructor);
3312
3313 JSObject* prototype;
3314 JSValue* p = r[constrProto].jsValue(exec);
3315 if (p->isObject())
3316 prototype = static_cast<JSObject*>(p);
3317 else
3318 prototype = scopeChain->globalObject()->objectPrototype();
3319 JSObject* newObject = new (exec) JSObject(prototype);
3320
3321 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3322 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3323 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
3324
3325 r[firstArg] = newObject; // "this" value
3326
3327 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
3328 initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
3329 exec->m_callFrame = callFrame;
3330
3331 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
3332 if (exceptionValue)
3333 goto vm_throw;
3334
3335 codeBlock = newCodeBlock;
3336 setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
3337 vPC = codeBlock->instructions.begin();
3338
3339 NEXT_OPCODE;
3340 }
3341
3342 if (constructType == ConstructTypeHost) {
3343 if (*enabledProfilerReference)
3344 (*enabledProfilerReference)->willExecute(exec, constructor);
3345
3346 ArgList args(r + firstArg + 1, argCount - 1);
3347
3348 MACHINE_SAMPLING_callingHostFunction();
3349
3350 JSValue* returnValue = constructData.native.function(exec, constructor, args);
3351
3352 VM_CHECK_EXCEPTION();
3353 r[dst] = returnValue;
3354
3355 if (*enabledProfilerReference)
3356 (*enabledProfilerReference)->didExecute(exec, constructor);
3357
3358 ++vPC;
3359 NEXT_OPCODE;
3360 }
3361
3362 ASSERT(constructType == ConstructTypeNone);
3363
3364 exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
3365 goto vm_throw;
3366 }
3367 BEGIN_OPCODE(op_construct_verify) {
3368 /* construct_verify dst(r) override(r)
3369
3370 Verifies that register dst holds an object. If not, moves
3371 the object in register override to register dst.
3372 */
3373
3374 int dst = vPC[1].u.operand;;
3375 if (LIKELY(r[dst].jsValue(exec)->isObject())) {
3376 vPC += 3;
3377 NEXT_OPCODE;
3378 }
3379
3380 int override = vPC[2].u.operand;
3381 r[dst] = r[override];
3382
3383 vPC += 3;
3384 NEXT_OPCODE;
3385 }
3386 BEGIN_OPCODE(op_push_scope) {
3387 /* push_scope scope(r)
3388
3389 Converts register scope to object, and pushes it onto the top
3390 of the current scope chain.
3391 */
3392 int scope = (++vPC)->u.operand;
3393 JSValue* v = r[scope].jsValue(exec);
3394 JSObject* o = v->toObject(exec);
3395 VM_CHECK_EXCEPTION();
3396
3397 setScopeChain(exec, scopeChain, scopeChain->push(o));
3398
3399 ++vPC;
3400 NEXT_OPCODE;
3401 }
3402 BEGIN_OPCODE(op_pop_scope) {
3403 /* pop_scope
3404
3405 Removes the top item from the current scope chain.
3406 */
3407 setScopeChain(exec, scopeChain, scopeChain->pop());
3408
3409 ++vPC;
3410 NEXT_OPCODE;
3411 }
3412 BEGIN_OPCODE(op_get_pnames) {
3413 /* get_pnames dst(r) base(r)
3414
3415 Creates a property name list for register base and puts it
3416 in register dst. This is not a true JavaScript value, just
3417 a synthetic value used to keep the iteration state in a
3418 register.
3419 */
3420 int dst = (++vPC)->u.operand;
3421 int base = (++vPC)->u.operand;
3422
3423 r[dst] = JSPropertyNameIterator::create(exec, r[base].jsValue(exec));
3424 ++vPC;
3425 NEXT_OPCODE;
3426 }
3427 BEGIN_OPCODE(op_next_pname) {
3428 /* next_pname dst(r) iter(r) target(offset)
3429
3430 Tries to copies the next name from property name list in
3431 register iter. If there are names left, then copies one to
3432 register dst, and jumps to offset target. If there are none
3433 left, invalidates the iterator and continues to the next
3434 instruction.
3435 */
3436 int dst = (++vPC)->u.operand;
3437 int iter = (++vPC)->u.operand;
3438 int target = (++vPC)->u.operand;
3439
3440 JSPropertyNameIterator* it = r[iter].jsPropertyNameIterator();
3441 if (JSValue* temp = it->next(exec)) {
3442 CHECK_FOR_TIMEOUT();
3443 r[dst] = temp;
3444 vPC += target;
3445 NEXT_OPCODE;
3446 }
3447 it->invalidate();
3448
3449 ++vPC;
3450 NEXT_OPCODE;
3451 }
3452 BEGIN_OPCODE(op_jmp_scopes) {
3453 /* jmp_scopes count(n) target(offset)
3454
3455 Removes the a number of items from the current scope chain
3456 specified by immediate number count, then jumps to offset
3457 target.
3458 */
3459 int count = (++vPC)->u.operand;
3460 int target = (++vPC)->u.operand;
3461
3462 ScopeChainNode* tmp = scopeChain;
3463 while (count--)
3464 tmp = tmp->pop();
3465 setScopeChain(exec, scopeChain, tmp);
3466
3467 vPC += target;
3468 NEXT_OPCODE;
3469 }
3470#if HAVE(COMPUTED_GOTO)
3471 // Appease GCC
3472 goto *(&&skip_new_scope);
3473#endif
3474 BEGIN_OPCODE(op_push_new_scope) {
3475 /* new_scope dst(r) property(id) value(r)
3476
3477 Constructs a new StaticScopeObject with property set to value. That scope
3478 object is then pushed onto the ScopeChain. The scope object is then stored
3479 in dst for GC.
3480 */
3481 setScopeChain(exec, scopeChain, createExceptionScope(exec, codeBlock, vPC, r, scopeChain));
3482 vPC += 4;
3483 NEXT_OPCODE;
3484 }
3485#if HAVE(COMPUTED_GOTO)
3486 skip_new_scope:
3487#endif
3488 BEGIN_OPCODE(op_catch) {
3489 /* catch ex(r)
3490
3491 Retrieves the VMs current exception and puts it in register
3492 ex. This is only valid after an exception has been raised,
3493 and usually forms the beginning of an exception handler.
3494 */
3495 ASSERT(exceptionValue);
3496 ASSERT(!exec->hadException());
3497 int ex = (++vPC)->u.operand;
3498 r[ex] = exceptionValue;
3499 exceptionValue = 0;
3500
3501 ++vPC;
3502 NEXT_OPCODE;
3503 }
3504 BEGIN_OPCODE(op_throw) {
3505 /* throw ex(r)
3506
3507 Throws register ex as an exception. This involves three
3508 steps: first, it is set as the current exception in the
3509 VM's internal state, then the stack is unwound until an
3510 exception handler or a native code boundary is found, and
3511 then control resumes at the exception handler if any or
3512 else the script returns control to the nearest native caller.
3513 */
3514
3515 int ex = (++vPC)->u.operand;
3516 exceptionValue = r[ex].jsValue(exec);
3517
3518 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, true);
3519 if (!handlerVPC) {
3520 *exception = exceptionValue;
3521 return jsNull();
3522 }
3523
3524#if HAVE(COMPUTED_GOTO)
3525 // Hack around gcc performance quirk by performing an indirect goto
3526 // in order to set the vPC -- attempting to do so directly results in a
3527 // significant regression.
3528 goto *op_throw_end_indirect; // indirect goto -> op_throw_end
3529 }
3530 op_throw_end: {
3531#endif
3532
3533 vPC = handlerVPC;
3534 NEXT_OPCODE;
3535 }
3536 BEGIN_OPCODE(op_unexpected_load) {
3537 /* unexpected_load load dst(r) src(k)
3538
3539 Copies constant src to register dst.
3540 */
3541 int dst = (++vPC)->u.operand;
3542 int src = (++vPC)->u.operand;
3543 r[dst] = codeBlock->unexpectedConstants[src];
3544
3545 ++vPC;
3546 NEXT_OPCODE;
3547 }
3548 BEGIN_OPCODE(op_new_error) {
3549 /* new_error dst(r) type(n) message(k)
3550
3551 Constructs a new Error instance using the original
3552 constructor, using immediate number n as the type and
3553 constant message as the message string. The result is
3554 written to register dst.
3555 */
3556 int dst = (++vPC)->u.operand;
3557 int type = (++vPC)->u.operand;
3558 int message = (++vPC)->u.operand;
3559
3560 r[dst] = Error::create(exec, (ErrorType)type, codeBlock->unexpectedConstants[message]->toString(exec), codeBlock->lineNumberForVPC(vPC), codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
3561
3562 ++vPC;
3563 NEXT_OPCODE;
3564 }
3565 BEGIN_OPCODE(op_end) {
3566 /* end result(r)
3567
3568 Return register result as the value of a global or eval
3569 program. Return control to the calling native code.
3570 */
3571
3572 if (codeBlock->needsFullScopeChain) {
3573 ASSERT(scopeChain->refCount > 1);
3574 scopeChain->deref();
3575 }
3576 int result = (++vPC)->u.operand;
3577 return r[result].jsValue(exec);
3578 }
3579 BEGIN_OPCODE(op_put_getter) {
3580 /* put_getter base(r) property(id) function(r)
3581
3582 Sets register function on register base as the getter named
3583 by identifier property. Base and function are assumed to be
3584 objects as this op should only be used for getters defined
3585 in object literal form.
3586
3587 Unlike many opcodes, this one does not write any output to
3588 the register file.
3589 */
3590 int base = (++vPC)->u.operand;
3591 int property = (++vPC)->u.operand;
3592 int function = (++vPC)->u.operand;
3593
3594 ASSERT(r[base].jsValue(exec)->isObject());
3595 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3596 Identifier& ident = codeBlock->identifiers[property];
3597 ASSERT(r[function].jsValue(exec)->isObject());
3598 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3599
3600 ++vPC;
3601 NEXT_OPCODE;
3602 }
3603 BEGIN_OPCODE(op_put_setter) {
3604 /* put_setter base(r) property(id) function(r)
3605
3606 Sets register function on register base as the setter named
3607 by identifier property. Base and function are assumed to be
3608 objects as this op should only be used for setters defined
3609 in object literal form.
3610
3611 Unlike many opcodes, this one does not write any output to
3612 the register file.
3613 */
3614 int base = (++vPC)->u.operand;
3615 int property = (++vPC)->u.operand;
3616 int function = (++vPC)->u.operand;
3617
3618 ASSERT(r[base].jsValue(exec)->isObject());
3619 JSObject* baseObj = static_cast<JSObject*>(r[base].jsValue(exec));
3620 Identifier& ident = codeBlock->identifiers[property];
3621 ASSERT(r[function].jsValue(exec)->isObject());
3622 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(r[function].jsValue(exec)));
3623
3624 ++vPC;
3625 NEXT_OPCODE;
3626 }
3627 BEGIN_OPCODE(op_jsr) {
3628 /* jsr retAddrDst(r) target(offset)
3629
3630 Places the address of the next instruction into the retAddrDst
3631 register and jumps to offset target from the current instruction.
3632 */
3633 int retAddrDst = (++vPC)->u.operand;
3634 int target = (++vPC)->u.operand;
3635 r[retAddrDst] = vPC + 1;
3636
3637 vPC += target;
3638 NEXT_OPCODE;
3639 }
3640 BEGIN_OPCODE(op_sret) {
3641 /* sret retAddrSrc(r)
3642
3643 Jumps to the address stored in the retAddrSrc register. This
3644 differs from op_jmp because the target address is stored in a
3645 register, not as an immediate.
3646 */
3647 int retAddrSrc = (++vPC)->u.operand;
3648 vPC = r[retAddrSrc].vPC();
3649 NEXT_OPCODE;
3650 }
3651 BEGIN_OPCODE(op_debug) {
3652 /* debug debugHookID(n) firstLine(n) lastLine(n)
3653
3654 Notifies the debugger of the current state of execution. This opcode
3655 is only generated while the debugger is attached.
3656 */
3657 int debugHookID = (++vPC)->u.operand;
3658 int firstLine = (++vPC)->u.operand;
3659 int lastLine = (++vPC)->u.operand;
3660
3661 debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3662
3663 ++vPC;
3664 NEXT_OPCODE;
3665 }
3666 vm_throw: {
3667 exec->clearException();
3668 if (!tickCount) {
3669 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3670 // cannot fathom if we don't assign to the exceptionValue before branching)
3671 exceptionValue = createInterruptedExecutionException(exec);
3672 }
3673 handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, scopeChain, r, false);
3674 if (!handlerVPC) {
3675 *exception = exceptionValue;
3676 return jsNull();
3677 }
3678 vPC = handlerVPC;
3679 NEXT_OPCODE;
3680 }
3681 }
3682 #undef NEXT_OPCODE
3683 #undef BEGIN_OPCODE
3684 #undef VM_CHECK_EXCEPTION
3685 #undef CHECK_FOR_TIMEOUT
3686}
3687
3688JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
3689{
3690 Register* callFrame = this->callFrame(exec, function);
3691 if (!callFrame)
3692 return jsNull();
3693
3694 JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
3695 if (!activation) {
3696 CodeBlock* codeBlock = &function->m_body->generatedByteCode();
3697 activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
3698 callFrame[RegisterFile::OptionalCalleeActivation] = activation;
3699 }
3700
3701 return activation->get(exec, exec->propertyNames().arguments);
3702}
3703
3704JSValue* Machine::retrieveCaller(ExecState* exec, InternalFunction* function) const
3705{
3706 Register* callFrame = this->callFrame(exec, function);
3707 if (!callFrame)
3708 return jsNull();
3709
3710 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3711 if (!callerCodeBlock)
3712 return jsNull();
3713
3714 Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3715 if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
3716 return caller;
3717
3718 return jsNull();
3719}
3720
3721void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const
3722{
3723 function = 0;
3724 lineNumber = -1;
3725 sourceURL = UString();
3726
3727 Register* callFrame = exec->m_callFrame;
3728 if (!callFrame)
3729 return;
3730
3731 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3732 if (!callerCodeBlock)
3733 return;
3734
3735 Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
3736 lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
3737 sourceId = callerCodeBlock->ownerNode->sourceId();
3738 sourceURL = callerCodeBlock->ownerNode->sourceURL();
3739
3740 JSValue* callee = callFrame[RegisterFile::Callee].getJSValue();
3741 if (callee->toThisObject(exec)->inherits(&InternalFunction::info))
3742 function = retrieveCaller(exec, static_cast<InternalFunction*>(callee));
3743}
3744
3745Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
3746{
3747 Register* callFrame = exec->m_callFrame;
3748
3749 while (1) {
3750 while (!callFrame) {
3751 exec = exec->m_prev;
3752 if (!exec)
3753 return 0;
3754 callFrame = exec->m_callFrame;
3755 }
3756
3757 if (callFrame[RegisterFile::Callee].jsValue(exec) == function)
3758 return callFrame;
3759
3760 CodeBlock* callerCodeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
3761 if (!callerCodeBlock) {
3762 callFrame = 0;
3763 continue;
3764 }
3765
3766 callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
3767 }
3768}
3769
3770void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
3771{
3772 function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
3773 ASSERT(function->inherits(&JSFunction::info));
3774
3775 argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; // + 1 to skip "this"
3776 argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
3777}
3778
3779#if ENABLE(CTI)
3780
3781NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress)
3782{
3783 ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline);
3784}
3785
3786NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot)
3787{
3788 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
3789
3790 if (JSImmediate::isImmediate(baseValue))
3791 return;
3792
3793 // Uncacheable: give up.
3794 if (!slot.isCacheable()) {
3795 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3796 return;
3797 }
3798
3799 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3800 StructureID* structureID = baseCell->structureID();
3801
3802 if (structureID->isDictionary()) {
3803 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3804 return;
3805 }
3806
3807 // In the interpreter the last structure is trapped here; in CTI we use the
3808 // *_second method to achieve a similar (but not quite the same) effect.
3809
3810 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3811 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3812
3813 // Cache hit: Specialize instruction and ref StructureIDs.
3814
3815 // If baseCell != base, then baseCell must be a proxy for another object.
3816 if (baseCell != slot.base()) {
3817 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic);
3818 return;
3819 }
3820
3821 // StructureID transition, cache transition info
3822 if (slot.type() == PutPropertySlot::NewProperty) {
3823 vPC[0] = getOpcode(op_put_by_id_transition);
3824 vPC[4] = structureID->previousID();
3825 vPC[5] = structureID;
3826 StructureIDChain* chain = structureID->cachedPrototypeChain();
3827 if (!chain) {
3828 chain = cachePrototypeChain(exec, structureID);
3829 if (!chain) {
3830 // This happens if someone has manually inserted null into the prototype chain
3831 vPC[0] = getOpcode(op_put_by_id_generic);
3832 return;
3833 }
3834 }
3835 vPC[6] = chain;
3836 vPC[7] = slot.cachedOffset();
3837 codeBlock->refStructureIDs(vPC);
3838 CTI::compilePutByIdTransition(this, exec, codeBlock, structureID->previousID(), structureID, slot.cachedOffset(), chain, returnAddress);
3839 return;
3840 }
3841
3842 vPC[0] = getOpcode(op_put_by_id_replace);
3843 vPC[4] = structureID;
3844 vPC[5] = slot.cachedOffset();
3845 codeBlock->refStructureIDs(vPC);
3846
3847#if USE(CTI_REPATCH_PIC)
3848 UNUSED_PARAM(exec);
3849 CTI::patchPutByIdReplace(codeBlock, structureID, slot.cachedOffset(), returnAddress);
3850#else
3851 CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
3852#endif
3853}
3854
3855void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3856{
3857 if (!m_ctiArrayLengthTrampoline)
3858 m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock);
3859
3860 return m_ctiArrayLengthTrampoline;
3861}
3862
3863void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock)
3864{
3865 if (!m_ctiStringLengthTrampoline)
3866 m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock);
3867
3868 return m_ctiStringLengthTrampoline;
3869}
3870
3871NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot)
3872{
3873 // FIXME: Write a test that proves we need to check for recursion here just
3874 // like the interpreter does, then add a check for recursion.
3875
3876 // FIXME: Cache property access for immediates.
3877 if (JSImmediate::isImmediate(baseValue)) {
3878 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3879 return;
3880 }
3881
3882 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) {
3883#if USE(CTI_REPATCH_PIC)
3884 CTI::compilePatchGetArrayLength(this, exec, codeBlock, returnAddress);
3885#else
3886 ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock));
3887#endif
3888 return;
3889 }
3890 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) {
3891 // The tradeoff of compiling an repatched inline string length access routine does not seem
3892 // to pay off, so we currently only do this for arrays.
3893 ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock));
3894 return;
3895 }
3896
3897 // Uncacheable: give up.
3898 if (!slot.isCacheable()) {
3899 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3900 return;
3901 }
3902
3903 JSCell* baseCell = static_cast<JSCell*>(baseValue);
3904 StructureID* structureID = baseCell->structureID();
3905
3906 if (structureID->isDictionary()) {
3907 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic);
3908 return;
3909 }
3910
3911 // In the interpreter the last structure is trapped here; in CTI we use the
3912 // *_second method to achieve a similar (but not quite the same) effect.
3913
3914 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress);
3915 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex;
3916
3917 // Cache hit: Specialize instruction and ref StructureIDs.
3918
3919 if (slot.slotBase() == baseValue) {
3920 // set this up, so derefStructureIDs can do it's job.
3921 vPC[0] = getOpcode(op_get_by_id_self);
3922 vPC[4] = structureID;
3923 vPC[5] = slot.cachedOffset();
3924 codeBlock->refStructureIDs(vPC);
3925
3926#if USE(CTI_REPATCH_PIC)
3927 CTI::patchGetByIdSelf(codeBlock, structureID, slot.cachedOffset(), returnAddress);
3928#else
3929 CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset(), returnAddress);
3930#endif
3931 return;
3932 }
3933
3934 if (slot.slotBase() == structureID->prototypeForLookup(exec)) {
3935 ASSERT(slot.slotBase()->isObject());
3936
3937 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());
3938
3939 // Heavy access to a prototype is a good indication that it's not being
3940 // used as a dictionary.
3941 if (slotBaseObject->structureID()->isDictionary()) {
3942 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID());
3943 slotBaseObject->setStructureID(transition.release());
3944 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
3945 }
3946
3947 vPC[0] = getOpcode(op_get_by_id_proto);
3948 vPC[4] = structureID;
3949 vPC[5] = slotBaseObject->structureID();
3950 vPC[6] = slot.cachedOffset();
3951 codeBlock->refStructureIDs(vPC);
3952
3953 CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset(), returnAddress);
3954 return;
3955 }
3956
3957 size_t count = 0;
3958 JSObject* o = static_cast<JSObject*>(baseValue);
3959 while (slot.slotBase() != o) {
3960 JSValue* v = o->structureID()->prototypeForLookup(exec);
3961
3962 // If we didn't find slotBase in baseValue's prototype chain, then baseValue
3963 // must be a proxy for another object.
3964
3965 if (v->isNull()) {
3966 vPC[0] = getOpcode(op_get_by_id_generic);
3967 return;
3968 }
3969
3970 o = static_cast<JSObject*>(v);
3971
3972 // Heavy access to a prototype is a good indication that it's not being
3973 // used as a dictionary.
3974 if (o->structureID()->isDictionary()) {
3975 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID());
3976 o->setStructureID(transition.release());
3977 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0);
3978 }
3979
3980 ++count;
3981 }
3982
3983 StructureIDChain* chain = structureID->cachedPrototypeChain();
3984 if (!chain)
3985 chain = cachePrototypeChain(exec, structureID);
3986
3987 ASSERT(chain);
3988 vPC[0] = getOpcode(op_get_by_id_chain);
3989 vPC[4] = structureID;
3990 vPC[5] = chain;
3991 vPC[6] = count;
3992 vPC[7] = slot.cachedOffset();
3993 codeBlock->refStructureIDs(vPC);
3994
3995 CTI::compileGetByIdChain(this, exec, codeBlock, structureID, chain, count, slot.cachedOffset(), returnAddress);
3996}
3997
3998
3999#define JSVALUE_VM_CHECK_EXCEPTION_ARG(exception) \
4000 do { \
4001 if (UNLIKELY(exception != 0)) { \
4002 exec->setException(exception); \
4003 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4004 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4005 return 0; \
4006 } \
4007 } while (0)
4008#define VM_CHECK_EXCEPTION_v() \
4009 do { \
4010 if (UNLIKELY(exec->hadException())) { \
4011 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4012 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4013 return; \
4014 } \
4015 } while (0)
4016#define VM_CHECK_EXCEPTION(type) \
4017 do { \
4018 if (UNLIKELY(exec->hadException())) { \
4019 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4020 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4021 return (type)0; \
4022 } \
4023 } while (0)
4024#define VM_CHECK_EXCEPTION_AT_END() \
4025 do { \
4026 if (UNLIKELY(exec->hadException())) { \
4027 /*printf("VM_CHECK_EXCEPTION_AT_END()\n");*/ \
4028 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \
4029 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \
4030 } \
4031 } while (0)
4032
4033void Machine::cti_op_end(CTI_ARGS)
4034{
4035 ASSERT(ARG_scopeChain->refCount > 1);
4036 ARG_scopeChain->deref();
4037}
4038
4039JSValue* Machine::cti_op_add(CTI_ARGS)
4040{
4041 JSValue* src1 = ARG_src1;
4042 JSValue* src2 = ARG_src2;
4043
4044 ExecState* exec = ARG_exec;
4045 JSValue* result = jsAdd(exec, src1, src2);
4046 VM_CHECK_EXCEPTION_AT_END();
4047 return result;
4048}
4049
4050JSValue* Machine::cti_op_pre_inc(CTI_ARGS)
4051{
4052 JSValue* v = ARG_src1;
4053
4054 ExecState* exec = ARG_exec;
4055 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1);
4056 VM_CHECK_EXCEPTION_AT_END();
4057 return result;
4058}
4059
4060void Machine::cti_timeout_check(CTI_ARGS)
4061{
4062 ExecState* exec = ARG_exec;
4063
4064 if (exec->machine()->checkTimeout(exec->dynamicGlobalObject()))
4065 exec->setException(createInterruptedExecutionException(exec));
4066
4067 VM_CHECK_EXCEPTION_AT_END();
4068}
4069
4070
4071int Machine::cti_op_loop_if_less(CTI_ARGS)
4072{
4073 JSValue* src1 = ARG_src1;
4074 JSValue* src2 = ARG_src2;
4075 ExecState* exec = ARG_exec;
4076
4077 bool result = jsLess(exec, src1, src2);
4078 VM_CHECK_EXCEPTION_AT_END();
4079 return result;
4080}
4081
4082int Machine::cti_op_loop_if_lesseq(CTI_ARGS)
4083{
4084 JSValue* src1 = ARG_src1;
4085 JSValue* src2 = ARG_src2;
4086 ExecState* exec = ARG_exec;
4087
4088 bool result = jsLessEq(exec, src1, src2);
4089 VM_CHECK_EXCEPTION_AT_END();
4090 return result;
4091}
4092
4093JSValue* Machine::cti_op_new_object(CTI_ARGS)
4094{
4095 return constructEmptyObject(ARG_exec);;
4096}
4097
4098void Machine::cti_op_put_by_id(CTI_ARGS)
4099{
4100 ExecState* exec = ARG_exec;
4101 Identifier& ident = *ARG_id2;
4102
4103 PutPropertySlot slot;
4104 ARG_src1->put(exec, ident, ARG_src3, slot);
4105
4106 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_second);
4107
4108 VM_CHECK_EXCEPTION_AT_END();
4109}
4110
4111void Machine::cti_op_put_by_id_second(CTI_ARGS)
4112{
4113 ExecState* exec = ARG_exec;
4114 Identifier& ident = *ARG_id2;
4115
4116 JSValue* baseValue = ARG_src1;
4117 PutPropertySlot slot;
4118 baseValue->put(exec, ident, ARG_src3, slot);
4119
4120 exec->machine()->tryCTICachePutByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, slot);
4121
4122 VM_CHECK_EXCEPTION_AT_END();
4123}
4124
4125void Machine::cti_op_put_by_id_generic(CTI_ARGS)
4126{
4127 ExecState* exec = ARG_exec;
4128 Identifier& ident = *ARG_id2;
4129
4130 PutPropertySlot slot;
4131 ARG_src1->put(exec, ident, ARG_src3, slot);
4132
4133 VM_CHECK_EXCEPTION_AT_END();
4134}
4135
4136void Machine::cti_op_put_by_id_fail(CTI_ARGS)
4137{
4138 ExecState* exec = ARG_exec;
4139 Identifier& ident = *ARG_id2;
4140
4141 PutPropertySlot slot;
4142 ARG_src1->put(exec, ident, ARG_src3, slot);
4143
4144 // should probably uncachePutByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
4145 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_generic);
4146
4147 VM_CHECK_EXCEPTION_AT_END();
4148}
4149
4150JSValue* Machine::cti_op_get_by_id(CTI_ARGS)
4151{
4152 ExecState* exec = ARG_exec;
4153 Identifier& ident = *ARG_id2;
4154
4155 JSValue* baseValue = ARG_src1;
4156 PropertySlot slot(baseValue);
4157 JSValue* result = baseValue->get(exec, ident, slot);
4158
4159 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_second);
4160
4161 VM_CHECK_EXCEPTION_AT_END();
4162 return result;
4163}
4164
4165JSValue* Machine::cti_op_get_by_id_second(CTI_ARGS)
4166{
4167 ExecState* exec = ARG_exec;
4168 Identifier& ident = *ARG_id2;
4169
4170 JSValue* baseValue = ARG_src1;
4171 PropertySlot slot(baseValue);
4172 JSValue* result = baseValue->get(exec, ident, slot);
4173
4174 exec->machine()->tryCTICacheGetByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, ident, slot);
4175
4176 VM_CHECK_EXCEPTION_AT_END();
4177 return result;
4178}
4179
4180JSValue* Machine::cti_op_get_by_id_generic(CTI_ARGS)
4181{
4182 ExecState* exec = ARG_exec;
4183 Identifier& ident = *ARG_id2;
4184
4185 JSValue* baseValue = ARG_src1;
4186 PropertySlot slot(baseValue);
4187 JSValue* result = baseValue->get(exec, ident, slot);
4188
4189 VM_CHECK_EXCEPTION_AT_END();
4190 return result;
4191}
4192
4193JSValue* Machine::cti_op_get_by_id_fail(CTI_ARGS)
4194{
4195 ExecState* exec = ARG_exec;
4196 Identifier& ident = *ARG_id2;
4197
4198 JSValue* baseValue = ARG_src1;
4199 PropertySlot slot(baseValue);
4200 JSValue* result = baseValue->get(exec, ident, slot);
4201
4202 // should probably uncacheGetByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end.
4203 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_generic);
4204
4205 VM_CHECK_EXCEPTION_AT_END();
4206 return result;
4207}
4208
4209JSValue* Machine::cti_op_instanceof(CTI_ARGS)
4210{
4211 ExecState* exec = ARG_exec;
4212 JSValue* baseVal = ARG_src2;
4213
4214 if (!baseVal->isObject()) {
4215 CodeBlock* codeBlock = ARG_codeBlock;
4216 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4217 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4218 exec->setException(createInvalidParamError(exec, "instanceof", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock));
4219 VM_CHECK_EXCEPTION(JSValue*);
4220 }
4221
4222 JSObject* baseObj = static_cast<JSObject*>(baseVal);
4223 JSValue* basePrototype = ARG_src3;
4224 JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, ARG_src1, basePrototype) : false);
4225 VM_CHECK_EXCEPTION_AT_END();
4226 return result;
4227}
4228
4229JSValue* Machine::cti_op_del_by_id(CTI_ARGS)
4230{
4231 ExecState* exec = ARG_exec;
4232 Identifier& ident = *ARG_id2;
4233
4234 JSObject* baseObj = ARG_src1->toObject(exec);
4235
4236 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident));
4237 VM_CHECK_EXCEPTION_AT_END();
4238 return result;
4239}
4240
4241JSValue* Machine::cti_op_mul(CTI_ARGS)
4242{
4243 ExecState* exec = ARG_exec;
4244 JSValue* src1 = ARG_src1;
4245 JSValue* src2 = ARG_src2;
4246
4247 double left;
4248 double right;
4249 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
4250 return jsNumber(exec, left * right);
4251 else {
4252 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec));
4253 VM_CHECK_EXCEPTION_AT_END();
4254 return result;
4255 }
4256}
4257
4258JSValue* Machine::cti_op_new_func(CTI_ARGS)
4259{
4260 return ARG_func1->makeFunction(ARG_exec, ARG_scopeChain);
4261}
4262
4263void* Machine::cti_op_call_JSFunction(CTI_ARGS)
4264{
4265 ExecState* exec = ARG_exec;
4266 RegisterFile* registerFile = ARG_registerFile;
4267 Register* r = ARG_r;
4268 CodeBlock* codeBlock = ARG_codeBlock;
4269 ScopeChainNode* scopeChain = ARG_scopeChain;
4270
4271 Machine* machine = exec->machine();
4272 JSValue* exceptionValue = 0;
4273 Register* registerBase = registerFile->base();
4274
4275 JSValue* funcVal = ARG_src1;
4276 JSValue* thisValue = ARG_src2;
4277 int firstArg = ARG_int3;
4278 int argCount = ARG_int4;
4279
4280 // In the JIT code before entering this function we wil have checked the vptr,
4281 // and know this is an object of type JSFunction.
4282#ifndef NDEBUG
4283 CallData callData;
4284#endif
4285 ASSERT(funcVal->getCallData(callData) == CallTypeJS);
4286
4287 if (*ARG_profilerReference)
4288 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
4289
4290 ScopeChainNode* callDataScopeChain = static_cast<JSFunction*>(funcVal)->m_scopeChain.node();
4291 FunctionBodyNode* functionBodyNode = static_cast<JSFunction*>(funcVal)->m_body.get();
4292
4293 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
4294
4295 r[firstArg] = thisValue;
4296
4297 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4298 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, funcVal);
4299 exec->m_callFrame = callFrame;
4300
4301 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
4302 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
4303
4304 codeBlock = newCodeBlock;
4305 machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
4306
4307 if (!codeBlock->ctiCode)
4308 CTI::compile(machine, exec, codeBlock);
4309
4310 ARG_setScopeChain(scopeChain);
4311 ARG_setCodeBlock(codeBlock);
4312 ARG_setR(r);
4313 return codeBlock->ctiCode;
4314}
4315
4316JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
4317{
4318 ExecState* exec = ARG_exec;
4319 Register* r = ARG_r;
4320
4321 JSValue* funcVal = ARG_src1;
4322 JSValue* thisValue = ARG_src2;
4323 int firstArg = ARG_int3;
4324 int argCount = ARG_int4;
4325
4326 CallData callData;
4327 CallType callType = funcVal->getCallData(callData);
4328
4329 ASSERT(callType != CallTypeJS);
4330
4331 if (callType == CallTypeHost) {
4332 CodeBlock* codeBlock = ARG_codeBlock;
4333 ScopeChainNode* scopeChain = ARG_scopeChain;
4334 Machine* machine = exec->machine();
4335
4336 Register* oldCallFrame = exec->m_callFrame;
4337 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4338 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, funcVal);
4339 exec->m_callFrame = callFrame;
4340
4341 if (*ARG_profilerReference)
4342 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
4343
4344 ArgList argList(r + firstArg + 1, argCount - 1);
4345
4346 CTI_MACHINE_SAMPLING_callingHostFunction();
4347
4348 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), thisValue, argList);
4349 exec->m_callFrame = oldCallFrame;
4350 VM_CHECK_EXCEPTION(JSValue*);
4351
4352 if (*ARG_profilerReference)
4353 (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(funcVal));
4354
4355 return returnValue;
4356
4357 }
4358
4359 ASSERT(callType == CallTypeNone);
4360
4361 exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr5, ARG_codeBlock));
4362 VM_CHECK_EXCEPTION_AT_END();
4363 return 0;
4364}
4365
4366JSValue* Machine::cti_op_ret(CTI_ARGS)
4367{
4368 ExecState* exec = ARG_exec;
4369 Register* r = ARG_r;
4370 CodeBlock* codeBlock = ARG_codeBlock;
4371 ScopeChainNode* scopeChain = ARG_scopeChain;
4372
4373 Machine* machine = exec->machine();
4374
4375 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
4376 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
4377 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
4378 ASSERT(activation->isActivationObject());
4379 activation->copyRegisters();
4380 }
4381
4382 if (*ARG_profilerReference)
4383 (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
4384
4385 if (codeBlock->needsFullScopeChain)
4386 scopeChain->deref();
4387
4388 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
4389 if (codeBlock) {
4390 machine->setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
4391 r = callFrame[RegisterFile::CallerRegisters].r();
4392 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
4393 }
4394
4395 ARG_setScopeChain(scopeChain);
4396 ARG_setCodeBlock(codeBlock);
4397 ARG_setR(r);
4398
4399 return ARG_src1;
4400}
4401
4402JSValue* Machine::cti_op_new_array(CTI_ARGS)
4403{
4404 ArgList argsList(ARG_registers1, ARG_int2);
4405 return constructArray(ARG_exec, argsList);
4406}
4407
4408JSValue* Machine::cti_op_resolve(CTI_ARGS)
4409{
4410 ExecState* exec = ARG_exec;
4411 ScopeChainNode* scopeChain = ARG_scopeChain;
4412
4413 ScopeChainIterator iter = scopeChain->begin();
4414 ScopeChainIterator end = scopeChain->end();
4415 ASSERT(iter != end);
4416
4417 Identifier& ident = *ARG_id1;
4418 do {
4419 JSObject* o = *iter;
4420 PropertySlot slot(o);
4421 if (o->getPropertySlot(exec, ident, slot)) {
4422 JSValue* result = slot.getValue(exec, ident);
4423 VM_CHECK_EXCEPTION_AT_END();
4424 return result;
4425 }
4426 } while (++iter != end);
4427
4428 CodeBlock* codeBlock = ARG_codeBlock;
4429 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4430 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4431 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
4432
4433 VM_CHECK_EXCEPTION_AT_END();
4434 return 0;
4435}
4436
4437void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
4438{
4439 ExecState* exec = ARG_exec;
4440 RegisterFile* registerFile = ARG_registerFile;
4441 Register* r = ARG_r;
4442 CodeBlock* codeBlock = ARG_codeBlock;
4443 ScopeChainNode* scopeChain = ARG_scopeChain;
4444
4445 Machine* machine = exec->machine();
4446 JSValue* exceptionValue = 0;
4447 Register* registerBase = registerFile->base();
4448
4449 JSValue* constrVal = ARG_src1;
4450 JSValue* constrProtoVal = ARG_src2;
4451 int firstArg = ARG_int3;
4452 int argCount = ARG_int4;
4453
4454 ConstructData constructData;
4455#ifndef NDEBUG
4456 ConstructType constructType =
4457#endif
4458 constrVal->getConstructData(constructData);
4459
4460 // Removing this line of code causes a measurable regression on sunspider.
4461 JSObject* constructor = static_cast<JSObject*>(constrVal);
4462
4463 ASSERT(constructType == ConstructTypeJS);
4464
4465 if (*ARG_profilerReference)
4466 (*ARG_profilerReference)->willExecute(exec, constructor);
4467
4468 JSObject* prototype;
4469 JSValue* p = constrProtoVal;
4470 if (p->isObject())
4471 prototype = static_cast<JSObject*>(p);
4472 else
4473 prototype = scopeChain->globalObject()->objectPrototype();
4474 JSObject* newObject = new (exec) JSObject(prototype);
4475
4476 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
4477 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
4478 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
4479
4480 r[firstArg] = newObject; // "this" value
4481
4482 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4483 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr4, scopeChain, r, 0/*dst*/, firstArg, argCount, constructor);
4484 exec->m_callFrame = callFrame;
4485
4486 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
4487 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
4488
4489 codeBlock = newCodeBlock;
4490 machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
4491
4492 if (!codeBlock->ctiCode)
4493 CTI::compile(machine, exec, codeBlock);
4494
4495 ARG_setScopeChain(scopeChain);
4496 ARG_setCodeBlock(codeBlock);
4497 ARG_setR(r);
4498 return codeBlock->ctiCode;
4499}
4500
4501void Machine::cti_op_construct_verify(CTI_ARGS)
4502{
4503 ExecState* exec = ARG_exec;
4504 Register* r = ARG_r;
4505 int dst = ARG_int1;
4506
4507 if (LIKELY(r[dst].jsValue(exec)->isObject()))
4508 return;
4509
4510 int override = ARG_int2;
4511 r[dst] = r[override];
4512}
4513
4514JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
4515{
4516 ExecState* exec = ARG_exec;
4517 Register* r = ARG_r;
4518
4519 JSValue* constrVal = ARG_src1;
4520 int firstArg = ARG_int3;
4521 int argCount = ARG_int4;
4522
4523 ConstructData constructData;
4524 ConstructType constructType = constrVal->getConstructData(constructData);
4525
4526 // Removing this line of code causes a measurable regression on squirrelfish.
4527 JSObject* constructor = static_cast<JSObject*>(constrVal);
4528
4529 ASSERT(constructType != ConstructTypeJS);
4530
4531 if (constructType == ConstructTypeHost) {
4532 CodeBlock* codeBlock = ARG_codeBlock;
4533 ScopeChainNode* scopeChain = ARG_scopeChain;
4534 Machine* machine = exec->machine();
4535
4536 Register* oldCallFrame = exec->m_callFrame;
4537 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
4538 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, constrVal);
4539 exec->m_callFrame = callFrame;
4540
4541 if (*ARG_profilerReference)
4542 (*ARG_profilerReference)->willExecute(exec, constructor);
4543
4544 ArgList argList(r + firstArg + 1, argCount - 1);
4545
4546 CTI_MACHINE_SAMPLING_callingHostFunction();
4547
4548 JSValue* returnValue = constructData.native.function(exec, constructor, argList);
4549 exec->m_callFrame = oldCallFrame;
4550 VM_CHECK_EXCEPTION(JSValue*);
4551
4552 if (*ARG_profilerReference)
4553 (*ARG_profilerReference)->didExecute(exec, constructor);
4554
4555 return returnValue;
4556 }
4557
4558 ASSERT(constructType == ConstructTypeNone);
4559
4560 exec->setException(createNotAConstructorError(exec, constrVal, ARG_instr5, ARG_codeBlock));
4561 VM_CHECK_EXCEPTION_AT_END();
4562 return 0;
4563}
4564
4565JSValue* Machine::cti_op_get_by_val(CTI_ARGS)
4566{
4567 ExecState* exec = ARG_exec;
4568 Machine* machine = exec->machine();
4569
4570 JSValue* baseValue = ARG_src1;
4571 JSValue* subscript = ARG_src2;
4572
4573 JSValue* result;
4574 unsigned i;
4575
4576 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
4577 if (LIKELY(isUInt32)) {
4578 if (machine->isJSArray(baseValue)) {
4579 JSArray* jsArray = static_cast<JSArray*>(baseValue);
4580 if (jsArray->canGetIndex(i))
4581 result = jsArray->getIndex(i);
4582 else
4583 result = jsArray->JSArray::get(exec, i);
4584 } else if (machine->isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
4585 result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
4586 else
4587 result = baseValue->get(exec, i);
4588 } else {
4589 Identifier property(exec, subscript->toString(exec));
4590 result = baseValue->get(exec, property);
4591 }
4592
4593 VM_CHECK_EXCEPTION_AT_END();
4594 return result;
4595}
4596
4597JSValue* Machine::cti_op_resolve_func(CTI_ARGS)
4598{
4599 ExecState* exec = ARG_exec;
4600 ScopeChainNode* scopeChain = ARG_scopeChain;
4601
4602 ScopeChainIterator iter = scopeChain->begin();
4603 ScopeChainIterator end = scopeChain->end();
4604
4605 // FIXME: add scopeDepthIsZero optimization
4606
4607 ASSERT(iter != end);
4608
4609 Identifier& ident = *ARG_id1;
4610 JSObject* base;
4611 do {
4612 base = *iter;
4613 PropertySlot slot(base);
4614 if (base->getPropertySlot(exec, ident, slot)) {
4615 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
4616 // However, section 10.2.3 says that in the case where the value provided
4617 // by the caller is null, the global object should be used. It also says
4618 // that the section does not apply to internal functions, but for simplicity
4619 // of implementation we use the global object anyway here. This guarantees
4620 // that in host objects you always get a valid object for this.
4621 // We also handle wrapper substitution for the global object at the same time.
4622 JSObject* thisObj = base->toThisObject(exec);
4623 JSValue* result = slot.getValue(exec, ident);
4624 VM_CHECK_EXCEPTION_AT_END();
4625
4626 ARG_set2ndResult(result);
4627 return thisObj;
4628 }
4629 ++iter;
4630 } while (iter != end);
4631
4632 CodeBlock* codeBlock = ARG_codeBlock;
4633 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4634 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4635 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
4636
4637 VM_CHECK_EXCEPTION_AT_END();
4638 return 0;
4639}
4640
4641JSValue* Machine::cti_op_sub(CTI_ARGS)
4642{
4643 JSValue* src1 = ARG_src1;
4644 JSValue* src2 = ARG_src2;
4645
4646 double left;
4647 double right;
4648 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
4649 return jsNumber(ARG_exec, left - right);
4650 else {
4651 ExecState* exec = ARG_exec;
4652 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec));
4653 VM_CHECK_EXCEPTION_AT_END();
4654 return result;
4655 }
4656}
4657
4658void Machine::cti_op_put_by_val(CTI_ARGS)
4659{
4660 ExecState* exec = ARG_exec;
4661 Machine* machine = exec->machine();
4662
4663 JSValue* baseValue = ARG_src1;
4664 JSValue* subscript = ARG_src2;
4665 JSValue* value = ARG_src3;
4666
4667 unsigned i;
4668
4669 bool isUInt32 = JSImmediate::getUInt32(subscript, i);
4670 if (LIKELY(isUInt32)) {
4671 if (machine->isJSArray(baseValue)) {
4672 JSArray* jsArray = static_cast<JSArray*>(baseValue);
4673 if (jsArray->canSetIndex(i))
4674 jsArray->setIndex(i, value);
4675 else
4676 jsArray->JSArray::put(exec, i, value);
4677 } else
4678 baseValue->put(exec, i, value);
4679 } else {
4680 Identifier property(exec, subscript->toString(exec));
4681 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
4682 PutPropertySlot slot;
4683 baseValue->put(exec, property, value, slot);
4684 }
4685 }
4686
4687 VM_CHECK_EXCEPTION_AT_END();
4688}
4689
4690void Machine::cti_op_put_by_val_array(CTI_ARGS)
4691{
4692 ExecState* exec = ARG_exec;
4693
4694 JSValue* baseValue = ARG_src1;
4695 int i = ARG_int2;
4696 JSValue* value = ARG_src3;
4697
4698 ASSERT(exec->machine()->isJSArray(baseValue));
4699
4700 if (LIKELY(i >= 0))
4701 static_cast<JSArray*>(baseValue)->JSArray::put(exec, i, value);
4702 else {
4703 Identifier property(exec, JSImmediate::from(i)->toString(exec));
4704 // FIXME: can toString throw an exception here?
4705 if (!exec->hadException()) { // Don't put to an object if toString threw an exception.
4706 PutPropertySlot slot;
4707 baseValue->put(exec, property, value, slot);
4708 }
4709 }
4710
4711 VM_CHECK_EXCEPTION_AT_END();
4712}
4713
4714JSValue* Machine::cti_op_lesseq(CTI_ARGS)
4715{
4716 ExecState* exec = ARG_exec;
4717 JSValue* result = jsBoolean(jsLessEq(exec, ARG_src1, ARG_src2));
4718 VM_CHECK_EXCEPTION_AT_END();
4719 return result;
4720}
4721
4722int Machine::cti_op_loop_if_true(CTI_ARGS)
4723{
4724 JSValue* src1 = ARG_src1;
4725
4726 ExecState* exec = ARG_exec;
4727
4728 bool result = src1->toBoolean(exec);
4729 VM_CHECK_EXCEPTION_AT_END();
4730 return result;
4731}
4732
4733JSValue* Machine::cti_op_negate(CTI_ARGS)
4734{
4735 JSValue* src = ARG_src1;
4736
4737 ExecState* exec = ARG_exec;
4738
4739 double v;
4740 if (fastIsNumber(src, v))
4741 return jsNumber(exec, -v);
4742 else {
4743 JSValue* result = jsNumber(exec, -src->toNumber(exec));
4744 VM_CHECK_EXCEPTION_AT_END();
4745 return result;
4746 }
4747}
4748
4749JSValue* Machine::cti_op_resolve_base(CTI_ARGS)
4750{
4751 return inlineResolveBase(ARG_exec, *ARG_id1, ARG_scopeChain);
4752}
4753
4754JSValue* Machine::cti_op_resolve_skip(CTI_ARGS)
4755{
4756 ExecState* exec = ARG_exec;
4757 ScopeChainNode* scopeChain = ARG_scopeChain;
4758
4759 int skip = ARG_int2;
4760
4761 ScopeChainIterator iter = scopeChain->begin();
4762 ScopeChainIterator end = scopeChain->end();
4763 ASSERT(iter != end);
4764 while (skip--) {
4765 ++iter;
4766 ASSERT(iter != end);
4767 }
4768 Identifier& ident = *ARG_id1;
4769 do {
4770 JSObject* o = *iter;
4771 PropertySlot slot(o);
4772 if (o->getPropertySlot(exec, ident, slot)) {
4773 JSValue* result = slot.getValue(exec, ident);
4774 VM_CHECK_EXCEPTION_AT_END();
4775 return result;
4776 }
4777 } while (++iter != end);
4778
4779 CodeBlock* codeBlock = ARG_codeBlock;
4780 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4781 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4782 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
4783
4784 VM_CHECK_EXCEPTION_AT_END();
4785 return 0;
4786}
4787
4788JSValue* Machine::cti_op_div(CTI_ARGS)
4789{
4790 ExecState* exec = ARG_exec;
4791 JSValue* src1 = ARG_src1;
4792 JSValue* src2 = ARG_src2;
4793
4794 double left;
4795 double right;
4796 if (fastIsNumber(src1, left) && fastIsNumber(src2, right))
4797 return jsNumber(exec, left / right);
4798 else {
4799 JSValue* result = jsNumber(exec, src1->toNumber(exec) / src2->toNumber(exec));
4800 VM_CHECK_EXCEPTION_AT_END();
4801 return result;
4802 }
4803}
4804
4805JSValue* Machine::cti_op_pre_dec(CTI_ARGS)
4806{
4807 JSValue* v = ARG_src1;
4808
4809 ExecState* exec = ARG_exec;
4810 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1);
4811 VM_CHECK_EXCEPTION_AT_END();
4812 return result;
4813}
4814
4815int Machine::cti_op_jless(CTI_ARGS)
4816{
4817 JSValue* src1 = ARG_src1;
4818 JSValue* src2 = ARG_src2;
4819 ExecState* exec = ARG_exec;
4820
4821 bool result = jsLess(exec, src1, src2);
4822 VM_CHECK_EXCEPTION_AT_END();
4823 return result;
4824}
4825
4826JSValue* Machine::cti_op_not(CTI_ARGS)
4827{
4828 JSValue* src = ARG_src1;
4829
4830 ExecState* exec = ARG_exec;
4831
4832 JSValue* result = jsBoolean(!src->toBoolean(exec));
4833 VM_CHECK_EXCEPTION_AT_END();
4834 return result;
4835}
4836
4837int SFX_CALL Machine::cti_op_jtrue(CTI_ARGS)
4838{
4839 JSValue* src1 = ARG_src1;
4840
4841 ExecState* exec = ARG_exec;
4842
4843 bool result = src1->toBoolean(exec);
4844 VM_CHECK_EXCEPTION_AT_END();
4845 return result;
4846}
4847
4848JSValue* Machine::cti_op_post_inc(CTI_ARGS)
4849{
4850 JSValue* v = ARG_src1;
4851
4852 ExecState* exec = ARG_exec;
4853
4854 JSValue* number = v->toJSNumber(exec);
4855 VM_CHECK_EXCEPTION(JSValue*);
4856 ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() + 1));
4857 return number;
4858}
4859
4860JSValue* Machine::cti_op_eq(CTI_ARGS)
4861{
4862 JSValue* src1 = ARG_src1;
4863 JSValue* src2 = ARG_src2;
4864
4865 if (JSImmediate::areBothImmediateNumbers(src1, src2))
4866 return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
4867 else {
4868 ExecState* exec = ARG_exec;
4869 JSValue* result = jsBoolean(equal(exec, src1, src2));
4870 VM_CHECK_EXCEPTION_AT_END();
4871 return result;
4872 }
4873}
4874
4875JSValue* Machine::cti_op_lshift(CTI_ARGS)
4876{
4877 JSValue* val = ARG_src1;
4878 JSValue* shift = ARG_src2;
4879
4880 ExecState* exec = ARG_exec;
4881
4882 int32_t left;
4883 uint32_t right;
4884 if (JSImmediate::areBothImmediateNumbers(val, shift))
4885 return jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f));
4886 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
4887 return jsNumber(exec, left << (right & 0x1f));
4888 else {
4889 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f));
4890 VM_CHECK_EXCEPTION_AT_END();
4891 return result;
4892 }
4893}
4894
4895JSValue* Machine::cti_op_bitand(CTI_ARGS)
4896{
4897 JSValue* src1 = ARG_src1;
4898 JSValue* src2 = ARG_src2;
4899
4900 ExecState* exec = ARG_exec;
4901
4902 int32_t left;
4903 int32_t right;
4904 if (fastToInt32(src1, left) && fastToInt32(src2, right))
4905 return jsNumber(exec, left & right);
4906 else {
4907 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec));
4908 VM_CHECK_EXCEPTION_AT_END();
4909 return result;
4910 }
4911}
4912
4913JSValue* Machine::cti_op_rshift(CTI_ARGS)
4914{
4915 JSValue* val = ARG_src1;
4916 JSValue* shift = ARG_src2;
4917
4918 ExecState* exec = ARG_exec;
4919
4920 int32_t left;
4921 uint32_t right;
4922 if (JSImmediate::areBothImmediateNumbers(val, shift))
4923 return JSImmediate::rightShiftImmediateNumbers(val, shift);
4924 else if (fastToInt32(val, left) && fastToUInt32(shift, right))
4925 return jsNumber(exec, left >> (right & 0x1f));
4926 else {
4927 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
4928 VM_CHECK_EXCEPTION_AT_END();
4929 return result;
4930 }
4931}
4932
4933JSValue* Machine::cti_op_bitnot(CTI_ARGS)
4934{
4935 JSValue* src = ARG_src1;
4936
4937 ExecState* exec = ARG_exec;
4938
4939 int value;
4940 if (fastToInt32(src, value))
4941 return jsNumber(exec, ~value);
4942
4943 JSValue* result = jsNumber(exec, ~src->toInt32(exec));
4944 VM_CHECK_EXCEPTION_AT_END();
4945 return result;
4946}
4947
4948JSValue* Machine::cti_op_resolve_with_base(CTI_ARGS)
4949{
4950 ExecState* exec = ARG_exec;
4951 ScopeChainNode* scopeChain = ARG_scopeChain;
4952
4953 ScopeChainIterator iter = scopeChain->begin();
4954 ScopeChainIterator end = scopeChain->end();
4955
4956 // FIXME: add scopeDepthIsZero optimization
4957
4958 ASSERT(iter != end);
4959
4960 Identifier& ident = *ARG_id1;
4961 JSObject* base;
4962 do {
4963 base = *iter;
4964 PropertySlot slot(base);
4965 if (base->getPropertySlot(exec, ident, slot)) {
4966 JSValue* result = slot.getValue(exec, ident);
4967 VM_CHECK_EXCEPTION_AT_END();
4968 ARG_set2ndResult(result);
4969 return base;
4970 }
4971 ++iter;
4972 } while (iter != end);
4973
4974 CodeBlock* codeBlock = ARG_codeBlock;
4975 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
4976 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
4977 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock));
4978
4979 VM_CHECK_EXCEPTION_AT_END();
4980 return 0;
4981}
4982
4983JSValue* Machine::cti_op_new_func_exp(CTI_ARGS)
4984{
4985 return ARG_funcexp1->makeFunction(ARG_exec, ARG_scopeChain);
4986}
4987
4988JSValue* Machine::cti_op_mod(CTI_ARGS)
4989{
4990 JSValue* dividendValue = ARG_src1;
4991 JSValue* divisorValue = ARG_src2;
4992
4993 ExecState* exec = ARG_exec;
4994 double d = dividendValue->toNumber(exec);
4995 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec)));
4996 VM_CHECK_EXCEPTION_AT_END();
4997 return result;
4998}
4999
5000JSValue* Machine::cti_op_less(CTI_ARGS)
5001{
5002 ExecState* exec = ARG_exec;
5003 JSValue* result = jsBoolean(jsLess(exec, ARG_src1, ARG_src2));
5004 VM_CHECK_EXCEPTION_AT_END();
5005 return result;
5006}
5007
5008JSValue* Machine::cti_op_neq(CTI_ARGS)
5009{
5010 JSValue* src1 = ARG_src1;
5011 JSValue* src2 = ARG_src2;
5012
5013 if (JSImmediate::areBothImmediateNumbers(src1, src2))
5014 return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
5015 else {
5016 ExecState* exec = ARG_exec;
5017 JSValue* result = jsBoolean(!equal(exec, src1, src2));
5018 VM_CHECK_EXCEPTION_AT_END();
5019 return result;
5020 }
5021}
5022
5023JSValue* Machine::cti_op_post_dec(CTI_ARGS)
5024{
5025 JSValue* v = ARG_src1;
5026
5027 ExecState* exec = ARG_exec;
5028
5029 JSValue* number = v->toJSNumber(exec);
5030 VM_CHECK_EXCEPTION(JSValue*);
5031
5032 ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() - 1));
5033 return number;
5034}
5035
5036JSValue* Machine::cti_op_urshift(CTI_ARGS)
5037{
5038 JSValue* val = ARG_src1;
5039 JSValue* shift = ARG_src2;
5040
5041 ExecState* exec = ARG_exec;
5042
5043 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val))
5044 return JSImmediate::rightShiftImmediateNumbers(val, shift);
5045 else {
5046 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f));
5047 VM_CHECK_EXCEPTION_AT_END();
5048 return result;
5049 }
5050}
5051
5052JSValue* Machine::cti_op_bitxor(CTI_ARGS)
5053{
5054 JSValue* src1 = ARG_src1;
5055 JSValue* src2 = ARG_src2;
5056
5057 ExecState* exec = ARG_exec;
5058
5059 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec));
5060 VM_CHECK_EXCEPTION_AT_END();
5061 return result;
5062}
5063
5064JSValue* Machine::cti_op_new_regexp(CTI_ARGS)
5065{
5066 return new (ARG_exec) RegExpObject(ARG_scopeChain->globalObject()->regExpPrototype(), ARG_regexp1);
5067}
5068
5069JSValue* Machine::cti_op_bitor(CTI_ARGS)
5070{
5071 JSValue* src1 = ARG_src1;
5072 JSValue* src2 = ARG_src2;
5073
5074 ExecState* exec = ARG_exec;
5075
5076 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec));
5077 VM_CHECK_EXCEPTION_AT_END();
5078 return result;
5079}
5080
5081JSValue* Machine::cti_op_call_eval(CTI_ARGS)
5082{
5083 ExecState* exec = ARG_exec;
5084 RegisterFile* registerFile = ARG_registerFile;
5085 Register* r = ARG_r;
5086 CodeBlock* codeBlock = ARG_codeBlock;
5087 ScopeChainNode* scopeChain = ARG_scopeChain;
5088
5089 Machine* machine = exec->machine();
5090 JSValue* exceptionValue = 0;
5091
5092 JSValue* funcVal = ARG_src1;
5093 JSValue* baseVal = ARG_src2;
5094 int firstArg = ARG_int3;
5095 int argCount = ARG_int4;
5096
5097 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
5098 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
5099 JSValue* result = machine->callEval(exec, codeBlock, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue);
5100 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
5101 return result;
5102 }
5103
5104 return JSImmediate::impossibleValue();
5105}
5106
5107void* Machine::cti_op_throw(CTI_ARGS)
5108{
5109 ExecState* exec = ARG_exec;
5110 CodeBlock* codeBlock = ARG_codeBlock;
5111 ScopeChainNode* scopeChain = ARG_scopeChain;
5112 Register* r = ARG_r;
5113
5114 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5115 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5116
5117 JSValue* exceptionValue = ARG_src1;
5118 Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, true);
5119
5120 if (handlerVPC) {
5121 exec->setException(exceptionValue);
5122 ARG_setScopeChain(scopeChain);
5123 ARG_setCodeBlock(codeBlock);
5124 ARG_setR(r);
5125
5126 void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC);
5127 ASSERT(catchRoutine);
5128 ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine);
5129 return catchRoutine;
5130 } else {
5131 exec->clearException();
5132 *ARG_exception = exceptionValue;
5133 return JSImmediate::nullImmediate();
5134 }
5135}
5136
5137JSPropertyNameIterator* Machine::cti_op_get_pnames(CTI_ARGS)
5138{
5139 return JSPropertyNameIterator::create(ARG_exec, ARG_src1);
5140}
5141
5142JSValue* Machine::cti_op_next_pname(CTI_ARGS)
5143{
5144 JSPropertyNameIterator* it = ARG_pni1;
5145 JSValue* temp = it->next(ARG_exec);
5146 if (!temp)
5147 it->invalidate();
5148 return temp;
5149}
5150
5151void Machine::cti_op_push_scope(CTI_ARGS)
5152{
5153 ExecState* exec = ARG_exec;
5154
5155 JSValue* v = ARG_src1;
5156 JSObject* o = v->toObject(exec);
5157 VM_CHECK_EXCEPTION_v();
5158
5159 ScopeChainNode* newScopeChain = ARG_scopeChain->push(o);
5160 ARG_setScopeChain(newScopeChain);
5161 exec->m_scopeChain = newScopeChain;
5162}
5163
5164void Machine::cti_op_pop_scope(CTI_ARGS)
5165{
5166 ExecState* exec = ARG_exec;
5167
5168 ScopeChainNode* newScopeChain = ARG_scopeChain->pop();
5169 ARG_setScopeChain(newScopeChain);
5170 exec->m_scopeChain = newScopeChain;
5171}
5172
5173JSValue* Machine::cti_op_typeof(CTI_ARGS)
5174{
5175 return jsTypeStringForValue(ARG_exec, ARG_src1);
5176}
5177
5178JSValue* Machine::cti_op_is_undefined(CTI_ARGS)
5179{
5180 JSValue* v = ARG_src1;
5181 return jsBoolean(v->isUndefined() || (v->isObject() && static_cast<JSObject*>(v)->masqueradeAsUndefined()));
5182}
5183
5184JSValue* Machine::cti_op_is_boolean(CTI_ARGS)
5185{
5186 return jsBoolean(ARG_src1->isBoolean());
5187}
5188
5189JSValue* Machine::cti_op_is_number(CTI_ARGS)
5190{
5191 return jsBoolean(ARG_src1->isNumber());
5192}
5193
5194JSValue* Machine::cti_op_is_string(CTI_ARGS)
5195{
5196 return jsBoolean(ARG_src1->isString());
5197}
5198
5199JSValue* Machine::cti_op_is_object(CTI_ARGS)
5200{
5201 return jsBoolean(jsIsObjectType(ARG_src1));
5202}
5203
5204JSValue* Machine::cti_op_is_function(CTI_ARGS)
5205{
5206 return jsBoolean(jsIsFunctionType(ARG_src1));
5207}
5208
5209JSValue* Machine::cti_op_stricteq(CTI_ARGS)
5210{
5211 JSValue* src1 = ARG_src1;
5212 JSValue* src2 = ARG_src2;
5213
5214 if (JSImmediate::areBothImmediateNumbers(src1, src2))
5215 return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
5216 else {
5217 ExecState* exec = ARG_exec;
5218 JSValue* result = jsBoolean(strictEqual(src1, src2));
5219 VM_CHECK_EXCEPTION_AT_END();
5220 return result;
5221 }
5222}
5223
5224JSValue* Machine::cti_op_nstricteq(CTI_ARGS)
5225{
5226 JSValue* src1 = ARG_src1;
5227 JSValue* src2 = ARG_src2;
5228
5229 if (JSImmediate::areBothImmediateNumbers(src1, src2))
5230 return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
5231 else {
5232 ExecState* exec = ARG_exec;
5233 JSValue* result = jsBoolean(!strictEqual(src1, src2));
5234 VM_CHECK_EXCEPTION_AT_END();
5235 return result;
5236 }
5237}
5238
5239JSValue* Machine::cti_op_to_jsnumber(CTI_ARGS)
5240{
5241 JSValue* src = ARG_src1;
5242 ExecState* exec = ARG_exec;
5243
5244 JSValue* result = src->toJSNumber(exec);
5245 VM_CHECK_EXCEPTION_AT_END();
5246 return result;
5247}
5248
5249JSValue* Machine::cti_op_in(CTI_ARGS)
5250{
5251 ExecState* exec = ARG_exec;
5252 JSValue* baseVal = ARG_src2;
5253
5254 if (!baseVal->isObject()) {
5255 CodeBlock* codeBlock = ARG_codeBlock;
5256 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS));
5257 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS);
5258 exec->setException(createInvalidParamError(exec, "in", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock));
5259 VM_CHECK_EXCEPTION(JSValue*);
5260 }
5261
5262 JSValue* propName = ARG_src1;
5263 JSObject* baseObj = static_cast<JSObject*>(baseVal);
5264
5265 uint32_t i;
5266 if (propName->getUInt32(i))
5267 return jsBoolean(baseObj->hasProperty(exec, i));
5268
5269 Identifier property(exec, propName->toString(exec));
5270 VM_CHECK_EXCEPTION(JSValue*);
5271 return jsBoolean(baseObj->hasProperty(exec, property));
5272}
5273
5274JSValue* Machine::cti_op_push_new_scope(CTI_ARGS)
5275{
5276 ExecState* exec = ARG_exec;
5277 JSObject* scope = new (exec) JSStaticScopeObject(exec, *ARG_id1, ARG_src2, DontDelete);
5278
5279 ScopeChainNode* newScopeChain = ARG_scopeChain->push(scope);
5280 ARG_setScopeChain(newScopeChain);
5281 exec->m_scopeChain = newScopeChain;
5282
5283 return scope;
5284}
5285
5286void Machine::cti_op_jmp_scopes(CTI_ARGS)
5287{
5288 ExecState* exec = ARG_exec;
5289 unsigned count = ARG_int1;
5290
5291 ScopeChainNode* tmp = ARG_scopeChain;
5292 while (count--)
5293 tmp = tmp->pop();
5294
5295 ARG_setScopeChain(tmp);
5296 exec->m_scopeChain = tmp;
5297}
5298
5299void Machine::cti_op_put_by_index(CTI_ARGS)
5300{
5301 ExecState* exec = ARG_exec;
5302 unsigned property = ARG_int2;
5303
5304 ARG_src1->put(exec, property, ARG_src3);
5305}
5306
5307void* Machine::cti_op_switch_imm(CTI_ARGS)
5308{
5309 JSValue* scrutinee = ARG_src1;
5310 unsigned tableIndex = ARG_int2;
5311
5312 CodeBlock* codeBlock = ARG_codeBlock;
5313
5314 if (JSImmediate::isNumber(scrutinee)) {
5315 int32_t value = JSImmediate::getTruncatedInt32(scrutinee);
5316 return codeBlock->immediateSwitchJumpTables[tableIndex].ctiForValue(value);
5317 }
5318
5319 return codeBlock->immediateSwitchJumpTables[tableIndex].ctiDefault;
5320}
5321
5322void* Machine::cti_op_switch_char(CTI_ARGS)
5323{
5324 JSValue* scrutinee = ARG_src1;
5325 unsigned tableIndex = ARG_int2;
5326
5327 CodeBlock* codeBlock = ARG_codeBlock;
5328
5329 void* result = codeBlock->characterSwitchJumpTables[tableIndex].ctiDefault;
5330
5331 if (scrutinee->isString()) {
5332 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
5333 if (value->size() == 1)
5334 result = codeBlock->characterSwitchJumpTables[tableIndex].ctiForValue(value->data()[0]);
5335 }
5336
5337 return result;
5338}
5339
5340void* Machine::cti_op_switch_string(CTI_ARGS)
5341{
5342 JSValue* scrutinee = ARG_src1;
5343 unsigned tableIndex = ARG_int2;
5344
5345 CodeBlock* codeBlock = ARG_codeBlock;
5346
5347 void* result = codeBlock->stringSwitchJumpTables[tableIndex].ctiDefault;
5348
5349 if (scrutinee->isString()) {
5350 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();
5351 result = codeBlock->stringSwitchJumpTables[tableIndex].ctiForValue(value);
5352 }
5353
5354 return result;
5355}
5356
5357JSValue* Machine::cti_op_del_by_val(CTI_ARGS)
5358{
5359 ExecState* exec = ARG_exec;
5360
5361 JSValue* baseValue = ARG_src1;
5362 JSObject* baseObj = baseValue->toObject(exec); // may throw
5363
5364 JSValue* subscript = ARG_src2;
5365 JSValue* result;
5366 uint32_t i;
5367 if (subscript->getUInt32(i))
5368 result = jsBoolean(baseObj->deleteProperty(exec, i));
5369 else {
5370 VM_CHECK_EXCEPTION(JSValue*);
5371 Identifier property(exec, subscript->toString(exec));
5372 VM_CHECK_EXCEPTION(JSValue*);
5373 result = jsBoolean(baseObj->deleteProperty(exec, property));
5374 }
5375
5376 VM_CHECK_EXCEPTION_AT_END();
5377 return result;
5378}
5379
5380void Machine::cti_op_put_getter(CTI_ARGS)
5381{
5382 ExecState* exec = ARG_exec;
5383
5384 ASSERT(ARG_src1->isObject());
5385 JSObject* baseObj = static_cast<JSObject*>(ARG_src1);
5386 Identifier& ident = *ARG_id2;
5387 ASSERT(ARG_src3->isObject());
5388 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(ARG_src3));
5389}
5390
5391void Machine::cti_op_put_setter(CTI_ARGS)
5392{
5393 ExecState* exec = ARG_exec;
5394
5395 ASSERT(ARG_src1->isObject());
5396 JSObject* baseObj = static_cast<JSObject*>(ARG_src1);
5397 Identifier& ident = *ARG_id2;
5398 ASSERT(ARG_src3->isObject());
5399 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(ARG_src3));
5400}
5401
5402JSValue* Machine::cti_op_new_error(CTI_ARGS)
5403{
5404 ExecState* exec = ARG_exec;
5405 CodeBlock* codeBlock = ARG_codeBlock;
5406 unsigned type = ARG_int1;
5407 JSValue* message = ARG_src2;
5408 unsigned lineNumber = ARG_int3;
5409
5410 return Error::create(exec, static_cast<ErrorType>(type), message->toString(exec), lineNumber, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
5411}
5412
5413void Machine::cti_op_debug(CTI_ARGS)
5414{
5415 ExecState* exec = ARG_exec;
5416 CodeBlock* codeBlock = ARG_codeBlock;
5417 ScopeChainNode* scopeChain = ARG_scopeChain;
5418 Register* r = ARG_r;
5419
5420 int debugHookID = ARG_int1;
5421 int firstLine = ARG_int2;
5422 int lastLine = ARG_int3;
5423
5424 exec->machine()->debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
5425}
5426
5427JSValue* Machine::cti_op_eq_null(CTI_ARGS)
5428{
5429 JSValue* src = ARG_src1;
5430
5431 if (src->isUndefinedOrNull())
5432 return jsBoolean(true);
5433
5434 return jsBoolean(ARG_exec->machine()->doesMasqueradesAsUndefined(src));
5435}
5436
5437JSValue* Machine::cti_op_neq_null(CTI_ARGS)
5438{
5439 JSValue* src = ARG_src1;
5440 if (src->isUndefinedOrNull())
5441 return jsBoolean(false);
5442
5443 return jsBoolean(!ARG_exec->machine()->doesMasqueradesAsUndefined(src));
5444}
5445
5446void* Machine::cti_vm_throw(CTI_ARGS)
5447{
5448 ExecState* exec = ARG_exec;
5449 CodeBlock* codeBlock = ARG_codeBlock;
5450 ScopeChainNode* scopeChain = ARG_scopeChain;
5451 Register* r = ARG_r;
5452
5453 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(exec->ctiReturnAddress()));
5454 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(exec->ctiReturnAddress());
5455
5456 ASSERT(exec->hadException());
5457
5458 JSValue* exceptionValue = exec->exception();
5459
5460 Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, false);
5461
5462 if (handlerVPC) {
5463 exec->setException(exceptionValue);
5464 ARG_setScopeChain(scopeChain);
5465 ARG_setCodeBlock(codeBlock);
5466 ARG_setR(r);
5467
5468 void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC);
5469 ASSERT(catchRoutine);
5470 ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine);
5471 return catchRoutine;
5472 } else {
5473 exec->clearException();
5474 *ARG_exception = exceptionValue;
5475 return JSImmediate::nullImmediate();
5476 }
5477}
5478
5479#undef VM_CHECK_EXCEPTION
5480#undef VM_CHECK_EXCEPTION_v
5481#undef VM_CHECK_EXCEPTION_AT_END
5482
5483#endif // ENABLE(CTI)
5484
5485} // namespace JSC
Note: See TracBrowser for help on using the repository browser.