2 * Copyright (C) 2008, 2009, 2010, 2012-2015 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 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 "BatchedTransitionOptimizer.h"
34 #include "CallFrameClosure.h"
35 #include "CallFrameInlines.h"
36 #include "ClonedArguments.h"
37 #include "CodeBlock.h"
38 #include "DirectArguments.h"
41 #include "DebuggerCallFrame.h"
42 #include "ErrorInstance.h"
43 #include "EvalCodeCache.h"
44 #include "Exception.h"
45 #include "ExceptionHelpers.h"
46 #include "GetterSetter.h"
48 #include "JSBoundFunction.h"
49 #include "JSCInlines.h"
50 #include "JSLexicalEnvironment.h"
51 #include "JSNameScope.h"
52 #include "JSNotAnObject.h"
53 #include "JSStackInlines.h"
55 #include "JSWithScope.h"
56 #include "LLIntCLoop.h"
57 #include "LLIntThunks.h"
58 #include "LegacyProfiler.h"
59 #include "LiteralParser.h"
60 #include "ObjectPrototype.h"
62 #include "ProtoCallFrame.h"
63 #include "RegExpObject.h"
64 #include "RegExpPrototype.h"
66 #include "SamplingTool.h"
67 #include "ScopedArguments.h"
68 #include "StackAlignment.h"
69 #include "StackVisitor.h"
70 #include "StrictEvalActivation.h"
71 #include "StrongInlines.h"
73 #include "VMEntryScope.h"
74 #include "VirtualRegister.h"
78 #include <wtf/StackStats.h>
79 #include <wtf/StdLibExtras.h>
80 #include <wtf/StringPrintStream.h>
81 #include <wtf/Threading.h>
82 #include <wtf/WTFThreadData.h>
83 #include <wtf/text/StringBuilder.h>
93 String
StackFrame::friendlySourceURL() const
98 case StackFrameEvalCode
:
99 case StackFrameFunctionCode
:
100 case StackFrameGlobalCode
:
101 if (!sourceURL
.isEmpty())
102 traceLine
= sourceURL
.impl();
104 case StackFrameNativeCode
:
105 traceLine
= "[native code]";
108 return traceLine
.isNull() ? emptyString() : traceLine
;
111 String
StackFrame::friendlyFunctionName(CallFrame
* callFrame
) const
114 JSObject
* stackFrameCallee
= callee
.get();
117 case StackFrameEvalCode
:
118 traceLine
= "eval code";
120 case StackFrameNativeCode
:
122 traceLine
= getCalculatedDisplayName(callFrame
, stackFrameCallee
).impl();
124 case StackFrameFunctionCode
:
125 traceLine
= getCalculatedDisplayName(callFrame
, stackFrameCallee
).impl();
127 case StackFrameGlobalCode
:
128 traceLine
= "global code";
131 return traceLine
.isNull() ? emptyString() : traceLine
;
134 JSValue
eval(CallFrame
* callFrame
)
136 if (!callFrame
->argumentCount())
137 return jsUndefined();
139 JSValue program
= callFrame
->argument(0);
140 if (!program
.isString())
143 TopCallFrameSetter
topCallFrame(callFrame
->vm(), callFrame
);
144 String programSource
= asString(program
)->value(callFrame
);
145 if (callFrame
->hadException())
148 CallFrame
* callerFrame
= callFrame
->callerFrame();
149 CodeBlock
* callerCodeBlock
= callerFrame
->codeBlock();
150 JSScope
* callerScopeChain
= callerFrame
->uncheckedR(callerCodeBlock
->scopeRegister().offset()).Register::scope();
151 EvalExecutable
* eval
= callerCodeBlock
->evalCodeCache().tryGet(callerCodeBlock
->isStrictMode(), programSource
, callerScopeChain
);
154 if (!callerCodeBlock
->isStrictMode()) {
155 if (programSource
.is8Bit()) {
156 LiteralParser
<LChar
> preparser(callFrame
, programSource
.characters8(), programSource
.length(), NonStrictJSON
);
157 if (JSValue parsedObject
= preparser
.tryLiteralParse())
160 LiteralParser
<UChar
> preparser(callFrame
, programSource
.characters16(), programSource
.length(), NonStrictJSON
);
161 if (JSValue parsedObject
= preparser
.tryLiteralParse())
166 // If the literal parser bailed, it should not have thrown exceptions.
167 ASSERT(!callFrame
->vm().exception());
169 ThisTDZMode thisTDZMode
= callerCodeBlock
->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived
? ThisTDZMode::AlwaysCheck
: ThisTDZMode::CheckIfNeeded
;
170 eval
= callerCodeBlock
->evalCodeCache().getSlow(callFrame
, callerCodeBlock
->ownerExecutable(), callerCodeBlock
->isStrictMode(), thisTDZMode
, programSource
, callerScopeChain
);
172 return jsUndefined();
175 JSValue thisValue
= callerFrame
->thisValue();
176 Interpreter
* interpreter
= callFrame
->vm().interpreter
;
177 return interpreter
->execute(eval
, callFrame
, thisValue
, callerScopeChain
);
180 unsigned sizeOfVarargs(CallFrame
* callFrame
, JSValue arguments
, uint32_t firstVarArgOffset
)
182 if (UNLIKELY(!arguments
.isCell())) {
183 if (arguments
.isUndefinedOrNull())
186 callFrame
->vm().throwException(callFrame
, createInvalidFunctionApplyParameterError(callFrame
, arguments
));
190 JSCell
* cell
= arguments
.asCell();
192 switch (cell
->type()) {
193 case DirectArgumentsType
:
194 length
= jsCast
<DirectArguments
*>(cell
)->length(callFrame
);
196 case ScopedArgumentsType
:
197 length
=jsCast
<ScopedArguments
*>(cell
)->length(callFrame
);
200 callFrame
->vm().throwException(callFrame
, createInvalidFunctionApplyParameterError(callFrame
, arguments
));
203 ASSERT(arguments
.isObject());
205 length
= jsCast
<JSArray
*>(cell
)->length();
207 length
= jsCast
<JSObject
*>(cell
)->get(callFrame
, callFrame
->propertyNames().length
).toUInt32(callFrame
);
211 if (length
>= firstVarArgOffset
)
212 length
-= firstVarArgOffset
;
219 unsigned sizeFrameForVarargs(CallFrame
* callFrame
, JSStack
* stack
, JSValue arguments
, unsigned numUsedStackSlots
, uint32_t firstVarArgOffset
)
221 unsigned length
= sizeOfVarargs(callFrame
, arguments
, firstVarArgOffset
);
223 CallFrame
* calleeFrame
= calleeFrameForVarargs(callFrame
, numUsedStackSlots
, length
+ 1);
224 if (length
> maxArguments
|| !stack
->ensureCapacityFor(calleeFrame
->registers())) {
225 throwStackOverflowError(callFrame
);
232 void loadVarargs(CallFrame
* callFrame
, VirtualRegister firstElementDest
, JSValue arguments
, uint32_t offset
, uint32_t length
)
234 if (UNLIKELY(!arguments
.isCell()))
237 JSCell
* cell
= arguments
.asCell();
238 switch (cell
->type()) {
239 case DirectArgumentsType
:
240 jsCast
<DirectArguments
*>(cell
)->copyToArguments(callFrame
, firstElementDest
, offset
, length
);
242 case ScopedArgumentsType
:
243 jsCast
<ScopedArguments
*>(cell
)->copyToArguments(callFrame
, firstElementDest
, offset
, length
);
246 ASSERT(arguments
.isObject());
247 JSObject
* object
= jsCast
<JSObject
*>(cell
);
248 if (isJSArray(object
)) {
249 jsCast
<JSArray
*>(object
)->copyToArguments(callFrame
, firstElementDest
, offset
, length
);
253 for (i
= 0; i
< length
&& object
->canGetIndexQuickly(i
+ offset
); ++i
)
254 callFrame
->r(firstElementDest
+ i
) = object
->getIndexQuickly(i
+ offset
);
255 for (; i
< length
; ++i
)
256 callFrame
->r(firstElementDest
+ i
) = object
->get(callFrame
, i
+ offset
);
261 void setupVarargsFrame(CallFrame
* callFrame
, CallFrame
* newCallFrame
, JSValue arguments
, uint32_t offset
, uint32_t length
)
263 VirtualRegister
calleeFrameOffset(newCallFrame
- callFrame
);
267 calleeFrameOffset
+ CallFrame::argumentOffset(0),
268 arguments
, offset
, length
);
270 newCallFrame
->setArgumentCountIncludingThis(length
+ 1);
273 void setupVarargsFrameAndSetThis(CallFrame
* callFrame
, CallFrame
* newCallFrame
, JSValue thisValue
, JSValue arguments
, uint32_t firstVarArgOffset
, uint32_t length
)
275 setupVarargsFrame(callFrame
, newCallFrame
, arguments
, firstVarArgOffset
, length
);
276 newCallFrame
->setThisValue(thisValue
);
279 Interpreter::Interpreter(VM
& vm
)
280 : m_sampleEntryDepth(0)
283 , m_errorHandlingModeReentry(0)
285 , m_initialized(false)
290 Interpreter::~Interpreter()
294 void Interpreter::initialize(bool canUseJIT
)
296 UNUSED_PARAM(canUseJIT
);
298 #if ENABLE(COMPUTED_GOTO_OPCODES)
299 m_opcodeTable
= LLInt::opcodeMap();
300 for (int i
= 0; i
< numOpcodeIDs
; ++i
)
301 m_opcodeIDTable
.add(m_opcodeTable
[i
], static_cast<OpcodeID
>(i
));
305 m_initialized
= true;
308 #if ENABLE(OPCODE_SAMPLING)
315 void Interpreter::dumpCallFrame(CallFrame
*)
321 void Interpreter::dumpCallFrame(CallFrame
* callFrame
)
323 callFrame
->codeBlock()->dumpBytecode();
324 dumpRegisters(callFrame
);
327 class DumpRegisterFunctor
{
329 DumpRegisterFunctor(const Register
*& it
)
330 : m_hasSkippedFirstFrame(false)
335 StackVisitor::Status
operator()(StackVisitor
& visitor
)
337 if (!m_hasSkippedFirstFrame
) {
338 m_hasSkippedFirstFrame
= true;
339 return StackVisitor::Continue
;
343 unsigned unusedColumn
= 0;
344 visitor
->computeLineAndColumn(line
, unusedColumn
);
345 dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", m_it
, visitor
->bytecodeOffset(), line
);
347 return StackVisitor::Done
;
351 bool m_hasSkippedFirstFrame
;
352 const Register
*& m_it
;
355 void Interpreter::dumpRegisters(CallFrame
* callFrame
)
357 dataLogF("Register frame: \n\n");
358 dataLogF("-----------------------------------------------------------------------------\n");
359 dataLogF(" use | address | value \n");
360 dataLogF("-----------------------------------------------------------------------------\n");
362 CodeBlock
* codeBlock
= callFrame
->codeBlock();
366 it
= callFrame
->registers() + JSStack::ThisArgument
+ callFrame
->argumentCount();
367 end
= callFrame
->registers() + JSStack::ThisArgument
- 1;
369 JSValue v
= it
->jsValue();
370 int registerNumber
= it
- callFrame
->registers();
371 String name
= codeBlock
->nameForRegister(VirtualRegister(registerNumber
));
372 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber
, name
.ascii().data(), it
, toCString(v
).data(), (long long)JSValue::encode(v
));
376 dataLogF("-----------------------------------------------------------------------------\n");
377 dataLogF("[ArgumentCount] | %10p | %lu \n", it
, (unsigned long) callFrame
->argumentCount());
379 dataLogF("[CallerFrame] | %10p | %p \n", it
, callFrame
->callerFrame());
381 dataLogF("[Callee] | %10p | %p \n", it
, callFrame
->callee());
383 // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header
386 AbstractPC pc
= callFrame
->abstractReturnPC(callFrame
->vm());
387 if (pc
.hasJITReturnAddress())
388 dataLogF("[ReturnJITPC] | %10p | %p \n", it
, pc
.jitReturnAddress().value());
391 DumpRegisterFunctor
functor(it
);
392 callFrame
->iterate(functor
);
394 dataLogF("[CodeBlock] | %10p | %p \n", it
, callFrame
->codeBlock());
396 dataLogF("-----------------------------------------------------------------------------\n");
398 end
= it
- codeBlock
->m_numVars
;
401 JSValue v
= it
->jsValue();
402 int registerNumber
= it
- callFrame
->registers();
403 String name
= codeBlock
->nameForRegister(VirtualRegister(registerNumber
));
404 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber
, name
.ascii().data(), it
, toCString(v
).data(), (long long)JSValue::encode(v
));
408 dataLogF("-----------------------------------------------------------------------------\n");
410 end
= it
- codeBlock
->m_numCalleeRegisters
+ codeBlock
->m_numVars
;
413 JSValue v
= (*it
).jsValue();
414 int registerNumber
= it
- callFrame
->registers();
415 dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerNumber
, it
, toCString(v
).data(), (long long)JSValue::encode(v
));
419 dataLogF("-----------------------------------------------------------------------------\n");
424 bool Interpreter::isOpcode(Opcode opcode
)
426 #if ENABLE(COMPUTED_GOTO_OPCODES)
427 return opcode
!= HashTraits
<Opcode
>::emptyValue()
428 && !HashTraits
<Opcode
>::isDeletedValue(opcode
)
429 && m_opcodeIDTable
.contains(opcode
);
431 return opcode
>= 0 && opcode
<= op_end
;
435 static bool unwindCallFrame(StackVisitor
& visitor
)
437 CallFrame
* callFrame
= visitor
->callFrame();
438 if (Debugger
* debugger
= callFrame
->vmEntryGlobalObject()->debugger()) {
439 SuspendExceptionScope
scope(&callFrame
->vm());
440 if (jsDynamicCast
<JSFunction
*>(callFrame
->callee()))
441 debugger
->returnEvent(callFrame
);
443 debugger
->didExecuteProgram(callFrame
);
444 ASSERT(!callFrame
->hadException());
447 return !visitor
->callerIsVMEntryFrame();
450 static StackFrameCodeType
getStackFrameCodeType(StackVisitor
& visitor
)
452 switch (visitor
->codeType()) {
453 case StackVisitor::Frame::Eval
:
454 return StackFrameEvalCode
;
455 case StackVisitor::Frame::Function
:
456 return StackFrameFunctionCode
;
457 case StackVisitor::Frame::Global
:
458 return StackFrameGlobalCode
;
459 case StackVisitor::Frame::Native
:
460 ASSERT_NOT_REACHED();
461 return StackFrameNativeCode
;
463 RELEASE_ASSERT_NOT_REACHED();
464 return StackFrameGlobalCode
;
467 void StackFrame::computeLineAndColumn(unsigned& line
, unsigned& column
)
476 int unusedStartOffset
= 0;
477 int unusedEndOffset
= 0;
478 unsigned divotLine
= 0;
479 unsigned divotColumn
= 0;
480 expressionInfo(divot
, unusedStartOffset
, unusedEndOffset
, divotLine
, divotColumn
);
482 line
= divotLine
+ lineOffset
;
483 column
= divotColumn
+ (divotLine
? 1 : firstLineColumnOffset
);
485 if (executable
->hasOverrideLineNumber())
486 line
= executable
->overrideLineNumber();
489 void StackFrame::expressionInfo(int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
491 codeBlock
->expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
492 divot
+= characterOffset
;
495 String
StackFrame::toString(CallFrame
* callFrame
)
497 StringBuilder traceBuild
;
498 String functionName
= friendlyFunctionName(callFrame
);
499 String sourceURL
= friendlySourceURL();
500 traceBuild
.append(functionName
);
501 if (!sourceURL
.isEmpty()) {
502 if (!functionName
.isEmpty())
503 traceBuild
.append('@');
504 traceBuild
.append(sourceURL
);
505 if (codeType
!= StackFrameNativeCode
) {
508 computeLineAndColumn(line
, column
);
510 traceBuild
.append(':');
511 traceBuild
.appendNumber(line
);
512 traceBuild
.append(':');
513 traceBuild
.appendNumber(column
);
516 return traceBuild
.toString().impl();
519 class GetStackTraceFunctor
{
521 GetStackTraceFunctor(VM
& vm
, Vector
<StackFrame
>& results
, size_t remainingCapacity
)
524 , m_remainingCapacityForFrameCapture(remainingCapacity
)
528 StackVisitor::Status
operator()(StackVisitor
& visitor
)
531 if (m_remainingCapacityForFrameCapture
) {
532 if (visitor
->isJSFrame() && !visitor
->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
533 CodeBlock
* codeBlock
= visitor
->codeBlock();
535 Strong
<JSObject
>(vm
, visitor
->callee()),
536 getStackFrameCodeType(visitor
),
537 Strong
<ScriptExecutable
>(vm
, codeBlock
->ownerExecutable()),
538 Strong
<UnlinkedCodeBlock
>(vm
, codeBlock
->unlinkedCodeBlock()),
540 codeBlock
->ownerExecutable()->firstLine(),
541 codeBlock
->firstLineColumnOffset(),
542 codeBlock
->sourceOffset(),
543 visitor
->bytecodeOffset(),
548 StackFrame s
= { Strong
<JSObject
>(vm
, visitor
->callee()), StackFrameNativeCode
, Strong
<ScriptExecutable
>(), Strong
<UnlinkedCodeBlock
>(), 0, 0, 0, 0, 0, String()};
552 m_remainingCapacityForFrameCapture
--;
553 return StackVisitor::Continue
;
555 return StackVisitor::Done
;
560 Vector
<StackFrame
>& m_results
;
561 size_t m_remainingCapacityForFrameCapture
;
564 void Interpreter::getStackTrace(Vector
<StackFrame
>& results
, size_t maxStackSize
)
567 CallFrame
* callFrame
= vm
.topCallFrame
;
571 GetStackTraceFunctor
functor(vm
, results
, maxStackSize
);
572 callFrame
->iterate(functor
);
575 JSString
* Interpreter::stackTraceAsString(ExecState
* exec
, Vector
<StackFrame
> stackTrace
)
577 // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
578 StringBuilder builder
;
579 for (unsigned i
= 0; i
< stackTrace
.size(); i
++) {
580 builder
.append(String(stackTrace
[i
].toString(exec
)));
581 if (i
!= stackTrace
.size() - 1)
582 builder
.append('\n');
584 return jsString(&exec
->vm(), builder
.toString());
587 class GetCatchHandlerFunctor
{
589 GetCatchHandlerFunctor()
594 HandlerInfo
* handler() { return m_handler
; }
596 StackVisitor::Status
operator()(StackVisitor
& visitor
)
598 CodeBlock
* codeBlock
= visitor
->codeBlock();
600 return StackVisitor::Continue
;
602 unsigned bytecodeOffset
= visitor
->bytecodeOffset();
603 m_handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
, CodeBlock::RequiredHandler::CatchHandler
);
605 return StackVisitor::Done
;
607 return StackVisitor::Continue
;
611 HandlerInfo
* m_handler
;
614 class UnwindFunctor
{
616 UnwindFunctor(VMEntryFrame
*& vmEntryFrame
, CallFrame
*& callFrame
, bool isTermination
, CodeBlock
*& codeBlock
, HandlerInfo
*& handler
)
617 : m_vmEntryFrame(vmEntryFrame
)
618 , m_callFrame(callFrame
)
619 , m_isTermination(isTermination
)
620 , m_codeBlock(codeBlock
)
625 StackVisitor::Status
operator()(StackVisitor
& visitor
)
627 VM
& vm
= m_callFrame
->vm();
628 m_vmEntryFrame
= visitor
->vmEntryFrame();
629 m_callFrame
= visitor
->callFrame();
630 m_codeBlock
= visitor
->codeBlock();
631 unsigned bytecodeOffset
= visitor
->bytecodeOffset();
633 if (m_isTermination
|| !(m_handler
= m_codeBlock
? m_codeBlock
->handlerForBytecodeOffset(bytecodeOffset
) : nullptr)) {
634 if (!unwindCallFrame(visitor
)) {
635 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
636 profiler
->exceptionUnwind(m_callFrame
);
637 return StackVisitor::Done
;
640 return StackVisitor::Done
;
642 return StackVisitor::Continue
;
646 VMEntryFrame
*& m_vmEntryFrame
;
647 CallFrame
*& m_callFrame
;
648 bool m_isTermination
;
649 CodeBlock
*& m_codeBlock
;
650 HandlerInfo
*& m_handler
;
653 NEVER_INLINE HandlerInfo
* Interpreter::unwind(VMEntryFrame
*& vmEntryFrame
, CallFrame
*& callFrame
, Exception
* exception
)
655 CodeBlock
* codeBlock
= callFrame
->codeBlock();
656 bool isTermination
= false;
658 JSValue exceptionValue
= exception
->value();
659 ASSERT(!exceptionValue
.isEmpty());
660 ASSERT(!exceptionValue
.isCell() || exceptionValue
.asCell());
661 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
662 // slow cases, so let's harden against it anyway to be safe.
663 if (exceptionValue
.isEmpty() || (exceptionValue
.isCell() && !exceptionValue
.asCell()))
664 exceptionValue
= jsNull();
666 if (exceptionValue
.isObject())
667 isTermination
= isTerminatedExecutionException(exception
);
669 ASSERT(callFrame
->vm().exception() && callFrame
->vm().exception()->stack().size());
671 Debugger
* debugger
= callFrame
->vmEntryGlobalObject()->debugger();
672 if (debugger
&& debugger
->needsExceptionCallbacks() && !exception
->didNotifyInspectorOfThrow()) {
673 // We need to clear the exception here in order to see if a new exception happens.
674 // Afterwards, the values are put back to continue processing this error.
675 SuspendExceptionScope
scope(&callFrame
->vm());
676 // This code assumes that if the debugger is enabled then there is no inlining.
677 // If that assumption turns out to be false then we'll ignore the inlined call
679 // https://bugs.webkit.org/show_bug.cgi?id=121754
681 bool hasCatchHandler
;
683 hasCatchHandler
= false;
685 GetCatchHandlerFunctor functor
;
686 callFrame
->iterate(functor
);
687 HandlerInfo
* handler
= functor
.handler();
688 ASSERT(!handler
|| handler
->isCatchHandler());
689 hasCatchHandler
= !!handler
;
692 debugger
->exception(callFrame
, exceptionValue
, hasCatchHandler
);
693 ASSERT(!callFrame
->hadException());
695 exception
->setDidNotifyInspectorOfThrow();
697 // Calculate an exception handler vPC, unwinding call frames as necessary.
698 HandlerInfo
* handler
= 0;
699 VM
& vm
= callFrame
->vm();
700 ASSERT(callFrame
== vm
.topCallFrame
);
701 UnwindFunctor
functor(vmEntryFrame
, callFrame
, isTermination
, codeBlock
, handler
);
702 callFrame
->iterate(functor
);
706 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
707 profiler
->exceptionUnwind(callFrame
);
709 // Unwind the scope chain within the exception handler's call frame.
710 int targetScopeDepth
= handler
->scopeDepth
;
711 if (codeBlock
->needsActivation() && callFrame
->hasActivation())
714 int scopeRegisterOffset
= codeBlock
->scopeRegister().offset();
715 JSScope
* scope
= callFrame
->scope(scopeRegisterOffset
);
716 int scopeDelta
= scope
->depth() - targetScopeDepth
;
717 RELEASE_ASSERT(scopeDelta
>= 0);
720 scope
= scope
->next();
722 callFrame
->setScope(scopeRegisterOffset
, scope
);
727 static inline JSValue
checkedReturn(JSValue returnValue
)
733 static inline JSObject
* checkedReturn(JSObject
* returnValue
)
739 class SamplingScope
{
741 SamplingScope(Interpreter
* interpreter
)
742 : m_interpreter(interpreter
)
744 interpreter
->startSampling();
748 m_interpreter
->stopSampling();
751 Interpreter
* m_interpreter
;
754 JSValue
Interpreter::execute(ProgramExecutable
* program
, CallFrame
* callFrame
, JSObject
* thisObj
)
756 SamplingScope
samplingScope(this);
758 JSScope
* scope
= thisObj
->globalObject();
759 VM
& vm
= *scope
->vm();
761 ASSERT(!vm
.exception());
762 ASSERT(!vm
.isCollectorBusy());
763 RELEASE_ASSERT(vm
.currentThreadIsHoldingAPILock());
764 if (vm
.isCollectorBusy())
767 if (!vm
.isSafeToRecurse())
768 return checkedReturn(throwStackOverflowError(callFrame
));
770 // First check if the "program" is actually just a JSON object. If so,
771 // we'll handle the JSON object here. Else, we'll handle real JS code
772 // below at failedJSONP.
774 Vector
<JSONPData
> JSONPData
;
776 const String programSource
= program
->source().toString();
777 if (programSource
.isNull())
778 return jsUndefined();
779 if (programSource
.is8Bit()) {
780 LiteralParser
<LChar
> literalParser(callFrame
, programSource
.characters8(), programSource
.length(), JSONP
);
781 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
783 LiteralParser
<UChar
> literalParser(callFrame
, programSource
.characters16(), programSource
.length(), JSONP
);
784 parseResult
= literalParser
.tryJSONPParse(JSONPData
, scope
->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope
->globalObject()));
788 JSGlobalObject
* globalObject
= scope
->globalObject();
790 for (unsigned entry
= 0; entry
< JSONPData
.size(); entry
++) {
791 Vector
<JSONPPathEntry
> JSONPPath
;
792 JSONPPath
.swap(JSONPData
[entry
].m_path
);
793 JSValue JSONPValue
= JSONPData
[entry
].m_value
.get();
794 if (JSONPPath
.size() == 1 && JSONPPath
[0].m_type
== JSONPPathEntryTypeDeclare
) {
795 globalObject
->addVar(callFrame
, JSONPPath
[0].m_pathEntryName
);
796 PutPropertySlot
slot(globalObject
);
797 globalObject
->methodTable()->put(globalObject
, callFrame
, JSONPPath
[0].m_pathEntryName
, JSONPValue
, slot
);
798 result
= jsUndefined();
801 JSValue
baseObject(globalObject
);
802 for (unsigned i
= 0; i
< JSONPPath
.size() - 1; i
++) {
803 ASSERT(JSONPPath
[i
].m_type
!= JSONPPathEntryTypeDeclare
);
804 switch (JSONPPath
[i
].m_type
) {
805 case JSONPPathEntryTypeDot
: {
807 PropertySlot
slot(globalObject
);
808 if (!globalObject
->getPropertySlot(callFrame
, JSONPPath
[i
].m_pathEntryName
, slot
)) {
810 return callFrame
->vm().throwException(callFrame
, createUndefinedVariableError(callFrame
, JSONPPath
[i
].m_pathEntryName
));
813 baseObject
= slot
.getValue(callFrame
, JSONPPath
[i
].m_pathEntryName
);
815 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathEntryName
);
816 if (callFrame
->hadException())
817 return jsUndefined();
820 case JSONPPathEntryTypeLookup
: {
821 baseObject
= baseObject
.get(callFrame
, JSONPPath
[i
].m_pathIndex
);
822 if (callFrame
->hadException())
823 return jsUndefined();
827 RELEASE_ASSERT_NOT_REACHED();
828 return jsUndefined();
831 PutPropertySlot
slot(baseObject
);
832 switch (JSONPPath
.last().m_type
) {
833 case JSONPPathEntryTypeCall
: {
834 JSValue function
= baseObject
.get(callFrame
, JSONPPath
.last().m_pathEntryName
);
835 if (callFrame
->hadException())
836 return jsUndefined();
838 CallType callType
= getCallData(function
, callData
);
839 if (callType
== CallTypeNone
)
840 return callFrame
->vm().throwException(callFrame
, createNotAFunctionError(callFrame
, function
));
841 MarkedArgumentBuffer jsonArg
;
842 jsonArg
.append(JSONPValue
);
843 JSValue thisValue
= JSONPPath
.size() == 1 ? jsUndefined(): baseObject
;
844 JSONPValue
= JSC::call(callFrame
, function
, callType
, callData
, thisValue
, jsonArg
);
845 if (callFrame
->hadException())
846 return jsUndefined();
849 case JSONPPathEntryTypeDot
: {
850 baseObject
.put(callFrame
, JSONPPath
.last().m_pathEntryName
, JSONPValue
, slot
);
851 if (callFrame
->hadException())
852 return jsUndefined();
855 case JSONPPathEntryTypeLookup
: {
856 baseObject
.putByIndex(callFrame
, JSONPPath
.last().m_pathIndex
, JSONPValue
, slot
.isStrictMode());
857 if (callFrame
->hadException())
858 return jsUndefined();
862 RELEASE_ASSERT_NOT_REACHED();
863 return jsUndefined();
870 // If we get here, then we have already proven that the script is not a JSON
873 VMEntryScope
entryScope(vm
, scope
->globalObject());
875 // Compile source to bytecode if necessary:
876 if (JSObject
* error
= program
->initializeGlobalProperties(vm
, callFrame
, scope
))
877 return checkedReturn(callFrame
->vm().throwException(callFrame
, error
));
879 if (JSObject
* error
= program
->prepareForExecution(callFrame
, nullptr, scope
, CodeForCall
))
880 return checkedReturn(callFrame
->vm().throwException(callFrame
, error
));
882 ProgramCodeBlock
* codeBlock
= program
->codeBlock();
884 if (UNLIKELY(vm
.watchdog
&& vm
.watchdog
->didFire(callFrame
)))
885 return throwTerminatedExecutionException(callFrame
);
887 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
889 ProtoCallFrame protoCallFrame
;
890 protoCallFrame
.init(codeBlock
, JSCallee::create(vm
, scope
->globalObject(), scope
), thisObj
, 1);
892 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
893 profiler
->willExecute(callFrame
, program
->sourceURL(), program
->firstLine(), program
->startColumn());
898 SamplingTool::CallRecord
callRecord(m_sampler
.get());
899 Watchdog::Scope
watchdogScope(vm
.watchdog
.get());
901 result
= program
->generatedJITCode()->execute(&vm
, &protoCallFrame
);
904 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
905 profiler
->didExecute(callFrame
, program
->sourceURL(), program
->firstLine(), program
->startColumn());
907 return checkedReturn(result
);
910 JSValue
Interpreter::executeCall(CallFrame
* callFrame
, JSObject
* function
, CallType callType
, const CallData
& callData
, JSValue thisValue
, const ArgList
& args
)
912 VM
& vm
= callFrame
->vm();
913 ASSERT(!callFrame
->hadException());
914 ASSERT(!vm
.isCollectorBusy());
915 if (vm
.isCollectorBusy())
918 bool isJSCall
= (callType
== CallTypeJS
);
919 JSScope
* scope
= nullptr;
920 CodeBlock
* newCodeBlock
;
921 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
923 JSGlobalObject
* globalObject
;
926 scope
= callData
.js
.scope
;
927 globalObject
= scope
->globalObject();
929 ASSERT(callType
== CallTypeHost
);
930 globalObject
= function
->globalObject();
933 VMEntryScope
entryScope(vm
, globalObject
);
934 if (!vm
.isSafeToRecurse())
935 return checkedReturn(throwStackOverflowError(callFrame
));
938 // Compile the callee:
939 JSObject
* compileError
= callData
.js
.functionExecutable
->prepareForExecution(callFrame
, jsCast
<JSFunction
*>(function
), scope
, CodeForCall
);
940 if (UNLIKELY(!!compileError
)) {
941 return checkedReturn(callFrame
->vm().throwException(callFrame
, compileError
));
943 newCodeBlock
= callData
.js
.functionExecutable
->codeBlockForCall();
944 ASSERT(!!newCodeBlock
);
945 newCodeBlock
->m_shouldAlwaysBeInlined
= false;
949 if (UNLIKELY(vm
.watchdog
&& vm
.watchdog
->didFire(callFrame
)))
950 return throwTerminatedExecutionException(callFrame
);
952 ProtoCallFrame protoCallFrame
;
953 protoCallFrame
.init(newCodeBlock
, function
, thisValue
, argsCount
, args
.data());
955 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
956 profiler
->willExecute(callFrame
, function
);
960 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSCall
);
961 Watchdog::Scope
watchdogScope(vm
.watchdog
.get());
965 result
= callData
.js
.functionExecutable
->generatedJITCodeForCall()->execute(&vm
, &protoCallFrame
);
967 result
= JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(callData
.native
.function
), &vm
, &protoCallFrame
));
968 if (callFrame
->hadException())
973 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
974 profiler
->didExecute(callFrame
, function
);
976 return checkedReturn(result
);
979 JSObject
* Interpreter::executeConstruct(CallFrame
* callFrame
, JSObject
* constructor
, ConstructType constructType
, const ConstructData
& constructData
, const ArgList
& args
)
981 VM
& vm
= callFrame
->vm();
982 ASSERT(!callFrame
->hadException());
983 ASSERT(!vm
.isCollectorBusy());
984 // We throw in this case because we have to return something "valid" but we're
985 // already in an invalid state.
986 if (vm
.isCollectorBusy())
987 return checkedReturn(throwStackOverflowError(callFrame
));
989 bool isJSConstruct
= (constructType
== ConstructTypeJS
);
990 JSScope
* scope
= nullptr;
991 CodeBlock
* newCodeBlock
;
992 size_t argsCount
= 1 + args
.size(); // implicit "this" parameter
994 JSGlobalObject
* globalObject
;
997 scope
= constructData
.js
.scope
;
998 globalObject
= scope
->globalObject();
1000 ASSERT(constructType
== ConstructTypeHost
);
1001 globalObject
= constructor
->globalObject();
1004 VMEntryScope
entryScope(vm
, globalObject
);
1005 if (!vm
.isSafeToRecurse())
1006 return checkedReturn(throwStackOverflowError(callFrame
));
1008 if (isJSConstruct
) {
1009 // Compile the callee:
1010 JSObject
* compileError
= constructData
.js
.functionExecutable
->prepareForExecution(callFrame
, jsCast
<JSFunction
*>(constructor
), scope
, CodeForConstruct
);
1011 if (UNLIKELY(!!compileError
)) {
1012 return checkedReturn(callFrame
->vm().throwException(callFrame
, compileError
));
1014 newCodeBlock
= constructData
.js
.functionExecutable
->codeBlockForConstruct();
1015 ASSERT(!!newCodeBlock
);
1016 newCodeBlock
->m_shouldAlwaysBeInlined
= false;
1020 if (UNLIKELY(vm
.watchdog
&& vm
.watchdog
->didFire(callFrame
)))
1021 return throwTerminatedExecutionException(callFrame
);
1023 ProtoCallFrame protoCallFrame
;
1024 protoCallFrame
.init(newCodeBlock
, constructor
, constructor
, argsCount
, args
.data());
1026 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1027 profiler
->willExecute(callFrame
, constructor
);
1031 SamplingTool::CallRecord
callRecord(m_sampler
.get(), !isJSConstruct
);
1032 Watchdog::Scope
watchdogScope(vm
.watchdog
.get());
1034 // Execute the code.
1036 result
= constructData
.js
.functionExecutable
->generatedJITCodeForConstruct()->execute(&vm
, &protoCallFrame
);
1038 result
= JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData
.native
.function
), &vm
, &protoCallFrame
));
1040 if (!callFrame
->hadException())
1041 RELEASE_ASSERT(result
.isObject());
1045 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1046 profiler
->didExecute(callFrame
, constructor
);
1048 if (callFrame
->hadException())
1050 ASSERT(result
.isObject());
1051 return checkedReturn(asObject(result
));
1054 CallFrameClosure
Interpreter::prepareForRepeatCall(FunctionExecutable
* functionExecutable
, CallFrame
* callFrame
, ProtoCallFrame
* protoCallFrame
, JSFunction
* function
, int argumentCountIncludingThis
, JSScope
* scope
, JSValue
* args
)
1056 VM
& vm
= *scope
->vm();
1057 ASSERT(!vm
.exception());
1059 if (vm
.isCollectorBusy())
1060 return CallFrameClosure();
1062 // Compile the callee:
1063 JSObject
* error
= functionExecutable
->prepareForExecution(callFrame
, function
, scope
, CodeForCall
);
1065 callFrame
->vm().throwException(callFrame
, error
);
1066 return CallFrameClosure();
1068 CodeBlock
* newCodeBlock
= functionExecutable
->codeBlockForCall();
1069 newCodeBlock
->m_shouldAlwaysBeInlined
= false;
1071 size_t argsCount
= argumentCountIncludingThis
;
1073 protoCallFrame
->init(newCodeBlock
, function
, jsUndefined(), argsCount
, args
);
1074 // Return the successful closure:
1075 CallFrameClosure result
= { callFrame
, protoCallFrame
, function
, functionExecutable
, &vm
, scope
, newCodeBlock
->numParameters(), argumentCountIncludingThis
};
1079 JSValue
Interpreter::execute(CallFrameClosure
& closure
)
1081 VM
& vm
= *closure
.vm
;
1082 SamplingScope
samplingScope(this);
1084 ASSERT(!vm
.isCollectorBusy());
1085 RELEASE_ASSERT(vm
.currentThreadIsHoldingAPILock());
1086 if (vm
.isCollectorBusy())
1089 StackStats::CheckPoint stackCheckPoint
;
1091 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1092 profiler
->willExecute(closure
.oldCallFrame
, closure
.function
);
1094 if (UNLIKELY(vm
.watchdog
&& vm
.watchdog
->didFire(closure
.oldCallFrame
)))
1095 return throwTerminatedExecutionException(closure
.oldCallFrame
);
1097 // Execute the code:
1100 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1101 Watchdog::Scope
watchdogScope(vm
.watchdog
.get());
1103 result
= closure
.functionExecutable
->generatedJITCodeForCall()->execute(&vm
, closure
.protoCallFrame
);
1106 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1107 profiler
->didExecute(closure
.oldCallFrame
, closure
.function
);
1109 return checkedReturn(result
);
1112 JSValue
Interpreter::execute(EvalExecutable
* eval
, CallFrame
* callFrame
, JSValue thisValue
, JSScope
* scope
)
1114 VM
& vm
= *scope
->vm();
1115 SamplingScope
samplingScope(this);
1117 ASSERT(scope
->vm() == &callFrame
->vm());
1118 ASSERT(!vm
.exception());
1119 ASSERT(!vm
.isCollectorBusy());
1120 RELEASE_ASSERT(vm
.currentThreadIsHoldingAPILock());
1121 if (vm
.isCollectorBusy())
1124 VMEntryScope
entryScope(vm
, scope
->globalObject());
1125 if (!vm
.isSafeToRecurse())
1126 return checkedReturn(throwStackOverflowError(callFrame
));
1128 unsigned numVariables
= eval
->numVariables();
1129 int numFunctions
= eval
->numberOfFunctionDecls();
1131 JSScope
* variableObject
;
1132 if ((numVariables
|| numFunctions
) && eval
->isStrictMode()) {
1133 scope
= StrictEvalActivation::create(callFrame
, scope
);
1134 variableObject
= scope
;
1136 for (JSScope
* node
= scope
; ; node
= node
->next()) {
1137 RELEASE_ASSERT(node
);
1138 if (node
->isVariableObject()) {
1139 ASSERT(!node
->isNameScopeObject());
1140 variableObject
= node
;
1146 JSObject
* compileError
= eval
->prepareForExecution(callFrame
, nullptr, scope
, CodeForCall
);
1147 if (UNLIKELY(!!compileError
))
1148 return checkedReturn(callFrame
->vm().throwException(callFrame
, compileError
));
1149 EvalCodeBlock
* codeBlock
= eval
->codeBlock();
1151 if (numVariables
|| numFunctions
) {
1152 BatchedTransitionOptimizer
optimizer(vm
, variableObject
);
1153 if (variableObject
->next())
1154 variableObject
->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint");
1156 for (unsigned i
= 0; i
< numVariables
; ++i
) {
1157 const Identifier
& ident
= codeBlock
->variable(i
);
1158 if (!variableObject
->hasProperty(callFrame
, ident
)) {
1159 PutPropertySlot
slot(variableObject
);
1160 variableObject
->methodTable()->put(variableObject
, callFrame
, ident
, jsUndefined(), slot
);
1164 for (int i
= 0; i
< numFunctions
; ++i
) {
1165 FunctionExecutable
* function
= codeBlock
->functionDecl(i
);
1166 PutPropertySlot
slot(variableObject
);
1167 variableObject
->methodTable()->put(variableObject
, callFrame
, function
->name(), JSFunction::create(vm
, function
, scope
), slot
);
1171 if (UNLIKELY(vm
.watchdog
&& vm
.watchdog
->didFire(callFrame
)))
1172 return throwTerminatedExecutionException(callFrame
);
1174 ASSERT(codeBlock
->numParameters() == 1); // 1 parameter for 'this'.
1176 ProtoCallFrame protoCallFrame
;
1177 protoCallFrame
.init(codeBlock
, JSCallee::create(vm
, scope
->globalObject(), scope
), thisValue
, 1);
1179 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1180 profiler
->willExecute(callFrame
, eval
->sourceURL(), eval
->firstLine(), eval
->startColumn());
1182 // Execute the code:
1185 SamplingTool::CallRecord
callRecord(m_sampler
.get());
1186 Watchdog::Scope
watchdogScope(vm
.watchdog
.get());
1188 result
= eval
->generatedJITCode()->execute(&vm
, &protoCallFrame
);
1191 if (LegacyProfiler
* profiler
= vm
.enabledProfiler())
1192 profiler
->didExecute(callFrame
, eval
->sourceURL(), eval
->firstLine(), eval
->startColumn());
1194 return checkedReturn(result
);
1197 NEVER_INLINE
void Interpreter::debug(CallFrame
* callFrame
, DebugHookID debugHookID
)
1199 Debugger
* debugger
= callFrame
->vmEntryGlobalObject()->debugger();
1203 ASSERT(callFrame
->codeBlock()->hasDebuggerRequests());
1204 ASSERT(!callFrame
->hadException());
1206 switch (debugHookID
) {
1207 case DidEnterCallFrame
:
1208 debugger
->callEvent(callFrame
);
1210 case WillLeaveCallFrame
:
1211 debugger
->returnEvent(callFrame
);
1213 case WillExecuteStatement
:
1214 debugger
->atStatement(callFrame
);
1216 case WillExecuteProgram
:
1217 debugger
->willExecuteProgram(callFrame
);
1219 case DidExecuteProgram
:
1220 debugger
->didExecuteProgram(callFrame
);
1222 case DidReachBreakpoint
:
1223 debugger
->didReachBreakpoint(callFrame
);
1226 ASSERT(!callFrame
->hadException());
1229 void Interpreter::enableSampler()
1231 #if ENABLE(OPCODE_SAMPLING)
1233 m_sampler
= std::make_unique
<SamplingTool
>(this);
1238 void Interpreter::dumpSampleData(ExecState
* exec
)
1240 #if ENABLE(OPCODE_SAMPLING)
1242 m_sampler
->dump(exec
);
1247 void Interpreter::startSampling()
1249 #if ENABLE(SAMPLING_THREAD)
1250 if (!m_sampleEntryDepth
)
1251 SamplingThread::start();
1253 m_sampleEntryDepth
++;
1256 void Interpreter::stopSampling()
1258 #if ENABLE(SAMPLING_THREAD)
1259 m_sampleEntryDepth
--;
1260 if (!m_sampleEntryDepth
)
1261 SamplingThread::stop();