2 * Copyright (C) 2008-2017 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 "CodeBlock.h"
36 #include "DirectArguments.h"
39 #include "DebuggerCallFrame.h"
40 #include "DirectEvalCodeCache.h"
41 #include "ErrorInstance.h"
42 #include "EvalCodeBlock.h"
43 #include "Exception.h"
44 #include "ExceptionHelpers.h"
45 #include "FunctionCodeBlock.h"
46 #include "JSArrayInlines.h"
47 #include "JSBoundFunction.h"
48 #include "JSCInlines.h"
49 #include "JSLexicalEnvironment.h"
50 #include "JSModuleEnvironment.h"
52 #include "JSWithScope.h"
53 #include "LLIntCLoop.h"
54 #include "LLIntData.h"
55 #include "LLIntThunks.h"
56 #include "LiteralParser.h"
57 #include "ModuleProgramCodeBlock.h"
58 #include "ObjectPrototype.h"
60 #include "ProgramCodeBlock.h"
61 #include "ProtoCallFrame.h"
62 #include "RegExpObject.h"
64 #include "ScopedArguments.h"
65 #include "StackAlignment.h"
66 #include "StackFrame.h"
67 #include "StackVisitor.h"
68 #include "StrictEvalActivation.h"
69 #include "StrongInlines.h"
71 #include "VMEntryScope.h"
72 #include "VMInlines.h"
73 #include "VirtualRegister.h"
77 #include <wtf/StackStats.h>
78 #include <wtf/StdLibExtras.h>
79 #include <wtf/StringPrintStream.h>
80 #include <wtf/Threading.h>
81 #include <wtf/text/StringBuilder.h>
91 JSValue eval(CallFrame* callFrame)
93 VM& vm = callFrame->vm();
94 auto scope = DECLARE_THROW_SCOPE(vm);
96 if (!callFrame->argumentCount())
99 JSValue program = callFrame->argument(0);
100 if (!program.isString())
103 TopCallFrameSetter topCallFrame(vm, callFrame);
104 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
105 if (!globalObject->evalEnabled()) {
106 throwException(callFrame, scope, createEvalError(callFrame, globalObject->evalDisabledErrorMessage()));
107 return jsUndefined();
109 String programSource = asString(program)->value(callFrame);
110 RETURN_IF_EXCEPTION(scope, JSValue());
112 CallFrame* callerFrame = callFrame->callerFrame();
113 CallSiteIndex callerCallSiteIndex = callerFrame->callSiteIndex();
114 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
115 JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
116 UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
118 bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext();
120 DerivedContextType derivedContextType = callerUnlinkedCodeBlock->derivedContextType();
121 if (!isArrowFunctionContext && callerUnlinkedCodeBlock->isClassContext()) {
122 derivedContextType = callerUnlinkedCodeBlock->isConstructor()
123 ? DerivedContextType::DerivedConstructorContext
124 : DerivedContextType::DerivedMethodContext;
127 EvalContextType evalContextType;
128 if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
129 evalContextType = EvalContextType::FunctionEvalContext;
130 else if (callerUnlinkedCodeBlock->codeType() == EvalCode)
131 evalContextType = callerUnlinkedCodeBlock->evalContextType();
133 evalContextType = EvalContextType::None;
135 DirectEvalExecutable* eval = callerCodeBlock->directEvalCodeCache().tryGet(programSource, callerCallSiteIndex);
137 if (!callerCodeBlock->isStrictMode()) {
138 if (programSource.is8Bit()) {
139 LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON);
140 if (JSValue parsedObject = preparser.tryLiteralParse())
143 LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON);
144 if (JSValue parsedObject = preparser.tryLiteralParse())
149 // If the literal parser bailed, it should not have thrown exceptions.
150 ASSERT(!scope.exception());
152 VariableEnvironment variablesUnderTDZ;
153 JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ);
154 eval = DirectEvalExecutable::create(callFrame, makeSource(programSource, callerCodeBlock->source()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, isArrowFunctionContext, evalContextType, &variablesUnderTDZ);
156 return jsUndefined();
158 callerCodeBlock->directEvalCodeCache().set(callFrame, callerCodeBlock, programSource, callerCallSiteIndex, eval);
161 JSValue thisValue = callerFrame->thisValue();
162 Interpreter* interpreter = vm.interpreter;
163 return interpreter->execute(eval, callFrame, thisValue, callerScopeChain);
166 unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset)
168 VM& vm = callFrame->vm();
169 auto scope = DECLARE_THROW_SCOPE(vm);
171 if (UNLIKELY(!arguments.isCell())) {
172 if (arguments.isUndefinedOrNull())
175 throwException(callFrame, scope, createInvalidFunctionApplyParameterError(callFrame, arguments));
179 JSCell* cell = arguments.asCell();
181 switch (cell->type()) {
182 case DirectArgumentsType:
183 length = jsCast<DirectArguments*>(cell)->length(callFrame);
185 case ScopedArgumentsType:
186 length = jsCast<ScopedArguments*>(cell)->length(callFrame);
190 throwException(callFrame, scope, createInvalidFunctionApplyParameterError(callFrame, arguments));
194 RELEASE_ASSERT(arguments.isObject());
195 length = getLength(callFrame, jsCast<JSObject*>(cell));
196 RETURN_IF_EXCEPTION(scope, 0);
201 if (length >= firstVarArgOffset)
202 length -= firstVarArgOffset;
209 unsigned sizeFrameForForwardArguments(CallFrame* callFrame, VM& vm, unsigned numUsedStackSlots)
211 auto scope = DECLARE_THROW_SCOPE(vm);
213 unsigned length = callFrame->argumentCount();
214 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
215 if (UNLIKELY(!vm.ensureStackCapacityFor(calleeFrame->registers())))
216 throwStackOverflowError(callFrame, scope);
221 unsigned sizeFrameForVarargs(CallFrame* callFrame, VM& vm, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
223 auto scope = DECLARE_THROW_SCOPE(vm);
225 unsigned length = sizeOfVarargs(callFrame, arguments, firstVarArgOffset);
227 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
228 if (UNLIKELY(length > maxArguments || !vm.ensureStackCapacityFor(calleeFrame->registers()))) {
229 throwStackOverflowError(callFrame, scope);
236 void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
238 if (UNLIKELY(!arguments.isCell()) || !length)
241 JSCell* cell = arguments.asCell();
243 switch (cell->type()) {
244 case DirectArgumentsType:
245 jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
247 case ScopedArgumentsType:
248 jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
251 ASSERT(arguments.isObject());
252 JSObject* object = jsCast<JSObject*>(cell);
253 if (isJSArray(object)) {
254 jsCast<JSArray*>(object)->copyToArguments(callFrame, firstElementDest, offset, length);
258 for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i)
259 callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset);
260 for (; i < length; ++i)
261 callFrame->r(firstElementDest + i) = object->get(callFrame, i + offset);
266 void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
268 VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
272 calleeFrameOffset + CallFrame::argumentOffset(0),
273 arguments, offset, length);
275 newCallFrame->setArgumentCountIncludingThis(length + 1);
278 void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
280 setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length);
281 newCallFrame->setThisValue(thisValue);
284 void setupForwardArgumentsFrame(CallFrame* execCaller, CallFrame* execCallee, uint32_t length)
286 ASSERT(length == execCaller->argumentCount());
287 unsigned offset = execCaller->argumentOffset(0) * sizeof(Register);
288 memcpy(reinterpret_cast<char*>(execCallee) + offset, reinterpret_cast<char*>(execCaller) + offset, length * sizeof(Register));
289 execCallee->setArgumentCountIncludingThis(length + 1);
292 void setupForwardArgumentsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length)
294 setupForwardArgumentsFrame(execCaller, execCallee, length);
295 execCallee->setThisValue(thisValue);
300 Interpreter::Interpreter(VM& vm)
306 , m_initialized(false)
311 Interpreter::~Interpreter()
315 void Interpreter::initialize()
317 #if ENABLE(COMPUTED_GOTO_OPCODES)
318 m_opcodeTable = LLInt::opcodeMap();
319 for (int i = 0; i < numOpcodeIDs; ++i)
320 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
324 m_initialized = true;
330 void Interpreter::dumpCallFrame(CallFrame*)
336 void Interpreter::dumpCallFrame(CallFrame* callFrame)
338 callFrame->codeBlock()->dumpBytecode();
339 dumpRegisters(callFrame);
342 class DumpRegisterFunctor {
344 DumpRegisterFunctor(const Register*& it)
345 : m_hasSkippedFirstFrame(false)
350 StackVisitor::Status operator()(StackVisitor& visitor) const
352 if (!m_hasSkippedFirstFrame) {
353 m_hasSkippedFirstFrame = true;
354 return StackVisitor::Continue;
358 unsigned unusedColumn = 0;
359 visitor->computeLineAndColumn(line, unusedColumn);
360 dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", m_it, visitor->bytecodeOffset(), line);
362 return StackVisitor::Done;
366 mutable bool m_hasSkippedFirstFrame;
367 const Register*& m_it;
370 void Interpreter::dumpRegisters(CallFrame* callFrame)
372 dataLogF("Register frame: \n\n");
373 dataLogF("-----------------------------------------------------------------------------\n");
374 dataLogF(" use | address | value \n");
375 dataLogF("-----------------------------------------------------------------------------\n");
377 CodeBlock* codeBlock = callFrame->codeBlock();
381 it = callFrame->registers() + CallFrameSlot::thisArgument + callFrame->argumentCount();
382 end = callFrame->registers() + CallFrameSlot::thisArgument - 1;
384 JSValue v = it->jsValue();
385 int registerNumber = it - callFrame->registers();
386 String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
387 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
391 dataLogF("-----------------------------------------------------------------------------\n");
392 dataLogF("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount());
394 dataLogF("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
396 dataLogF("[Callee] | %10p | %p \n", it, callFrame->jsCallee());
398 // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header
401 AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm());
402 if (pc.hasJITReturnAddress())
403 dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
406 DumpRegisterFunctor functor(it);
407 callFrame->iterate(functor);
409 dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
411 dataLogF("-----------------------------------------------------------------------------\n");
413 end = it - codeBlock->m_numVars;
416 JSValue v = it->jsValue();
417 int registerNumber = it - callFrame->registers();
418 String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
419 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
423 dataLogF("-----------------------------------------------------------------------------\n");
425 end = it - codeBlock->m_numCalleeLocals + codeBlock->m_numVars;
428 JSValue v = (*it).jsValue();
429 int registerNumber = it - callFrame->registers();
430 dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerNumber, it, toCString(v).data(), (long long)JSValue::encode(v));
434 dataLogF("-----------------------------------------------------------------------------\n");
439 bool Interpreter::isOpcode(Opcode opcode)
441 #if ENABLE(COMPUTED_GOTO_OPCODES)
442 return opcode != HashTraits<Opcode>::emptyValue()
443 && !HashTraits<Opcode>::isDeletedValue(opcode)
444 && m_opcodeIDTable.contains(opcode);
446 return opcode >= 0 && opcode <= op_end;
450 class GetStackTraceFunctor {
452 GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t framesToSkip, size_t capacity)
455 , m_framesToSkip(framesToSkip)
456 , m_remainingCapacityForFrameCapture(capacity)
458 m_results.reserveInitialCapacity(capacity);
461 StackVisitor::Status operator()(StackVisitor& visitor) const
463 if (m_framesToSkip > 0) {
465 return StackVisitor::Continue;
468 if (m_remainingCapacityForFrameCapture) {
469 if (!visitor->isWasmFrame()
470 && !!visitor->codeBlock()
471 && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
473 StackFrame(m_vm, visitor->callee(), visitor->codeBlock(), visitor->bytecodeOffset()));
476 StackFrame(m_vm, visitor->callee()));
479 m_remainingCapacityForFrameCapture--;
480 return StackVisitor::Continue;
482 return StackVisitor::Done;
487 Vector<StackFrame>& m_results;
488 mutable size_t m_framesToSkip;
489 mutable size_t m_remainingCapacityForFrameCapture;
492 void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t framesToSkip, size_t maxStackSize)
495 CallFrame* callFrame = vm.topCallFrame;
499 size_t framesCount = 0;
500 callFrame->iterate([&] (StackVisitor&) -> StackVisitor::Status {
502 return StackVisitor::Continue;
504 if (framesCount <= framesToSkip)
507 framesCount -= framesToSkip;
508 framesCount = std::min(maxStackSize, framesCount);
510 GetStackTraceFunctor functor(vm, results, framesToSkip, framesCount);
511 callFrame->iterate(functor);
512 ASSERT(results.size() == results.capacity());
515 JSString* Interpreter::stackTraceAsString(VM& vm, const Vector<StackFrame>& stackTrace)
517 // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
518 StringBuilder builder;
519 for (unsigned i = 0; i < stackTrace.size(); i++) {
520 builder.append(String(stackTrace[i].toString(vm)));
521 if (i != stackTrace.size() - 1)
522 builder.append('\n');
524 return jsString(&vm, builder.toString());
527 ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, RequiredHandler requiredHandler)
531 ASSERT(!visitor->isInlinedFrame());
534 CallFrame* callFrame = visitor->callFrame();
535 unsigned exceptionHandlerIndex;
536 if (JITCode::isOptimizingJIT(codeBlock->jitType()))
537 exceptionHandlerIndex = callFrame->callSiteIndex().bits();
539 exceptionHandlerIndex = callFrame->bytecodeOffset();
541 return codeBlock->handlerForIndex(exceptionHandlerIndex, requiredHandler);
544 class GetCatchHandlerFunctor {
546 GetCatchHandlerFunctor()
551 HandlerInfo* handler() { return m_handler; }
553 StackVisitor::Status operator()(StackVisitor& visitor) const
555 visitor.unwindToMachineCodeBlockFrame();
557 CodeBlock* codeBlock = visitor->codeBlock();
559 return StackVisitor::Continue;
561 m_handler = findExceptionHandler(visitor, codeBlock, RequiredHandler::CatchHandler);
563 return StackVisitor::Done;
565 return StackVisitor::Continue;
569 mutable HandlerInfo* m_handler;
572 ALWAYS_INLINE static void notifyDebuggerOfUnwinding(CallFrame* callFrame)
574 VM& vm = callFrame->vm();
575 auto catchScope = DECLARE_CATCH_SCOPE(vm);
576 if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) {
577 SuspendExceptionScope scope(&vm);
578 if (jsDynamicCast<JSFunction*>(vm, callFrame->jsCallee()))
579 debugger->unwindEvent(callFrame);
581 debugger->didExecuteProgram(callFrame);
582 ASSERT_UNUSED(catchScope, !catchScope.exception());
586 class UnwindFunctor {
588 UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
589 : m_callFrame(callFrame)
590 , m_isTermination(isTermination)
591 , m_codeBlock(codeBlock)
596 StackVisitor::Status operator()(StackVisitor& visitor) const
598 visitor.unwindToMachineCodeBlockFrame();
599 m_callFrame = visitor->callFrame();
600 m_codeBlock = visitor->codeBlock();
603 if (!m_isTermination) {
605 m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler);
607 return StackVisitor::Done;
611 notifyDebuggerOfUnwinding(m_callFrame);
613 copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(visitor);
615 bool shouldStopUnwinding = visitor->callerIsVMEntryFrame();
616 if (shouldStopUnwinding)
617 return StackVisitor::Done;
619 return StackVisitor::Continue;
623 void copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(StackVisitor& visitor) const
625 #if ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
626 RegisterAtOffsetList* currentCalleeSaves = visitor->calleeSaveRegisters();
628 if (!currentCalleeSaves)
631 VM& vm = m_callFrame->vm();
632 RegisterAtOffsetList* allCalleeSaves = vm.getAllCalleeSaveRegisterOffsets();
633 RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
634 intptr_t* frame = reinterpret_cast<intptr_t*>(m_callFrame->registers());
636 unsigned registerCount = currentCalleeSaves->size();
637 VMEntryRecord* record = vmEntryRecord(vm.topVMEntryFrame);
638 for (unsigned i = 0; i < registerCount; i++) {
639 RegisterAtOffset currentEntry = currentCalleeSaves->at(i);
640 if (dontCopyRegisters.get(currentEntry.reg()))
642 RegisterAtOffset* calleeSavesEntry = allCalleeSaves->find(currentEntry.reg());
644 record->calleeSaveRegistersBuffer[calleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex());
647 UNUSED_PARAM(visitor);
651 CallFrame*& m_callFrame;
652 bool m_isTermination;
653 CodeBlock*& m_codeBlock;
654 HandlerInfo*& m_handler;
657 NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception, UnwindStart unwindStart)
659 auto scope = DECLARE_CATCH_SCOPE(vm);
661 if (unwindStart == UnwindFromCallerFrame) {
662 if (callFrame->callerFrameOrVMEntryFrame() == vm.topVMEntryFrame)
665 callFrame = callFrame->callerFrame();
666 vm.topCallFrame = callFrame;
669 CodeBlock* codeBlock = callFrame->codeBlock();
671 JSValue exceptionValue = exception->value();
672 ASSERT(!exceptionValue.isEmpty());
673 ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
674 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
675 // slow cases, so let's harden against it anyway to be safe.
676 if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell()))
677 exceptionValue = jsNull();
679 ASSERT_UNUSED(scope, scope.exception() && scope.exception()->stack().size());
681 // Calculate an exception handler vPC, unwinding call frames as necessary.
682 HandlerInfo* handler = nullptr;
683 UnwindFunctor functor(callFrame, isTerminatedExecutionException(vm, exception), codeBlock, handler);
684 callFrame->iterate(functor);
691 void Interpreter::notifyDebuggerOfExceptionToBeThrown(CallFrame* callFrame, Exception* exception)
693 VM& vm = callFrame->vm();
694 Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
695 if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
696 // This code assumes that if the debugger is enabled then there is no inlining.
697 // If that assumption turns out to be false then we'll ignore the inlined call
699 // https://bugs.webkit.org/show_bug.cgi?id=121754
701 bool hasCatchHandler;
702 bool isTermination = isTerminatedExecutionException(vm, exception);
704 hasCatchHandler = false;
706 GetCatchHandlerFunctor functor;
707 callFrame->iterate(functor);
708 HandlerInfo* handler = functor.handler();
709 ASSERT(!handler || handler->isCatchHandler());
710 hasCatchHandler = !!handler;
713 debugger->exception(callFrame, exception->value(), hasCatchHandler);
715 exception->setDidNotifyInspectorOfThrow();
718 static inline JSValue checkedReturn(JSValue returnValue)
724 static inline JSObject* checkedReturn(JSObject* returnValue)
730 JSValue Interpreter::executeProgram(const SourceCode& source, CallFrame* callFrame, JSObject* thisObj)
732 JSScope* scope = thisObj->globalObject()->globalScope();
733 VM& vm = *scope->vm();
734 auto throwScope = DECLARE_THROW_SCOPE(vm);
736 ProgramExecutable* program = ProgramExecutable::create(callFrame, source);
737 ASSERT(throwScope.exception() || program);
738 RETURN_IF_EXCEPTION(throwScope, { });
740 ASSERT(!throwScope.exception());
741 ASSERT(!vm.isCollectorBusyOnCurrentThread());
742 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
743 if (vm.isCollectorBusyOnCurrentThread())
746 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
747 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
749 // First check if the "program" is actually just a JSON object. If so,
750 // we'll handle the JSON object here. Else, we'll handle real JS code
751 // below at failedJSONP.
753 Vector<JSONPData> JSONPData;
755 StringView programSource = program->source().view();
756 if (programSource.isNull())
757 return jsUndefined();
758 if (programSource.is8Bit()) {
759 LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP);
760 parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
762 LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP);
763 parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
767 JSGlobalObject* globalObject = scope->globalObject();
769 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
770 Vector<JSONPPathEntry> JSONPPath;
771 JSONPPath.swap(JSONPData[entry].m_path);
772 JSValue JSONPValue = JSONPData[entry].m_value.get();
773 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclare) {
774 globalObject->addVar(callFrame, JSONPPath[0].m_pathEntryName);
775 PutPropertySlot slot(globalObject);
776 globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
777 result = jsUndefined();
780 JSValue baseObject(globalObject);
781 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
782 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclare);
783 switch (JSONPPath[i].m_type) {
784 case JSONPPathEntryTypeDot: {
786 PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get);
787 if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
788 RETURN_IF_EXCEPTION(throwScope, JSValue());
790 return throwException(callFrame, throwScope, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName));
793 baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
795 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
796 RETURN_IF_EXCEPTION(throwScope, JSValue());
799 case JSONPPathEntryTypeLookup: {
800 baseObject = baseObject.get(callFrame, static_cast<unsigned>(JSONPPath[i].m_pathIndex));
801 RETURN_IF_EXCEPTION(throwScope, JSValue());
805 RELEASE_ASSERT_NOT_REACHED();
806 return jsUndefined();
809 PutPropertySlot slot(baseObject);
810 switch (JSONPPath.last().m_type) {
811 case JSONPPathEntryTypeCall: {
812 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
813 RETURN_IF_EXCEPTION(throwScope, JSValue());
815 CallType callType = getCallData(function, callData);
816 if (callType == CallType::None)
817 return throwException(callFrame, throwScope, createNotAFunctionError(callFrame, function));
818 MarkedArgumentBuffer jsonArg;
819 jsonArg.append(JSONPValue);
820 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
821 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
822 RETURN_IF_EXCEPTION(throwScope, JSValue());
825 case JSONPPathEntryTypeDot: {
826 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
827 RETURN_IF_EXCEPTION(throwScope, JSValue());
830 case JSONPPathEntryTypeLookup: {
831 baseObject.putByIndex(callFrame, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode());
832 RETURN_IF_EXCEPTION(throwScope, JSValue());
836 RELEASE_ASSERT_NOT_REACHED();
837 return jsUndefined();
844 // If we get here, then we have already proven that the script is not a JSON
847 VMEntryScope entryScope(vm, scope->globalObject());
849 // Compile source to bytecode if necessary:
850 if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope))
851 return checkedReturn(throwException(callFrame, throwScope, error));
853 ProgramCodeBlock* codeBlock;
855 CodeBlock* tempCodeBlock;
856 JSObject* error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
857 ASSERT(!throwScope.exception() || throwScope.exception() == jsDynamicCast<Exception*>(vm, error));
859 return checkedReturn(throwException(callFrame, throwScope, error));
860 codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
863 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
864 return throwTerminatedExecutionException(callFrame, throwScope);
866 if (scope->structure()->isUncacheableDictionary())
867 scope->flattenDictionaryObject(vm);
869 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
871 ProtoCallFrame protoCallFrame;
872 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisObj, 1);
875 JSValue result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
876 throwScope.release();
877 return checkedReturn(result);
880 JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
882 VM& vm = callFrame->vm();
883 auto throwScope = DECLARE_THROW_SCOPE(vm);
885 ASSERT(!throwScope.exception());
886 ASSERT(!vm.isCollectorBusyOnCurrentThread());
887 if (vm.isCollectorBusyOnCurrentThread())
890 bool isJSCall = (callType == CallType::JS);
891 JSScope* scope = nullptr;
892 CodeBlock* newCodeBlock;
893 size_t argsCount = 1 + args.size(); // implicit "this" parameter
895 JSGlobalObject* globalObject;
898 scope = callData.js.scope;
899 globalObject = scope->globalObject();
901 ASSERT(callType == CallType::Host);
902 globalObject = function->globalObject();
905 VMEntryScope entryScope(vm, globalObject);
906 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
907 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
910 // Compile the callee:
911 JSObject* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
912 ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(compileError));
913 if (UNLIKELY(!!compileError))
914 return checkedReturn(throwException(callFrame, throwScope, compileError));
916 ASSERT(!!newCodeBlock);
917 newCodeBlock->m_shouldAlwaysBeInlined = false;
921 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
922 return throwTerminatedExecutionException(callFrame, throwScope);
924 ProtoCallFrame protoCallFrame;
925 protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data());
931 result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
932 throwScope.release();
934 result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame));
935 RETURN_IF_EXCEPTION(throwScope, JSValue());
939 return checkedReturn(result);
942 JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
944 VM& vm = callFrame->vm();
945 auto throwScope = DECLARE_THROW_SCOPE(vm);
947 ASSERT(!throwScope.exception());
948 ASSERT(!vm.isCollectorBusyOnCurrentThread());
949 // We throw in this case because we have to return something "valid" but we're
950 // already in an invalid state.
951 if (vm.isCollectorBusyOnCurrentThread())
952 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
954 bool isJSConstruct = (constructType == ConstructType::JS);
955 JSScope* scope = nullptr;
956 CodeBlock* newCodeBlock;
957 size_t argsCount = 1 + args.size(); // implicit "this" parameter
959 JSGlobalObject* globalObject;
962 scope = constructData.js.scope;
963 globalObject = scope->globalObject();
965 ASSERT(constructType == ConstructType::Host);
966 globalObject = constructor->globalObject();
969 VMEntryScope entryScope(vm, globalObject);
970 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
971 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
974 // Compile the callee:
975 JSObject* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
976 if (UNLIKELY(!!compileError))
977 return checkedReturn(throwException(callFrame, throwScope, compileError));
979 ASSERT(!!newCodeBlock);
980 newCodeBlock->m_shouldAlwaysBeInlined = false;
984 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
985 return throwTerminatedExecutionException(callFrame, throwScope);
987 ProtoCallFrame protoCallFrame;
988 protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
994 result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
996 result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame));
998 if (LIKELY(!throwScope.exception()))
999 RELEASE_ASSERT(result.isObject());
1003 RETURN_IF_EXCEPTION(throwScope, 0);
1004 ASSERT(result.isObject());
1005 return checkedReturn(asObject(result));
1008 CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, const ArgList& args)
1010 VM& vm = *scope->vm();
1011 auto throwScope = DECLARE_THROW_SCOPE(vm);
1012 ASSERT(!throwScope.exception());
1014 if (vm.isCollectorBusyOnCurrentThread())
1015 return CallFrameClosure();
1017 // Compile the callee:
1018 CodeBlock* newCodeBlock;
1019 JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock);
1021 throwException(callFrame, throwScope, error);
1022 return CallFrameClosure();
1024 newCodeBlock->m_shouldAlwaysBeInlined = false;
1026 size_t argsCount = argumentCountIncludingThis;
1028 protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args.data());
1029 // Return the successful closure:
1030 CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
1034 JSValue Interpreter::execute(CallFrameClosure& closure)
1036 VM& vm = *closure.vm;
1037 auto throwScope = DECLARE_THROW_SCOPE(vm);
1039 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1040 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1041 if (vm.isCollectorBusyOnCurrentThread())
1044 StackStats::CheckPoint stackCheckPoint;
1046 if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame)))
1047 return throwTerminatedExecutionException(closure.oldCallFrame, throwScope);
1049 // Execute the code:
1050 JSValue result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame);
1052 return checkedReturn(result);
1055 JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
1057 VM& vm = *scope->vm();
1058 auto throwScope = DECLARE_THROW_SCOPE(vm);
1060 ASSERT(scope->vm() == &callFrame->vm());
1061 ASSERT(!throwScope.exception());
1062 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1063 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1064 if (vm.isCollectorBusyOnCurrentThread())
1067 VMEntryScope entryScope(vm, scope->globalObject());
1068 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1069 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
1071 unsigned numVariables = eval->numVariables();
1072 int numFunctions = eval->numberOfFunctionDecls();
1074 JSScope* variableObject;
1075 if ((numVariables || numFunctions) && eval->isStrictMode()) {
1076 scope = StrictEvalActivation::create(callFrame, scope);
1077 variableObject = scope;
1079 for (JSScope* node = scope; ; node = node->next()) {
1080 RELEASE_ASSERT(node);
1081 if (node->isGlobalObject()) {
1082 variableObject = node;
1085 if (node->isJSLexicalEnvironment()) {
1086 JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(node);
1087 if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) {
1088 variableObject = node;
1095 EvalCodeBlock* codeBlock;
1097 CodeBlock* tempCodeBlock;
1098 JSObject* compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1099 if (UNLIKELY(!!compileError))
1100 return checkedReturn(throwException(callFrame, throwScope, compileError));
1101 codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock);
1104 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
1105 if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numFunctions)) {
1106 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment();
1107 for (unsigned i = 0; i < numVariables; ++i) {
1108 const Identifier& ident = codeBlock->variable(i);
1109 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1110 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, ident, slot)) {
1111 return checkedReturn(throwTypeError(callFrame, throwScope, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'")));
1115 for (int i = 0; i < numFunctions; ++i) {
1116 FunctionExecutable* function = codeBlock->functionDecl(i);
1117 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1118 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, function->name(), slot)) {
1119 return checkedReturn(throwTypeError(callFrame, throwScope, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'")));
1124 if (variableObject->structure()->isUncacheableDictionary())
1125 variableObject->flattenDictionaryObject(vm);
1127 if (numVariables || numFunctions) {
1128 BatchedTransitionOptimizer optimizer(vm, variableObject);
1129 if (variableObject->next() && !eval->isStrictMode())
1130 variableObject->globalObject()->varInjectionWatchpoint()->fireAll(vm, "Executed eval, fired VarInjection watchpoint");
1132 for (unsigned i = 0; i < numVariables; ++i) {
1133 const Identifier& ident = codeBlock->variable(i);
1134 if (!variableObject->hasProperty(callFrame, ident)) {
1135 PutPropertySlot slot(variableObject);
1136 variableObject->methodTable()->put(variableObject, callFrame, ident, jsUndefined(), slot);
1140 for (int i = 0; i < numFunctions; ++i) {
1141 FunctionExecutable* function = codeBlock->functionDecl(i);
1142 PutPropertySlot slot(variableObject);
1143 variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot);
1147 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1148 return throwTerminatedExecutionException(callFrame, throwScope);
1150 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1152 ProtoCallFrame protoCallFrame;
1153 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1);
1155 // Execute the code:
1156 JSValue result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
1158 return checkedReturn(result);
1161 JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* callFrame, JSModuleEnvironment* scope)
1163 VM& vm = *scope->vm();
1164 auto throwScope = DECLARE_THROW_SCOPE(vm);
1166 ASSERT(scope->vm() == &callFrame->vm());
1167 ASSERT(!throwScope.exception());
1168 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1169 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1170 if (vm.isCollectorBusyOnCurrentThread())
1173 VMEntryScope entryScope(vm, scope->globalObject());
1174 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1175 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
1177 ModuleProgramCodeBlock* codeBlock;
1179 CodeBlock* tempCodeBlock;
1180 JSObject* compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1181 if (UNLIKELY(!!compileError))
1182 return checkedReturn(throwException(callFrame, throwScope, compileError));
1183 codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
1186 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1187 return throwTerminatedExecutionException(callFrame, throwScope);
1189 if (scope->structure()->isUncacheableDictionary())
1190 scope->flattenDictionaryObject(vm);
1192 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1194 // The |this| of the module is always `undefined`.
1195 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding
1196 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding
1197 ProtoCallFrame protoCallFrame;
1198 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), jsUndefined(), 1);
1200 // Execute the code:
1201 JSValue result = executable->generatedJITCode()->execute(&vm, &protoCallFrame);
1203 return checkedReturn(result);
1206 NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookType debugHookType)
1208 VM& vm = callFrame->vm();
1209 auto scope = DECLARE_CATCH_SCOPE(vm);
1210 Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
1214 ASSERT(callFrame->codeBlock()->hasDebuggerRequests());
1215 ASSERT_UNUSED(scope, !scope.exception());
1217 switch (debugHookType) {
1218 case DidEnterCallFrame:
1219 debugger->callEvent(callFrame);
1221 case WillLeaveCallFrame:
1222 debugger->returnEvent(callFrame);
1224 case WillExecuteStatement:
1225 debugger->atStatement(callFrame);
1227 case WillExecuteExpression:
1228 debugger->atExpression(callFrame);
1230 case WillExecuteProgram:
1231 debugger->willExecuteProgram(callFrame);
1233 case DidExecuteProgram:
1234 debugger->didExecuteProgram(callFrame);
1236 case DidReachBreakpoint:
1237 debugger->didReachBreakpoint(callFrame);
1240 ASSERT(!scope.exception());