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