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