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