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
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
769 debugger
->exception(debuggerCallFrame
, codeBlock
->ownerExecutable()->sourceID(), codeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
), 0, hasHandler
);
772 // Calculate an exception handler vPC, unwinding call frames as necessary.
773 HandlerInfo
* handler
= 0;
774 while (isTermination
|| !(handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
))) {
775 if (!unwindCallFrame(callFrame
, exceptionValue
, bytecodeOffset
, codeBlock
)) {
776 if (LegacyProfiler
* profiler
= callFrame
->vm().enabledProfiler())
777 profiler
->exceptionUnwind(callFrame
);
782 if (LegacyProfiler
* profiler
= callFrame
->vm().enabledProfiler())
783 profiler
->exceptionUnwind(callFrame
);
785 // Unwind the scope chain within the exception handler's call frame.
786 JSScope
* scope
= callFrame
->scope();
788 if (!codeBlock
->needsFullScopeChain() || codeBlock
->codeType() != FunctionCode
789 || callFrame
->uncheckedR(codeBlock
->activationRegister()).jsValue()) {
790 int currentDepth
= depth(codeBlock
, scope
);
791 int targetDepth
= handler
->scopeDepth
;
792 scopeDelta
= currentDepth
- targetDepth
;
793 RELEASE_ASSERT(scopeDelta
>= 0);
796 scope
= scope
->next();
797 callFrame
->setScope(scope
);
802 static inline JSValue
checkedReturn(JSValue returnValue
)
808 static inline JSObject
* checkedReturn(JSObject
* returnValue
)
814 class SamplingScope
{
816 SamplingScope(Interpreter
* interpreter
)
817 : m_interpreter(interpreter
)
819 interpreter
->startSampling();
823 m_interpreter
->stopSampling();
826 Interpreter
* m_interpreter
;
829 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, JSObject
* thisObj
)
831 SamplingScope
samplingScope(this);
833 JSScope
* scope
= callFrame
->scope();
834 VM
& vm
= *scope
->vm();
836 ASSERT(isValidThisObject(thisObj
, callFrame
));
837 ASSERT(!vm
.exception
);
838 ASSERT(!vm
.isCollectorBusy());
839 if (vm
.isCollectorBusy())
842 StackStats::CheckPoint stackCheckPoint
;
843 const StackBounds
& nativeStack
= wtfThreadData().stack();
844 StackPolicy
policy(*this, nativeStack
);
845 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
846 return checkedReturn(throwStackOverflowError(callFrame
));
848 // First check if the "program" is actually just a JSON object. If so,
849 // we'll handle the JSON object here. Else, we'll handle real JS code
850 // below at failedJSONP.
851 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
852 Vector
<JSONPData
> JSONPData
;
854 const String programSource
= program
->source().toString();
855 if (programSource
.isNull())
856 return jsUndefined();
857 if (programSource
.is8Bit()) {
858 LiteralParser
<LChar
> literalParser(callFrame
, programSource
.characters8(), programSource
.length(), JSONP
);
859 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
861 LiteralParser
<UChar
> literalParser(callFrame
, programSource
.characters16(), programSource
.length(), JSONP
);
862 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
866 JSGlobalObject
* globalObject
= scope
->globalObject();
868 for (unsigned entry
= 0; entry
< JSONPData
.size(); entry
++) {
869 Vector
<JSONPPathEntry
> JSONPPath
;
870 JSONPPath
.swap(JSONPData
[entry
].m_path
);
871 JSValue JSONPValue
= JSONPData
[entry
].m_value
.get();
872 if (JSONPPath
.size() == 1 && JSONPPath
[0].m_type
== JSONPPathEntryTypeDeclare
) {
873 if (globalObject
->hasProperty(callFrame
, JSONPPath
[0].m_pathEntryName
)) {
874 PutPropertySlot slot
;
875 globalObject
->methodTable()->put(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, slot
);
877 globalObject
->methodTable()->putDirectVirtual(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, DontEnum
| DontDelete
);
878 // var declarations return undefined
879 result
= jsUndefined();
882 JSValue
baseObject(globalObject
);
883 for (unsigned i
= 0; i
< JSONPPath
.size() - 1; i
++) {
884 ASSERT(JSONPPath
[i
].m_type
!= JSONPPathEntryTypeDeclare
);
885 switch (JSONPPath
[i
].m_type
) {
886 case JSONPPathEntryTypeDot
: {
888 PropertySlot
slot(globalObject
);
889 if (!globalObject
->getPropertySlot(callFrame
, JSONPPath
[i
].m_pathEntryName
, slot
)) {
891 return throwError(callFrame
, createUndefinedVariableError(globalObject
->globalExec(), JSONPPath
[i
].m_pathEntryName
));
894 baseObject
= slot
.getValue(callFrame
, JSONPPath
[i
].m_pathEntryName
);
896 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathEntryName
);
897 if (callFrame
->hadException())
898 return jsUndefined();
901 case JSONPPathEntryTypeLookup
: {
902 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathIndex
);
903 if (callFrame
->hadException())
904 return jsUndefined();
908 RELEASE_ASSERT_NOT_REACHED();
909 return jsUndefined();
912 PutPropertySlot slot
;
913 switch (JSONPPath
.last().m_type
) {
914 case JSONPPathEntryTypeCall
: {
915 JSValue function
= baseObject
.get(callFrame
, JSONPPath
.last().m_pathEntryName
);
916 if (callFrame
->hadException())
917 return jsUndefined();
919 CallType callType
= getCallData(function
, callData
);
920 if (callType
== CallTypeNone
)
921 return throwError(callFrame
, createNotAFunctionError(callFrame
, function
));
922 MarkedArgumentBuffer jsonArg
;
923 jsonArg
.append(JSONPValue
);
924 JSValue thisValue
= JSONPPath
.size() == 1 ? jsUndefined(): baseObject
;
925 JSONPValue
= JSC::call(callFrame
, function
, callType
, callData
, thisValue
, jsonArg
);
926 if (callFrame
->hadException())
927 return jsUndefined();
930 case JSONPPathEntryTypeDot
: {
931 baseObject
.put(callFrame
, JSONPPath
.last().m_pathEntryName
, JSONPValue
, slot
);
932 if (callFrame
->hadException())
933 return jsUndefined();
936 case JSONPPathEntryTypeLookup
: {
937 baseObject
.putByIndex(callFrame
, JSONPPath
.last().m_pathIndex
, JSONPValue
, slot
.isStrictMode());
938 if (callFrame
->hadException())
939 return jsUndefined();
943 RELEASE_ASSERT_NOT_REACHED();
944 return jsUndefined();
951 // If we get here, then we have already proven that the script is not a JSON
954 // Compile source to bytecode if necessary:
955 if (JSObject
* error
= program
->initializeGlobalProperties(vm
, callFrame
, scope
))
956 return checkedReturn(throwError(callFrame
, error
));
958 if (JSObject
* error
= program
->compile(callFrame
, scope
))
959 return checkedReturn(throwError(callFrame
, error
));
961 ProgramCodeBlock
* codeBlock
= &program
->generatedBytecode();
963 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
964 return throwTerminatedExecutionException(callFrame
);
966 // Push the call frame for this invocation:
967 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
968 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, codeBlock
, scope
, 1, 0);
969 if (UNLIKELY(!newCallFrame
))
970 return checkedReturn(throwStackOverflowError(callFrame
));
972 // Set the arguments for the callee:
973 newCallFrame
->setThisValue(thisObj
);
975 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
976 profiler
->willExecute(callFrame
, program
->sourceURL(), program
->lineNo());
981 SamplingTool::CallRecord
callRecord(m_sampler
.get());
982 Watchdog::Scope
watchdogScope(vm
.watchdog
);
984 #if ENABLE(LLINT_C_LOOP)
985 result
= LLInt::CLoop::execute(newCallFrame
, llint_program_prologue
);
987 result
= program
->generatedJITCode().execute(&m_stack
, newCallFrame
, &vm
);
988 #endif // ENABLE(JIT)
991 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
992 profiler
->didExecute(callFrame
, program
->sourceURL(), program
->lineNo());
994 m_stack
.popFrame(newCallFrame
);
996 return checkedReturn(result
);
999 JSValue
Interpreter::executeCall(CallFrame
* callFrame
, JSObject
* function
, CallType callType
, const CallData
& callData
, JSValue thisValue
, const ArgList
& args
)
1001 VM
& vm
= callFrame
->vm();
1002 ASSERT(isValidThisObject(thisValue
, callFrame
));
1003 ASSERT(!callFrame
->hadException());
1004 ASSERT(!vm
.isCollectorBusy());
1005 if (vm
.isCollectorBusy())
1008 StackStats::CheckPoint stackCheckPoint
;
1009 const StackBounds
& nativeStack
= wtfThreadData().stack();
1010 StackPolicy
policy(*this, nativeStack
);
1011 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1012 return checkedReturn(throwStackOverflowError(callFrame
));
1014 bool isJSCall
= (callType
== CallTypeJS
);
1016 CodeBlock
* newCodeBlock
;
1017 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
1020 scope
= callData
.js
.scope
;
1022 ASSERT(callType
== CallTypeHost
);
1023 scope
= callFrame
->scope();
1025 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1028 // Compile the callee:
1029 JSObject
* compileError
= callData
.js
.functionExecutable
->compileForCall(callFrame
, scope
);
1030 if (UNLIKELY(!!compileError
)) {
1031 return checkedReturn(throwError(callFrame
, compileError
));
1033 newCodeBlock
= &callData
.js
.functionExecutable
->generatedBytecodeForCall();
1034 ASSERT(!!newCodeBlock
);
1038 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1039 return throwTerminatedExecutionException(callFrame
);
1041 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, function
);
1042 if (UNLIKELY(!newCallFrame
))
1043 return checkedReturn(throwStackOverflowError(callFrame
));
1045 // Set the arguments for the callee:
1046 newCallFrame
->setThisValue(thisValue
);
1047 for (size_t i
= 0; i
< args
.size(); ++i
)
1048 newCallFrame
->setArgument(i
, args
.at(i
));
1050 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1051 profiler
->willExecute(callFrame
, function
);
1055 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSCall
);
1056 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1058 // Execute the code:
1060 #if ENABLE(LLINT_C_LOOP)
1061 result
= LLInt::CLoop::execute(newCallFrame
, llint_function_for_call_prologue
);
1063 result
= callData
.js
.functionExecutable
->generatedJITCodeForCall().execute(&m_stack
, newCallFrame
, &vm
);
1064 #endif // ENABLE(JIT)
1066 result
= JSValue::decode(callData
.native
.function(newCallFrame
));
1069 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1070 profiler
->didExecute(callFrame
, function
);
1072 m_stack
.popFrame(newCallFrame
);
1073 return checkedReturn(result
);
1076 JSObject
* Interpreter::executeConstruct(CallFrame
* callFrame
, JSObject
* constructor
, ConstructType constructType
, const ConstructData
& constructData
, const ArgList
& args
)
1078 VM
& vm
= callFrame
->vm();
1079 ASSERT(!callFrame
->hadException());
1080 ASSERT(!vm
.isCollectorBusy());
1081 // We throw in this case because we have to return something "valid" but we're
1082 // already in an invalid state.
1083 if (vm
.isCollectorBusy())
1084 return checkedReturn(throwStackOverflowError(callFrame
));
1086 StackStats::CheckPoint stackCheckPoint
;
1087 const StackBounds
& nativeStack
= wtfThreadData().stack();
1088 StackPolicy
policy(*this, nativeStack
);
1089 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1090 return checkedReturn(throwStackOverflowError(callFrame
));
1092 bool isJSConstruct
= (constructType
== ConstructTypeJS
);
1094 CodeBlock
* newCodeBlock
;
1095 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
1098 scope
= constructData
.js
.scope
;
1100 ASSERT(constructType
== ConstructTypeHost
);
1101 scope
= callFrame
->scope();
1104 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1106 if (isJSConstruct
) {
1107 // Compile the callee:
1108 JSObject
* compileError
= constructData
.js
.functionExecutable
->compileForConstruct(callFrame
, scope
);
1109 if (UNLIKELY(!!compileError
)) {
1110 return checkedReturn(throwError(callFrame
, compileError
));
1112 newCodeBlock
= &constructData
.js
.functionExecutable
->generatedBytecodeForConstruct();
1113 ASSERT(!!newCodeBlock
);
1117 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1118 return throwTerminatedExecutionException(callFrame
);
1120 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, constructor
);
1121 if (UNLIKELY(!newCallFrame
))
1122 return checkedReturn(throwStackOverflowError(callFrame
));
1124 // Set the arguments for the callee:
1125 newCallFrame
->setThisValue(jsUndefined());
1126 for (size_t i
= 0; i
< args
.size(); ++i
)
1127 newCallFrame
->setArgument(i
, args
.at(i
));
1129 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1130 profiler
->willExecute(callFrame
, constructor
);
1134 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSConstruct
);
1135 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1137 // Execute the code.
1138 if (isJSConstruct
) {
1139 #if ENABLE(LLINT_C_LOOP)
1140 result
= LLInt::CLoop::execute(newCallFrame
, llint_function_for_construct_prologue
);
1142 result
= constructData
.js
.functionExecutable
->generatedJITCodeForConstruct().execute(&m_stack
, newCallFrame
, &vm
);
1143 #endif // ENABLE(JIT)
1145 result
= JSValue::decode(constructData
.native
.function(newCallFrame
));
1148 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1149 profiler
->didExecute(callFrame
, constructor
);
1151 m_stack
.popFrame(newCallFrame
);
1153 if (callFrame
->hadException())
1155 ASSERT(result
.isObject());
1156 return checkedReturn(asObject(result
));
1159 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, JSFunction
* function
, int argumentCountIncludingThis
, JSScope
* scope
)
1161 VM
& vm
= *scope
->vm();
1162 ASSERT(!vm
.exception
);
1164 if (vm
.isCollectorBusy())
1165 return CallFrameClosure();
1167 StackStats::CheckPoint stackCheckPoint
;
1168 const StackBounds
& nativeStack
= wtfThreadData().stack();
1169 StackPolicy
policy(*this, nativeStack
);
1170 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity())) {
1171 throwStackOverflowError(callFrame
);
1172 return CallFrameClosure();
1175 // Compile the callee:
1176 JSObject
* error
= functionExecutable
->compileForCall(callFrame
, scope
);
1178 throwError(callFrame
, error
);
1179 return CallFrameClosure();
1181 CodeBlock
* newCodeBlock
= &functionExecutable
->generatedBytecodeForCall();
1183 size_t argsCount
= argumentCountIncludingThis
;
1185 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, newCodeBlock
, scope
, argsCount
, function
);
1186 if (UNLIKELY(!newCallFrame
)) {
1187 throwStackOverflowError(callFrame
);
1188 return CallFrameClosure();
1191 if (UNLIKELY(!newCallFrame
)) {
1192 throwStackOverflowError(callFrame
);
1193 return CallFrameClosure();
1196 // Return the successful closure:
1197 CallFrameClosure result
= { callFrame
, newCallFrame
, function
, functionExecutable
, &vm
, scope
, newCodeBlock
->numParameters(), argumentCountIncludingThis
};
1201 JSValue
Interpreter::execute(CallFrameClosure
& closure
)
1203 VM
& vm
= *closure
.vm
;
1204 SamplingScope
samplingScope(this);
1206 ASSERT(!vm
.isCollectorBusy());
1207 if (vm
.isCollectorBusy())
1210 StackStats::CheckPoint stackCheckPoint
;
1211 m_stack
.validateFence(closure
.newCallFrame
, "BEFORE");
1212 closure
.resetCallFrame();
1213 m_stack
.validateFence(closure
.newCallFrame
, "STEP 1");
1215 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1216 profiler
->willExecute(closure
.oldCallFrame
, closure
.function
);
1218 if (UNLIKELY(vm
.watchdog
.didFire(closure
.oldCallFrame
)))
1219 return throwTerminatedExecutionException(closure
.oldCallFrame
);
1221 // The code execution below may push more frames and point the topCallFrame
1222 // to those newer frames, or it may pop to the top frame to the caller of
1223 // the current repeat frame, or it may leave the top frame pointing to the
1224 // current repeat frame.
1226 // Hence, we need to preserve the topCallFrame here ourselves before
1227 // repeating this call on a second callback function.
1229 TopCallFrameSetter
topCallFrame(vm
, closure
.newCallFrame
);
1231 // Execute the code:
1234 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1235 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1237 #if ENABLE(LLINT_C_LOOP)
1238 result
= LLInt::CLoop::execute(closure
.newCallFrame
, llint_function_for_call_prologue
);
1240 result
= closure
.functionExecutable
->generatedJITCodeForCall().execute(&m_stack
, closure
.newCallFrame
, &vm
);
1241 #endif // ENABLE(JIT)
1244 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1245 profiler
->didExecute(closure
.oldCallFrame
, closure
.function
);
1247 m_stack
.validateFence(closure
.newCallFrame
, "AFTER");
1248 return checkedReturn(result
);
1251 void Interpreter::endRepeatCall(CallFrameClosure
& closure
)
1253 m_stack
.popFrame(closure
.newCallFrame
);
1256 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSValue thisValue
, JSScope
* scope
)
1258 VM
& vm
= *scope
->vm();
1259 SamplingScope
samplingScope(this);
1261 ASSERT(scope
->vm() == &callFrame
->vm());
1262 ASSERT(isValidThisObject(thisValue
, callFrame
));
1263 ASSERT(!vm
.exception
);
1264 ASSERT(!vm
.isCollectorBusy());
1265 if (vm
.isCollectorBusy())
1268 DynamicGlobalObjectScope
globalObjectScope(vm
, scope
->globalObject());
1270 StackStats::CheckPoint stackCheckPoint
;
1271 const StackBounds
& nativeStack
= wtfThreadData().stack();
1272 StackPolicy
policy(*this, nativeStack
);
1273 if (!nativeStack
.isSafeToRecurse(policy
.requiredCapacity()))
1274 return checkedReturn(throwStackOverflowError(callFrame
));
1276 // Compile the callee:
1277 JSObject
* compileError
= eval
->compile(callFrame
, scope
);
1278 if (UNLIKELY(!!compileError
))
1279 return checkedReturn(throwError(callFrame
, compileError
));
1280 EvalCodeBlock
* codeBlock
= &eval
->generatedBytecode();
1282 JSObject
* variableObject
;
1283 for (JSScope
* node
= scope
; ; node
= node
->next()) {
1284 RELEASE_ASSERT(node
);
1285 if (node
->isVariableObject() && !node
->isNameScopeObject()) {
1286 variableObject
= node
;
1291 unsigned numVariables
= codeBlock
->numVariables();
1292 int numFunctions
= codeBlock
->numberOfFunctionDecls();
1293 if (numVariables
|| numFunctions
) {
1294 if (codeBlock
->isStrictMode()) {
1295 scope
= StrictEvalActivation::create(callFrame
);
1296 variableObject
= scope
;
1298 // Scope for BatchedTransitionOptimizer
1299 BatchedTransitionOptimizer
optimizer(vm
, variableObject
);
1301 for (unsigned i
= 0; i
< numVariables
; ++i
) {
1302 const Identifier
& ident
= codeBlock
->variable(i
);
1303 if (!variableObject
->hasProperty(callFrame
, ident
)) {
1304 PutPropertySlot slot
;
1305 variableObject
->methodTable()->put(variableObject
, callFrame
, ident
, jsUndefined(), slot
);
1309 for (int i
= 0; i
< numFunctions
; ++i
) {
1310 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
1311 PutPropertySlot slot
;
1312 variableObject
->methodTable()->put(variableObject
, callFrame
, function
->name(), JSFunction::create(callFrame
, function
, scope
), slot
);
1316 if (UNLIKELY(vm
.watchdog
.didFire(callFrame
)))
1317 return throwTerminatedExecutionException(callFrame
);
1320 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
1321 CallFrame
* newCallFrame
= m_stack
.pushFrame(callFrame
, codeBlock
, scope
, 1, 0);
1322 if (UNLIKELY(!newCallFrame
))
1323 return checkedReturn(throwStackOverflowError(callFrame
));
1325 // Set the arguments for the callee:
1326 newCallFrame
->setThisValue(thisValue
);
1328 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1329 profiler
->willExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1331 // Execute the code:
1334 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1335 Watchdog::Scope
watchdogScope(vm
.watchdog
);
1337 #if ENABLE(LLINT_C_LOOP)
1338 result
= LLInt::CLoop::execute(newCallFrame
, llint_eval_prologue
);
1340 result
= eval
->generatedJITCode().execute(&m_stack
, newCallFrame
, &vm
);
1341 #endif // ENABLE(JIT)
1344 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1345 profiler
->didExecute(callFrame
, eval
->sourceURL(), eval
->lineNo());
1347 m_stack
.popFrame(newCallFrame
);
1348 return checkedReturn(result
);
1351 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
, int firstLine
, int lastLine
, int column
)
1353 Debugger
* debugger
= callFrame
->dynamicGlobalObject()->debugger();
1357 switch (debugHookID
) {
1358 case DidEnterCallFrame
:
1359 debugger
->callEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1361 case WillLeaveCallFrame
:
1362 debugger
->returnEvent(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1364 case WillExecuteStatement
:
1365 debugger
->atStatement(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1367 case WillExecuteProgram
:
1368 debugger
->willExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), firstLine
, column
);
1370 case DidExecuteProgram
:
1371 debugger
->didExecuteProgram(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1373 case DidReachBreakpoint
:
1374 debugger
->didReachBreakpoint(callFrame
, callFrame
->codeBlock()->ownerExecutable()->sourceID(), lastLine
, column
);
1379 JSValue
Interpreter::retrieveArgumentsFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
1381 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
1382 if (!functionCallFrame
)
1385 Arguments
* arguments
= Arguments::create(functionCallFrame
->vm(), functionCallFrame
);
1386 arguments
->tearOff(functionCallFrame
);
1387 return JSValue(arguments
);
1390 JSValue
Interpreter::retrieveCallerFromVMCode(CallFrame
* callFrame
, JSFunction
* function
) const
1392 CallFrame
* functionCallFrame
= findFunctionCallFrameFromVMCode(callFrame
, function
);
1394 if (!functionCallFrame
)
1397 unsigned bytecodeOffset
;
1398 CodeBlock
* unusedCallerCodeBlock
= 0;
1399 CallFrame
* callerFrame
= getCallerInfo(&callFrame
->vm(), functionCallFrame
, bytecodeOffset
, unusedCallerCodeBlock
);
1402 JSValue caller
= callerFrame
->callee();
1406 // Skip over function bindings.
1407 ASSERT(caller
.isObject());
1408 while (asObject(caller
)->inherits(&JSBoundFunction::s_info
)) {
1409 callerFrame
= getCallerInfo(&callFrame
->vm(), callerFrame
, bytecodeOffset
, unusedCallerCodeBlock
);
1412 caller
= callerFrame
->callee();
1420 void Interpreter::retrieveLastCaller(CallFrame
* callFrame
, int& lineNumber
, intptr_t& sourceID
, String
& sourceURL
, JSValue
& function
) const
1422 function
= JSValue();
1424 sourceURL
= String();
1426 CallFrame
* callerFrame
= callFrame
->callerFrame();
1427 if (callerFrame
->hasHostCallFrameFlag())
1430 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
1431 if (!callerCodeBlock
)
1433 unsigned bytecodeOffset
= 0;
1434 bytecodeOffset
= callerCodeBlock
->bytecodeOffset(callerFrame
, callFrame
->returnPC());
1435 lineNumber
= callerCodeBlock
->lineNumberForBytecodeOffset(bytecodeOffset
- 1);
1436 sourceID
= callerCodeBlock
->ownerExecutable()->sourceID();
1437 sourceURL
= callerCodeBlock
->ownerExecutable()->sourceURL();
1438 function
= callerFrame
->callee();
1441 CallFrame
* Interpreter::findFunctionCallFrameFromVMCode(CallFrame
* callFrame
, JSFunction
* function
)
1443 for (CallFrame
* candidate
= callFrame
->trueCallFrameFromVMCode(); candidate
; candidate
= candidate
->trueCallerFrame()) {
1444 if (candidate
->callee() == function
)
1450 void Interpreter::enableSampler()
1452 #if ENABLE(OPCODE_SAMPLING)
1454 m_sampler
= adoptPtr(new SamplingTool(this));
1459 void Interpreter::dumpSampleData(ExecState
* exec
)
1461 #if ENABLE(OPCODE_SAMPLING)
1463 m_sampler
->dump(exec
);
1468 void Interpreter::startSampling()
1470 #if ENABLE(SAMPLING_THREAD)
1471 if (!m_sampleEntryDepth
)
1472 SamplingThread::start();
1474 m_sampleEntryDepth
++;
1477 void Interpreter::stopSampling()
1479 #if ENABLE(SAMPLING_THREAD)
1480 m_sampleEntryDepth
--;
1481 if (!m_sampleEntryDepth
)
1482 SamplingThread::stop();