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