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

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

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

Reviewed by Cameron Zwarich.


  • split the "prototype" lookup for hasInstance into opcode stream so it can be cached


~5% speedup on v8 earley-boyer test

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