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

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

JavaScriptCore:

2008-09-23 Maciej Stachowiak <[email protected]>

Reviewed by Darin.


~2% speedup on EarleyBoyer

The idea here is to record in the StructureID whether the class
needs a special hasInstance or if it can use the normal logic from
JSObject.


Based on this I inlined the real work directly into
cti_op_instanceof and put the fastest checks up front and the
error handling at the end (so it should be fairly straightforward
to split off the beginning to be inlined if desired).

I only did this for CTI, not the bytecode interpreter.


  • API/JSCallbackObject.h: (JSC::JSCallbackObject::createStructureID):
  • ChangeLog:
  • VM/Machine.cpp: (JSC::Machine::cti_op_instanceof):
  • kjs/JSImmediate.h: (JSC::JSImmediate::isAnyImmediate):
  • kjs/TypeInfo.h: (JSC::TypeInfo::overridesHasInstance): (JSC::TypeInfo::flags):

WebCore:

2008-09-23 Maciej Stachowiak <[email protected]>

Reviewed by Darin.

~2% speedup on EarleyBoyer

(WebCore updates.)


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