source: webkit/trunk/JavaScriptCore/interpreter/Interpreter.cpp@ 39440

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

2008-12-22 Sam Weinig <[email protected]>

Reviewed by Gavin Barraclough.

Rename all uses of the term "repatch" to "patch".

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