2 * Copyright (C) 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "Interpreter.h"
33 #include "Arguments.h"
34 #include "BatchedTransitionOptimizer.h"
35 #include "CallFrame.h"
36 #include "CallFrameClosure.h"
37 #include "CodeBlock.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"
47 #include "JSBoundFunction.h"
48 #include "JSNameScope.h"
49 #include "JSNotAnObject.h"
50 #include "JSPropertyNameIterator.h"
51 #include "JSStackInlines.h"
53 #include "JSWithScope.h"
54 #include "LLIntCLoop.h"
55 #include "LegacyProfiler.h"
56 #include "LiteralParser.h"
57 #include "NameInstance.h"
58 #include "ObjectPrototype.h"
59 #include "Operations.h"
61 #include "RegExpObject.h"
62 #include "RegExpPrototype.h"
64 #include "SamplingTool.h"
65 #include "StrictEvalActivation.h"
66 #include "StrongInlines.h"
69 #include <wtf/StackStats.h>
70 #include <wtf/StringPrintStream.h>
71 #include <wtf/Threading.h>
72 #include <wtf/WTFThreadData.h>
73 #include <wtf/text/StringBuilder.h>
79 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(LLINT) && !defined(__llvm__))
85 Interpreter::ErrorHandlingMode::ErrorHandlingMode(ExecState
*exec
)
86 : m_interpreter(*exec
->interpreter())
88 if (!m_interpreter
.m_errorHandlingModeReentry
)
89 m_interpreter
.stack().enableErrorStackReserve();
90 m_interpreter
.m_errorHandlingModeReentry
++;
93 Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
95 m_interpreter
.m_errorHandlingModeReentry
--;
96 ASSERT(m_interpreter
.m_errorHandlingModeReentry
>= 0);
97 if (!m_interpreter
.m_errorHandlingModeReentry
)
98 m_interpreter
.stack().disableErrorStackReserve();
102 // The Interpreter::StackPolicy class is used to compute a stack capacity
103 // requirement to ensure that we have enough room on the native stack for:
104 // 1. the max cumulative stack used by the interpreter and all code
105 // paths sub of it up till leaf functions.
106 // 2. the max cumulative stack used by the interpreter before it reaches
107 // the next checkpoint (execute...() function) in the interpreter.
109 // The interpreter can be run on different threads and hence, different
110 // native stacks (with different sizes) before exiting out of the first
111 // frame. Hence, the required capacity needs to be re-computed on every
112 // entry into the interpreter.
114 // Currently the requiredStack is computed based on a policy. See comments
115 // in StackPolicy::StackPolicy() for details.
117 Interpreter::StackPolicy::StackPolicy(Interpreter
& interpreter
, const StackBounds
& stack
)
118 : m_interpreter(interpreter
)
120 const size_t size
= stack
.size();
122 // We have two separate stack limits, one for regular JS execution, and one
123 // for when we're handling errors. We need the error stack to be smaller
124 // otherwise there would obviously not be any stack left to execute JS in when
125 // there's a stack overflow.
127 // These sizes were derived from the stack usage of a number of sites when
128 // layout occurs when we've already consumed most of the C stack.
129 const size_t requiredStack
= 256 * KB
;
130 const size_t errorModeRequiredStack
= 64 * KB
;
132 size_t requiredCapacity
= m_interpreter
.m_errorHandlingModeReentry
? errorModeRequiredStack
: requiredStack
;
134 RELEASE_ASSERT(size
> requiredCapacity
);
136 m_requiredCapacity
= requiredCapacity
;
140 static CallFrame
* getCallerInfo(VM
*, CallFrame
*, unsigned& bytecodeOffset
, CodeBlock
*& callerOut
);
142 // Returns the depth of the scope chain within a given call frame.
143 static int depth(CodeBlock
* codeBlock
, JSScope
* sc
)
145 if (!codeBlock
->needsFullScopeChain())
147 return sc
->localDepth();
150 JSValue
eval(CallFrame
* callFrame
)
152 if (!callFrame
->argumentCount())
153 return jsUndefined();
155 JSValue program
= callFrame
->argument(0);
156 if (!program
.isString())
159 TopCallFrameSetter
topCallFrame(callFrame
->vm(), callFrame
);
160 String programSource
= asString(program
)->value(callFrame
);
161 if (callFrame
->hadException())
164 CallFrame
* callerFrame
= callFrame
->callerFrame();
165 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
166 JSScope
* callerScopeChain
= callerFrame
->scope();
167 EvalExecutable
* eval
= callerCodeBlock
->evalCodeCache().tryGet(callerCodeBlock
->isStrictMode(), programSource
, callerScopeChain
);
170 if (!callerCodeBlock
->isStrictMode()) {
171 // FIXME: We can use the preparser in strict mode, we just need additional logic
172 // to prevent duplicates.
173 if (programSource
.is8Bit()) {
174 LiteralParser
<LChar
> preparser(callFrame
, programSource
.characters8(), programSource
.length(), NonStrictJSON
);
175 if (JSValue parsedObject
= preparser
.tryLiteralParse())
178 LiteralParser
<UChar
> preparser(callFrame
, programSource
.characters16(), programSource
.length(), NonStrictJSON
);
179 if (JSValue parsedObject
= preparser
.tryLiteralParse())
184 // If the literal parser bailed, it should not have thrown exceptions.
185 ASSERT(!callFrame
->vm().exception
);
187 JSValue exceptionValue
;
188 eval
= callerCodeBlock
->evalCodeCache().getSlow(callFrame
, callerCodeBlock
->unlinkedCodeBlock()->codeCacheForEval().get(), callerCodeBlock
->ownerExecutable(), callerCodeBlock
->isStrictMode(), programSource
, callerScopeChain
, exceptionValue
);
190 ASSERT(!eval
== exceptionValue
);
192 return throwError(callFrame
, exceptionValue
);
195 JSValue thisValue
= callerFrame
->thisValue();
196 ASSERT(isValidThisObject(thisValue
, callFrame
));
197 Interpreter
* interpreter
= callFrame
->vm().interpreter
;
198 return interpreter
->execute(eval
, callFrame
, thisValue
, callerScopeChain
);
201 CallFrame
* loadVarargs(CallFrame
* callFrame
, JSStack
* stack
, JSValue thisValue
, JSValue arguments
, int firstFreeRegister
)
203 if (!arguments
) { // f.apply(x, arguments), with arguments unmodified.
204 unsigned argumentCountIncludingThis
= callFrame
->argumentCountIncludingThis();
205 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ argumentCountIncludingThis
+ JSStack::CallFrameHeaderSize
);
206 if (argumentCountIncludingThis
> Arguments::MaxArguments
+ 1 || !stack
->grow(newCallFrame
->registers())) {
207 callFrame
->vm().exception
= createStackOverflowError(callFrame
);
211 newCallFrame
->setArgumentCountIncludingThis(argumentCountIncludingThis
);
212 newCallFrame
->setThisValue(thisValue
);
213 for (size_t i
= 0; i
< callFrame
->argumentCount(); ++i
)
214 newCallFrame
->setArgument(i
, callFrame
->argumentAfterCapture(i
));
218 if (arguments
.isUndefinedOrNull()) {
219 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ 1 + JSStack::CallFrameHeaderSize
);
220 if (!stack
->grow(newCallFrame
->registers())) {
221 callFrame
->vm().exception
= createStackOverflowError(callFrame
);
224 newCallFrame
->setArgumentCountIncludingThis(1);
225 newCallFrame
->setThisValue(thisValue
);
229 if (!arguments
.isObject()) {
230 callFrame
->vm().exception
= createInvalidParamError(callFrame
, "Function.prototype.apply", arguments
);
234 if (asObject(arguments
)->classInfo() == &Arguments::s_info
) {
235 Arguments
* argsObject
= asArguments(arguments
);
236 unsigned argCount
= argsObject
->length(callFrame
);
237 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
238 if (argCount
> Arguments::MaxArguments
|| !stack
->grow(newCallFrame
->registers())) {
239 callFrame
->vm().exception
= createStackOverflowError(callFrame
);
242 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
243 newCallFrame
->setThisValue(thisValue
);
244 argsObject
->copyToArguments(callFrame
, newCallFrame
, argCount
);
248 if (isJSArray(arguments
)) {
249 JSArray
* array
= asArray(arguments
);
250 unsigned argCount
= array
->length();
251 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
252 if (argCount
> Arguments::MaxArguments
|| !stack
->grow(newCallFrame
->registers())) {
253 callFrame
->vm().exception
= createStackOverflowError(callFrame
);
256 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
257 newCallFrame
->setThisValue(thisValue
);
258 array
->copyToArguments(callFrame
, newCallFrame
, argCount
);
262 JSObject
* argObject
= asObject(arguments
);
263 unsigned argCount
= argObject
->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
264 CallFrame
* newCallFrame
= CallFrame::create(callFrame
->registers() + firstFreeRegister
+ CallFrame::offsetFor(argCount
+ 1));
265 if (argCount
> Arguments::MaxArguments
|| !stack
->grow(newCallFrame
->registers())) {
266 callFrame
->vm().exception
= createStackOverflowError(callFrame
);
269 newCallFrame
->setArgumentCountIncludingThis(argCount
+ 1);
270 newCallFrame
->setThisValue(thisValue
);
271 for (size_t i
= 0; i
< argCount
; ++i
) {
272 newCallFrame
->setArgument(i
, asObject(arguments
)->get(callFrame
, i
));
273 if (UNLIKELY(callFrame
->vm().exception
))
279 Interpreter::Interpreter(VM
& vm
)
280 : m_sampleEntryDepth(0)
282 , m_errorHandlingModeReentry(0)
284 , m_initialized(false)
289 Interpreter::~Interpreter()
293 void Interpreter::initialize(bool canUseJIT
)
295 UNUSED_PARAM(canUseJIT
);
297 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT)
298 m_opcodeTable
= LLInt::opcodeMap();
299 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
300 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
304 m_initialized
= true;
307 #if ENABLE(OPCODE_SAMPLING)
314 void Interpreter::dumpCallFrame(CallFrame
*)
320 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
322 callFrame
->codeBlock()->dumpBytecode();
323 dumpRegisters(callFrame
);
326 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
328 dataLogF("Register frame: \n\n");
329 dataLogF("-----------------------------------------------------------------------------\n");
330 dataLogF(" use | address | value \n");
331 dataLogF("-----------------------------------------------------------------------------\n");
333 CodeBlock
* codeBlock
= callFrame
->codeBlock();
337 it
= callFrame
->registers() - JSStack::CallFrameHeaderSize
- callFrame
->argumentCountIncludingThis();
338 end
= callFrame
->registers() - JSStack::CallFrameHeaderSize
;
340 JSValue v
= it
->jsValue();
341 int registerNumber
= it
- callFrame
->registers();
342 String name
= codeBlock
->nameForRegister(registerNumber
);
343 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber
, name
.ascii().data(), it
, toCString(v
).data(), (long long)JSValue::encode(v
));
347 dataLogF("-----------------------------------------------------------------------------\n");
348 dataLogF("[ArgumentCount] | %10p | %lu \n", it
, (unsigned long) callFrame
->argumentCount());
350 dataLogF("[CallerFrame] | %10p | %p \n", it
, callFrame
->callerFrame());
352 dataLogF("[Callee] | %10p | %p \n", it
, callFrame
->callee());
354 dataLogF("[ScopeChain] | %10p | %p \n", it
, callFrame
->scope());
357 AbstractPC pc
= callFrame
->abstractReturnPC(callFrame
->vm());
358 if (pc
.hasJITReturnAddress())
359 dataLogF("[ReturnJITPC] | %10p | %p \n", it
, pc
.jitReturnAddress().value());
361 unsigned bytecodeOffset
= 0;
363 CodeBlock
* callerCodeBlock
= 0;
364 getCallerInfo(&callFrame
->vm(), callFrame
, bytecodeOffset
, callerCodeBlock
);
365 line
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
);
366 dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", it
, bytecodeOffset
, line
);
368 dataLogF("[CodeBlock] | %10p | %p \n", it
, callFrame
->codeBlock());
370 dataLogF("-----------------------------------------------------------------------------\n");
372 int registerCount
= 0;
374 end
= it
+ codeBlock
->m_numVars
;
377 JSValue v
= it
->jsValue();
378 int registerNumber
= it
- callFrame
->registers();
379 String name
= codeBlock
->nameForRegister(registerNumber
);
380 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber
, name
.ascii().data(), it
, toCString(v
).data(), (long long)JSValue::encode(v
));
385 dataLogF("-----------------------------------------------------------------------------\n");
387 end
= it
+ codeBlock
->m_numCalleeRegisters
- codeBlock
->m_numVars
;
390 JSValue v
= (*it
).jsValue();
391 dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerCount
, it
, toCString(v
).data(), (long long)JSValue::encode(v
));
396 dataLogF("-----------------------------------------------------------------------------\n");
401 bool Interpreter::isOpcode(Opcode opcode
)
403 #if ENABLE(COMPUTED_GOTO_OPCODES)
405 return static_cast<OpcodeID
>(bitwise_cast
<uintptr_t>(opcode
)) <= op_end
;
407 return opcode
!= HashTraits
<Opcode
>::emptyValue()
408 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
409 && m_opcodeIDTable
.contains(opcode
);
412 return opcode
>= 0 && opcode
<= op_end
;
416 NEVER_INLINE
bool Interpreter::unwindCallFrame(CallFrame
*& callFrame
, JSValue exceptionValue
, unsigned& bytecodeOffset
, CodeBlock
*& codeBlock
)
418 CodeBlock
* oldCodeBlock
= codeBlock
;
419 JSScope
* scope
= callFrame
->scope();
421 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
422 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
423 if (callFrame
->callee())
424 debugger
->returnEvent(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine(), 0);
426 debugger
->didExecuteProgram(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->ownerExecutable()->lastLine(), 0);
430 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->needsActivation()) {
431 activation
= callFrame
->uncheckedR(oldCodeBlock
->activationRegister()).jsValue();
433 jsCast
<JSActivation
*>(activation
)->tearOff(*scope
->vm());
436 if (oldCodeBlock
->codeType() == FunctionCode
&& oldCodeBlock
->usesArguments()) {
437 if (JSValue arguments
= callFrame
->uncheckedR(unmodifiedArgumentsRegister(oldCodeBlock
->argumentsRegister())).jsValue()) {
439 jsCast
<Arguments
*>(arguments
)->didTearOffActivation(callFrame
, jsCast
<JSActivation
*>(activation
));
441 jsCast
<Arguments
*>(arguments
)->tearOff(callFrame
);
445 CallFrame
* callerFrame
= callFrame
->callerFrame();
446 callFrame
->vm().topCallFrame
= callerFrame
;
447 if (callerFrame
->hasHostCallFrameFlag())
449 callFrame
= getCallerInfo(&callFrame
->vm(), callFrame
, bytecodeOffset
, codeBlock
);
453 static void appendSourceToError(CallFrame
* callFrame
, ErrorInstance
* exception
, unsigned bytecodeOffset
)
455 exception
->clearAppendSourceToMessage();
457 if (!callFrame
->codeBlock()->hasExpressionInfo())
466 CodeBlock
* codeBlock
= callFrame
->codeBlock();
467 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divotPoint
, startOffset
, endOffset
, line
, column
);
469 int expressionStart
= divotPoint
- startOffset
;
470 int expressionStop
= divotPoint
+ endOffset
;
472 const String
& sourceString
= codeBlock
->source()->source();
473 if (!expressionStop
|| expressionStart
> static_cast<int>(sourceString
.length()))
476 VM
* vm
= &callFrame
->vm();
477 JSValue jsMessage
= exception
->getDirect(*vm
, vm
->propertyNames
->message
);
478 if (!jsMessage
|| !jsMessage
.isString())
481 String message
= asString(jsMessage
)->value(callFrame
);
483 if (expressionStart
< expressionStop
)
484 message
= makeString(message
, " (evaluating '", codeBlock
->source()->getRange(expressionStart
, expressionStop
), "')");
486 // No range information, so give a few characters of context
487 const StringImpl
* data
= sourceString
.impl();
488 int dataLength
= sourceString
.length();
489 int start
= expressionStart
;
490 int stop
= expressionStart
;
491 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
492 // then strip whitespace.
493 while (start
> 0 && (expressionStart
- start
< 20) && (*data
)[start
- 1] != '\n')
495 while (start
< (expressionStart
- 1) && isStrWhiteSpace((*data
)[start
]))
497 while (stop
< dataLength
&& (stop
- expressionStart
< 20) && (*data
)[stop
] != '\n')
499 while (stop
> expressionStart
&& isStrWhiteSpace((*data
)[stop
- 1]))
501 message
= makeString(message
, " (near '...", codeBlock
->source()->getRange(start
, stop
), "...')");
504 exception
->putDirect(*vm
, vm
->propertyNames
->message
, jsString(vm
, message
));
507 static unsigned getBytecodeOffsetForCallFrame(CallFrame
* callFrame
)
509 callFrame
= callFrame
->removeHostCallFrameFlag();
510 CodeBlock
* codeBlock
= callFrame
->codeBlock();
514 if (codeBlock
->getJITType() == JITCode::DFGJIT
)
515 return codeBlock
->codeOrigin(callFrame
->codeOriginIndexForDFG()).bytecodeIndex
;
517 return callFrame
->bytecodeOffsetForNonDFGCode();
520 static CallFrame
* getCallerInfo(VM
* vm
, CallFrame
* callFrame
, unsigned& bytecodeOffset
, CodeBlock
*& caller
)
522 ASSERT_UNUSED(vm
, vm
);
524 ASSERT(!callFrame
->hasHostCallFrameFlag());
525 CallFrame
* trueCallerFrame
= callFrame
->trueCallerFrame();
526 bool wasCalledByHost
= callFrame
->callerFrame()->hasHostCallFrameFlag();
527 ASSERT(!trueCallerFrame
->hasHostCallFrameFlag());
529 if (trueCallerFrame
== CallFrame::noCaller() || !trueCallerFrame
|| !trueCallerFrame
->codeBlock()) {
531 return trueCallerFrame
;
534 CodeBlock
* callerCodeBlock
= trueCallerFrame
->codeBlock();
536 if (!callFrame
->hasReturnPC())
537 wasCalledByHost
= true;
539 if (wasCalledByHost
) {
541 if (callerCodeBlock
&& callerCodeBlock
->getJITType() == JITCode::DFGJIT
) {
542 unsigned codeOriginIndex
= callFrame
->callerFrame()->removeHostCallFrameFlag()->codeOriginIndexForDFG();
543 CodeOrigin origin
= callerCodeBlock
->codeOrigin(codeOriginIndex
);
544 bytecodeOffset
= origin
.bytecodeIndex
;
545 if (InlineCallFrame
* inlineCallFrame
= origin
.inlineCallFrame
)
546 callerCodeBlock
= inlineCallFrame
->baselineCodeBlock();
549 bytecodeOffset
= trueCallerFrame
->bytecodeOffsetForNonDFGCode();
552 if (callFrame
->isInlineCallFrame()) {
553 InlineCallFrame
* icf
= callFrame
->inlineCallFrame();
554 bytecodeOffset
= icf
->caller
.bytecodeIndex
;
555 if (InlineCallFrame
* parentCallFrame
= icf
->caller
.inlineCallFrame
) {
556 FunctionExecutable
* executable
= static_cast<FunctionExecutable
*>(parentCallFrame
->executable
.get());
557 CodeBlock
* newCodeBlock
= executable
->baselineCodeBlockFor(parentCallFrame
->isCall
? CodeForCall
: CodeForConstruct
);
558 ASSERT(newCodeBlock
);
559 ASSERT(newCodeBlock
->instructionCount() > bytecodeOffset
);
560 callerCodeBlock
= newCodeBlock
;
562 } else if (callerCodeBlock
&& callerCodeBlock
->getJITType() == JITCode::DFGJIT
) {
564 if (!callerCodeBlock
->codeOriginForReturn(callFrame
->returnPC(), origin
)) {
565 // This should not be possible, but we're seeing cases where it does happen
566 // CallFrame already has robustness against bogus stack walks, so
567 // we'll extend that to here as well.
568 ASSERT_NOT_REACHED();
572 bytecodeOffset
= origin
.bytecodeIndex
;
573 if (InlineCallFrame
* icf
= origin
.inlineCallFrame
) {
574 FunctionExecutable
* executable
= static_cast<FunctionExecutable
*>(icf
->executable
.get());
575 CodeBlock
* newCodeBlock
= executable
->baselineCodeBlockFor(icf
->isCall
? CodeForCall
: CodeForConstruct
);
576 ASSERT(newCodeBlock
);
577 ASSERT(newCodeBlock
->instructionCount() > bytecodeOffset
);
578 callerCodeBlock
= newCodeBlock
;
583 RELEASE_ASSERT(callerCodeBlock
);
584 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(trueCallerFrame
, callFrame
->returnPC());
588 RELEASE_ASSERT(callerCodeBlock
);
589 caller
= callerCodeBlock
;
590 return trueCallerFrame
;
593 static ALWAYS_INLINE
const String
getSourceURLFromCallFrame(CallFrame
* callFrame
)
595 ASSERT(!callFrame
->hasHostCallFrameFlag());
596 return callFrame
->codeBlock()->ownerExecutable()->sourceURL();
599 static StackFrameCodeType
getStackFrameCodeType(CallFrame
* callFrame
)
601 ASSERT(!callFrame
->hasHostCallFrameFlag());
603 switch (callFrame
->codeBlock()->codeType()) {
605 return StackFrameEvalCode
;
607 return StackFrameFunctionCode
;
609 return StackFrameGlobalCode
;
611 RELEASE_ASSERT_NOT_REACHED();
612 return StackFrameGlobalCode
;
615 void StackFrame::computeLineAndColumn(unsigned& line
, unsigned& column
)
624 int unusedStartOffset
= 0;
625 int unusedEndOffset
= 0;
626 unsigned divotLine
= 0;
627 unsigned divotColumn
= 0;
628 expressionInfo(divot
, unusedStartOffset
, unusedEndOffset
, divotLine
, divotColumn
);
630 line
= divotLine
+ lineOffset
;
631 column
= divotColumn
+ (divotLine
? 1 : firstLineColumnOffset
);
634 void StackFrame::expressionInfo(int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
636 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
637 divot
+= characterOffset
;
640 String
StackFrame::toString(CallFrame
* callFrame
)
642 StringBuilder traceBuild
;
643 String functionName
= friendlyFunctionName(callFrame
);
644 String sourceURL
= friendlySourceURL();
645 traceBuild
.append(functionName
);
646 if (!sourceURL
.isEmpty()) {
647 if (!functionName
.isEmpty())
648 traceBuild
.append('@');
649 traceBuild
.append(sourceURL
);
650 if (codeType
!= StackFrameNativeCode
) {
653 computeLineAndColumn(line
, column
);
655 traceBuild
.append(':');
656 traceBuild
.appendNumber(line
);
657 traceBuild
.append(':');
658 traceBuild
.appendNumber(column
);
661 return traceBuild
.toString().impl();
664 void Interpreter::getStackTrace(VM
* vm
, Vector
<StackFrame
>& results
, size_t maxStackSize
)
666 CallFrame
* callFrame
= vm
->topCallFrame
->removeHostCallFrameFlag();
667 if (!callFrame
|| callFrame
== CallFrame::noCaller())
669 unsigned bytecodeOffset
= getBytecodeOffsetForCallFrame(callFrame
);
670 callFrame
= callFrame
->trueCallFrameFromVMCode();
673 CodeBlock
* callerCodeBlock
= callFrame
->codeBlock();
675 while (callFrame
&& callFrame
!= CallFrame::noCaller() && maxStackSize
--) {
677 if (callerCodeBlock
) {
678 sourceURL
= getSourceURLFromCallFrame(callFrame
);
680 Strong
<JSObject
>(*vm
, callFrame
->callee()),
681 getStackFrameCodeType(callFrame
),
682 Strong
<ExecutableBase
>(*vm
, callerCodeBlock
->ownerExecutable()),
683 Strong
<UnlinkedCodeBlock
>(*vm
, callerCodeBlock
->unlinkedCodeBlock()),
684 callerCodeBlock
->source(),
685 callerCodeBlock
->ownerExecutable()->lineNo(),
686 callerCodeBlock
->firstLineColumnOffset(),
687 callerCodeBlock
->sourceOffset(),
694 StackFrame s
= { Strong
<JSObject
>(*vm
, callFrame
->callee()), StackFrameNativeCode
, Strong
<ExecutableBase
>(), Strong
<UnlinkedCodeBlock
>(), 0, 0, 0, 0, 0, String()};
697 callFrame
= getCallerInfo(vm
, callFrame
, bytecodeOffset
, callerCodeBlock
);
701 void Interpreter::addStackTraceIfNecessary(CallFrame
* callFrame
, JSValue error
)
703 VM
* vm
= &callFrame
->vm();
704 ASSERT(callFrame
== vm
->topCallFrame
|| callFrame
== callFrame
->lexicalGlobalObject()->globalExec() || callFrame
== callFrame
->dynamicGlobalObject()->globalExec());
706 Vector
<StackFrame
> stackTrace
;
707 getStackTrace(&callFrame
->vm(), stackTrace
);
708 vm
->exceptionStack() = RefCountedArray
<StackFrame
>(stackTrace
);
709 if (stackTrace
.isEmpty() || !error
.isObject())
712 JSObject
* errorObject
= asObject(error
);
713 JSGlobalObject
* globalObject
= 0;
714 if (isTerminatedExecutionException(error
))
715 globalObject
= vm
->dynamicGlobalObject
;
717 globalObject
= errorObject
->globalObject();
719 // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
720 StringBuilder builder
;
721 for (unsigned i
= 0; i
< stackTrace
.size(); i
++) {
722 builder
.append(String(stackTrace
[i
].toString(globalObject
->globalExec()).impl()));
723 if (i
!= stackTrace
.size() - 1)
724 builder
.append('\n');
727 if (errorObject
->hasProperty(callFrame
, vm
->propertyNames
->stack
))
729 errorObject
->putDirect(*vm
, vm
->propertyNames
->stack
, jsString(vm
, builder
.toString()), ReadOnly
| DontDelete
);
732 NEVER_INLINE HandlerInfo
* Interpreter::throwException(CallFrame
*& callFrame
, JSValue
& exceptionValue
, unsigned bytecodeOffset
)
734 CodeBlock
* codeBlock
= callFrame
->codeBlock();
735 bool isTermination
= false;
737 ASSERT(!exceptionValue
.isEmpty());
738 ASSERT(!exceptionValue
.isCell() || exceptionValue
.asCell());
739 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
740 // slow cases, so let's harden against it anyway to be safe.
741 if (exceptionValue
.isEmpty() || (exceptionValue
.isCell() && !exceptionValue
.asCell()))
742 exceptionValue
= jsNull();
744 // Set up the exception object
745 if (exceptionValue
.isObject()) {
746 JSObject
* exception
= asObject(exceptionValue
);
748 if (exception
->isErrorInstance() && static_cast<ErrorInstance
*>(exception
)->appendSourceToMessage())
749 appendSourceToError(callFrame
, static_cast<ErrorInstance
*>(exception
), bytecodeOffset
);
751 if (!hasErrorInfo(callFrame
, exception
)) {
752 // FIXME: should only really be adding these properties to VM generated exceptions,
753 // but the inspector currently requires these for all thrown objects.
754 addErrorInfo(callFrame
, exception
, codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), codeBlock
->ownerExecutable()->source());
757 isTermination
= isTerminatedExecutionException(exception
);
759 if (!callFrame
->vm().exceptionStack().size()) {
760 Vector
<StackFrame
> stack
;
761 Interpreter::getStackTrace(&callFrame
->vm(), stack
);
762 callFrame
->vm().exceptionStack() = RefCountedArray
<StackFrame
>(stack
);
766 if (Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger()) {
767 DebuggerCallFrame
debuggerCallFrame(callFrame
, exceptionValue
);
768 bool hasHandler
= false;
769 if (!isTermination
) {
770 VM
* vm
= &callFrame
->vm();
771 CallFrame
* currentFrame
= callFrame
;
772 CodeBlock
* currentCB
= codeBlock
;
773 unsigned currentOffset
= bytecodeOffset
;
774 while (currentFrame
) {
775 if (currentCB
&& currentCB
->handlerForBytecodeOffset(currentOffset
)) {
779 currentFrame
= getCallerInfo(vm
, currentFrame
, currentOffset
, currentCB
);
782 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), 0, hasHandler
);
785 // Calculate an exception handler vPC, unwinding call frames as necessary.
786 HandlerInfo
* handler
= 0;
787 while (isTermination
|| !(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
788 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
789 if (LegacyProfiler
* profiler
= callFrame
->vm().enabledProfiler())
790 profiler
->exceptionUnwind(callFrame
);
795 if (LegacyProfiler
* profiler
= callFrame
->vm().enabledProfiler())
796 profiler
->exceptionUnwind(callFrame
);
798 // Unwind the scope chain within the exception handler's call frame.
799 JSScope
* scope
= callFrame
->scope();
801 if (!codeBlock
->needsFullScopeChain() || codeBlock
->codeType() != FunctionCode
802 || callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue()) {
803 int currentDepth
= depth(codeBlock
, scope
);
804 int targetDepth
= handler
->scopeDepth
;
805 scopeDelta
= currentDepth
- targetDepth
;
806 RELEASE_ASSERT(scopeDelta
>= 0);
809 scope
= scope
->next();
810 callFrame
->setScope(scope
);
815 static inline JSValue
checkedReturn(JSValue returnValue
)
821 static inline JSObject
* checkedReturn(JSObject
* returnValue
)
827 class SamplingScope
{
829 SamplingScope(Interpreter
* interpreter
)
830 : m_interpreter(interpreter
)
832 interpreter
->startSampling();
836 m_interpreter
->stopSampling();
839 Interpreter
* m_interpreter
;
842 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, JSObject
* thisObj
)
844 SamplingScope
samplingScope(this);
846 JSScope
* scope
= callFrame
->scope();
847 VM
& vm
= *scope
->vm();
849 ASSERT(isValidThisObject(thisObj
, callFrame
));
850 ASSERT(!vm
.exception
);
851 ASSERT(!vm
.isCollectorBusy());
852 if (vm
.isCollectorBusy())
855 StackStats::CheckPoint stackCheckPoint
;
856 const StackBounds
& nativeStack
= wtfThreadData().stack();
857 StackPolicy
policy(*this, nativeStack
);
858 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
859 return checkedReturn(throwStackOverflowError(callFrame
));
861 // First check if the "program" is actually just a JSON object. If so,
862 // we'll handle the JSON object here. Else, we'll handle real JS code
863 // below at failedJSONP.
864 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
865 Vector
<JSONPData
> JSONPData
;
867 const String programSource
= program
->source().toString();
868 if (programSource
.isNull())
869 return jsUndefined();
870 if (programSource
.is8Bit()) {
871 LiteralParser
<LChar
> literalParser(callFrame
, programSource
.characters8(), programSource
.length(), JSONP
);
872 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
874 LiteralParser
<UChar
> literalParser(callFrame
, programSource
.characters16(), programSource
.length(), JSONP
);
875 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
879 JSGlobalObject
* globalObject
= scope
->globalObject();
881 for (unsigned entry
= 0; entry
< JSONPData
.size(); entry
++) {
882 Vector
<JSONPPathEntry
> JSONPPath
;
883 JSONPPath
.swap(JSONPData
[entry
].m_path
);
884 JSValue JSONPValue
= JSONPData
[entry
].m_value
.get();
885 if (JSONPPath
.size() == 1 && JSONPPath
[0].m_type
== JSONPPathEntryTypeDeclare
) {
886 if (globalObject
->hasProperty(callFrame
, JSONPPath
[0].m_pathEntryName
)) {
887 PutPropertySlot slot
;
888 globalObject
->methodTable()->put(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, slot
);
890 globalObject
->methodTable()->putDirectVirtual(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, DontEnum
| DontDelete
);
891 // var declarations return undefined
892 result
= jsUndefined();
895 JSValue
baseObject(globalObject
);
896 for (unsigned i
= 0; i
< JSONPPath
.size() - 1; i
++) {
897 ASSERT(JSONPPath
[i
].m_type
!= JSONPPathEntryTypeDeclare
);
898 switch (JSONPPath
[i
].m_type
) {
899 case JSONPPathEntryTypeDot
: {
901 PropertySlot
slot(globalObject
);
902 if (!globalObject
->getPropertySlot(callFrame
, JSONPPath
[i
].m_pathEntryName
, slot
)) {
904 return throwError(callFrame
, createUndefinedVariableError(globalObject
->globalExec(), JSONPPath
[i
].m_pathEntryName
));
907 baseObject
= slot
.getValue(callFrame
, JSONPPath
[i
].m_pathEntryName
);
909 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathEntryName
);
910 if (callFrame
->hadException())
911 return jsUndefined();
914 case JSONPPathEntryTypeLookup
: {
915 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathIndex
);
916 if (callFrame
->hadException())
917 return jsUndefined();
921 RELEASE_ASSERT_NOT_REACHED();
922 return jsUndefined();
925 PutPropertySlot slot
;
926 switch (JSONPPath
.last().m_type
) {
927 case JSONPPathEntryTypeCall
: {
928 JSValue function
= baseObject
.get(callFrame
, JSONPPath
.last().m_pathEntryName
);
929 if (callFrame
->hadException())
930 return jsUndefined();
932 CallType callType
= getCallData(function
, callData
);
933 if (callType
== CallTypeNone
)
934 return throwError(callFrame
, createNotAFunctionError(callFrame
, function
));
935 MarkedArgumentBuffer jsonArg
;
936 jsonArg
.append(JSONPValue
);
937 JSValue thisValue
= JSONPPath
.size() == 1 ? jsUndefined(): baseObject
;
938 JSONPValue
= JSC::call(callFrame
, function
, callType
, callData
, thisValue
, jsonArg
);
939 if (callFrame
->hadException())
940 return jsUndefined();
943 case JSONPPathEntryTypeDot
: {
944 baseObject
.put(callFrame
, JSONPPath
.last().m_pathEntryName
, JSONPValue
, slot
);
945 if (callFrame
->hadException())
946 return jsUndefined();
949 case JSONPPathEntryTypeLookup
: {
950 baseObject
.putByIndex(callFrame
, JSONPPath
.last().m_pathIndex
, JSONPValue
, slot
.isStrictMode());
951 if (callFrame
->hadException())
952 return jsUndefined();
956 RELEASE_ASSERT_NOT_REACHED();
957 return jsUndefined();
964 // If we get here, then we have already proven that the script is not a JSON
967 // Compile source to bytecode if necessary:
968 if (JSObject
* error
= program
->initializeGlobalProperties(vm
, callFrame
, scope
))
969 return checkedReturn(throwError(callFrame
, error
));
971 if (JSObject
* error
= program
->compile(callFrame
, scope
))
972 return checkedReturn(throwError(callFrame
, error
));
974 ProgramCodeBlock
* codeBlock
= &program
->generatedBytecode();
976 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
977 return throwTerminatedExecutionException(callFrame
);
979 // Push the call frame for this invocation:
980 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
981 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, codeBlock
, scope
, 1, 0);
982 if (UNLIKELY(!newCallFrame
))
983 return checkedReturn(throwStackOverflowError(callFrame
));
985 // Set the arguments for the callee:
986 newCallFrame
->setThisValue(thisObj
);
988 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
989 profiler
->willExecute(callFrame
, program
->sourceURL(), program
->lineNo());
994 SamplingTool::CallRecord
callRecord(m_sampler
.get());
995 Watchdog::Scope
watchdogScope(vm
.watchdog
);
997 #if ENABLE(LLINT_C_LOOP)
998 result
= LLInt::CLoop::execute(newCallFrame
, llint_program_prologue
);
1000 result
= program
->generatedJITCode().execute(&m_stack
, newCallFrame
, &vm
);
1001 #endif // ENABLE(JIT)
1004 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1005 profiler
->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
1007 m_stack
.popFrame(newCallFrame
);
1009 return checkedReturn(result
);
1012 JSValue
Interpreter::executeCall(CallFrame
* callFrame
, JSObject
* function
, CallType callType
, const CallData
& callData
, JSValue thisValue
, const ArgList
& args
)
1014 VM
& vm
= callFrame
->vm();
1015 ASSERT(isValidThisObject(thisValue
, callFrame
));
1016 ASSERT(!callFrame
->hadException());
1017 ASSERT(!vm
.isCollectorBusy());
1018 if (vm
.isCollectorBusy())
1021 StackStats::CheckPoint stackCheckPoint
;
1022 const StackBounds
& nativeStack
= wtfThreadData().stack();
1023 StackPolicy
policy(*this, nativeStack
);
1024 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1025 return checkedReturn(throwStackOverflowError(callFrame
));
1027 bool isJSCall
= (callType
== CallTypeJS
);
1029 CodeBlock
* newCodeBlock
;
1030 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
1033 scope
= callData
.js
.scope
;
1035 ASSERT(callType
== CallTypeHost
);
1036 scope
= callFrame
->scope();
1038 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1041 // Compile the callee:
1042 JSObject
* compileError
= callData
.js
.functionExecutable
->compileForCall(callFrame
, scope
);
1043 if (UNLIKELY(!!compileError
)) {
1044 return checkedReturn(throwError(callFrame
, compileError
));
1046 newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
1047 ASSERT(!!newCodeBlock
);
1051 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1052 return throwTerminatedExecutionException(callFrame
);
1054 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, function
);
1055 if (UNLIKELY(!newCallFrame
))
1056 return checkedReturn(throwStackOverflowError(callFrame
));
1058 // Set the arguments for the callee:
1059 newCallFrame
->setThisValue(thisValue
);
1060 for (size_t i
= 0; i
< args
.size(); ++i
)
1061 newCallFrame
->setArgument(i
, args
.at(i
));
1063 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1064 profiler
->willExecute(callFrame
, function
);
1068 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSCall
);
1069 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1071 // Execute the code:
1073 #if ENABLE(LLINT_C_LOOP)
1074 result
= LLInt::CLoop::execute(newCallFrame
, llint_function_for_call_prologue
);
1076 result
= callData
.js
.functionExecutable
->generatedJITCodeForCall().execute(&m_stack
, newCallFrame
, &vm
);
1077 #endif // ENABLE(JIT)
1079 result
= JSValue::decode(callData
.native
.function(newCallFrame
));
1082 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1083 profiler
->didExecute(callFrame
, function
);
1085 m_stack
.popFrame(newCallFrame
);
1086 return checkedReturn(result
);
1089 JSObject
* Interpreter::executeConstruct(CallFrame
* callFrame
, JSObject
* constructor
, ConstructType constructType
, const ConstructData
& constructData
, const ArgList
& args
)
1091 VM
& vm
= callFrame
->vm();
1092 ASSERT(!callFrame
->hadException());
1093 ASSERT(!vm
.isCollectorBusy());
1094 // We throw in this case because we have to return something "valid" but we're
1095 // already in an invalid state.
1096 if (vm
.isCollectorBusy())
1097 return checkedReturn(throwStackOverflowError(callFrame
));
1099 StackStats::CheckPoint stackCheckPoint
;
1100 const StackBounds
& nativeStack
= wtfThreadData().stack();
1101 StackPolicy
policy(*this, nativeStack
);
1102 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1103 return checkedReturn(throwStackOverflowError(callFrame
));
1105 bool isJSConstruct
= (constructType
== ConstructTypeJS
);
1107 CodeBlock
* newCodeBlock
;
1108 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
1111 scope
= constructData
.js
.scope
;
1113 ASSERT(constructType
== ConstructTypeHost
);
1114 scope
= callFrame
->scope();
1117 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1119 if (isJSConstruct
) {
1120 // Compile the callee:
1121 JSObject
* compileError
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, scope
);
1122 if (UNLIKELY(!!compileError
)) {
1123 return checkedReturn(throwError(callFrame
, compileError
));
1125 newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
1126 ASSERT(!!newCodeBlock
);
1130 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1131 return throwTerminatedExecutionException(callFrame
);
1133 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, constructor
);
1134 if (UNLIKELY(!newCallFrame
))
1135 return checkedReturn(throwStackOverflowError(callFrame
));
1137 // Set the arguments for the callee:
1138 newCallFrame
->setThisValue(jsUndefined());
1139 for (size_t i
= 0; i
< args
.size(); ++i
)
1140 newCallFrame
->setArgument(i
, args
.at(i
));
1142 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1143 profiler
->willExecute(callFrame
, constructor
);
1147 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSConstruct
);
1148 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1150 // Execute the code.
1151 if (isJSConstruct
) {
1152 #if ENABLE(LLINT_C_LOOP)
1153 result
= LLInt::CLoop::execute(newCallFrame
, llint_function_for_construct_prologue
);
1155 result
= constructData
.js
.functionExecutable
->generatedJITCodeForConstruct().execute(&m_stack
, newCallFrame
, &vm
);
1156 #endif // ENABLE(JIT)
1158 result
= JSValue::decode(constructData
.native
.function(newCallFrame
));
1161 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1162 profiler
->didExecute(callFrame
, constructor
);
1164 m_stack
.popFrame(newCallFrame
);
1166 if (callFrame
->hadException())
1168 ASSERT(result
.isObject());
1169 return checkedReturn(asObject(result
));
1172 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argumentCountIncludingThis
, JSScope
* scope
)
1174 VM
& vm
= *scope
->vm();
1175 ASSERT(!vm
.exception
);
1177 if (vm
.isCollectorBusy())
1178 return CallFrameClosure();
1180 StackStats::CheckPoint stackCheckPoint
;
1181 const StackBounds
& nativeStack
= wtfThreadData().stack();
1182 StackPolicy
policy(*this, nativeStack
);
1183 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity())) {
1184 throwStackOverflowError(callFrame
);
1185 return CallFrameClosure();
1188 // Compile the callee:
1189 JSObject
* error
= functionExecutable
->compileForCall(callFrame
, scope
);
1191 throwError(callFrame
, error
);
1192 return CallFrameClosure();
1194 CodeBlock
* newCodeBlock
= &functionExecutable
->generatedBytecodeForCall();
1196 size_t argsCount
= argumentCountIncludingThis
;
1198 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, function
);
1199 if (UNLIKELY(!newCallFrame
)) {
1200 throwStackOverflowError(callFrame
);
1201 return CallFrameClosure();
1204 if (UNLIKELY(!newCallFrame
)) {
1205 throwStackOverflowError(callFrame
);
1206 return CallFrameClosure();
1209 // Return the successful closure:
1210 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, functionExecutable
, &vm
, scope
, newCodeBlock
->numParameters(), argumentCountIncludingThis
};
1214 JSValue
Interpreter::execute(CallFrameClosure
& closure
)
1216 VM
& vm
= *closure
.vm
;
1217 SamplingScope
samplingScope(this);
1219 ASSERT(!vm
.isCollectorBusy());
1220 if (vm
.isCollectorBusy())
1223 StackStats::CheckPoint stackCheckPoint
;
1224 m_stack
.validateFence(closure
.newCallFrame
, "BEFORE");
1225 closure
.resetCallFrame();
1226 m_stack
.validateFence(closure
.newCallFrame
, "STEP 1");
1228 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1229 profiler
->willExecute(closure
.oldCallFrame
, closure
.function
);
1231 if (UNLIKELY(vm
.watchdog
.didFire(closure
.oldCallFrame
)))
1232 return throwTerminatedExecutionException(closure
.oldCallFrame
);
1234 // The code execution below may push more frames and point the topCallFrame
1235 // to those newer frames, or it may pop to the top frame to the caller of
1236 // the current repeat frame, or it may leave the top frame pointing to the
1237 // current repeat frame.
1239 // Hence, we need to preserve the topCallFrame here ourselves before
1240 // repeating this call on a second callback function.
1242 TopCallFrameSetter
topCallFrame(vm
, closure
.newCallFrame
);
1244 // Execute the code:
1247 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1248 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1250 #if ENABLE(LLINT_C_LOOP)
1251 result
= LLInt::CLoop::execute(closure
.newCallFrame
, llint_function_for_call_prologue
);
1253 result
= closure
.functionExecutable
->generatedJITCodeForCall().execute(&m_stack
, closure
.newCallFrame
, &vm
);
1254 #endif // ENABLE(JIT)
1257 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1258 profiler
->didExecute(closure
.oldCallFrame
, closure
.function
);
1260 m_stack
.validateFence(closure
.newCallFrame
, "AFTER");
1261 return checkedReturn(result
);
1264 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
1266 m_stack
.popFrame(closure
.newCallFrame
);
1269 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSValue thisValue
, JSScope
* scope
)
1271 VM
& vm
= *scope
->vm();
1272 SamplingScope
samplingScope(this);
1274 ASSERT(scope
->vm() == &callFrame
->vm());
1275 ASSERT(isValidThisObject(thisValue
, callFrame
));
1276 ASSERT(!vm
.exception
);
1277 ASSERT(!vm
.isCollectorBusy());
1278 if (vm
.isCollectorBusy())
1281 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1283 StackStats::CheckPoint stackCheckPoint
;
1284 const StackBounds
& nativeStack
= wtfThreadData().stack();
1285 StackPolicy
policy(*this, nativeStack
);
1286 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1287 return checkedReturn(throwStackOverflowError(callFrame
));
1289 // Compile the callee:
1290 JSObject
* compileError
= eval
->compile(callFrame
, scope
);
1291 if (UNLIKELY(!!compileError
))
1292 return checkedReturn(throwError(callFrame
, compileError
));
1293 EvalCodeBlock
* codeBlock
= &eval
->generatedBytecode();
1295 JSObject
* variableObject
;
1296 for (JSScope
* node
= scope
; ; node
= node
->next()) {
1297 RELEASE_ASSERT(node
);
1298 if (node
->isVariableObject() && !node
->isNameScopeObject()) {
1299 variableObject
= node
;
1304 unsigned numVariables
= codeBlock
->numVariables();
1305 int numFunctions
= codeBlock
->numberOfFunctionDecls();
1306 if (numVariables
|| numFunctions
) {
1307 if (codeBlock
->isStrictMode()) {
1308 scope
= StrictEvalActivation::create(callFrame
);
1309 variableObject
= scope
;
1311 // Scope for BatchedTransitionOptimizer
1312 BatchedTransitionOptimizer
optimizer(vm
, variableObject
);
1314 for (unsigned i
= 0; i
< numVariables
; ++i
) {
1315 const Identifier
& ident
= codeBlock
->variable(i
);
1316 if (!variableObject
->hasProperty(callFrame
, ident
)) {
1317 PutPropertySlot slot
;
1318 variableObject
->methodTable()->put(variableObject
, callFrame
, ident
, jsUndefined(), slot
);
1322 for (int i
= 0; i
< numFunctions
; ++i
) {
1323 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
1324 PutPropertySlot slot
;
1325 variableObject
->methodTable()->put(variableObject
, callFrame
, function
->name(), JSFunction::create(callFrame
, function
, scope
), slot
);
1329 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1330 return throwTerminatedExecutionException(callFrame
);
1333 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
1334 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, codeBlock
, scope
, 1, 0);
1335 if (UNLIKELY(!newCallFrame
))
1336 return checkedReturn(throwStackOverflowError(callFrame
));
1338 // Set the arguments for the callee:
1339 newCallFrame
->setThisValue(thisValue
);
1341 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1342 profiler
->willExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1344 // Execute the code:
1347 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1348 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1350 #if ENABLE(LLINT_C_LOOP)
1351 result
= LLInt::CLoop::execute(newCallFrame
, llint_eval_prologue
);
1353 result
= eval
->generatedJITCode().execute(&m_stack
, newCallFrame
, &vm
);
1354 #endif // ENABLE(JIT)
1357 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1358 profiler
->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1360 m_stack
.popFrame(newCallFrame
);
1361 return checkedReturn(result
);
1364 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
, int column
)
1366 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
1370 switch (debugHookID
) {
1371 case DidEnterCallFrame
:
1372 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1374 case WillLeaveCallFrame
:
1375 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1377 case WillExecuteStatement
:
1378 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1380 case WillExecuteProgram
:
1381 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1383 case DidExecuteProgram
:
1384 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1386 case DidReachBreakpoint
:
1387 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1392 JSValue
Interpreter::retrieveArgumentsFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
1394 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
1395 if (!functionCallFrame
)
1398 Arguments
* arguments
= Arguments::create(functionCallFrame
->vm(), functionCallFrame
);
1399 arguments
->tearOff(functionCallFrame
);
1400 return JSValue(arguments
);
1403 JSValue
Interpreter::retrieveCallerFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
1405 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
1407 if (!functionCallFrame
)
1410 unsigned bytecodeOffset
;
1411 CodeBlock
* unusedCallerCodeBlock
= 0;
1412 CallFrame
* callerFrame
= getCallerInfo(&callFrame
->vm(), functionCallFrame
, bytecodeOffset
, unusedCallerCodeBlock
);
1415 JSValue caller
= callerFrame
->callee();
1419 // Skip over function bindings.
1420 ASSERT(caller
.isObject());
1421 while (asObject(caller
)->inherits(&JSBoundFunction::s_info
)) {
1422 callerFrame
= getCallerInfo(&callFrame
->vm(), callerFrame
, bytecodeOffset
, unusedCallerCodeBlock
);
1425 caller
= callerFrame
->callee();
1433 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, String
& sourceURL
, JSValue
& function
) const
1435 function
= JSValue();
1437 sourceURL
= String();
1439 CallFrame
* callerFrame
= callFrame
->callerFrame();
1440 if (callerFrame
->hasHostCallFrameFlag())
1443 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
1444 if (!callerCodeBlock
)
1446 unsigned bytecodeOffset
= 0;
1447 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
1448 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
1449 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
1450 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
1451 function
= callerFrame
->callee();
1454 CallFrame
* Interpreter::findFunctionCallFrameFromVMCode(CallFrame
* callFrame
, JSFunction
* function
)
1456 for (CallFrame
* candidate
= callFrame
->trueCallFrameFromVMCode(); candidate
; candidate
= candidate
->trueCallerFrame()) {
1457 if (candidate
->callee() == function
)
1463 void Interpreter::enableSampler()
1465 #if ENABLE(OPCODE_SAMPLING)
1467 m_sampler
= adoptPtr(new SamplingTool(this));
1472 void Interpreter::dumpSampleData(ExecState
* exec
)
1474 #if ENABLE(OPCODE_SAMPLING)
1476 m_sampler
->dump(exec
);
1481 void Interpreter::startSampling()
1483 #if ENABLE(SAMPLING_THREAD)
1484 if (!m_sampleEntryDepth
)
1485 SamplingThread::start();
1487 m_sampleEntryDepth
++;
1490 void Interpreter::stopSampling()
1492 #if ENABLE(SAMPLING_THREAD)
1493 m_sampleEntryDepth
--;
1494 if (!m_sampleEntryDepth
)
1495 SamplingThread::stop();