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 "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.h"
38 #include "Collector.h"
39 #include "Debugger.h"
40 #include "DebuggerCallFrame.h"
41 #include "EvalCodeCache.h"
42 #include "ExceptionHelpers.h"
43 #include "GlobalEvalFunction.h"
44 #include "JSActivation.h"
45 #include "JSArray.h"
46 #include "JSByteArray.h"
47 #include "JSFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "LiteralParser.h"
51 #include "JSStaticScopeObject.h"
52 #include "JSString.h"
53 #include "ObjectPrototype.h"
54 #include "Operations.h"
55 #include "Parser.h"
56 #include "Profiler.h"
57 #include "RegExpObject.h"
58 #include "RegExpPrototype.h"
59 #include "Register.h"
60 #include "SamplingTool.h"
61 #include <limits.h>
62 #include <stdio.h>
63 #include <wtf/Threading.h>
64
65 #if ENABLE(JIT)
66 #include "JIT.h"
67 #endif
68
69 using namespace std;
70
71 namespace JSC {
72
bytecodeOffsetForPC(CallFrame * callFrame,CodeBlock * codeBlock,void * pc)73 static ALWAYS_INLINE unsigned bytecodeOffsetForPC(CallFrame* callFrame, CodeBlock* codeBlock, void* pc)
74 {
75 #if ENABLE(JIT)
76 return codeBlock->getBytecodeIndex(callFrame, ReturnAddressPtr(pc));
77 #else
78 UNUSED_PARAM(callFrame);
79 return static_cast<Instruction*>(pc) - codeBlock->instructions().begin();
80 #endif
81 }
82
83 // Returns the depth of the scope chain within a given call frame.
depth(CodeBlock * codeBlock,ScopeChain & sc)84 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
85 {
86 if (!codeBlock->needsFullScopeChain())
87 return 0;
88 return sc.localDepth();
89 }
90
91 #if USE(INTERPRETER)
resolve(CallFrame * callFrame,Instruction * vPC,JSValue & exceptionValue)92 NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
93 {
94 int dst = (vPC + 1)->u.operand;
95 int property = (vPC + 2)->u.operand;
96
97 ScopeChainNode* scopeChain = callFrame->scopeChain();
98 ScopeChainIterator iter = scopeChain->begin();
99 ScopeChainIterator end = scopeChain->end();
100 ASSERT(iter != end);
101
102 CodeBlock* codeBlock = callFrame->codeBlock();
103 Identifier& ident = codeBlock->identifier(property);
104 do {
105 JSObject* o = *iter;
106 PropertySlot slot(o);
107 if (o->getPropertySlot(callFrame, ident, slot)) {
108 JSValue result = slot.getValue(callFrame, ident);
109 exceptionValue = callFrame->globalData().exception;
110 if (exceptionValue)
111 return false;
112 callFrame->r(dst) = JSValue(result);
113 return true;
114 }
115 } while (++iter != end);
116 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
117 return false;
118 }
119
resolveSkip(CallFrame * callFrame,Instruction * vPC,JSValue & exceptionValue)120 NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
121 {
122 CodeBlock* codeBlock = callFrame->codeBlock();
123
124 int dst = (vPC + 1)->u.operand;
125 int property = (vPC + 2)->u.operand;
126 int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain();
127
128 ScopeChainNode* scopeChain = callFrame->scopeChain();
129 ScopeChainIterator iter = scopeChain->begin();
130 ScopeChainIterator end = scopeChain->end();
131 ASSERT(iter != end);
132 while (skip--) {
133 ++iter;
134 ASSERT(iter != end);
135 }
136 Identifier& ident = codeBlock->identifier(property);
137 do {
138 JSObject* o = *iter;
139 PropertySlot slot(o);
140 if (o->getPropertySlot(callFrame, ident, slot)) {
141 JSValue result = slot.getValue(callFrame, ident);
142 exceptionValue = callFrame->globalData().exception;
143 if (exceptionValue)
144 return false;
145 callFrame->r(dst) = JSValue(result);
146 return true;
147 }
148 } while (++iter != end);
149 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
150 return false;
151 }
152
resolveGlobal(CallFrame * callFrame,Instruction * vPC,JSValue & exceptionValue)153 NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
154 {
155 int dst = (vPC + 1)->u.operand;
156 JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell);
157 ASSERT(globalObject->isGlobalObject());
158 int property = (vPC + 3)->u.operand;
159 Structure* structure = (vPC + 4)->u.structure;
160 int offset = (vPC + 5)->u.operand;
161
162 if (structure == globalObject->structure()) {
163 callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset));
164 return true;
165 }
166
167 CodeBlock* codeBlock = callFrame->codeBlock();
168 Identifier& ident = codeBlock->identifier(property);
169 PropertySlot slot(globalObject);
170 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
171 JSValue result = slot.getValue(callFrame, ident);
172 if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) {
173 if (vPC[4].u.structure)
174 vPC[4].u.structure->deref();
175 globalObject->structure()->ref();
176 vPC[4] = globalObject->structure();
177 vPC[5] = slot.cachedOffset();
178 callFrame->r(dst) = JSValue(result);
179 return true;
180 }
181
182 exceptionValue = callFrame->globalData().exception;
183 if (exceptionValue)
184 return false;
185 callFrame->r(dst) = JSValue(result);
186 return true;
187 }
188
189 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
190 return false;
191 }
192
resolveBase(CallFrame * callFrame,Instruction * vPC)193 NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC)
194 {
195 int dst = (vPC + 1)->u.operand;
196 int property = (vPC + 2)->u.operand;
197 callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain()));
198 }
199
resolveBaseAndProperty(CallFrame * callFrame,Instruction * vPC,JSValue & exceptionValue)200 NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
201 {
202 int baseDst = (vPC + 1)->u.operand;
203 int propDst = (vPC + 2)->u.operand;
204 int property = (vPC + 3)->u.operand;
205
206 ScopeChainNode* scopeChain = callFrame->scopeChain();
207 ScopeChainIterator iter = scopeChain->begin();
208 ScopeChainIterator end = scopeChain->end();
209
210 // FIXME: add scopeDepthIsZero optimization
211
212 ASSERT(iter != end);
213
214 CodeBlock* codeBlock = callFrame->codeBlock();
215 Identifier& ident = codeBlock->identifier(property);
216 JSObject* base;
217 do {
218 base = *iter;
219 PropertySlot slot(base);
220 if (base->getPropertySlot(callFrame, ident, slot)) {
221 JSValue result = slot.getValue(callFrame, ident);
222 exceptionValue = callFrame->globalData().exception;
223 if (exceptionValue)
224 return false;
225 callFrame->r(propDst) = JSValue(result);
226 callFrame->r(baseDst) = JSValue(base);
227 return true;
228 }
229 ++iter;
230 } while (iter != end);
231
232 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
233 return false;
234 }
235
resolveBaseAndFunc(CallFrame * callFrame,Instruction * vPC,JSValue & exceptionValue)236 NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue)
237 {
238 int baseDst = (vPC + 1)->u.operand;
239 int funcDst = (vPC + 2)->u.operand;
240 int property = (vPC + 3)->u.operand;
241
242 ScopeChainNode* scopeChain = callFrame->scopeChain();
243 ScopeChainIterator iter = scopeChain->begin();
244 ScopeChainIterator end = scopeChain->end();
245
246 // FIXME: add scopeDepthIsZero optimization
247
248 ASSERT(iter != end);
249
250 CodeBlock* codeBlock = callFrame->codeBlock();
251 Identifier& ident = codeBlock->identifier(property);
252 JSObject* base;
253 do {
254 base = *iter;
255 PropertySlot slot(base);
256 if (base->getPropertySlot(callFrame, ident, slot)) {
257 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
258 // However, section 10.2.3 says that in the case where the value provided
259 // by the caller is null, the global object should be used. It also says
260 // that the section does not apply to internal functions, but for simplicity
261 // of implementation we use the global object anyway here. This guarantees
262 // that in host objects you always get a valid object for this.
263 // We also handle wrapper substitution for the global object at the same time.
264 JSObject* thisObj = base->toThisObject(callFrame);
265 JSValue result = slot.getValue(callFrame, ident);
266 exceptionValue = callFrame->globalData().exception;
267 if (exceptionValue)
268 return false;
269
270 callFrame->r(baseDst) = JSValue(thisObj);
271 callFrame->r(funcDst) = JSValue(result);
272 return true;
273 }
274 ++iter;
275 } while (iter != end);
276
277 exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock);
278 return false;
279 }
280
281 #endif // USE(INTERPRETER)
282
slideRegisterWindowForCall(CodeBlock * newCodeBlock,RegisterFile * registerFile,CallFrame * callFrame,size_t registerOffset,int argc)283 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc)
284 {
285 Register* r = callFrame->registers();
286 Register* newEnd = r + registerOffset + newCodeBlock->m_numCalleeRegisters;
287
288 if (LIKELY(argc == newCodeBlock->m_numParameters)) { // correct number of arguments
289 if (UNLIKELY(!registerFile->grow(newEnd)))
290 return 0;
291 r += registerOffset;
292 } else if (argc < newCodeBlock->m_numParameters) { // too few arguments -- fill in the blanks
293 size_t omittedArgCount = newCodeBlock->m_numParameters - argc;
294 registerOffset += omittedArgCount;
295 newEnd += omittedArgCount;
296 if (!registerFile->grow(newEnd))
297 return 0;
298 r += registerOffset;
299
300 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
301 for (size_t i = 0; i < omittedArgCount; ++i)
302 argv[i] = jsUndefined();
303 } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
304 size_t numParameters = newCodeBlock->m_numParameters;
305 registerOffset += numParameters;
306 newEnd += numParameters;
307
308 if (!registerFile->grow(newEnd))
309 return 0;
310 r += registerOffset;
311
312 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
313 for (size_t i = 0; i < numParameters; ++i)
314 argv[i + argc] = argv[i];
315 }
316
317 return CallFrame::create(r);
318 }
319
320 #if USE(INTERPRETER)
isInvalidParamForIn(CallFrame * callFrame,CodeBlock * codeBlock,const Instruction * vPC,JSValue value,JSValue & exceptionData)321 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
322 {
323 if (value.isObject())
324 return false;
325 exceptionData = createInvalidParamError(callFrame, "in" , value, vPC - codeBlock->instructions().begin(), codeBlock);
326 return true;
327 }
328
isInvalidParamForInstanceOf(CallFrame * callFrame,CodeBlock * codeBlock,const Instruction * vPC,JSValue value,JSValue & exceptionData)329 static NEVER_INLINE bool isInvalidParamForInstanceOf(CallFrame* callFrame, CodeBlock* codeBlock, const Instruction* vPC, JSValue value, JSValue& exceptionData)
330 {
331 if (value.isObject() && asObject(value)->structure()->typeInfo().implementsHasInstance())
332 return false;
333 exceptionData = createInvalidParamError(callFrame, "instanceof" , value, vPC - codeBlock->instructions().begin(), codeBlock);
334 return true;
335 }
336 #endif
337
callEval(CallFrame * callFrame,RegisterFile * registerFile,Register * argv,int argc,int registerOffset,JSValue & exceptionValue)338 NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue& exceptionValue)
339 {
340 if (argc < 2)
341 return jsUndefined();
342
343 JSValue program = argv[1].jsValue();
344
345 if (!program.isString())
346 return program;
347
348 UString programSource = asString(program)->value();
349
350 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON);
351 if (JSValue parsedObject = preparser.tryLiteralParse())
352 return parsedObject;
353
354
355 ScopeChainNode* scopeChain = callFrame->scopeChain();
356 CodeBlock* codeBlock = callFrame->codeBlock();
357 RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue);
358
359 JSValue result = jsUndefined();
360 if (evalNode)
361 result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue);
362
363 return result;
364 }
365
Interpreter()366 Interpreter::Interpreter()
367 : m_sampler(0)
368 , m_reentryDepth(0)
369 {
370 privateExecute(InitializeAndReturn, 0, 0, 0);
371 }
372
373 #ifndef NDEBUG
374
dumpCallFrame(CallFrame * callFrame)375 void Interpreter::dumpCallFrame(CallFrame* callFrame)
376 {
377 callFrame->codeBlock()->dump(callFrame);
378 dumpRegisters(callFrame);
379 }
380
dumpRegisters(CallFrame * callFrame)381 void Interpreter::dumpRegisters(CallFrame* callFrame)
382 {
383 printf("Register frame: \n\n");
384 printf("-----------------------------------------------------------------------------\n");
385 printf(" use | address | value \n");
386 printf("-----------------------------------------------------------------------------\n");
387
388 CodeBlock* codeBlock = callFrame->codeBlock();
389 RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile();
390 const Register* it;
391 const Register* end;
392 JSValue v;
393
394 if (codeBlock->codeType() == GlobalCode) {
395 it = registerFile->lastGlobal();
396 end = it + registerFile->numGlobals();
397 while (it != end) {
398 v = (*it).jsValue();
399 #if USE(JSVALUE32_64)
400 printf("[global var] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
401 #else
402 printf("[global var] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
403 #endif
404 ++it;
405 }
406 printf("-----------------------------------------------------------------------------\n");
407 }
408
409 it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->m_numParameters;
410 v = (*it).jsValue();
411 #if USE(JSVALUE32_64)
412 printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
413 #else
414 printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
415 #endif
416 end = it + max(codeBlock->m_numParameters - 1, 0); // - 1 to skip "this"
417 if (it != end) {
418 do {
419 v = (*it).jsValue();
420 #if USE(JSVALUE32_64)
421 printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
422 #else
423 printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
424 #endif
425 ++it;
426 } while (it != end);
427 }
428 printf("-----------------------------------------------------------------------------\n");
429 printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it;
430 printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it;
431 printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it;
432 printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it;
433 printf("[ReturnValueRegister] | %10p | %d \n", it, (*it).i()); ++it;
434 printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it;
435 printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it;
436 printf("[OptionalCalleeArguments] | %10p | %p \n", it, (*it).arguments()); ++it;
437 printf("-----------------------------------------------------------------------------\n");
438
439 int registerCount = 0;
440
441 end = it + codeBlock->m_numVars;
442 if (it != end) {
443 do {
444 v = (*it).jsValue();
445 #if USE(JSVALUE32_64)
446 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
447 #else
448 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
449 #endif
450 ++it;
451 ++registerCount;
452 } while (it != end);
453 }
454 printf("-----------------------------------------------------------------------------\n");
455
456 end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
457 if (it != end) {
458 do {
459 v = (*it).jsValue();
460 #if USE(JSVALUE32_64)
461 printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
462 #else
463 printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
464 #endif
465 ++it;
466 ++registerCount;
467 } while (it != end);
468 }
469 printf("-----------------------------------------------------------------------------\n");
470 }
471
472 #endif
473
isOpcode(Opcode opcode)474 bool Interpreter::isOpcode(Opcode opcode)
475 {
476 #if HAVE(COMPUTED_GOTO)
477 return opcode != HashTraits<Opcode>::emptyValue()
478 && !HashTraits<Opcode>::isDeletedValue(opcode)
479 && m_opcodeIDTable.contains(opcode);
480 #else
481 return opcode >= 0 && opcode <= op_end;
482 #endif
483 }
484
unwindCallFrame(CallFrame * & callFrame,JSValue exceptionValue,unsigned & bytecodeOffset,CodeBlock * & codeBlock)485 NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue exceptionValue, unsigned& bytecodeOffset, CodeBlock*& codeBlock)
486 {
487 CodeBlock* oldCodeBlock = codeBlock;
488 ScopeChainNode* scopeChain = callFrame->scopeChain();
489
490 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
491 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
492 if (callFrame->callee())
493 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
494 else
495 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine());
496 }
497
498 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
499 if (callFrame->callee())
500 profiler->didExecute(callFrame, callFrame->callee());
501 else
502 profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo());
503 }
504
505 // If this call frame created an activation or an 'arguments' object, tear it off.
506 if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) {
507 while (!scopeChain->object->isObject(&JSActivation::info))
508 scopeChain = scopeChain->pop();
509 static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments());
510 } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) {
511 if (!arguments->isTornOff())
512 arguments->copyRegisters();
513 }
514
515 if (oldCodeBlock->needsFullScopeChain())
516 scopeChain->deref();
517
518 void* returnPC = callFrame->returnPC();
519 callFrame = callFrame->callerFrame();
520 if (callFrame->hasHostCallFrameFlag())
521 return false;
522
523 codeBlock = callFrame->codeBlock();
524 bytecodeOffset = bytecodeOffsetForPC(callFrame, codeBlock, returnPC);
525 return true;
526 }
527
throwException(CallFrame * & callFrame,JSValue & exceptionValue,unsigned bytecodeOffset,bool explicitThrow)528 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset, bool explicitThrow)
529 {
530 // Set up the exception object
531
532 CodeBlock* codeBlock = callFrame->codeBlock();
533 if (exceptionValue.isObject()) {
534 JSObject* exception = asObject(exceptionValue);
535 if (exception->isNotAnObjectErrorStub()) {
536 exception = createNotAnObjectError(callFrame, static_cast<JSNotAnObjectErrorStub*>(exception), bytecodeOffset, codeBlock);
537 exceptionValue = exception;
538 } else {
539 if (!exception->hasProperty(callFrame, Identifier(callFrame, "line")) &&
540 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceId")) &&
541 !exception->hasProperty(callFrame, Identifier(callFrame, "sourceURL")) &&
542 !exception->hasProperty(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName)) &&
543 !exception->hasProperty(callFrame, Identifier(callFrame, expressionCaretOffsetPropertyName)) &&
544 !exception->hasProperty(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName))) {
545 if (explicitThrow) {
546 int startOffset = 0;
547 int endOffset = 0;
548 int divotPoint = 0;
549 int line = codeBlock->expressionRangeForBytecodeOffset(callFrame, bytecodeOffset, divotPoint, startOffset, endOffset);
550 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, line), ReadOnly | DontDelete);
551
552 // We only hit this path for error messages and throw statements, which don't have a specific failure position
553 // So we just give the full range of the error/throw statement.
554 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionBeginOffsetPropertyName), jsNumber(callFrame, divotPoint - startOffset), ReadOnly | DontDelete);
555 exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete);
556 } else
557 exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete);
558 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete);
559 exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete);
560 }
561
562 if (exception->isWatchdogException()) {
563 while (unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock)) {
564 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
565 }
566 return 0;
567 }
568 }
569 }
570
571 if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) {
572 DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue);
573 debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset));
574 }
575
576 // If we throw in the middle of a call instruction, we need to notify
577 // the profiler manually that the call instruction has returned, since
578 // we'll never reach the relevant op_profile_did_call.
579 if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
580 #if !ENABLE(JIT)
581 if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode))
582 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue());
583 else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct))
584 profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue());
585 #else
586 int functionRegisterIndex;
587 if (codeBlock->functionRegisterForBytecodeOffset(bytecodeOffset, functionRegisterIndex))
588 profiler->didExecute(callFrame, callFrame->r(functionRegisterIndex).jsValue());
589 #endif
590 }
591
592 // Calculate an exception handler vPC, unwinding call frames as necessary.
593
594 HandlerInfo* handler = 0;
595 while (!(handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) {
596 if (!unwindCallFrame(callFrame, exceptionValue, bytecodeOffset, codeBlock))
597 return 0;
598 }
599
600 // Now unwind the scope chain within the exception handler's call frame.
601
602 ScopeChainNode* scopeChain = callFrame->scopeChain();
603 ScopeChain sc(scopeChain);
604 int scopeDelta = depth(codeBlock, sc) - handler->scopeDepth;
605 ASSERT(scopeDelta >= 0);
606 while (scopeDelta--)
607 scopeChain = scopeChain->pop();
608 callFrame->setScopeChain(scopeChain);
609
610 return handler;
611 }
612
execute(ProgramNode * programNode,CallFrame * callFrame,ScopeChainNode * scopeChain,JSObject * thisObj,JSValue * exception)613 JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception)
614 {
615 ASSERT(!scopeChain->globalData->exception);
616
617 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
618 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
619 *exception = createStackOverflowError(callFrame);
620 return jsNull();
621 }
622 }
623
624 CodeBlock* codeBlock = &programNode->bytecode(scopeChain);
625
626 Register* oldEnd = m_registerFile.end();
627 Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters;
628 if (!m_registerFile.grow(newEnd)) {
629 *exception = createStackOverflowError(callFrame);
630 return jsNull();
631 }
632
633 DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject());
634
635 JSGlobalObject* lastGlobalObject = m_registerFile.globalObject();
636 JSGlobalObject* globalObject = callFrame->dynamicGlobalObject();
637 globalObject->copyGlobalsTo(m_registerFile);
638
639 CallFrame* newCallFrame = CallFrame::create(oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize);
640 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
641 newCallFrame->init(codeBlock, 0, scopeChain, CallFrame::noCaller(), 0, 0, 0);
642
643 if (codeBlock->needsFullScopeChain())
644 scopeChain->ref();
645
646 Profiler** profiler = Profiler::enabledProfilerReference();
647 if (*profiler)
648 (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo());
649
650 JSValue result;
651 {
652 SamplingTool::CallRecord callRecord(m_sampler);
653
654 m_reentryDepth++;
655 #if ENABLE(JIT)
656 result = programNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
657 #else
658 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
659 #endif
660 m_reentryDepth--;
661 }
662
663 if (*profiler)
664 (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo());
665
666 if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject)
667 lastGlobalObject->copyGlobalsTo(m_registerFile);
668
669 m_registerFile.shrink(oldEnd);
670
671 return result;
672 }
673
execute(FunctionBodyNode * functionBodyNode,CallFrame * callFrame,JSFunction * function,JSObject * thisObj,const ArgList & args,ScopeChainNode * scopeChain,JSValue * exception)674 JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception)
675 {
676 ASSERT(!scopeChain->globalData->exception);
677
678 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
679 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
680 *exception = createStackOverflowError(callFrame);
681 return jsNull();
682 }
683 }
684
685 Register* oldEnd = m_registerFile.end();
686 int argc = 1 + args.size(); // implicit "this" parameter
687
688 if (!m_registerFile.grow(oldEnd + argc)) {
689 *exception = createStackOverflowError(callFrame);
690 return jsNull();
691 }
692
693 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
694
695 CallFrame* newCallFrame = CallFrame::create(oldEnd);
696 size_t dst = 0;
697 newCallFrame->r(0) = JSValue(thisObj);
698 ArgList::const_iterator end = args.end();
699 for (ArgList::const_iterator it = args.begin(); it != end; ++it)
700 newCallFrame->r(++dst) = *it;
701
702 CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain);
703 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
704 if (UNLIKELY(!newCallFrame)) {
705 *exception = createStackOverflowError(callFrame);
706 m_registerFile.shrink(oldEnd);
707 return jsNull();
708 }
709 // a 0 codeBlock indicates a built-in caller
710 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
711
712 Profiler** profiler = Profiler::enabledProfilerReference();
713 if (*profiler)
714 (*profiler)->willExecute(callFrame, function);
715
716 JSValue result;
717 {
718 SamplingTool::CallRecord callRecord(m_sampler);
719
720 m_reentryDepth++;
721 #if ENABLE(JIT)
722 result = functionBodyNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
723 #else
724 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
725 #endif
726 m_reentryDepth--;
727 }
728
729 if (*profiler)
730 (*profiler)->didExecute(callFrame, function);
731
732 m_registerFile.shrink(oldEnd);
733 return result;
734 }
735
prepareForRepeatCall(FunctionBodyNode * functionBodyNode,CallFrame * callFrame,JSFunction * function,int argCount,ScopeChainNode * scopeChain,JSValue * exception)736 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception)
737 {
738 ASSERT(!scopeChain->globalData->exception);
739
740 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
741 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
742 *exception = createStackOverflowError(callFrame);
743 return CallFrameClosure();
744 }
745 }
746
747 Register* oldEnd = m_registerFile.end();
748 int argc = 1 + argCount; // implicit "this" parameter
749
750 if (!m_registerFile.grow(oldEnd + argc)) {
751 *exception = createStackOverflowError(callFrame);
752 return CallFrameClosure();
753 }
754
755 CallFrame* newCallFrame = CallFrame::create(oldEnd);
756 size_t dst = 0;
757 for (int i = 0; i < argc; ++i)
758 newCallFrame->r(++dst) = jsUndefined();
759
760 CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain);
761 newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc);
762 if (UNLIKELY(!newCallFrame)) {
763 *exception = createStackOverflowError(callFrame);
764 m_registerFile.shrink(oldEnd);
765 return CallFrameClosure();
766 }
767 // a 0 codeBlock indicates a built-in caller
768 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function);
769 #if ENABLE(JIT)
770 functionBodyNode->jitCode(scopeChain);
771 #endif
772
773 CallFrameClosure result = { callFrame, newCallFrame, function, functionBodyNode, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc };
774 return result;
775 }
776
execute(CallFrameClosure & closure,JSValue * exception)777 JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception)
778 {
779 closure.resetCallFrame();
780 Profiler** profiler = Profiler::enabledProfilerReference();
781 if (*profiler)
782 (*profiler)->willExecute(closure.oldCallFrame, closure.function);
783
784 JSValue result;
785 {
786 SamplingTool::CallRecord callRecord(m_sampler);
787
788 m_reentryDepth++;
789 #if ENABLE(JIT)
790 result = closure.functionBody->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception);
791 #else
792 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception);
793 #endif
794 m_reentryDepth--;
795 }
796
797 if (*profiler)
798 (*profiler)->didExecute(closure.oldCallFrame, closure.function);
799 return result;
800 }
801
endRepeatCall(CallFrameClosure & closure)802 void Interpreter::endRepeatCall(CallFrameClosure& closure)
803 {
804 m_registerFile.shrink(closure.oldEnd);
805 }
806
execute(EvalNode * evalNode,CallFrame * callFrame,JSObject * thisObj,ScopeChainNode * scopeChain,JSValue * exception)807 JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception)
808 {
809 return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->bytecode(scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
810 }
811
execute(EvalNode * evalNode,CallFrame * callFrame,JSObject * thisObj,int globalRegisterOffset,ScopeChainNode * scopeChain,JSValue * exception)812 JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception)
813 {
814 ASSERT(!scopeChain->globalData->exception);
815
816 if (m_reentryDepth >= MaxSecondaryThreadReentryDepth) {
817 if (!isMainThread() || m_reentryDepth >= MaxMainThreadReentryDepth) {
818 *exception = createStackOverflowError(callFrame);
819 return jsNull();
820 }
821 }
822
823 DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject());
824
825 EvalCodeBlock* codeBlock = &evalNode->bytecode(scopeChain);
826
827 JSVariableObject* variableObject;
828 for (ScopeChainNode* node = scopeChain; ; node = node->next) {
829 ASSERT(node);
830 if (node->object->isVariableObject()) {
831 variableObject = static_cast<JSVariableObject*>(node->object);
832 break;
833 }
834 }
835
836 { // Scope for BatchedTransitionOptimizer
837
838 BatchedTransitionOptimizer optimizer(variableObject);
839
840 const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack();
841 DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end();
842 for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) {
843 const Identifier& ident = (*it).first;
844 if (!variableObject->hasProperty(callFrame, ident)) {
845 PutPropertySlot slot;
846 variableObject->put(callFrame, ident, jsUndefined(), slot);
847 }
848 }
849
850 const DeclarationStacks::FunctionStack& functionStack = codeBlock->ownerNode()->functionStack();
851 DeclarationStacks::FunctionStack::const_iterator functionStackEnd = functionStack.end();
852 for (DeclarationStacks::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) {
853 PutPropertySlot slot;
854 variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot);
855 }
856
857 }
858
859 Register* oldEnd = m_registerFile.end();
860 Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->m_numCalleeRegisters;
861 if (!m_registerFile.grow(newEnd)) {
862 *exception = createStackOverflowError(callFrame);
863 return jsNull();
864 }
865
866 CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset);
867
868 // a 0 codeBlock indicates a built-in caller
869 newCallFrame->r(codeBlock->thisRegister()) = JSValue(thisObj);
870 newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, 0, 0);
871
872 if (codeBlock->needsFullScopeChain())
873 scopeChain->ref();
874
875 Profiler** profiler = Profiler::enabledProfilerReference();
876 if (*profiler)
877 (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo());
878
879 JSValue result;
880 {
881 SamplingTool::CallRecord callRecord(m_sampler);
882
883 m_reentryDepth++;
884 #if ENABLE(JIT)
885 result = evalNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception);
886 #else
887 result = privateExecute(Normal, &m_registerFile, newCallFrame, exception);
888 #endif
889 m_reentryDepth--;
890 }
891
892 if (*profiler)
893 (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo());
894
895 m_registerFile.shrink(oldEnd);
896 return result;
897 }
898
debug(CallFrame * callFrame,DebugHookID debugHookID,int firstLine,int lastLine)899 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID, int firstLine, int lastLine)
900 {
901 Debugger* debugger = callFrame->dynamicGlobalObject()->debugger();
902 if (!debugger)
903 return;
904
905 switch (debugHookID) {
906 case DidEnterCallFrame:
907 debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
908 return;
909 case WillLeaveCallFrame:
910 debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
911 return;
912 case WillExecuteStatement:
913 debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
914 return;
915 case WillExecuteProgram:
916 debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine);
917 return;
918 case DidExecuteProgram:
919 debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
920 return;
921 case DidReachBreakpoint:
922 debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine);
923 return;
924 }
925 }
926
927 #if USE(INTERPRETER)
createExceptionScope(CallFrame * callFrame,const Instruction * vPC)928 NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC)
929 {
930 int dst = (++vPC)->u.operand;
931 CodeBlock* codeBlock = callFrame->codeBlock();
932 Identifier& property = codeBlock->identifier((++vPC)->u.operand);
933 JSValue value = callFrame->r((++vPC)->u.operand).jsValue();
934 JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete);
935 callFrame->r(dst) = JSValue(scope);
936
937 return callFrame->scopeChain()->push(scope);
938 }
939
tryCachePutByID(CallFrame * callFrame,CodeBlock * codeBlock,Instruction * vPC,JSValue baseValue,const PutPropertySlot & slot)940 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)
941 {
942 // Recursive invocation may already have specialized this instruction.
943 if (vPC[0].u.opcode != getOpcode(op_put_by_id))
944 return;
945
946 if (!baseValue.isCell())
947 return;
948
949 // Uncacheable: give up.
950 if (!slot.isCacheable()) {
951 vPC[0] = getOpcode(op_put_by_id_generic);
952 return;
953 }
954
955 JSCell* baseCell = asCell(baseValue);
956 Structure* structure = baseCell->structure();
957
958 if (structure->isDictionary()) {
959 vPC[0] = getOpcode(op_put_by_id_generic);
960 return;
961 }
962
963 // Cache miss: record Structure to compare against next time.
964 Structure* lastStructure = vPC[4].u.structure;
965 if (structure != lastStructure) {
966 // First miss: record Structure to compare against next time.
967 if (!lastStructure) {
968 vPC[4] = structure;
969 return;
970 }
971
972 // Second miss: give up.
973 vPC[0] = getOpcode(op_put_by_id_generic);
974 return;
975 }
976
977 // Cache hit: Specialize instruction and ref Structures.
978
979 // If baseCell != slot.base(), then baseCell must be a proxy for another object.
980 if (baseCell != slot.base()) {
981 vPC[0] = getOpcode(op_put_by_id_generic);
982 return;
983 }
984
985 StructureChain* protoChain = structure->prototypeChain(callFrame);
986 if (!protoChain->isCacheable()) {
987 vPC[0] = getOpcode(op_put_by_id_generic);
988 return;
989 }
990
991 // Structure transition, cache transition info
992 if (slot.type() == PutPropertySlot::NewProperty) {
993 vPC[0] = getOpcode(op_put_by_id_transition);
994 vPC[4] = structure->previousID();
995 vPC[5] = structure;
996 vPC[6] = protoChain;
997 vPC[7] = slot.cachedOffset();
998 codeBlock->refStructures(vPC);
999 return;
1000 }
1001
1002 vPC[0] = getOpcode(op_put_by_id_replace);
1003 vPC[5] = slot.cachedOffset();
1004 codeBlock->refStructures(vPC);
1005 }
1006
uncachePutByID(CodeBlock * codeBlock,Instruction * vPC)1007 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock* codeBlock, Instruction* vPC)
1008 {
1009 codeBlock->derefStructures(vPC);
1010 vPC[0] = getOpcode(op_put_by_id);
1011 vPC[4] = 0;
1012 }
1013
tryCacheGetByID(CallFrame * callFrame,CodeBlock * codeBlock,Instruction * vPC,JSValue baseValue,const Identifier & propertyName,const PropertySlot & slot)1014 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
1015 {
1016 // Recursive invocation may already have specialized this instruction.
1017 if (vPC[0].u.opcode != getOpcode(op_get_by_id))
1018 return;
1019
1020 // FIXME: Cache property access for immediates.
1021 if (!baseValue.isCell()) {
1022 vPC[0] = getOpcode(op_get_by_id_generic);
1023 return;
1024 }
1025
1026 JSGlobalData* globalData = &callFrame->globalData();
1027 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1028 vPC[0] = getOpcode(op_get_array_length);
1029 return;
1030 }
1031
1032 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
1033 vPC[0] = getOpcode(op_get_string_length);
1034 return;
1035 }
1036
1037 // Uncacheable: give up.
1038 if (!slot.isCacheable()) {
1039 vPC[0] = getOpcode(op_get_by_id_generic);
1040 return;
1041 }
1042
1043 Structure* structure = asCell(baseValue)->structure();
1044
1045 if (structure->isDictionary()) {
1046 vPC[0] = getOpcode(op_get_by_id_generic);
1047 return;
1048 }
1049
1050 // Cache miss
1051 Structure* lastStructure = vPC[4].u.structure;
1052 if (structure != lastStructure) {
1053 // First miss: record Structure to compare against next time.
1054 if (!lastStructure) {
1055 vPC[4] = structure;
1056 return;
1057 }
1058
1059 // Second miss: give up.
1060 vPC[0] = getOpcode(op_get_by_id_generic);
1061 return;
1062 }
1063
1064 // Cache hit: Specialize instruction and ref Structures.
1065
1066 if (slot.slotBase() == baseValue) {
1067 vPC[0] = getOpcode(op_get_by_id_self);
1068 vPC[5] = slot.cachedOffset();
1069
1070 codeBlock->refStructures(vPC);
1071 return;
1072 }
1073
1074 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1075 ASSERT(slot.slotBase().isObject());
1076
1077 JSObject* baseObject = asObject(slot.slotBase());
1078
1079 // Since we're accessing a prototype in a loop, it's a good bet that it
1080 // should not be treated as a dictionary.
1081 if (baseObject->structure()->isDictionary())
1082 baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure()));
1083
1084 vPC[0] = getOpcode(op_get_by_id_proto);
1085 vPC[5] = baseObject->structure();
1086 vPC[6] = slot.cachedOffset();
1087
1088 codeBlock->refStructures(vPC);
1089 return;
1090 }
1091
1092 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
1093 if (!count) {
1094 vPC[0] = getOpcode(op_get_by_id_generic);
1095 return;
1096 }
1097
1098 StructureChain* protoChain = structure->prototypeChain(callFrame);
1099 if (!protoChain->isCacheable()) {
1100 vPC[0] = getOpcode(op_get_by_id_generic);
1101 return;
1102 }
1103
1104 vPC[0] = getOpcode(op_get_by_id_chain);
1105 vPC[4] = structure;
1106 vPC[5] = protoChain;
1107 vPC[6] = count;
1108 vPC[7] = slot.cachedOffset();
1109 codeBlock->refStructures(vPC);
1110 }
1111
uncacheGetByID(CodeBlock * codeBlock,Instruction * vPC)1112 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock* codeBlock, Instruction* vPC)
1113 {
1114 codeBlock->derefStructures(vPC);
1115 vPC[0] = getOpcode(op_get_by_id);
1116 vPC[4] = 0;
1117 }
1118
1119 #endif // USE(INTERPRETER)
1120
privateExecute(ExecutionFlag flag,RegisterFile * registerFile,CallFrame * callFrame,JSValue * exception)1121 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame, JSValue* exception)
1122 {
1123 // One-time initialization of our address tables. We have to put this code
1124 // here because our labels are only in scope inside this function.
1125 if (flag == InitializeAndReturn) {
1126 #if HAVE(COMPUTED_GOTO)
1127 #define ADD_BYTECODE(id, length) m_opcodeTable[id] = &&id;
1128 FOR_EACH_OPCODE_ID(ADD_BYTECODE);
1129 #undef ADD_BYTECODE
1130
1131 #define ADD_OPCODE_ID(id, length) m_opcodeIDTable.add(&&id, id);
1132 FOR_EACH_OPCODE_ID(ADD_OPCODE_ID);
1133 #undef ADD_OPCODE_ID
1134 ASSERT(m_opcodeIDTable.size() == numOpcodeIDs);
1135 #endif // HAVE(COMPUTED_GOTO)
1136 return JSValue();
1137 }
1138
1139 #if ENABLE(JIT)
1140 // Mixing Interpreter + JIT is not supported.
1141 ASSERT_NOT_REACHED();
1142 #endif
1143 #if !USE(INTERPRETER)
1144 UNUSED_PARAM(registerFile);
1145 UNUSED_PARAM(callFrame);
1146 UNUSED_PARAM(exception);
1147 return JSValue();
1148 #else
1149
1150 JSGlobalData* globalData = &callFrame->globalData();
1151 JSValue exceptionValue;
1152 HandlerInfo* handler = 0;
1153
1154 Instruction* vPC = callFrame->codeBlock()->instructions().begin();
1155 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference();
1156 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();
1157
1158 #define CHECK_FOR_EXCEPTION() \
1159 do { \
1160 if (UNLIKELY(globalData->exception != JSValue())) { \
1161 exceptionValue = globalData->exception; \
1162 goto vm_throw; \
1163 } \
1164 } while (0)
1165
1166 #if ENABLE(OPCODE_STATS)
1167 OpcodeStats::resetLastInstruction();
1168 #endif
1169
1170 #define CHECK_FOR_TIMEOUT() \
1171 if (!--tickCount) { \
1172 if (globalData->timeoutChecker.didTimeOut(callFrame)) { \
1173 exceptionValue = jsNull(); \
1174 goto vm_throw; \
1175 } \
1176 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \
1177 }
1178
1179 #if ENABLE(OPCODE_SAMPLING)
1180 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
1181 #else
1182 #define SAMPLE(codeBlock, vPC)
1183 #endif
1184
1185 #if HAVE(COMPUTED_GOTO)
1186 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto *vPC->u.opcode
1187 #if ENABLE(OPCODE_STATS)
1188 #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
1189 #else
1190 #define DEFINE_OPCODE(opcode) opcode:
1191 #endif
1192 NEXT_INSTRUCTION();
1193 #else
1194 #define NEXT_INSTRUCTION() SAMPLE(callFrame->codeBlock(), vPC); goto interpreterLoopStart
1195 #if ENABLE(OPCODE_STATS)
1196 #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
1197 #else
1198 #define DEFINE_OPCODE(opcode) case opcode:
1199 #endif
1200 while (1) { // iterator loop begins
1201 interpreterLoopStart:;
1202 switch (vPC->u.opcode)
1203 #endif
1204 {
1205 DEFINE_OPCODE(op_new_object) {
1206 /* new_object dst(r)
1207
1208 Constructs a new empty Object instance using the original
1209 constructor, and puts the result in register dst.
1210 */
1211 int dst = (++vPC)->u.operand;
1212 callFrame->r(dst) = JSValue(constructEmptyObject(callFrame));
1213
1214 ++vPC;
1215 NEXT_INSTRUCTION();
1216 }
1217 DEFINE_OPCODE(op_new_array) {
1218 /* new_array dst(r) firstArg(r) argCount(n)
1219
1220 Constructs a new Array instance using the original
1221 constructor, and puts the result in register dst.
1222 The array will contain argCount elements with values
1223 taken from registers starting at register firstArg.
1224 */
1225 int dst = (++vPC)->u.operand;
1226 int firstArg = (++vPC)->u.operand;
1227 int argCount = (++vPC)->u.operand;
1228 ArgList args(callFrame->registers() + firstArg, argCount);
1229 callFrame->r(dst) = JSValue(constructArray(callFrame, args));
1230
1231 ++vPC;
1232 NEXT_INSTRUCTION();
1233 }
1234 DEFINE_OPCODE(op_new_regexp) {
1235 /* new_regexp dst(r) regExp(re)
1236
1237 Constructs a new RegExp instance using the original
1238 constructor from regexp regExp, and puts the result in
1239 register dst.
1240 */
1241 int dst = (++vPC)->u.operand;
1242 int regExp = (++vPC)->u.operand;
1243 callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject()->regExpStructure(), callFrame->codeBlock()->regexp(regExp)));
1244
1245 ++vPC;
1246 NEXT_INSTRUCTION();
1247 }
1248 DEFINE_OPCODE(op_mov) {
1249 /* mov dst(r) src(r)
1250
1251 Copies register src to register dst.
1252 */
1253 int dst = (++vPC)->u.operand;
1254 int src = (++vPC)->u.operand;
1255 callFrame->r(dst) = callFrame->r(src);
1256
1257 ++vPC;
1258 NEXT_INSTRUCTION();
1259 }
1260 DEFINE_OPCODE(op_eq) {
1261 /* eq dst(r) src1(r) src2(r)
1262
1263 Checks whether register src1 and register src2 are equal,
1264 as with the ECMAScript '==' operator, and puts the result
1265 as a boolean in register dst.
1266 */
1267 int dst = (++vPC)->u.operand;
1268 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1269 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1270 if (src1.isInt32() && src2.isInt32())
1271 callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32());
1272 else {
1273 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));
1274 CHECK_FOR_EXCEPTION();
1275 callFrame->r(dst) = result;
1276 }
1277
1278 ++vPC;
1279 NEXT_INSTRUCTION();
1280 }
1281 DEFINE_OPCODE(op_eq_null) {
1282 /* eq_null dst(r) src(r)
1283
1284 Checks whether register src is null, as with the ECMAScript '!='
1285 operator, and puts the result as a boolean in register dst.
1286 */
1287 int dst = (++vPC)->u.operand;
1288 JSValue src = callFrame->r((++vPC)->u.operand).jsValue();
1289
1290 if (src.isUndefinedOrNull()) {
1291 callFrame->r(dst) = jsBoolean(true);
1292 ++vPC;
1293 NEXT_INSTRUCTION();
1294 }
1295
1296 callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined());
1297 ++vPC;
1298 NEXT_INSTRUCTION();
1299 }
1300 DEFINE_OPCODE(op_neq) {
1301 /* neq dst(r) src1(r) src2(r)
1302
1303 Checks whether register src1 and register src2 are not
1304 equal, as with the ECMAScript '!=' operator, and puts the
1305 result as a boolean in register dst.
1306 */
1307 int dst = (++vPC)->u.operand;
1308 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1309 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1310 if (src1.isInt32() && src2.isInt32())
1311 callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32());
1312 else {
1313 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));
1314 CHECK_FOR_EXCEPTION();
1315 callFrame->r(dst) = result;
1316 }
1317
1318 ++vPC;
1319 NEXT_INSTRUCTION();
1320 }
1321 DEFINE_OPCODE(op_neq_null) {
1322 /* neq_null dst(r) src(r)
1323
1324 Checks whether register src is not null, as with the ECMAScript '!='
1325 operator, and puts the result as a boolean in register dst.
1326 */
1327 int dst = (++vPC)->u.operand;
1328 JSValue src = callFrame->r((++vPC)->u.operand).jsValue();
1329
1330 if (src.isUndefinedOrNull()) {
1331 callFrame->r(dst) = jsBoolean(false);
1332 ++vPC;
1333 NEXT_INSTRUCTION();
1334 }
1335
1336 callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined());
1337 ++vPC;
1338 NEXT_INSTRUCTION();
1339 }
1340 DEFINE_OPCODE(op_stricteq) {
1341 /* stricteq dst(r) src1(r) src2(r)
1342
1343 Checks whether register src1 and register src2 are strictly
1344 equal, as with the ECMAScript '===' operator, and puts the
1345 result as a boolean in register dst.
1346 */
1347 int dst = (++vPC)->u.operand;
1348 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1349 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1350 callFrame->r(dst) = jsBoolean(JSValue::strictEqual(src1, src2));
1351
1352 ++vPC;
1353 NEXT_INSTRUCTION();
1354 }
1355 DEFINE_OPCODE(op_nstricteq) {
1356 /* nstricteq dst(r) src1(r) src2(r)
1357
1358 Checks whether register src1 and register src2 are not
1359 strictly equal, as with the ECMAScript '!==' operator, and
1360 puts the result as a boolean in register dst.
1361 */
1362 int dst = (++vPC)->u.operand;
1363 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1364 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1365 callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(src1, src2));
1366
1367 ++vPC;
1368 NEXT_INSTRUCTION();
1369 }
1370 DEFINE_OPCODE(op_less) {
1371 /* less dst(r) src1(r) src2(r)
1372
1373 Checks whether register src1 is less than register src2, as
1374 with the ECMAScript '<' operator, and puts the result as
1375 a boolean in register dst.
1376 */
1377 int dst = (++vPC)->u.operand;
1378 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1379 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1380 JSValue result = jsBoolean(jsLess(callFrame, src1, src2));
1381 CHECK_FOR_EXCEPTION();
1382 callFrame->r(dst) = result;
1383
1384 ++vPC;
1385 NEXT_INSTRUCTION();
1386 }
1387 DEFINE_OPCODE(op_lesseq) {
1388 /* lesseq dst(r) src1(r) src2(r)
1389
1390 Checks whether register src1 is less than or equal to
1391 register src2, as with the ECMAScript '<=' operator, and
1392 puts the result as a boolean in register dst.
1393 */
1394 int dst = (++vPC)->u.operand;
1395 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1396 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1397 JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2));
1398 CHECK_FOR_EXCEPTION();
1399 callFrame->r(dst) = result;
1400
1401 ++vPC;
1402 NEXT_INSTRUCTION();
1403 }
1404 DEFINE_OPCODE(op_pre_inc) {
1405 /* pre_inc srcDst(r)
1406
1407 Converts register srcDst to number, adds one, and puts the result
1408 back in register srcDst.
1409 */
1410 int srcDst = (++vPC)->u.operand;
1411 JSValue v = callFrame->r(srcDst).jsValue();
1412 if (v.isInt32() && v.asInt32() < INT_MAX)
1413 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1414 else {
1415 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) + 1);
1416 CHECK_FOR_EXCEPTION();
1417 callFrame->r(srcDst) = result;
1418 }
1419
1420 ++vPC;
1421 NEXT_INSTRUCTION();
1422 }
1423 DEFINE_OPCODE(op_pre_dec) {
1424 /* pre_dec srcDst(r)
1425
1426 Converts register srcDst to number, subtracts one, and puts the result
1427 back in register srcDst.
1428 */
1429 int srcDst = (++vPC)->u.operand;
1430 JSValue v = callFrame->r(srcDst).jsValue();
1431 if (v.isInt32() && v.asInt32() > INT_MIN)
1432 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1433 else {
1434 JSValue result = jsNumber(callFrame, v.toNumber(callFrame) - 1);
1435 CHECK_FOR_EXCEPTION();
1436 callFrame->r(srcDst) = result;
1437 }
1438
1439 ++vPC;
1440 NEXT_INSTRUCTION();
1441 }
1442 DEFINE_OPCODE(op_post_inc) {
1443 /* post_inc dst(r) srcDst(r)
1444
1445 Converts register srcDst to number. The number itself is
1446 written to register dst, and the number plus one is written
1447 back to register srcDst.
1448 */
1449 int dst = (++vPC)->u.operand;
1450 int srcDst = (++vPC)->u.operand;
1451 JSValue v = callFrame->r(srcDst).jsValue();
1452 if (v.isInt32() && v.asInt32() < INT_MAX) {
1453 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1);
1454 callFrame->r(dst) = v;
1455 } else {
1456 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1457 CHECK_FOR_EXCEPTION();
1458 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() + 1);
1459 callFrame->r(dst) = number;
1460 }
1461
1462 ++vPC;
1463 NEXT_INSTRUCTION();
1464 }
1465 DEFINE_OPCODE(op_post_dec) {
1466 /* post_dec dst(r) srcDst(r)
1467
1468 Converts register srcDst to number. The number itself is
1469 written to register dst, and the number minus one is written
1470 back to register srcDst.
1471 */
1472 int dst = (++vPC)->u.operand;
1473 int srcDst = (++vPC)->u.operand;
1474 JSValue v = callFrame->r(srcDst).jsValue();
1475 if (v.isInt32() && v.asInt32() > INT_MIN) {
1476 callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1);
1477 callFrame->r(dst) = v;
1478 } else {
1479 JSValue number = callFrame->r(srcDst).jsValue().toJSNumber(callFrame);
1480 CHECK_FOR_EXCEPTION();
1481 callFrame->r(srcDst) = jsNumber(callFrame, number.uncheckedGetNumber() - 1);
1482 callFrame->r(dst) = number;
1483 }
1484
1485 ++vPC;
1486 NEXT_INSTRUCTION();
1487 }
1488 DEFINE_OPCODE(op_to_jsnumber) {
1489 /* to_jsnumber dst(r) src(r)
1490
1491 Converts register src to number, and puts the result
1492 in register dst.
1493 */
1494 int dst = (++vPC)->u.operand;
1495 int src = (++vPC)->u.operand;
1496
1497 JSValue srcVal = callFrame->r(src).jsValue();
1498
1499 if (LIKELY(srcVal.isNumber()))
1500 callFrame->r(dst) = callFrame->r(src);
1501 else {
1502 JSValue result = srcVal.toJSNumber(callFrame);
1503 CHECK_FOR_EXCEPTION();
1504 callFrame->r(dst) = result;
1505 }
1506
1507 ++vPC;
1508 NEXT_INSTRUCTION();
1509 }
1510 DEFINE_OPCODE(op_negate) {
1511 /* negate dst(r) src(r)
1512
1513 Converts register src to number, negates it, and puts the
1514 result in register dst.
1515 */
1516 int dst = (++vPC)->u.operand;
1517 JSValue src = callFrame->r((++vPC)->u.operand).jsValue();
1518 if (src.isInt32() && src.asInt32())
1519 callFrame->r(dst) = jsNumber(callFrame, -src.asInt32());
1520 else {
1521 JSValue result = jsNumber(callFrame, -src.toNumber(callFrame));
1522 CHECK_FOR_EXCEPTION();
1523 callFrame->r(dst) = result;
1524 }
1525
1526 ++vPC;
1527 NEXT_INSTRUCTION();
1528 }
1529 DEFINE_OPCODE(op_add) {
1530 /* add dst(r) src1(r) src2(r)
1531
1532 Adds register src1 and register src2, and puts the result
1533 in register dst. (JS add may be string concatenation or
1534 numeric add, depending on the types of the operands.)
1535 */
1536 int dst = (++vPC)->u.operand;
1537 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1538 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1539 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow
1540 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32());
1541 else {
1542 JSValue result = jsAdd(callFrame, src1, src2);
1543 CHECK_FOR_EXCEPTION();
1544 callFrame->r(dst) = result;
1545 }
1546 vPC += 2;
1547 NEXT_INSTRUCTION();
1548 }
1549 DEFINE_OPCODE(op_mul) {
1550 /* mul dst(r) src1(r) src2(r)
1551
1552 Multiplies register src1 and register src2 (converted to
1553 numbers), and puts the product in register dst.
1554 */
1555 int dst = (++vPC)->u.operand;
1556 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1557 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1558 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow
1559 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32());
1560 else {
1561 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) * src2.toNumber(callFrame));
1562 CHECK_FOR_EXCEPTION();
1563 callFrame->r(dst) = result;
1564 }
1565
1566 vPC += 2;
1567 NEXT_INSTRUCTION();
1568 }
1569 DEFINE_OPCODE(op_div) {
1570 /* div dst(r) dividend(r) divisor(r)
1571
1572 Divides register dividend (converted to number) by the
1573 register divisor (converted to number), and puts the
1574 quotient in register dst.
1575 */
1576 int dst = (++vPC)->u.operand;
1577 JSValue dividend = callFrame->r((++vPC)->u.operand).jsValue();
1578 JSValue divisor = callFrame->r((++vPC)->u.operand).jsValue();
1579
1580 JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame));
1581 CHECK_FOR_EXCEPTION();
1582 callFrame->r(dst) = result;
1583
1584 vPC += 2;
1585 NEXT_INSTRUCTION();
1586 }
1587 DEFINE_OPCODE(op_mod) {
1588 /* mod dst(r) dividend(r) divisor(r)
1589
1590 Divides register dividend (converted to number) by
1591 register divisor (converted to number), and puts the
1592 remainder in register dst.
1593 */
1594 int dst = (++vPC)->u.operand;
1595 JSValue dividend = callFrame->r((++vPC)->u.operand).jsValue();
1596 JSValue divisor = callFrame->r((++vPC)->u.operand).jsValue();
1597
1598 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) {
1599 JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32());
1600 ASSERT(result);
1601 callFrame->r(dst) = result;
1602 ++vPC;
1603 NEXT_INSTRUCTION();
1604 }
1605
1606 // Conversion to double must happen outside the call to fmod since the
1607 // order of argument evaluation is not guaranteed.
1608 double d1 = dividend.toNumber(callFrame);
1609 double d2 = divisor.toNumber(callFrame);
1610 JSValue result = jsNumber(callFrame, fmod(d1, d2));
1611 CHECK_FOR_EXCEPTION();
1612 callFrame->r(dst) = result;
1613 ++vPC;
1614 NEXT_INSTRUCTION();
1615 }
1616 DEFINE_OPCODE(op_sub) {
1617 /* sub dst(r) src1(r) src2(r)
1618
1619 Subtracts register src2 (converted to number) from register
1620 src1 (converted to number), and puts the difference in
1621 register dst.
1622 */
1623 int dst = (++vPC)->u.operand;
1624 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1625 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1626 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow
1627 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32());
1628 else {
1629 JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame));
1630 CHECK_FOR_EXCEPTION();
1631 callFrame->r(dst) = result;
1632 }
1633 vPC += 2;
1634 NEXT_INSTRUCTION();
1635 }
1636 DEFINE_OPCODE(op_lshift) {
1637 /* lshift dst(r) val(r) shift(r)
1638
1639 Performs left shift of register val (converted to int32) by
1640 register shift (converted to uint32), and puts the result
1641 in register dst.
1642 */
1643 int dst = (++vPC)->u.operand;
1644 JSValue val = callFrame->r((++vPC)->u.operand).jsValue();
1645 JSValue shift = callFrame->r((++vPC)->u.operand).jsValue();
1646
1647 if (val.isInt32() && shift.isInt32())
1648 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f));
1649 else {
1650 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
1651 CHECK_FOR_EXCEPTION();
1652 callFrame->r(dst) = result;
1653 }
1654
1655 ++vPC;
1656 NEXT_INSTRUCTION();
1657 }
1658 DEFINE_OPCODE(op_rshift) {
1659 /* rshift dst(r) val(r) shift(r)
1660
1661 Performs arithmetic right shift of register val (converted
1662 to int32) by register shift (converted to
1663 uint32), and puts the result in register dst.
1664 */
1665 int dst = (++vPC)->u.operand;
1666 JSValue val = callFrame->r((++vPC)->u.operand).jsValue();
1667 JSValue shift = callFrame->r((++vPC)->u.operand).jsValue();
1668
1669 if (val.isInt32() && shift.isInt32())
1670 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1671 else {
1672 JSValue result = jsNumber(callFrame, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1673 CHECK_FOR_EXCEPTION();
1674 callFrame->r(dst) = result;
1675 }
1676
1677 ++vPC;
1678 NEXT_INSTRUCTION();
1679 }
1680 DEFINE_OPCODE(op_urshift) {
1681 /* rshift dst(r) val(r) shift(r)
1682
1683 Performs logical right shift of register val (converted
1684 to uint32) by register shift (converted to
1685 uint32), and puts the result in register dst.
1686 */
1687 int dst = (++vPC)->u.operand;
1688 JSValue val = callFrame->r((++vPC)->u.operand).jsValue();
1689 JSValue shift = callFrame->r((++vPC)->u.operand).jsValue();
1690 if (val.isUInt32() && shift.isInt32())
1691 callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f));
1692 else {
1693 JSValue result = jsNumber(callFrame, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
1694 CHECK_FOR_EXCEPTION();
1695 callFrame->r(dst) = result;
1696 }
1697
1698 ++vPC;
1699 NEXT_INSTRUCTION();
1700 }
1701 DEFINE_OPCODE(op_bitand) {
1702 /* bitand dst(r) src1(r) src2(r)
1703
1704 Computes bitwise AND of register src1 (converted to int32)
1705 and register src2 (converted to int32), and puts the result
1706 in register dst.
1707 */
1708 int dst = (++vPC)->u.operand;
1709 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1710 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1711 if (src1.isInt32() && src2.isInt32())
1712 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32());
1713 else {
1714 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) & src2.toInt32(callFrame));
1715 CHECK_FOR_EXCEPTION();
1716 callFrame->r(dst) = result;
1717 }
1718
1719 vPC += 2;
1720 NEXT_INSTRUCTION();
1721 }
1722 DEFINE_OPCODE(op_bitxor) {
1723 /* bitxor dst(r) src1(r) src2(r)
1724
1725 Computes bitwise XOR of register src1 (converted to int32)
1726 and register src2 (converted to int32), and puts the result
1727 in register dst.
1728 */
1729 int dst = (++vPC)->u.operand;
1730 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1731 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1732 if (src1.isInt32() && src2.isInt32())
1733 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32());
1734 else {
1735 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
1736 CHECK_FOR_EXCEPTION();
1737 callFrame->r(dst) = result;
1738 }
1739
1740 vPC += 2;
1741 NEXT_INSTRUCTION();
1742 }
1743 DEFINE_OPCODE(op_bitor) {
1744 /* bitor dst(r) src1(r) src2(r)
1745
1746 Computes bitwise OR of register src1 (converted to int32)
1747 and register src2 (converted to int32), and puts the
1748 result in register dst.
1749 */
1750 int dst = (++vPC)->u.operand;
1751 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
1752 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
1753 if (src1.isInt32() && src2.isInt32())
1754 callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32());
1755 else {
1756 JSValue result = jsNumber(callFrame, src1.toInt32(callFrame) | src2.toInt32(callFrame));
1757 CHECK_FOR_EXCEPTION();
1758 callFrame->r(dst) = result;
1759 }
1760
1761 vPC += 2;
1762 NEXT_INSTRUCTION();
1763 }
1764 DEFINE_OPCODE(op_bitnot) {
1765 /* bitnot dst(r) src(r)
1766
1767 Computes bitwise NOT of register src1 (converted to int32),
1768 and puts the result in register dst.
1769 */
1770 int dst = (++vPC)->u.operand;
1771 JSValue src = callFrame->r((++vPC)->u.operand).jsValue();
1772 if (src.isInt32())
1773 callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32());
1774 else {
1775 JSValue result = jsNumber(callFrame, ~src.toInt32(callFrame));
1776 CHECK_FOR_EXCEPTION();
1777 callFrame->r(dst) = result;
1778 }
1779 ++vPC;
1780 NEXT_INSTRUCTION();
1781 }
1782 DEFINE_OPCODE(op_not) {
1783 /* not dst(r) src(r)
1784
1785 Computes logical NOT of register src (converted to
1786 boolean), and puts the result in register dst.
1787 */
1788 int dst = (++vPC)->u.operand;
1789 int src = (++vPC)->u.operand;
1790 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));
1791 CHECK_FOR_EXCEPTION();
1792 callFrame->r(dst) = result;
1793
1794 ++vPC;
1795 NEXT_INSTRUCTION();
1796 }
1797 DEFINE_OPCODE(op_instanceof) {
1798 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)
1799
1800 Tests whether register value is an instance of register
1801 constructor, and puts the boolean result in register
1802 dst. Register constructorProto must contain the "prototype"
1803 property (not the actual prototype) of the object in
1804 register constructor. This lookup is separated so that
1805 polymorphic inline caching can apply.
1806
1807 Raises an exception if register constructor is not an
1808 object.
1809 */
1810 int dst = vPC[1].u.operand;
1811 int value = vPC[2].u.operand;
1812 int base = vPC[3].u.operand;
1813 int baseProto = vPC[4].u.operand;
1814
1815 JSValue baseVal = callFrame->r(base).jsValue();
1816
1817 if (isInvalidParamForInstanceOf(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1818 goto vm_throw;
1819
1820 bool result = asObject(baseVal)->hasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());
1821 CHECK_FOR_EXCEPTION();
1822 callFrame->r(dst) = jsBoolean(result);
1823
1824 vPC += 5;
1825 NEXT_INSTRUCTION();
1826 }
1827 DEFINE_OPCODE(op_typeof) {
1828 /* typeof dst(r) src(r)
1829
1830 Determines the type string for src according to ECMAScript
1831 rules, and puts the result in register dst.
1832 */
1833 int dst = (++vPC)->u.operand;
1834 int src = (++vPC)->u.operand;
1835 callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));
1836
1837 ++vPC;
1838 NEXT_INSTRUCTION();
1839 }
1840 DEFINE_OPCODE(op_is_undefined) {
1841 /* is_undefined dst(r) src(r)
1842
1843 Determines whether the type string for src according to
1844 the ECMAScript rules is "undefined", and puts the result
1845 in register dst.
1846 */
1847 int dst = (++vPC)->u.operand;
1848 int src = (++vPC)->u.operand;
1849 JSValue v = callFrame->r(src).jsValue();
1850 callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined());
1851
1852 ++vPC;
1853 NEXT_INSTRUCTION();
1854 }
1855 DEFINE_OPCODE(op_is_boolean) {
1856 /* is_boolean dst(r) src(r)
1857
1858 Determines whether the type string for src according to
1859 the ECMAScript rules is "boolean", and puts the result
1860 in register dst.
1861 */
1862 int dst = (++vPC)->u.operand;
1863 int src = (++vPC)->u.operand;
1864 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());
1865
1866 ++vPC;
1867 NEXT_INSTRUCTION();
1868 }
1869 DEFINE_OPCODE(op_is_number) {
1870 /* is_number dst(r) src(r)
1871
1872 Determines whether the type string for src according to
1873 the ECMAScript rules is "number", and puts the result
1874 in register dst.
1875 */
1876 int dst = (++vPC)->u.operand;
1877 int src = (++vPC)->u.operand;
1878 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());
1879
1880 ++vPC;
1881 NEXT_INSTRUCTION();
1882 }
1883 DEFINE_OPCODE(op_is_string) {
1884 /* is_string dst(r) src(r)
1885
1886 Determines whether the type string for src according to
1887 the ECMAScript rules is "string", and puts the result
1888 in register dst.
1889 */
1890 int dst = (++vPC)->u.operand;
1891 int src = (++vPC)->u.operand;
1892 callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString());
1893
1894 ++vPC;
1895 NEXT_INSTRUCTION();
1896 }
1897 DEFINE_OPCODE(op_is_object) {
1898 /* is_object dst(r) src(r)
1899
1900 Determines whether the type string for src according to
1901 the ECMAScript rules is "object", and puts the result
1902 in register dst.
1903 */
1904 int dst = (++vPC)->u.operand;
1905 int src = (++vPC)->u.operand;
1906 callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue()));
1907
1908 ++vPC;
1909 NEXT_INSTRUCTION();
1910 }
1911 DEFINE_OPCODE(op_is_function) {
1912 /* is_function dst(r) src(r)
1913
1914 Determines whether the type string for src according to
1915 the ECMAScript rules is "function", and puts the result
1916 in register dst.
1917 */
1918 int dst = (++vPC)->u.operand;
1919 int src = (++vPC)->u.operand;
1920 callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));
1921
1922 ++vPC;
1923 NEXT_INSTRUCTION();
1924 }
1925 DEFINE_OPCODE(op_in) {
1926 /* in dst(r) property(r) base(r)
1927
1928 Tests whether register base has a property named register
1929 property, and puts the boolean result in register dst.
1930
1931 Raises an exception if register constructor is not an
1932 object.
1933 */
1934 int dst = (++vPC)->u.operand;
1935 int property = (++vPC)->u.operand;
1936 int base = (++vPC)->u.operand;
1937
1938 JSValue baseVal = callFrame->r(base).jsValue();
1939 if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue))
1940 goto vm_throw;
1941
1942 JSObject* baseObj = asObject(baseVal);
1943
1944 JSValue propName = callFrame->r(property).jsValue();
1945
1946 uint32_t i;
1947 if (propName.getUInt32(i))
1948 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));
1949 else {
1950 Identifier property(callFrame, propName.toString(callFrame));
1951 CHECK_FOR_EXCEPTION();
1952 callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));
1953 }
1954
1955 ++vPC;
1956 NEXT_INSTRUCTION();
1957 }
1958 DEFINE_OPCODE(op_resolve) {
1959 /* resolve dst(r) property(id)
1960
1961 Looks up the property named by identifier property in the
1962 scope chain, and writes the resulting value to register
1963 dst. If the property is not found, raises an exception.
1964 */
1965 if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue)))
1966 goto vm_throw;
1967
1968 vPC += 3;
1969 NEXT_INSTRUCTION();
1970 }
1971 DEFINE_OPCODE(op_resolve_skip) {
1972 /* resolve_skip dst(r) property(id) skip(n)
1973
1974 Looks up the property named by identifier property in the
1975 scope chain skipping the top 'skip' levels, and writes the resulting
1976 value to register dst. If the property is not found, raises an exception.
1977 */
1978 if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue)))
1979 goto vm_throw;
1980
1981 vPC += 4;
1982
1983 NEXT_INSTRUCTION();
1984 }
1985 DEFINE_OPCODE(op_resolve_global) {
1986 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)
1987
1988 Performs a dynamic property lookup for the given property, on the provided
1989 global object. If structure matches the Structure of the global then perform
1990 a fast lookup using the case offset, otherwise fall back to a full resolve and
1991 cache the new structure and offset
1992 */
1993 if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue)))
1994 goto vm_throw;
1995
1996 vPC += 6;
1997
1998 NEXT_INSTRUCTION();
1999 }
2000 DEFINE_OPCODE(op_get_global_var) {
2001 /* get_global_var dst(r) globalObject(c) index(n)
2002
2003 Gets the global var at global slot index and places it in register dst.
2004 */
2005 int dst = (++vPC)->u.operand;
2006 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2007 ASSERT(scope->isGlobalObject());
2008 int index = (++vPC)->u.operand;
2009
2010 callFrame->r(dst) = scope->registerAt(index);
2011 ++vPC;
2012 NEXT_INSTRUCTION();
2013 }
2014 DEFINE_OPCODE(op_put_global_var) {
2015 /* put_global_var globalObject(c) index(n) value(r)
2016
2017 Puts value into global slot index.
2018 */
2019 JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell);
2020 ASSERT(scope->isGlobalObject());
2021 int index = (++vPC)->u.operand;
2022 int value = (++vPC)->u.operand;
2023
2024 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
2025 ++vPC;
2026 NEXT_INSTRUCTION();
2027 }
2028 DEFINE_OPCODE(op_get_scoped_var) {
2029 /* get_scoped_var dst(r) index(n) skip(n)
2030
2031 Loads the contents of the index-th local from the scope skip nodes from
2032 the top of the scope chain, and places it in register dst
2033 */
2034 int dst = (++vPC)->u.operand;
2035 int index = (++vPC)->u.operand;
2036 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();
2037
2038 ScopeChainNode* scopeChain = callFrame->scopeChain();
2039 ScopeChainIterator iter = scopeChain->begin();
2040 ScopeChainIterator end = scopeChain->end();
2041 ASSERT(iter != end);
2042 while (skip--) {
2043 ++iter;
2044 ASSERT(iter != end);
2045 }
2046
2047 ASSERT((*iter)->isVariableObject());
2048 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2049 callFrame->r(dst) = scope->registerAt(index);
2050 ++vPC;
2051 NEXT_INSTRUCTION();
2052 }
2053 DEFINE_OPCODE(op_put_scoped_var) {
2054 /* put_scoped_var index(n) skip(n) value(r)
2055
2056 */
2057 int index = (++vPC)->u.operand;
2058 int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain();
2059 int value = (++vPC)->u.operand;
2060
2061 ScopeChainNode* scopeChain = callFrame->scopeChain();
2062 ScopeChainIterator iter = scopeChain->begin();
2063 ScopeChainIterator end = scopeChain->end();
2064 ASSERT(iter != end);
2065 while (skip--) {
2066 ++iter;
2067 ASSERT(iter != end);
2068 }
2069
2070 ASSERT((*iter)->isVariableObject());
2071 JSVariableObject* scope = static_cast<JSVariableObject*>(*iter);
2072 scope->registerAt(index) = JSValue(callFrame->r(value).jsValue());
2073 ++vPC;
2074 NEXT_INSTRUCTION();
2075 }
2076 DEFINE_OPCODE(op_resolve_base) {
2077 /* resolve_base dst(r) property(id)
2078
2079 Searches the scope chain for an object containing
2080 identifier property, and if one is found, writes it to
2081 register dst. If none is found, the outermost scope (which
2082 will be the global object) is stored in register dst.
2083 */
2084 resolveBase(callFrame, vPC);
2085
2086 vPC += 3;
2087 NEXT_INSTRUCTION();
2088 }
2089 DEFINE_OPCODE(op_resolve_with_base) {
2090 /* resolve_with_base baseDst(r) propDst(r) property(id)
2091
2092 Searches the scope chain for an object containing
2093 identifier property, and if one is found, writes it to
2094 register srcDst, and the retrieved property value to register
2095 propDst. If the property is not found, raises an exception.
2096
2097 This is more efficient than doing resolve_base followed by
2098 resolve, or resolve_base followed by get_by_id, as it
2099 avoids duplicate hash lookups.
2100 */
2101 if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue)))
2102 goto vm_throw;
2103
2104 vPC += 4;
2105 NEXT_INSTRUCTION();
2106 }
2107 DEFINE_OPCODE(op_get_by_id) {
2108 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)
2109
2110 Generic property access: Gets the property named by identifier
2111 property from the value base, and puts the result in register dst.
2112 */
2113 int dst = vPC[1].u.operand;
2114 int base = vPC[2].u.operand;
2115 int property = vPC[3].u.operand;
2116
2117 CodeBlock* codeBlock = callFrame->codeBlock();
2118 Identifier& ident = codeBlock->identifier(property);
2119 JSValue baseValue = callFrame->r(base).jsValue();
2120 PropertySlot slot(baseValue);
2121 JSValue result = baseValue.get(callFrame, ident, slot);
2122 CHECK_FOR_EXCEPTION();
2123
2124 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);
2125
2126 callFrame->r(dst) = result;
2127 vPC += 8;
2128 NEXT_INSTRUCTION();
2129 }
2130 DEFINE_OPCODE(op_get_by_id_self) {
2131 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)
2132
2133 Cached property access: Attempts to get a cached property from the
2134 value base. If the cache misses, op_get_by_id_self reverts to
2135 op_get_by_id.
2136 */
2137 int base = vPC[2].u.operand;
2138 JSValue baseValue = callFrame->r(base).jsValue();
2139
2140 if (LIKELY(baseValue.isCell())) {
2141 JSCell* baseCell = asCell(baseValue);
2142 Structure* structure = vPC[4].u.structure;
2143
2144 if (LIKELY(baseCell->structure() == structure)) {
2145 ASSERT(baseCell->isObject());
2146 JSObject* baseObject = asObject(baseCell);
2147 int dst = vPC[1].u.operand;
2148 int offset = vPC[5].u.operand;
2149
2150 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2151 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2152
2153 vPC += 8;
2154 NEXT_INSTRUCTION();
2155 }
2156 }
2157
2158 uncacheGetByID(callFrame->codeBlock(), vPC);
2159 NEXT_INSTRUCTION();
2160 }
2161 DEFINE_OPCODE(op_get_by_id_proto) {
2162 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)
2163
2164 Cached property access: Attempts to get a cached property from the
2165 value base's prototype. If the cache misses, op_get_by_id_proto
2166 reverts to op_get_by_id.
2167 */
2168 int base = vPC[2].u.operand;
2169 JSValue baseValue = callFrame->r(base).jsValue();
2170
2171 if (LIKELY(baseValue.isCell())) {
2172 JSCell* baseCell = asCell(baseValue);
2173 Structure* structure = vPC[4].u.structure;
2174
2175 if (LIKELY(baseCell->structure() == structure)) {
2176 ASSERT(structure->prototypeForLookup(callFrame).isObject());
2177 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
2178 Structure* prototypeStructure = vPC[5].u.structure;
2179
2180 if (LIKELY(protoObject->structure() == prototypeStructure)) {
2181 int dst = vPC[1].u.operand;
2182 int offset = vPC[6].u.operand;
2183
2184 ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));
2185 callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset));
2186
2187 vPC += 8;
2188 NEXT_INSTRUCTION();
2189 }
2190 }
2191 }
2192
2193 uncacheGetByID(callFrame->codeBlock(), vPC);
2194 NEXT_INSTRUCTION();
2195 }
2196 DEFINE_OPCODE(op_get_by_id_self_list) {
2197 // Polymorphic self access caching currently only supported when JITting.
2198 ASSERT_NOT_REACHED();
2199 // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)!
2200 vPC += 8;
2201 NEXT_INSTRUCTION();
2202 }
2203 DEFINE_OPCODE(op_get_by_id_proto_list) {
2204 // Polymorphic prototype access caching currently only supported when JITting.
2205 ASSERT_NOT_REACHED();
2206 // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)!
2207 vPC += 8;
2208 NEXT_INSTRUCTION();
2209 }
2210 DEFINE_OPCODE(op_get_by_id_chain) {
2211 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)
2212
2213 Cached property access: Attempts to get a cached property from the
2214 value base's prototype chain. If the cache misses, op_get_by_id_chain
2215 reverts to op_get_by_id.
2216 */
2217 int base = vPC[2].u.operand;
2218 JSValue baseValue = callFrame->r(base).jsValue();
2219
2220 if (LIKELY(baseValue.isCell())) {
2221 JSCell* baseCell = asCell(baseValue);
2222 Structure* structure = vPC[4].u.structure;
2223
2224 if (LIKELY(baseCell->structure() == structure)) {
2225 RefPtr<Structure>* it = vPC[5].u.structureChain->head();
2226 size_t count = vPC[6].u.operand;
2227 RefPtr<Structure>* end = it + count;
2228
2229 while (true) {
2230 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));
2231
2232 if (UNLIKELY(baseObject->structure() != (*it).get()))
2233 break;
2234
2235 if (++it == end) {
2236 int dst = vPC[1].u.operand;
2237 int offset = vPC[7].u.operand;
2238
2239 ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));
2240 callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset));
2241
2242 vPC += 8;
2243 NEXT_INSTRUCTION();
2244 }
2245
2246 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.
2247 baseCell = baseObject;
2248 }
2249 }
2250 }
2251
2252 uncacheGetByID(callFrame->codeBlock(), vPC);
2253 NEXT_INSTRUCTION();
2254 }
2255 DEFINE_OPCODE(op_get_by_id_generic) {
2256 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2257
2258 Generic property access: Gets the property named by identifier
2259 property from the value base, and puts the result in register dst.
2260 */
2261 int dst = vPC[1].u.operand;
2262 int base = vPC[2].u.operand;
2263 int property = vPC[3].u.operand;
2264
2265 Identifier& ident = callFrame->codeBlock()->identifier(property);
2266 JSValue baseValue = callFrame->r(base).jsValue();
2267 PropertySlot slot(baseValue);
2268 JSValue result = baseValue.get(callFrame, ident, slot);
2269 CHECK_FOR_EXCEPTION();
2270
2271 callFrame->r(dst) = result;
2272 vPC += 8;
2273 NEXT_INSTRUCTION();
2274 }
2275 DEFINE_OPCODE(op_get_array_length) {
2276 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2277
2278 Cached property access: Gets the length of the array in register base,
2279 and puts the result in register dst. If register base does not hold
2280 an array, op_get_array_length reverts to op_get_by_id.
2281 */
2282
2283 int base = vPC[2].u.operand;
2284 JSValue baseValue = callFrame->r(base).jsValue();
2285 if (LIKELY(isJSArray(globalData, baseValue))) {
2286 int dst = vPC[1].u.operand;
2287 callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length());
2288 vPC += 8;
2289 NEXT_INSTRUCTION();
2290 }
2291
2292 uncacheGetByID(callFrame->codeBlock(), vPC);
2293 NEXT_INSTRUCTION();
2294 }
2295 DEFINE_OPCODE(op_get_string_length) {
2296 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)
2297
2298 Cached property access: Gets the length of the string in register base,
2299 and puts the result in register dst. If register base does not hold
2300 a string, op_get_string_length reverts to op_get_by_id.
2301 */
2302
2303 int base = vPC[2].u.operand;
2304 JSValue baseValue = callFrame->r(base).jsValue();
2305 if (LIKELY(isJSString(globalData, baseValue))) {
2306 int dst = vPC[1].u.operand;
2307 callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->value().size());
2308 vPC += 8;
2309 NEXT_INSTRUCTION();
2310 }
2311
2312 uncacheGetByID(callFrame->codeBlock(), vPC);
2313 NEXT_INSTRUCTION();
2314 }
2315 DEFINE_OPCODE(op_put_by_id) {
2316 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2317
2318 Generic property access: Sets the property named by identifier
2319 property, belonging to register base, to register value.
2320
2321 Unlike many opcodes, this one does not write any output to
2322 the register file.
2323 */
2324
2325 int base = vPC[1].u.operand;
2326 int property = vPC[2].u.operand;
2327 int value = vPC[3].u.operand;
2328
2329 CodeBlock* codeBlock = callFrame->codeBlock();
2330 JSValue baseValue = callFrame->r(base).jsValue();
2331 Identifier& ident = codeBlock->identifier(property);
2332 PutPropertySlot slot;
2333 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2334 CHECK_FOR_EXCEPTION();
2335
2336 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);
2337
2338 vPC += 8;
2339 NEXT_INSTRUCTION();
2340 }
2341 DEFINE_OPCODE(op_put_by_id_transition) {
2342 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n)
2343
2344 Cached property access: Attempts to set a new property with a cached transition
2345 property named by identifier property, belonging to register base,
2346 to register value. If the cache misses, op_put_by_id_transition
2347 reverts to op_put_by_id_generic.
2348
2349 Unlike many opcodes, this one does not write any output to
2350 the register file.
2351 */
2352 int base = vPC[1].u.operand;
2353 JSValue baseValue = callFrame->r(base).jsValue();
2354
2355 if (LIKELY(baseValue.isCell())) {
2356 JSCell* baseCell = asCell(baseValue);
2357 Structure* oldStructure = vPC[4].u.structure;
2358 Structure* newStructure = vPC[5].u.structure;
2359
2360 if (LIKELY(baseCell->structure() == oldStructure)) {
2361 ASSERT(baseCell->isObject());
2362 JSObject* baseObject = asObject(baseCell);
2363
2364 RefPtr<Structure>* it = vPC[6].u.structureChain->head();
2365
2366 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);
2367 while (!proto.isNull()) {
2368 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {
2369 uncachePutByID(callFrame->codeBlock(), vPC);
2370 NEXT_INSTRUCTION();
2371 }
2372 ++it;
2373 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);
2374 }
2375
2376 baseObject->transitionTo(newStructure);
2377
2378 int value = vPC[3].u.operand;
2379 unsigned offset = vPC[7].u.operand;
2380 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2381 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2382
2383 vPC += 8;
2384 NEXT_INSTRUCTION();
2385 }
2386 }
2387
2388 uncachePutByID(callFrame->codeBlock(), vPC);
2389 NEXT_INSTRUCTION();
2390 }
2391 DEFINE_OPCODE(op_put_by_id_replace) {
2392 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n)
2393
2394 Cached property access: Attempts to set a pre-existing, cached
2395 property named by identifier property, belonging to register base,
2396 to register value. If the cache misses, op_put_by_id_replace
2397 reverts to op_put_by_id.
2398
2399 Unlike many opcodes, this one does not write any output to
2400 the register file.
2401 */
2402 int base = vPC[1].u.operand;
2403 JSValue baseValue = callFrame->r(base).jsValue();
2404
2405 if (LIKELY(baseValue.isCell())) {
2406 JSCell* baseCell = asCell(baseValue);
2407 Structure* structure = vPC[4].u.structure;
2408
2409 if (LIKELY(baseCell->structure() == structure)) {
2410 ASSERT(baseCell->isObject());
2411 JSObject* baseObject = asObject(baseCell);
2412 int value = vPC[3].u.operand;
2413 unsigned offset = vPC[5].u.operand;
2414
2415 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset);
2416 baseObject->putDirectOffset(offset, callFrame->r(value).jsValue());
2417
2418 vPC += 8;
2419 NEXT_INSTRUCTION();
2420 }
2421 }
2422
2423 uncachePutByID(callFrame->codeBlock(), vPC);
2424 NEXT_INSTRUCTION();
2425 }
2426 DEFINE_OPCODE(op_put_by_id_generic) {
2427 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n)
2428
2429 Generic property access: Sets the property named by identifier
2430 property, belonging to register base, to register value.
2431
2432 Unlike many opcodes, this one does not write any output to
2433 the register file.
2434 */
2435 int base = vPC[1].u.operand;
2436 int property = vPC[2].u.operand;
2437 int value = vPC[3].u.operand;
2438
2439 JSValue baseValue = callFrame->r(base).jsValue();
2440 Identifier& ident = callFrame->codeBlock()->identifier(property);
2441 PutPropertySlot slot;
2442 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);
2443 CHECK_FOR_EXCEPTION();
2444
2445 vPC += 8;
2446 NEXT_INSTRUCTION();
2447 }
2448 DEFINE_OPCODE(op_del_by_id) {
2449 /* del_by_id dst(r) base(r) property(id)
2450
2451 Converts register base to Object, deletes the property
2452 named by identifier property from the object, and writes a
2453 boolean indicating success (if true) or failure (if false)
2454 to register dst.
2455 */
2456 int dst = (++vPC)->u.operand;
2457 int base = (++vPC)->u.operand;
2458 int property = (++vPC)->u.operand;
2459
2460 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);
2461 Identifier& ident = callFrame->codeBlock()->identifier(property);
2462 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident));
2463 CHECK_FOR_EXCEPTION();
2464 callFrame->r(dst) = result;
2465 ++vPC;
2466 NEXT_INSTRUCTION();
2467 }
2468 DEFINE_OPCODE(op_get_by_val) {
2469 /* get_by_val dst(r) base(r) property(r)
2470
2471 Converts register base to Object, gets the property named
2472 by register property from the object, and puts the result
2473 in register dst. property is nominally converted to string
2474 but numbers are treated more efficiently.
2475 */
2476 int dst = (++vPC)->u.operand;
2477 int base = (++vPC)->u.operand;
2478 int property = (++vPC)->u.operand;
2479
2480 JSValue baseValue = callFrame->r(base).jsValue();
2481 JSValue subscript = callFrame->r(property).jsValue();
2482
2483 JSValue result;
2484
2485 if (LIKELY(subscript.isUInt32())) {
2486 uint32_t i = subscript.asUInt32();
2487 if (isJSArray(globalData, baseValue)) {
2488 JSArray* jsArray = asArray(baseValue);
2489 if (jsArray->canGetIndex(i))
2490 result = jsArray->getIndex(i);
2491 else
2492 result = jsArray->JSArray::get(callFrame, i);
2493 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
2494 result = asString(baseValue)->getIndex(&callFrame->globalData(), i);
2495 else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i))
2496 result = asByteArray(baseValue)->getIndex(callFrame, i);
2497 else
2498 result = baseValue.get(callFrame, i);
2499 } else {
2500 Identifier property(callFrame, subscript.toString(callFrame));
2501 result = baseValue.get(callFrame, property);
2502 }
2503
2504 CHECK_FOR_EXCEPTION();
2505 callFrame->r(dst) = result;
2506 ++vPC;
2507 NEXT_INSTRUCTION();
2508 }
2509 DEFINE_OPCODE(op_put_by_val) {
2510 /* put_by_val base(r) property(r) value(r)
2511
2512 Sets register value on register base as the property named
2513 by register property. Base is converted to object
2514 first. register property is nominally converted to string
2515 but numbers are treated more efficiently.
2516
2517 Unlike many opcodes, this one does not write any output to
2518 the register file.
2519 */
2520 int base = (++vPC)->u.operand;
2521 int property = (++vPC)->u.operand;
2522 int value = (++vPC)->u.operand;
2523
2524 JSValue baseValue = callFrame->r(base).jsValue();
2525 JSValue subscript = callFrame->r(property).jsValue();
2526
2527 if (LIKELY(subscript.isUInt32())) {
2528 uint32_t i = subscript.asUInt32();
2529 if (isJSArray(globalData, baseValue)) {
2530 JSArray* jsArray = asArray(baseValue);
2531 if (jsArray->canSetIndex(i))
2532 jsArray->setIndex(i, callFrame->r(value).jsValue());
2533 else
2534 jsArray->JSArray::put(callFrame, i, callFrame->r(value).jsValue());
2535 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2536 JSByteArray* jsByteArray = asByteArray(baseValue);
2537 double dValue = 0;
2538 JSValue jsValue = callFrame->r(value).jsValue();
2539 if (jsValue.isInt32())
2540 jsByteArray->setIndex(i, jsValue.asInt32());
2541 else if (jsValue.getNumber(dValue))
2542 jsByteArray->setIndex(i, dValue);
2543 else
2544 baseValue.put(callFrame, i, jsValue);
2545 } else
2546 baseValue.put(callFrame, i, callFrame->r(value).jsValue());
2547 } else {
2548 Identifier property(callFrame, subscript.toString(callFrame));
2549 if (!globalData->exception) { // Don't put to an object if toString threw an exception.
2550 PutPropertySlot slot;
2551 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);
2552 }
2553 }
2554
2555 CHECK_FOR_EXCEPTION();
2556 ++vPC;
2557 NEXT_INSTRUCTION();
2558 }
2559 DEFINE_OPCODE(op_del_by_val) {
2560 /* del_by_val dst(r) base(r) property(r)
2561
2562 Converts register base to Object, deletes the property
2563 named by register property from the object, and writes a
2564 boolean indicating success (if true) or failure (if false)
2565 to register dst.
2566 */
2567 int dst = (++vPC)->u.operand;
2568 int base = (++vPC)->u.operand;
2569 int property = (++vPC)->u.operand;
2570
2571 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw
2572
2573 JSValue subscript = callFrame->r(property).jsValue();
2574 JSValue result;
2575 uint32_t i;
2576 if (subscript.getUInt32(i))
2577 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2578 else {
2579 CHECK_FOR_EXCEPTION();
2580 Identifier property(callFrame, subscript.toString(callFrame));
2581 CHECK_FOR_EXCEPTION();
2582 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2583 }
2584
2585 CHECK_FOR_EXCEPTION();
2586 callFrame->r(dst) = result;
2587 ++vPC;
2588 NEXT_INSTRUCTION();
2589 }
2590 DEFINE_OPCODE(op_put_by_index) {
2591 /* put_by_index base(r) property(n) value(r)
2592
2593 Sets register value on register base as the property named
2594 by the immediate number property. Base is converted to
2595 object first.
2596
2597 Unlike many opcodes, this one does not write any output to
2598 the register file.
2599
2600 This opcode is mainly used to initialize array literals.
2601 */
2602 int base = (++vPC)->u.operand;
2603 unsigned property = (++vPC)->u.operand;
2604 int value = (++vPC)->u.operand;
2605
2606 callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue());
2607
2608 ++vPC;
2609 NEXT_INSTRUCTION();
2610 }
2611 DEFINE_OPCODE(op_loop) {
2612 /* loop target(offset)
2613
2614 Jumps unconditionally to offset target from the current
2615 instruction.
2616
2617 Additionally this loop instruction may terminate JS execution is
2618 the JS timeout is reached.
2619 */
2620 #if ENABLE(OPCODE_STATS)
2621 OpcodeStats::resetLastInstruction();
2622 #endif
2623 int target = (++vPC)->u.operand;
2624 CHECK_FOR_TIMEOUT();
2625 vPC += target;
2626 NEXT_INSTRUCTION();
2627 }
2628 DEFINE_OPCODE(op_jmp) {
2629 /* jmp target(offset)
2630
2631 Jumps unconditionally to offset target from the current
2632 instruction.
2633 */
2634 #if ENABLE(OPCODE_STATS)
2635 OpcodeStats::resetLastInstruction();
2636 #endif
2637 int target = (++vPC)->u.operand;
2638
2639 vPC += target;
2640 NEXT_INSTRUCTION();
2641 }
2642 DEFINE_OPCODE(op_loop_if_true) {
2643 /* loop_if_true cond(r) target(offset)
2644
2645 Jumps to offset target from the current instruction, if and
2646 only if register cond converts to boolean as true.
2647
2648 Additionally this loop instruction may terminate JS execution is
2649 the JS timeout is reached.
2650 */
2651 int cond = (++vPC)->u.operand;
2652 int target = (++vPC)->u.operand;
2653 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2654 vPC += target;
2655 CHECK_FOR_TIMEOUT();
2656 NEXT_INSTRUCTION();
2657 }
2658
2659 ++vPC;
2660 NEXT_INSTRUCTION();
2661 }
2662 DEFINE_OPCODE(op_jtrue) {
2663 /* jtrue cond(r) target(offset)
2664
2665 Jumps to offset target from the current instruction, if and
2666 only if register cond converts to boolean as true.
2667 */
2668 int cond = (++vPC)->u.operand;
2669 int target = (++vPC)->u.operand;
2670 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2671 vPC += target;
2672 NEXT_INSTRUCTION();
2673 }
2674
2675 ++vPC;
2676 NEXT_INSTRUCTION();
2677 }
2678 DEFINE_OPCODE(op_jfalse) {
2679 /* jfalse cond(r) target(offset)
2680
2681 Jumps to offset target from the current instruction, if and
2682 only if register cond converts to boolean as false.
2683 */
2684 int cond = (++vPC)->u.operand;
2685 int target = (++vPC)->u.operand;
2686 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {
2687 vPC += target;
2688 NEXT_INSTRUCTION();
2689 }
2690
2691 ++vPC;
2692 NEXT_INSTRUCTION();
2693 }
2694 DEFINE_OPCODE(op_jeq_null) {
2695 /* jeq_null src(r) target(offset)
2696
2697 Jumps to offset target from the current instruction, if and
2698 only if register src is null.
2699 */
2700 int src = (++vPC)->u.operand;
2701 int target = (++vPC)->u.operand;
2702 JSValue srcValue = callFrame->r(src).jsValue();
2703
2704 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2705 vPC += target;
2706 NEXT_INSTRUCTION();
2707 }
2708
2709 ++vPC;
2710 NEXT_INSTRUCTION();
2711 }
2712 DEFINE_OPCODE(op_jneq_null) {
2713 /* jneq_null src(r) target(offset)
2714
2715 Jumps to offset target from the current instruction, if and
2716 only if register src is not null.
2717 */
2718 int src = (++vPC)->u.operand;
2719 int target = (++vPC)->u.operand;
2720 JSValue srcValue = callFrame->r(src).jsValue();
2721
2722 if (!srcValue.isUndefinedOrNull() || (srcValue.isCell() && !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) {
2723 vPC += target;
2724 NEXT_INSTRUCTION();
2725 }
2726
2727 ++vPC;
2728 NEXT_INSTRUCTION();
2729 }
2730 DEFINE_OPCODE(op_jneq_ptr) {
2731 /* jneq_ptr src(r) ptr(jsCell) target(offset)
2732
2733 Jumps to offset target from the current instruction, if the value r is equal
2734 to ptr, using pointer equality.
2735 */
2736 int src = (++vPC)->u.operand;
2737 JSValue ptr = JSValue((++vPC)->u.jsCell);
2738 int target = (++vPC)->u.operand;
2739 JSValue srcValue = callFrame->r(src).jsValue();
2740 if (srcValue != ptr) {
2741 vPC += target;
2742 NEXT_INSTRUCTION();
2743 }
2744
2745 ++vPC;
2746 NEXT_INSTRUCTION();
2747 }
2748 DEFINE_OPCODE(op_loop_if_less) {
2749 /* loop_if_less src1(r) src2(r) target(offset)
2750
2751 Checks whether register src1 is less than register src2, as
2752 with the ECMAScript '<' operator, and then jumps to offset
2753 target from the current instruction, if and only if the
2754 result of the comparison is true.
2755
2756 Additionally this loop instruction may terminate JS execution is
2757 the JS timeout is reached.
2758 */
2759 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
2760 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
2761 int target = (++vPC)->u.operand;
2762
2763 bool result = jsLess(callFrame, src1, src2);
2764 CHECK_FOR_EXCEPTION();
2765
2766 if (result) {
2767 vPC += target;
2768 CHECK_FOR_TIMEOUT();
2769 NEXT_INSTRUCTION();
2770 }
2771
2772 ++vPC;
2773 NEXT_INSTRUCTION();
2774 }
2775 DEFINE_OPCODE(op_loop_if_lesseq) {
2776 /* loop_if_lesseq src1(r) src2(r) target(offset)
2777
2778 Checks whether register src1 is less than or equal to register
2779 src2, as with the ECMAScript '<=' operator, and then jumps to
2780 offset target from the current instruction, if and only if the
2781 result of the comparison is true.
2782
2783 Additionally this loop instruction may terminate JS execution is
2784 the JS timeout is reached.
2785 */
2786 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
2787 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
2788 int target = (++vPC)->u.operand;
2789
2790 bool result = jsLessEq(callFrame, src1, src2);
2791 CHECK_FOR_EXCEPTION();
2792
2793 if (result) {
2794 vPC += target;
2795 CHECK_FOR_TIMEOUT();
2796 NEXT_INSTRUCTION();
2797 }
2798
2799 ++vPC;
2800 NEXT_INSTRUCTION();
2801 }
2802 DEFINE_OPCODE(op_jnless) {
2803 /* jnless src1(r) src2(r) target(offset)
2804
2805 Checks whether register src1 is less than register src2, as
2806 with the ECMAScript '<' operator, and then jumps to offset
2807 target from the current instruction, if and only if the
2808 result of the comparison is false.
2809 */
2810 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
2811 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
2812 int target = (++vPC)->u.operand;
2813
2814 bool result = jsLess(callFrame, src1, src2);
2815 CHECK_FOR_EXCEPTION();
2816
2817 if (!result) {
2818 vPC += target;
2819 NEXT_INSTRUCTION();
2820 }
2821
2822 ++vPC;
2823 NEXT_INSTRUCTION();
2824 }
2825 DEFINE_OPCODE(op_jnlesseq) {
2826 /* jnlesseq src1(r) src2(r) target(offset)
2827
2828 Checks whether register src1 is less than or equal to
2829 register src2, as with the ECMAScript '<=' operator,
2830 and then jumps to offset target from the current instruction,
2831 if and only if theresult of the comparison is false.
2832 */
2833 JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue();
2834 JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue();
2835 int target = (++vPC)->u.operand;
2836
2837 bool result = jsLessEq(callFrame, src1, src2);
2838 CHECK_FOR_EXCEPTION();
2839
2840 if (!result) {
2841 vPC += target;
2842 NEXT_INSTRUCTION();
2843 }
2844
2845 ++vPC;
2846 NEXT_INSTRUCTION();
2847 }
2848 DEFINE_OPCODE(op_switch_imm) {
2849 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)
2850
2851 Performs a range checked switch on the scrutinee value, using
2852 the tableIndex-th immediate switch jump table. If the scrutinee value
2853 is an immediate number in the range covered by the referenced jump
2854 table, and the value at jumpTable[scrutinee value] is non-zero, then
2855 that value is used as the jump offset, otherwise defaultOffset is used.
2856 */
2857 int tableIndex = (++vPC)->u.operand;
2858 int defaultOffset = (++vPC)->u.operand;
2859 JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue();
2860 if (scrutinee.isInt32())
2861 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);
2862 else {
2863 double value;
2864 int32_t intValue;
2865 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
2866 vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(intValue, defaultOffset);
2867 else
2868 vPC += defaultOffset;
2869 }
2870 NEXT_INSTRUCTION();
2871 }
2872 DEFINE_OPCODE(op_switch_char) {
2873 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)
2874
2875 Performs a range checked switch on the scrutinee value, using
2876 the tableIndex-th character switch jump table. If the scrutinee value
2877 is a single character string in the range covered by the referenced jump
2878 table, and the value at jumpTable[scrutinee value] is non-zero, then
2879 that value is used as the jump offset, otherwise defaultOffset is used.
2880 */
2881 int tableIndex = (++vPC)->u.operand;
2882 int defaultOffset = (++vPC)->u.operand;
2883 JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue();
2884 if (!scrutinee.isString())
2885 vPC += defaultOffset;
2886 else {
2887 UString::Rep* value = asString(scrutinee)->value().rep();
2888 if (value->size() != 1)
2889 vPC += defaultOffset;
2890 else
2891 vPC += callFrame->codeBlock()->characterSwitchJumpTable(tableIndex).offsetForValue(value->data()[0], defaultOffset);
2892 }
2893 NEXT_INSTRUCTION();
2894 }
2895 DEFINE_OPCODE(op_switch_string) {
2896 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)
2897
2898 Performs a sparse hashmap based switch on the value in the scrutinee
2899 register, using the tableIndex-th string switch jump table. If the
2900 scrutinee value is a string that exists as a key in the referenced
2901 jump table, then the value associated with the string is used as the
2902 jump offset, otherwise defaultOffset is used.
2903 */
2904 int tableIndex = (++vPC)->u.operand;
2905 int defaultOffset = (++vPC)->u.operand;
2906 JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue();
2907 if (!scrutinee.isString())
2908 vPC += defaultOffset;
2909 else
2910 vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset);
2911 NEXT_INSTRUCTION();
2912 }
2913 DEFINE_OPCODE(op_new_func) {
2914 /* new_func dst(r) func(f)
2915
2916 Constructs a new Function instance from function func and
2917 the current scope chain using the original Function
2918 constructor, using the rules for function declarations, and
2919 puts the result in register dst.
2920 */
2921 int dst = (++vPC)->u.operand;
2922 int func = (++vPC)->u.operand;
2923
2924 callFrame->r(dst) = JSValue(callFrame->codeBlock()->function(func)->makeFunction(callFrame, callFrame->scopeChain()));
2925
2926 ++vPC;
2927 NEXT_INSTRUCTION();
2928 }
2929 DEFINE_OPCODE(op_new_func_exp) {
2930 /* new_func_exp dst(r) func(f)
2931
2932 Constructs a new Function instance from function func and
2933 the current scope chain using the original Function
2934 constructor, using the rules for function expressions, and
2935 puts the result in register dst.
2936 */
2937 int dst = (++vPC)->u.operand;
2938 int func = (++vPC)->u.operand;
2939
2940 callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionExpression(func)->makeFunction(callFrame, callFrame->scopeChain()));
2941
2942 ++vPC;
2943 NEXT_INSTRUCTION();
2944 }
2945 DEFINE_OPCODE(op_call_eval) {
2946 /* call_eval dst(r) func(r) argCount(n) registerOffset(n)
2947
2948 Call a function named "eval" with no explicit "this" value
2949 (which may therefore be the eval operator). If register
2950 thisVal is the global object, and register func contains
2951 that global object's original global eval function, then
2952 perform the eval operator in local scope (interpreting
2953 the argument registers as for the "call"
2954 opcode). Otherwise, act exactly as the "call" opcode would.
2955 */
2956
2957 int dst = vPC[1].u.operand;
2958 int func = vPC[2].u.operand;
2959 int argCount = vPC[3].u.operand;
2960 int registerOffset = vPC[4].u.operand;
2961
2962 JSValue funcVal = callFrame->r(func).jsValue();
2963
2964 Register* newCallFrame = callFrame->registers() + registerOffset;
2965 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
2966 JSValue thisValue = argv[0].jsValue();
2967 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
2968
2969 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
2970 JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
2971 if (exceptionValue)
2972 goto vm_throw;
2973 callFrame->r(dst) = result;
2974
2975 vPC += 5;
2976 NEXT_INSTRUCTION();
2977 }
2978
2979 // We didn't find the blessed version of eval, so process this
2980 // instruction as a normal function call.
2981 // fall through to op_call
2982 }
2983 DEFINE_OPCODE(op_call) {
2984 /* call dst(r) func(r) argCount(n) registerOffset(n)
2985
2986 Perform a function call.
2987
2988 registerOffset is the distance the callFrame pointer should move
2989 before the VM initializes the new call frame's header.
2990
2991 dst is where op_ret should store its result.
2992 */
2993
2994 int dst = vPC[1].u.operand;
2995 int func = vPC[2].u.operand;
2996 int argCount = vPC[3].u.operand;
2997 int registerOffset = vPC[4].u.operand;
2998
2999 JSValue v = callFrame->r(func).jsValue();
3000
3001 CallData callData;
3002 CallType callType = v.getCallData(callData);
3003
3004 if (callType == CallTypeJS) {
3005 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3006 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3007 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);
3008
3009 CallFrame* previousCallFrame = callFrame;
3010
3011 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3012 if (UNLIKELY(!callFrame)) {
3013 callFrame = previousCallFrame;
3014 exceptionValue = createStackOverflowError(callFrame);
3015 goto vm_throw;
3016 }
3017
3018 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3019 vPC = newCodeBlock->instructions().begin();
3020
3021 #if ENABLE(OPCODE_STATS)
3022 OpcodeStats::resetLastInstruction();
3023 #endif
3024
3025 NEXT_INSTRUCTION();
3026 }
3027
3028 if (callType == CallTypeHost) {
3029 ScopeChainNode* scopeChain = callFrame->scopeChain();
3030 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3031 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
3032
3033 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3034 ArgList args(thisRegister + 1, argCount - 1);
3035
3036 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3037 JSValue thisValue = thisRegister->jsValue();
3038 if (thisValue == jsNull())
3039 thisValue = callFrame->globalThisValue();
3040
3041 JSValue returnValue;
3042 {
3043 SamplingTool::HostCallRecord callRecord(m_sampler);
3044 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3045 }
3046 CHECK_FOR_EXCEPTION();
3047
3048 callFrame->r(dst) = returnValue;
3049
3050 vPC += 5;
3051 NEXT_INSTRUCTION();
3052 }
3053
3054 ASSERT(callType == CallTypeNone);
3055
3056 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3057 goto vm_throw;
3058 }
3059 DEFINE_OPCODE(op_load_varargs) {
3060 int argCountDst = (++vPC)->u.operand;
3061 int argsOffset = (++vPC)->u.operand;
3062
3063 JSValue arguments = callFrame->r(argsOffset).jsValue();
3064 int32_t argCount = 0;
3065 if (!arguments) {
3066 argCount = (uint32_t)(callFrame->argumentCount()) - 1;
3067 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3068 Register* newEnd = callFrame->registers() + sizeDelta;
3069 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3070 exceptionValue = createStackOverflowError(callFrame);
3071 goto vm_throw;
3072 }
3073 int32_t expectedParams = callFrame->callee()->body()->parameterCount();
3074 int32_t inplaceArgs = min(argCount, expectedParams);
3075 int32_t i = 0;
3076 Register* argStore = callFrame->registers() + argsOffset;
3077
3078 // First step is to copy the "expected" parameters from their normal location relative to the callframe
3079 for (; i < inplaceArgs; i++)
3080 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams];
3081 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
3082 for (; i < argCount; i++)
3083 argStore[i] = callFrame->registers()[i - RegisterFile::CallFrameHeaderSize - expectedParams - argCount - 1];
3084 } else if (!arguments.isUndefinedOrNull()) {
3085 if (!arguments.isObject()) {
3086 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3087 goto vm_throw;
3088 }
3089 if (asObject(arguments)->classInfo() == &Arguments::info) {
3090 Arguments* args = asArguments(arguments);
3091 argCount = args->numProvidedArguments(callFrame);
3092 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3093 Register* newEnd = callFrame->registers() + sizeDelta;
3094 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3095 exceptionValue = createStackOverflowError(callFrame);
3096 goto vm_throw;
3097 }
3098 args->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3099 } else if (isJSArray(&callFrame->globalData(), arguments)) {
3100 JSArray* array = asArray(arguments);
3101 argCount = array->length();
3102 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3103 Register* newEnd = callFrame->registers() + sizeDelta;
3104 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3105 exceptionValue = createStackOverflowError(callFrame);
3106 goto vm_throw;
3107 }
3108 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
3109 } else if (asObject(arguments)->inherits(&JSArray::info)) {
3110 JSObject* argObject = asObject(arguments);
3111 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
3112 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
3113 Register* newEnd = callFrame->registers() + sizeDelta;
3114 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
3115 exceptionValue = createStackOverflowError(callFrame);
3116 goto vm_throw;
3117 }
3118 Register* argsBuffer = callFrame->registers() + argsOffset;
3119 for (int32_t i = 0; i < argCount; ++i) {
3120 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
3121 CHECK_FOR_EXCEPTION();
3122 }
3123 } else {
3124 if (!arguments.isObject()) {
3125 exceptionValue = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3126 goto vm_throw;
3127 }
3128 }
3129 }
3130 CHECK_FOR_EXCEPTION();
3131 callFrame->r(argCountDst) = Register::withInt(argCount + 1);
3132 ++vPC;
3133 NEXT_INSTRUCTION();
3134 }
3135 DEFINE_OPCODE(op_call_varargs) {
3136 /* call_varargs dst(r) func(r) argCountReg(r) baseRegisterOffset(n)
3137
3138 Perform a function call with a dynamic set of arguments.
3139
3140 registerOffset is the distance the callFrame pointer should move
3141 before the VM initializes the new call frame's header, excluding
3142 space for arguments.
3143
3144 dst is where op_ret should store its result.
3145 */
3146
3147 int dst = vPC[1].u.operand;
3148 int func = vPC[2].u.operand;
3149 int argCountReg = vPC[3].u.operand;
3150 int registerOffset = vPC[4].u.operand;
3151
3152 JSValue v = callFrame->r(func).jsValue();
3153 int argCount = callFrame->r(argCountReg).i();
3154 registerOffset += argCount;
3155 CallData callData;
3156 CallType callType = v.getCallData(callData);
3157
3158 if (callType == CallTypeJS) {
3159 ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
3160 FunctionBodyNode* functionBodyNode = callData.js.functionBody;
3161 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);
3162
3163 CallFrame* previousCallFrame = callFrame;
3164
3165 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3166 if (UNLIKELY(!callFrame)) {
3167 callFrame = previousCallFrame;
3168 exceptionValue = createStackOverflowError(callFrame);
3169 goto vm_throw;
3170 }
3171
3172 callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3173 vPC = newCodeBlock->instructions().begin();
3174
3175 #if ENABLE(OPCODE_STATS)
3176 OpcodeStats::resetLastInstruction();
3177 #endif
3178
3179 NEXT_INSTRUCTION();
3180 }
3181
3182 if (callType == CallTypeHost) {
3183 ScopeChainNode* scopeChain = callFrame->scopeChain();
3184 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3185 newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0);
3186
3187 Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
3188 ArgList args(thisRegister + 1, argCount - 1);
3189
3190 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
3191 JSValue thisValue = thisRegister->jsValue();
3192 if (thisValue == jsNull())
3193 thisValue = callFrame->globalThisValue();
3194
3195 JSValue returnValue;
3196 {
3197 SamplingTool::HostCallRecord callRecord(m_sampler);
3198 returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args);
3199 }
3200 CHECK_FOR_EXCEPTION();
3201
3202 callFrame->r(dst) = returnValue;
3203
3204 vPC += 5;
3205 NEXT_INSTRUCTION();
3206 }
3207
3208 ASSERT(callType == CallTypeNone);
3209
3210 exceptionValue = createNotAFunctionError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3211 goto vm_throw;
3212 }
3213 DEFINE_OPCODE(op_tear_off_activation) {
3214 /* tear_off_activation activation(r)
3215
3216 Copy all locals and parameters to new memory allocated on
3217 the heap, and make the passed activation use this memory
3218 in the future when looking up entries in the symbol table.
3219 If there is an 'arguments' object, then it will also use
3220 this memory for storing the named parameters, but not any
3221 extra arguments.
3222
3223 This opcode should only be used immediately before op_ret.
3224 */
3225
3226 int src = (++vPC)->u.operand;
3227 ASSERT(callFrame->codeBlock()->needsFullScopeChain());
3228
3229 asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments());
3230
3231 ++vPC;
3232 NEXT_INSTRUCTION();
3233 }
3234 DEFINE_OPCODE(op_tear_off_arguments) {
3235 /* tear_off_arguments
3236
3237 Copy all arguments to new memory allocated on the heap,
3238 and make the 'arguments' object use this memory in the
3239 future when looking up named parameters, but not any
3240 extra arguments. If an activation object exists for the
3241 current function context, then the tear_off_activation
3242 opcode should be used instead.
3243
3244 This opcode should only be used immediately before op_ret.
3245 */
3246
3247 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
3248
3249 if (callFrame->optionalCalleeArguments())
3250 callFrame->optionalCalleeArguments()->copyRegisters();
3251
3252 ++vPC;
3253 NEXT_INSTRUCTION();
3254 }
3255 DEFINE_OPCODE(op_ret) {
3256 /* ret result(r)
3257
3258 Return register result as the return value of the current
3259 function call, writing it into the caller's expected return
3260 value register. In addition, unwind one call frame and
3261 restore the scope chain, code block instruction pointer and
3262 register base to those of the calling function.
3263 */
3264
3265 int result = (++vPC)->u.operand;
3266
3267 if (callFrame->codeBlock()->needsFullScopeChain())
3268 callFrame->scopeChain()->deref();
3269
3270 JSValue returnValue = callFrame->r(result).jsValue();
3271
3272 vPC = callFrame->returnPC();
3273 int dst = callFrame->returnValueRegister();
3274 callFrame = callFrame->callerFrame();
3275
3276 if (callFrame->hasHostCallFrameFlag())
3277 return returnValue;
3278
3279 callFrame->r(dst) = returnValue;
3280
3281 NEXT_INSTRUCTION();
3282 }
3283 DEFINE_OPCODE(op_enter) {
3284 /* enter
3285
3286 Initializes local variables to undefined and fills constant
3287 registers with their values. If the code block requires an
3288 activation, enter_with_activation should be used instead.
3289
3290 This opcode should only be used at the beginning of a code
3291 block.
3292 */
3293
3294 size_t i = 0;
3295 CodeBlock* codeBlock = callFrame->codeBlock();
3296
3297 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3298 callFrame->r(i) = jsUndefined();
3299
3300 ++vPC;
3301 NEXT_INSTRUCTION();
3302 }
3303 DEFINE_OPCODE(op_enter_with_activation) {
3304 /* enter_with_activation dst(r)
3305
3306 Initializes local variables to undefined, fills constant
3307 registers with their values, creates an activation object,
3308 and places the new activation both in dst and at the top
3309 of the scope chain. If the code block does not require an
3310 activation, enter should be used instead.
3311
3312 This opcode should only be used at the beginning of a code
3313 block.
3314 */
3315
3316 size_t i = 0;
3317 CodeBlock* codeBlock = callFrame->codeBlock();
3318
3319 for (size_t count = codeBlock->m_numVars; i < count; ++i)
3320 callFrame->r(i) = jsUndefined();
3321
3322 int dst = (++vPC)->u.operand;
3323 JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionBodyNode*>(codeBlock->ownerNode()));
3324 callFrame->r(dst) = JSValue(activation);
3325 callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation));
3326
3327 ++vPC;
3328 NEXT_INSTRUCTION();
3329 }
3330 DEFINE_OPCODE(op_convert_this) {
3331 /* convert_this this(r)
3332
3333 Takes the value in the 'this' register, converts it to a
3334 value that is suitable for use as the 'this' value, and
3335 stores it in the 'this' register. This opcode is emitted
3336 to avoid doing the conversion in the caller unnecessarily.
3337
3338 This opcode should only be used at the beginning of a code
3339 block.
3340 */
3341
3342 int thisRegister = (++vPC)->u.operand;
3343 JSValue thisVal = callFrame->r(thisRegister).jsValue();
3344 if (thisVal.needsThisConversion())
3345 callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame));
3346
3347 ++vPC;
3348 NEXT_INSTRUCTION();
3349 }
3350 DEFINE_OPCODE(op_init_arguments) {
3351 /* create_arguments
3352
3353 Initialises the arguments object reference to null to ensure
3354 we can correctly detect that we need to create it later (or
3355 avoid creating it altogether).
3356
3357 This opcode should only be used at the beginning of a code
3358 block.
3359 */
3360 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue();
3361 ++vPC;
3362 NEXT_INSTRUCTION();
3363 }
3364 DEFINE_OPCODE(op_create_arguments) {
3365 /* create_arguments
3366
3367 Creates the 'arguments' object and places it in both the
3368 'arguments' call frame slot and the local 'arguments'
3369 register, if it has not already been initialised.
3370 */
3371
3372 if (!callFrame->r(RegisterFile::ArgumentsRegister).jsValue()) {
3373 Arguments* arguments = new (globalData) Arguments(callFrame);
3374 callFrame->setCalleeArguments(arguments);
3375 callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3376 }
3377 ++vPC;
3378 NEXT_INSTRUCTION();
3379 }
3380 DEFINE_OPCODE(op_construct) {
3381 /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)
3382
3383 Invoke register "func" as a constructor. For JS
3384 functions, the calling convention is exactly as for the
3385 "call" opcode, except that the "this" value is a newly
3386 created Object. For native constructors, no "this"
3387 value is passed. In either case, the argCount and registerOffset
3388 registers are interpreted as for the "call" opcode.
3389
3390 Register proto must contain the prototype property of
3391 register func. This is to enable polymorphic inline
3392 caching of this lookup.
3393 */
3394
3395 int dst = vPC[1].u.operand;
3396 int func = vPC[2].u.operand;
3397 int argCount = vPC[3].u.operand;
3398 int registerOffset = vPC[4].u.operand;
3399 int proto = vPC[5].u.operand;
3400 int thisRegister = vPC[6].u.operand;
3401
3402 JSValue v = callFrame->r(func).jsValue();
3403
3404 ConstructData constructData;
3405 ConstructType constructType = v.getConstructData(constructData);
3406
3407 if (constructType == ConstructTypeJS) {
3408 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
3409 FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
3410 CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain);
3411
3412 Structure* structure;
3413 JSValue prototype = callFrame->r(proto).jsValue();
3414 if (prototype.isObject())
3415 structure = asObject(prototype)->inheritorID();
3416 else
3417 structure = callDataScopeChain->globalObject()->emptyObjectStructure();
3418 JSObject* newObject = new (globalData) JSObject(structure);
3419
3420 callFrame->r(thisRegister) = JSValue(newObject); // "this" value
3421
3422 CallFrame* previousCallFrame = callFrame;
3423
3424 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);
3425 if (UNLIKELY(!callFrame)) {
3426 callFrame = previousCallFrame;
3427 exceptionValue = createStackOverflowError(callFrame);
3428 goto vm_throw;
3429 }
3430
3431 callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v));
3432 vPC = newCodeBlock->instructions().begin();
3433
3434 #if ENABLE(OPCODE_STATS)
3435 OpcodeStats::resetLastInstruction();
3436 #endif
3437
3438 NEXT_INSTRUCTION();
3439 }
3440
3441 if (constructType == ConstructTypeHost) {
3442 ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1);
3443
3444 ScopeChainNode* scopeChain = callFrame->scopeChain();
3445 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);
3446 newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0);
3447
3448 JSValue returnValue;
3449 {
3450 SamplingTool::HostCallRecord callRecord(m_sampler);
3451 returnValue = constructData.native.function(newCallFrame, asObject(v), args);
3452 }
3453 CHECK_FOR_EXCEPTION();
3454 callFrame->r(dst) = JSValue(returnValue);
3455
3456 vPC += 7;
3457 NEXT_INSTRUCTION();
3458 }
3459
3460 ASSERT(constructType == ConstructTypeNone);
3461
3462 exceptionValue = createNotAConstructorError(callFrame, v, vPC - callFrame->codeBlock()->instructions().begin(), callFrame->codeBlock());
3463 goto vm_throw;
3464 }
3465 DEFINE_OPCODE(op_construct_verify) {
3466 /* construct_verify dst(r) override(r)
3467
3468 Verifies that register dst holds an object. If not, moves
3469 the object in register override to register dst.
3470 */
3471
3472 int dst = vPC[1].u.operand;
3473 if (LIKELY(callFrame->r(dst).jsValue().isObject())) {
3474 vPC += 3;
3475 NEXT_INSTRUCTION();
3476 }
3477
3478 int override = vPC[2].u.operand;
3479 callFrame->r(dst) = callFrame->r(override);
3480
3481 vPC += 3;
3482 NEXT_INSTRUCTION();
3483 }
3484 DEFINE_OPCODE(op_strcat) {
3485 int dst = (++vPC)->u.operand;
3486 int src = (++vPC)->u.operand;
3487 int count = (++vPC)->u.operand;
3488
3489 callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);
3490 ++vPC;
3491
3492 NEXT_INSTRUCTION();
3493 }
3494 DEFINE_OPCODE(op_to_primitive) {
3495 int dst = (++vPC)->u.operand;
3496 int src = (++vPC)->u.operand;
3497
3498 callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);
3499 ++vPC;
3500
3501 NEXT_INSTRUCTION();
3502 }
3503 DEFINE_OPCODE(op_push_scope) {
3504 /* push_scope scope(r)
3505
3506 Converts register scope to object, and pushes it onto the top
3507 of the current scope chain. The contents of the register scope
3508 are replaced by the result of toObject conversion of the scope.
3509 */
3510 int scope = (++vPC)->u.operand;
3511 JSValue v = callFrame->r(scope).jsValue();
3512 JSObject* o = v.toObject(callFrame);
3513 CHECK_FOR_EXCEPTION();
3514
3515 callFrame->r(scope) = JSValue(o);
3516 callFrame->setScopeChain(callFrame->scopeChain()->push(o));
3517
3518 ++vPC;
3519 NEXT_INSTRUCTION();
3520 }
3521 DEFINE_OPCODE(op_pop_scope) {
3522 /* pop_scope
3523
3524 Removes the top item from the current scope chain.
3525 */
3526 callFrame->setScopeChain(callFrame->scopeChain()->pop());
3527
3528 ++vPC;
3529 NEXT_INSTRUCTION();
3530 }
3531 DEFINE_OPCODE(op_get_pnames) {
3532 /* get_pnames dst(r) base(r)
3533
3534 Creates a property name list for register base and puts it
3535 in register dst. This is not a true JavaScript value, just
3536 a synthetic value used to keep the iteration state in a
3537 register.
3538 */
3539 int dst = (++vPC)->u.operand;
3540 int base = (++vPC)->u.operand;
3541
3542 callFrame->r(dst) = JSPropertyNameIterator::create(callFrame, callFrame->r(base).jsValue());
3543 ++vPC;
3544 NEXT_INSTRUCTION();
3545 }
3546 DEFINE_OPCODE(op_next_pname) {
3547 /* next_pname dst(r) iter(r) target(offset)
3548
3549 Tries to copies the next name from property name list in
3550 register iter. If there are names left, then copies one to
3551 register dst, and jumps to offset target. If there are none
3552 left, invalidates the iterator and continues to the next
3553 instruction.
3554 */
3555 int dst = (++vPC)->u.operand;
3556 int iter = (++vPC)->u.operand;
3557 int target = (++vPC)->u.operand;
3558
3559 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();
3560 if (JSValue temp = it->next(callFrame)) {
3561 CHECK_FOR_TIMEOUT();
3562 callFrame->r(dst) = JSValue(temp);
3563 vPC += target;
3564 NEXT_INSTRUCTION();
3565 }
3566 it->invalidate();
3567
3568 ++vPC;
3569 NEXT_INSTRUCTION();
3570 }
3571 DEFINE_OPCODE(op_jmp_scopes) {
3572 /* jmp_scopes count(n) target(offset)
3573
3574 Removes the a number of items from the current scope chain
3575 specified by immediate number count, then jumps to offset
3576 target.
3577 */
3578 int count = (++vPC)->u.operand;
3579 int target = (++vPC)->u.operand;
3580
3581 ScopeChainNode* tmp = callFrame->scopeChain();
3582 while (count--)
3583 tmp = tmp->pop();
3584 callFrame->setScopeChain(tmp);
3585
3586 vPC += target;
3587 NEXT_INSTRUCTION();
3588 }
3589 #if HAVE(COMPUTED_GOTO)
3590 // Appease GCC
3591 goto *(&&skip_new_scope);
3592 #endif
3593 DEFINE_OPCODE(op_push_new_scope) {
3594 /* new_scope dst(r) property(id) value(r)
3595
3596 Constructs a new StaticScopeObject with property set to value. That scope
3597 object is then pushed onto the ScopeChain. The scope object is then stored
3598 in dst for GC.
3599 */
3600 callFrame->setScopeChain(createExceptionScope(callFrame, vPC));
3601
3602 vPC += 4;
3603 NEXT_INSTRUCTION();
3604 }
3605 #if HAVE(COMPUTED_GOTO)
3606 skip_new_scope:
3607 #endif
3608 DEFINE_OPCODE(op_catch) {
3609 /* catch ex(r)
3610
3611 Retrieves the VM's current exception and puts it in register
3612 ex. This is only valid after an exception has been raised,
3613 and usually forms the beginning of an exception handler.
3614 */
3615 ASSERT(exceptionValue);
3616 ASSERT(!globalData->exception);
3617 int ex = (++vPC)->u.operand;
3618 callFrame->r(ex) = exceptionValue;
3619 exceptionValue = JSValue();
3620
3621 ++vPC;
3622 NEXT_INSTRUCTION();
3623 }
3624 DEFINE_OPCODE(op_throw) {
3625 /* throw ex(r)
3626
3627 Throws register ex as an exception. This involves three
3628 steps: first, it is set as the current exception in the
3629 VM's internal state, then the stack is unwound until an
3630 exception handler or a native code boundary is found, and
3631 then control resumes at the exception handler if any or
3632 else the script returns control to the nearest native caller.
3633 */
3634
3635 int ex = (++vPC)->u.operand;
3636 exceptionValue = callFrame->r(ex).jsValue();
3637
3638 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true);
3639 if (!handler) {
3640 *exception = exceptionValue;
3641 return jsNull();
3642 }
3643
3644 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3645 NEXT_INSTRUCTION();
3646 }
3647 DEFINE_OPCODE(op_new_error) {
3648 /* new_error dst(r) type(n) message(k)
3649
3650 Constructs a new Error instance using the original
3651 constructor, using immediate number n as the type and
3652 constant message as the message string. The result is
3653 written to register dst.
3654 */
3655 int dst = (++vPC)->u.operand;
3656 int type = (++vPC)->u.operand;
3657 int message = (++vPC)->u.operand;
3658
3659 CodeBlock* codeBlock = callFrame->codeBlock();
3660 callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()));
3661
3662 ++vPC;
3663 NEXT_INSTRUCTION();
3664 }
3665 DEFINE_OPCODE(op_end) {
3666 /* end result(r)
3667
3668 Return register result as the value of a global or eval
3669 program. Return control to the calling native code.
3670 */
3671
3672 if (callFrame->codeBlock()->needsFullScopeChain()) {
3673 ScopeChainNode* scopeChain = callFrame->scopeChain();
3674 ASSERT(scopeChain->refCount > 1);
3675 scopeChain->deref();
3676 }
3677 int result = (++vPC)->u.operand;
3678 return callFrame->r(result).jsValue();
3679 }
3680 DEFINE_OPCODE(op_put_getter) {
3681 /* put_getter base(r) property(id) function(r)
3682
3683 Sets register function on register base as the getter named
3684 by identifier property. Base and function are assumed to be
3685 objects as this op should only be used for getters defined
3686 in object literal form.
3687
3688 Unlike many opcodes, this one does not write any output to
3689 the register file.
3690 */
3691 int base = (++vPC)->u.operand;
3692 int property = (++vPC)->u.operand;
3693 int function = (++vPC)->u.operand;
3694
3695 ASSERT(callFrame->r(base).jsValue().isObject());
3696 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3697 Identifier& ident = callFrame->codeBlock()->identifier(property);
3698 ASSERT(callFrame->r(function).jsValue().isObject());
3699 baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
3700
3701 ++vPC;
3702 NEXT_INSTRUCTION();
3703 }
3704 DEFINE_OPCODE(op_put_setter) {
3705 /* put_setter base(r) property(id) function(r)
3706
3707 Sets register function on register base as the setter named
3708 by identifier property. Base and function are assumed to be
3709 objects as this op should only be used for setters defined
3710 in object literal form.
3711
3712 Unlike many opcodes, this one does not write any output to
3713 the register file.
3714 */
3715 int base = (++vPC)->u.operand;
3716 int property = (++vPC)->u.operand;
3717 int function = (++vPC)->u.operand;
3718
3719 ASSERT(callFrame->r(base).jsValue().isObject());
3720 JSObject* baseObj = asObject(callFrame->r(base).jsValue());
3721 Identifier& ident = callFrame->codeBlock()->identifier(property);
3722 ASSERT(callFrame->r(function).jsValue().isObject());
3723 baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()));
3724
3725 ++vPC;
3726 NEXT_INSTRUCTION();
3727 }
3728 DEFINE_OPCODE(op_method_check) {
3729 vPC++;
3730 NEXT_INSTRUCTION();
3731 }
3732 DEFINE_OPCODE(op_jsr) {
3733 /* jsr retAddrDst(r) target(offset)
3734
3735 Places the address of the next instruction into the retAddrDst
3736 register and jumps to offset target from the current instruction.
3737 */
3738 int retAddrDst = (++vPC)->u.operand;
3739 int target = (++vPC)->u.operand;
3740 callFrame->r(retAddrDst) = vPC + 1;
3741
3742 vPC += target;
3743 NEXT_INSTRUCTION();
3744 }
3745 DEFINE_OPCODE(op_sret) {
3746 /* sret retAddrSrc(r)
3747
3748 Jumps to the address stored in the retAddrSrc register. This
3749 differs from op_jmp because the target address is stored in a
3750 register, not as an immediate.
3751 */
3752 int retAddrSrc = (++vPC)->u.operand;
3753 vPC = callFrame->r(retAddrSrc).vPC();
3754 NEXT_INSTRUCTION();
3755 }
3756 DEFINE_OPCODE(op_debug) {
3757 /* debug debugHookID(n) firstLine(n) lastLine(n)
3758
3759 Notifies the debugger of the current state of execution. This opcode
3760 is only generated while the debugger is attached.
3761 */
3762 int debugHookID = (++vPC)->u.operand;
3763 int firstLine = (++vPC)->u.operand;
3764 int lastLine = (++vPC)->u.operand;
3765
3766 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3767
3768 ++vPC;
3769 NEXT_INSTRUCTION();
3770 }
3771 DEFINE_OPCODE(op_profile_will_call) {
3772 /* op_profile_will_call function(r)
3773
3774 Notifies the profiler of the beginning of a function call. This opcode
3775 is only generated if developer tools are enabled.
3776 */
3777 int function = vPC[1].u.operand;
3778
3779 if (*enabledProfilerReference)
3780 (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue());
3781
3782 vPC += 2;
3783 NEXT_INSTRUCTION();
3784 }
3785 DEFINE_OPCODE(op_profile_did_call) {
3786 /* op_profile_did_call function(r)
3787
3788 Notifies the profiler of the end of a function call. This opcode
3789 is only generated if developer tools are enabled.
3790 */
3791 int function = vPC[1].u.operand;
3792
3793 if (*enabledProfilerReference)
3794 (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue());
3795
3796 vPC += 2;
3797 NEXT_INSTRUCTION();
3798 }
3799 vm_throw: {
3800 globalData->exception = JSValue();
3801 if (!tickCount) {
3802 // The exceptionValue is a lie! (GCC produces bad code for reasons I
3803 // cannot fathom if we don't assign to the exceptionValue before branching)
3804 exceptionValue = createInterruptedExecutionException(globalData);
3805 }
3806 handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), false);
3807 if (!handler) {
3808 *exception = exceptionValue;
3809 return jsNull();
3810 }
3811
3812 vPC = callFrame->codeBlock()->instructions().begin() + handler->target;
3813 NEXT_INSTRUCTION();
3814 }
3815 }
3816 #if !HAVE(COMPUTED_GOTO)
3817 } // iterator loop ends
3818 #endif
3819 #endif // USE(INTERPRETER)
3820 #undef NEXT_INSTRUCTION
3821 #undef DEFINE_OPCODE
3822 #undef CHECK_FOR_EXCEPTION
3823 #undef CHECK_FOR_TIMEOUT
3824 }
3825
retrieveArguments(CallFrame * callFrame,JSFunction * function) const3826 JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* function) const
3827 {
3828 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3829 if (!functionCallFrame)
3830 return jsNull();
3831
3832 CodeBlock* codeBlock = functionCallFrame->codeBlock();
3833 if (codeBlock->usesArguments()) {
3834 ASSERT(codeBlock->codeType() == FunctionCode);
3835 SymbolTable& symbolTable = codeBlock->symbolTable();
3836 int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex();
3837 if (!functionCallFrame->r(argumentsIndex).jsValue()) {
3838 Arguments* arguments = new (callFrame) Arguments(functionCallFrame);
3839 functionCallFrame->setCalleeArguments(arguments);
3840 functionCallFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments);
3841 }
3842 return functionCallFrame->r(argumentsIndex).jsValue();
3843 }
3844
3845 Arguments* arguments = functionCallFrame->optionalCalleeArguments();
3846 if (!arguments) {
3847 arguments = new (functionCallFrame) Arguments(functionCallFrame);
3848 arguments->copyRegisters();
3849 callFrame->setCalleeArguments(arguments);
3850 }
3851
3852 return arguments;
3853 }
3854
retrieveCaller(CallFrame * callFrame,InternalFunction * function) const3855 JSValue Interpreter::retrieveCaller(CallFrame* callFrame, InternalFunction* function) const
3856 {
3857 CallFrame* functionCallFrame = findFunctionCallFrame(callFrame, function);
3858 if (!functionCallFrame)
3859 return jsNull();
3860
3861 CallFrame* callerFrame = functionCallFrame->callerFrame();
3862 if (callerFrame->hasHostCallFrameFlag())
3863 return jsNull();
3864
3865 JSValue caller = callerFrame->callee();
3866 if (!caller)
3867 return jsNull();
3868
3869 return caller;
3870 }
3871
retrieveLastCaller(CallFrame * callFrame,int & lineNumber,intptr_t & sourceID,UString & sourceURL,JSValue & function) const3872 void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intptr_t& sourceID, UString& sourceURL, JSValue& function) const
3873 {
3874 function = JSValue();
3875 lineNumber = -1;
3876 sourceURL = UString();
3877
3878 CallFrame* callerFrame = callFrame->callerFrame();
3879 if (callerFrame->hasHostCallFrameFlag())
3880 return;
3881
3882 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
3883 if (!callerCodeBlock)
3884 return;
3885
3886 unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC());
3887 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1);
3888 sourceID = callerCodeBlock->ownerNode()->sourceID();
3889 sourceURL = callerCodeBlock->ownerNode()->sourceURL();
3890 function = callerFrame->callee();
3891 }
3892
findFunctionCallFrame(CallFrame * callFrame,InternalFunction * function)3893 CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunction* function)
3894 {
3895 for (CallFrame* candidate = callFrame; candidate; candidate = candidate->callerFrame()->removeHostCallFrameFlag()) {
3896 if (candidate->callee() == function)
3897 return candidate;
3898 }
3899 return 0;
3900 }
3901
3902 } // namespace JSC
3903