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