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

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

JavaScriptCore:

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

Reviewed by Dave Hyatt.


Based on initial work by Darin Adler.


0.5% speedup on SunSpider
~4% speedup on Richards benchmark


  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass):
  • VM/Machine.cpp: (JSC::jsTypeStringForValue): (JSC::jsIsObjectType): (JSC::Machine::privateExecute): (JSC::Machine::cti_op_is_undefined):
  • VM/Machine.h:
  • kjs/JSCell.h:
  • kjs/JSValue.h:
  • kjs/StringObjectThatMasqueradesAsUndefined.h: (JSC::StringObjectThatMasqueradesAsUndefined::create): (JSC::StringObjectThatMasqueradesAsUndefined::createStructureID):
  • kjs/StructureID.h: (JSC::StructureID::mutableTypeInfo):
  • kjs/TypeInfo.h: (JSC::TypeInfo::TypeInfo): (JSC::TypeInfo::masqueradesAsUndefined):
  • kjs/operations.cpp: (JSC::equal):
  • masm/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::setne_r): (JSC::X86Assembler::setnz_r): (JSC::X86Assembler::testl_i32m):

WebCore:

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

Reviewed by Dave Hyatt.

Based on initial work by Darin Adler.



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