1/*
2 * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "Interpreter.h"
32
33#include "BatchedTransitionOptimizer.h"
34#include "Bytecodes.h"
35#include "CallFrameClosure.h"
36#include "CatchScope.h"
37#include "CodeBlock.h"
38#include "CodeCache.h"
39#include "DirectArguments.h"
40#include "ExecutableBaseInlines.h"
41#include "Heap.h"
42#include "Debugger.h"
43#include "DebuggerCallFrame.h"
44#include "DirectEvalCodeCache.h"
45#include "ErrorInstance.h"
46#include "EvalCodeBlock.h"
47#include "Exception.h"
48#include "ExceptionHelpers.h"
49#include "FrameTracers.h"
50#include "FunctionCodeBlock.h"
51#include "InterpreterInlines.h"
52#include "JITCodeInlines.h"
53#include "JSArrayInlines.h"
54#include "JSBoundFunction.h"
55#include "JSCInlines.h"
56#include "JSFixedArray.h"
57#include "JSImmutableButterfly.h"
58#include "JSLexicalEnvironment.h"
59#include "JSModuleEnvironment.h"
60#include "JSString.h"
61#include "JSWithScope.h"
62#include "LLIntCLoop.h"
63#include "LLIntThunks.h"
64#include "LiteralParser.h"
65#include "ModuleProgramCodeBlock.h"
66#include "ObjectPrototype.h"
67#include "Parser.h"
68#include "ProgramCodeBlock.h"
69#include "ProtoCallFrame.h"
70#include "RegExpObject.h"
71#include "Register.h"
72#include "RegisterAtOffsetList.h"
73#include "ScopedArguments.h"
74#include "StackAlignment.h"
75#include "StackFrame.h"
76#include "StackVisitor.h"
77#include "StrictEvalActivation.h"
78#include "StrongInlines.h"
79#include "Symbol.h"
80#include "VMEntryScope.h"
81#include "VMInlines.h"
82#include "VMInspector.h"
83#include "VirtualRegister.h"
84#include <limits.h>
85#include <stdio.h>
86#include <wtf/NeverDestroyed.h>
87#include <wtf/StackStats.h>
88#include <wtf/StdLibExtras.h>
89#include <wtf/StringPrintStream.h>
90#include <wtf/Threading.h>
91#include <wtf/text/StringBuilder.h>
92
93#if ENABLE(JIT)
94#include "JIT.h"
95#endif
96
97#if ENABLE(WEBASSEMBLY)
98#include "WasmContextInlines.h"
99#include "WebAssemblyFunction.h"
100#endif
101
102namespace JSC {
103
104JSValue eval(CallFrame* callFrame)
105{
106 VM& vm = callFrame->vm();
107 auto scope = DECLARE_THROW_SCOPE(vm);
108
109 if (!callFrame->argumentCount())
110 return jsUndefined();
111
112 JSValue program = callFrame->argument(0);
113 if (!program.isString())
114 return program;
115
116 TopCallFrameSetter topCallFrame(vm, callFrame);
117 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
118 if (!globalObject->evalEnabled()) {
119 throwException(callFrame, scope, createEvalError(callFrame, globalObject->evalDisabledErrorMessage()));
120 return jsUndefined();
121 }
122 String programSource = asString(program)->value(callFrame);
123 RETURN_IF_EXCEPTION(scope, JSValue());
124
125 CallFrame* callerFrame = callFrame->callerFrame();
126 CallSiteIndex callerCallSiteIndex = callerFrame->callSiteIndex();
127 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
128 JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
129 UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
130
131 bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext();
132
133 DerivedContextType derivedContextType = callerUnlinkedCodeBlock->derivedContextType();
134 if (!isArrowFunctionContext && callerUnlinkedCodeBlock->isClassContext()) {
135 derivedContextType = callerUnlinkedCodeBlock->isConstructor()
136 ? DerivedContextType::DerivedConstructorContext
137 : DerivedContextType::DerivedMethodContext;
138 }
139
140 EvalContextType evalContextType;
141 if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
142 evalContextType = EvalContextType::FunctionEvalContext;
143 else if (callerUnlinkedCodeBlock->codeType() == EvalCode)
144 evalContextType = callerUnlinkedCodeBlock->evalContextType();
145 else
146 evalContextType = EvalContextType::None;
147
148 DirectEvalExecutable* eval = callerCodeBlock->directEvalCodeCache().tryGet(programSource, callerCallSiteIndex);
149 if (!eval) {
150 if (!callerCodeBlock->isStrictMode()) {
151 if (programSource.is8Bit()) {
152 LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON);
153 if (JSValue parsedObject = preparser.tryLiteralParse())
154 RELEASE_AND_RETURN(scope, parsedObject);
155
156 } else {
157 LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON);
158 if (JSValue parsedObject = preparser.tryLiteralParse())
159 RELEASE_AND_RETURN(scope, parsedObject);
160
161 }
162 RETURN_IF_EXCEPTION(scope, JSValue());
163 }
164
165 VariableEnvironment variablesUnderTDZ;
166 JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ);
167 eval = DirectEvalExecutable::create(callFrame, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, isArrowFunctionContext, evalContextType, &variablesUnderTDZ);
168 EXCEPTION_ASSERT(!!scope.exception() == !eval);
169 if (!eval)
170 return jsUndefined();
171
172 callerCodeBlock->directEvalCodeCache().set(callFrame, callerCodeBlock, programSource, callerCallSiteIndex, eval);
173 }
174
175 JSValue thisValue = callerFrame->thisValue();
176 Interpreter* interpreter = vm.interpreter;
177 RELEASE_AND_RETURN(scope, interpreter->execute(eval, callFrame, thisValue, callerScopeChain));
178}
179
180unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset)
181{
182 VM& vm = callFrame->vm();
183 auto scope = DECLARE_THROW_SCOPE(vm);
184
185 if (UNLIKELY(!arguments.isCell())) {
186 if (arguments.isUndefinedOrNull())
187 return 0;
188
189 throwException(callFrame, scope, createInvalidFunctionApplyParameterError(callFrame, arguments));
190 return 0;
191 }
192
193 JSCell* cell = arguments.asCell();
194 unsigned length;
195 switch (cell->type()) {
196 case DirectArgumentsType:
197 length = jsCast<DirectArguments*>(cell)->length(callFrame);
198 break;
199 case ScopedArgumentsType:
200 length = jsCast<ScopedArguments*>(cell)->length(callFrame);
201 break;
202 case JSFixedArrayType:
203 length = jsCast<JSFixedArray*>(cell)->size();
204 break;
205 case JSImmutableButterflyType:
206 length = jsCast<JSImmutableButterfly*>(cell)->length();
207 break;
208 case StringType:
209 case SymbolType:
210 case BigIntType:
211 throwException(callFrame, scope, createInvalidFunctionApplyParameterError(callFrame, arguments));
212 return 0;
213
214 default:
215 RELEASE_ASSERT(arguments.isObject());
216 length = clampToUnsigned(toLength(callFrame, jsCast<JSObject*>(cell)));
217 break;
218 }
219 RETURN_IF_EXCEPTION(scope, 0);
220
221 if (length >= firstVarArgOffset)
222 length -= firstVarArgOffset;
223 else
224 length = 0;
225
226 return length;
227}
228
229unsigned sizeFrameForForwardArguments(CallFrame* callFrame, VM& vm, unsigned numUsedStackSlots)
230{
231 auto scope = DECLARE_THROW_SCOPE(vm);
232
233 unsigned length = callFrame->argumentCount();
234 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
235 if (UNLIKELY(!vm.ensureStackCapacityFor(calleeFrame->registers())))
236 throwStackOverflowError(callFrame, scope);
237
238 return length;
239}
240
241unsigned sizeFrameForVarargs(CallFrame* callFrame, VM& vm, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
242{
243 auto scope = DECLARE_THROW_SCOPE(vm);
244
245 unsigned length = sizeOfVarargs(callFrame, arguments, firstVarArgOffset);
246 RETURN_IF_EXCEPTION(scope, 0);
247
248 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
249 if (UNLIKELY(length > maxArguments || !vm.ensureStackCapacityFor(calleeFrame->registers()))) {
250 throwStackOverflowError(callFrame, scope);
251 return 0;
252 }
253
254 return length;
255}
256
257void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
258{
259 if (UNLIKELY(!arguments.isCell()) || !length)
260 return;
261
262 VM& vm = callFrame->vm();
263 auto scope = DECLARE_THROW_SCOPE(vm);
264 JSCell* cell = arguments.asCell();
265
266 switch (cell->type()) {
267 case DirectArgumentsType:
268 scope.release();
269 jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
270 return;
271 case ScopedArgumentsType:
272 scope.release();
273 jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
274 return;
275 case JSFixedArrayType:
276 scope.release();
277 jsCast<JSFixedArray*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
278 return;
279 case JSImmutableButterflyType:
280 scope.release();
281 jsCast<JSImmutableButterfly*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
282 return;
283 default: {
284 ASSERT(arguments.isObject());
285 JSObject* object = jsCast<JSObject*>(cell);
286 if (isJSArray(object)) {
287 scope.release();
288 jsCast<JSArray*>(object)->copyToArguments(callFrame, firstElementDest, offset, length);
289 return;
290 }
291 unsigned i;
292 for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i)
293 callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset);
294 for (; i < length; ++i) {
295 JSValue value = object->get(callFrame, i + offset);
296 RETURN_IF_EXCEPTION(scope, void());
297 callFrame->r(firstElementDest + i) = value;
298 }
299 return;
300 } }
301}
302
303void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
304{
305 VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
306
307 loadVarargs(
308 callFrame,
309 calleeFrameOffset + CallFrame::argumentOffset(0),
310 arguments, offset, length);
311
312 newCallFrame->setArgumentCountIncludingThis(length + 1);
313}
314
315void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
316{
317 setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length);
318 newCallFrame->setThisValue(thisValue);
319}
320
321void setupForwardArgumentsFrame(CallFrame* execCaller, CallFrame* execCallee, uint32_t length)
322{
323 ASSERT(length == execCaller->argumentCount());
324 unsigned offset = execCaller->argumentOffset(0) * sizeof(Register);
325 memcpy(reinterpret_cast<char*>(execCallee) + offset, reinterpret_cast<char*>(execCaller) + offset, length * sizeof(Register));
326 execCallee->setArgumentCountIncludingThis(length + 1);
327}
328
329void setupForwardArgumentsFrameAndSetThis(CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length)
330{
331 setupForwardArgumentsFrame(execCaller, execCallee, length);
332 execCallee->setThisValue(thisValue);
333}
334
335
336
337Interpreter::Interpreter(VM& vm)
338 : m_vm(vm)
339#if ENABLE(C_LOOP)
340 , m_cloopStack(vm)
341#endif
342{
343#if !ASSERT_DISABLED
344 static std::once_flag assertOnceKey;
345 std::call_once(assertOnceKey, [] {
346 for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i) {
347 OpcodeID opcodeID = static_cast<OpcodeID>(i);
348 RELEASE_ASSERT(getOpcodeID(getOpcode(opcodeID)) == opcodeID);
349 }
350 });
351#endif // USE(LLINT_EMBEDDED_OPCODE_ID)
352}
353
354Interpreter::~Interpreter()
355{
356}
357
358#if ENABLE(COMPUTED_GOTO_OPCODES)
359#if !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
360HashMap<Opcode, OpcodeID>& Interpreter::opcodeIDTable()
361{
362 static NeverDestroyed<HashMap<Opcode, OpcodeID>> opcodeIDTable;
363
364 static std::once_flag initializeKey;
365 std::call_once(initializeKey, [&] {
366 const Opcode* opcodeTable = LLInt::opcodeMap();
367 for (unsigned i = 0; i < NUMBER_OF_BYTECODE_IDS; ++i)
368 opcodeIDTable.get().add(opcodeTable[i], static_cast<OpcodeID>(i));
369 });
370
371 return opcodeIDTable;
372}
373#endif // !USE(LLINT_EMBEDDED_OPCODE_ID) || !ASSERT_DISABLED
374#endif // ENABLE(COMPUTED_GOTO_OPCODES)
375
376#if !ASSERT_DISABLED
377bool Interpreter::isOpcode(Opcode opcode)
378{
379#if ENABLE(COMPUTED_GOTO_OPCODES)
380 return opcode != HashTraits<Opcode>::emptyValue()
381 && !HashTraits<Opcode>::isDeletedValue(opcode)
382 && opcodeIDTable().contains(opcode);
383#else
384 return opcode >= 0 && opcode <= op_end;
385#endif
386}
387#endif // !ASSERT_DISABLED
388
389class GetStackTraceFunctor {
390public:
391 GetStackTraceFunctor(VM& vm, JSCell* owner, Vector<StackFrame>& results, size_t framesToSkip, size_t capacity)
392 : m_vm(vm)
393 , m_owner(owner)
394 , m_results(results)
395 , m_framesToSkip(framesToSkip)
396 , m_remainingCapacityForFrameCapture(capacity)
397 {
398 m_results.reserveInitialCapacity(capacity);
399 }
400
401 StackVisitor::Status operator()(StackVisitor& visitor) const
402 {
403 if (m_framesToSkip > 0) {
404 m_framesToSkip--;
405 return StackVisitor::Continue;
406 }
407
408 if (m_remainingCapacityForFrameCapture) {
409 if (visitor->isWasmFrame()) {
410 m_results.append(StackFrame(visitor->wasmFunctionIndexOrName()));
411 } else if (!!visitor->codeBlock() && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
412 m_results.append(
413 StackFrame(m_vm, m_owner, visitor->callee().asCell(), visitor->codeBlock(), visitor->bytecodeOffset()));
414 } else {
415 m_results.append(
416 StackFrame(m_vm, m_owner, visitor->callee().asCell()));
417 }
418
419 m_remainingCapacityForFrameCapture--;
420 return StackVisitor::Continue;
421 }
422 return StackVisitor::Done;
423 }
424
425private:
426 VM& m_vm;
427 JSCell* m_owner;
428 Vector<StackFrame>& m_results;
429 mutable size_t m_framesToSkip;
430 mutable size_t m_remainingCapacityForFrameCapture;
431};
432
433void Interpreter::getStackTrace(JSCell* owner, Vector<StackFrame>& results, size_t framesToSkip, size_t maxStackSize)
434{
435 DisallowGC disallowGC;
436 VM& vm = m_vm;
437 CallFrame* callFrame = vm.topCallFrame;
438 if (!callFrame || !maxStackSize)
439 return;
440
441 size_t framesCount = 0;
442 size_t maxFramesCountNeeded = maxStackSize + framesToSkip;
443 StackVisitor::visit(callFrame, &vm, [&] (StackVisitor&) -> StackVisitor::Status {
444 if (++framesCount < maxFramesCountNeeded)
445 return StackVisitor::Continue;
446 return StackVisitor::Done;
447 });
448 if (framesCount <= framesToSkip)
449 return;
450
451 framesCount -= framesToSkip;
452 framesCount = std::min(maxStackSize, framesCount);
453
454 GetStackTraceFunctor functor(vm, owner, results, framesToSkip, framesCount);
455 StackVisitor::visit(callFrame, &vm, functor);
456 ASSERT(results.size() == results.capacity());
457}
458
459String Interpreter::stackTraceAsString(VM& vm, const Vector<StackFrame>& stackTrace)
460{
461 // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
462 StringBuilder builder;
463 for (unsigned i = 0; i < stackTrace.size(); i++) {
464 builder.append(String(stackTrace[i].toString(vm)));
465 if (i != stackTrace.size() - 1)
466 builder.append('\n');
467 }
468 return builder.toString();
469}
470
471ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, RequiredHandler requiredHandler)
472{
473 ASSERT(codeBlock);
474#if ENABLE(DFG_JIT)
475 ASSERT(!visitor->isInlinedFrame());
476#endif
477
478 CallFrame* callFrame = visitor->callFrame();
479 unsigned exceptionHandlerIndex;
480 if (JITCode::isOptimizingJIT(codeBlock->jitType()))
481 exceptionHandlerIndex = callFrame->callSiteIndex().bits();
482 else
483 exceptionHandlerIndex = callFrame->bytecodeOffset();
484
485 return codeBlock->handlerForIndex(exceptionHandlerIndex, requiredHandler);
486}
487
488class GetCatchHandlerFunctor {
489public:
490 GetCatchHandlerFunctor()
491 : m_handler(0)
492 {
493 }
494
495 HandlerInfo* handler() { return m_handler; }
496
497 StackVisitor::Status operator()(StackVisitor& visitor) const
498 {
499 visitor.unwindToMachineCodeBlockFrame();
500
501 CodeBlock* codeBlock = visitor->codeBlock();
502 if (!codeBlock)
503 return StackVisitor::Continue;
504
505 m_handler = findExceptionHandler(visitor, codeBlock, RequiredHandler::CatchHandler);
506 if (m_handler)
507 return StackVisitor::Done;
508
509 return StackVisitor::Continue;
510 }
511
512private:
513 mutable HandlerInfo* m_handler;
514};
515
516ALWAYS_INLINE static void notifyDebuggerOfUnwinding(VM& vm, CallFrame* callFrame)
517{
518 auto catchScope = DECLARE_CATCH_SCOPE(vm);
519 if (Debugger* debugger = vm.vmEntryGlobalObject(callFrame)->debugger()) {
520 SuspendExceptionScope scope(&vm);
521 if (callFrame->isAnyWasmCallee()
522 || (callFrame->callee().isCell() && callFrame->callee().asCell()->inherits<JSFunction>(vm)))
523 debugger->unwindEvent(callFrame);
524 else
525 debugger->didExecuteProgram(callFrame);
526 catchScope.assertNoException();
527 }
528}
529
530class UnwindFunctor {
531public:
532 UnwindFunctor(VM& vm, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
533 : m_vm(vm)
534 , m_callFrame(callFrame)
535 , m_isTermination(isTermination)
536 , m_codeBlock(codeBlock)
537 , m_handler(handler)
538 {
539 }
540
541 StackVisitor::Status operator()(StackVisitor& visitor) const
542 {
543 visitor.unwindToMachineCodeBlockFrame();
544 m_callFrame = visitor->callFrame();
545 m_codeBlock = visitor->codeBlock();
546
547 m_handler = nullptr;
548 if (!m_isTermination) {
549 if (m_codeBlock) {
550 m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler);
551 if (m_handler)
552 return StackVisitor::Done;
553 }
554 }
555
556#if ENABLE(WEBASSEMBLY)
557 if (visitor->callee().isCell()) {
558 if (auto* jsToWasmICCallee = jsDynamicCast<JSToWasmICCallee*>(m_vm, visitor->callee().asCell()))
559 m_vm.wasmContext.store(jsToWasmICCallee->function()->previousInstance(m_callFrame), m_vm.softStackLimit());
560 }
561#endif
562
563 notifyDebuggerOfUnwinding(m_vm, m_callFrame);
564
565 copyCalleeSavesToEntryFrameCalleeSavesBuffer(visitor);
566
567 bool shouldStopUnwinding = visitor->callerIsEntryFrame();
568 if (shouldStopUnwinding)
569 return StackVisitor::Done;
570
571 return StackVisitor::Continue;
572 }
573
574private:
575 void copyCalleeSavesToEntryFrameCalleeSavesBuffer(StackVisitor& visitor) const
576 {
577#if ENABLE(ASSEMBLER)
578 Optional<RegisterAtOffsetList> currentCalleeSaves = visitor->calleeSaveRegistersForUnwinding();
579
580 if (!currentCalleeSaves)
581 return;
582
583 RegisterAtOffsetList* allCalleeSaves = RegisterSet::vmCalleeSaveRegisterOffsets();
584 RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
585 CPURegister* frame = reinterpret_cast<CPURegister*>(m_callFrame->registers());
586
587 unsigned registerCount = currentCalleeSaves->size();
588 VMEntryRecord* record = vmEntryRecord(m_vm.topEntryFrame);
589 for (unsigned i = 0; i < registerCount; i++) {
590 RegisterAtOffset currentEntry = currentCalleeSaves->at(i);
591 if (dontCopyRegisters.get(currentEntry.reg()))
592 continue;
593 RegisterAtOffset* calleeSavesEntry = allCalleeSaves->find(currentEntry.reg());
594
595 record->calleeSaveRegistersBuffer[calleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex());
596 }
597#else
598 UNUSED_PARAM(visitor);
599#endif
600 }
601
602 VM& m_vm;
603 CallFrame*& m_callFrame;
604 bool m_isTermination;
605 CodeBlock*& m_codeBlock;
606 HandlerInfo*& m_handler;
607};
608
609NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception)
610{
611 auto scope = DECLARE_CATCH_SCOPE(vm);
612
613 ASSERT(reinterpret_cast<void*>(callFrame) != vm.topEntryFrame);
614 CodeBlock* codeBlock = callFrame->codeBlock();
615
616 JSValue exceptionValue = exception->value();
617 ASSERT(!exceptionValue.isEmpty());
618 ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
619 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
620 // slow cases, so let's harden against it anyway to be safe.
621 if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell()))
622 exceptionValue = jsNull();
623
624 EXCEPTION_ASSERT_UNUSED(scope, scope.exception());
625
626 // Calculate an exception handler vPC, unwinding call frames as necessary.
627 HandlerInfo* handler = nullptr;
628 UnwindFunctor functor(vm, callFrame, isTerminatedExecutionException(vm, exception), codeBlock, handler);
629 StackVisitor::visit<StackVisitor::TerminateIfTopEntryFrameIsEmpty>(callFrame, &vm, functor);
630 if (!handler)
631 return nullptr;
632
633 return handler;
634}
635
636void Interpreter::notifyDebuggerOfExceptionToBeThrown(VM& vm, CallFrame* callFrame, Exception* exception)
637{
638 Debugger* debugger = vm.vmEntryGlobalObject(callFrame)->debugger();
639 if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
640 // This code assumes that if the debugger is enabled then there is no inlining.
641 // If that assumption turns out to be false then we'll ignore the inlined call
642 // frames.
643 // https://bugs.webkit.org/show_bug.cgi?id=121754
644
645 bool hasCatchHandler;
646 bool isTermination = isTerminatedExecutionException(vm, exception);
647 if (isTermination)
648 hasCatchHandler = false;
649 else {
650 GetCatchHandlerFunctor functor;
651 StackVisitor::visit(callFrame, &vm, functor);
652 HandlerInfo* handler = functor.handler();
653 ASSERT(!handler || handler->isCatchHandler());
654 hasCatchHandler = !!handler;
655 }
656
657 debugger->exception(callFrame, exception->value(), hasCatchHandler);
658 }
659 exception->setDidNotifyInspectorOfThrow();
660}
661
662JSValue Interpreter::executeProgram(const SourceCode& source, CallFrame* callFrame, JSObject* thisObj)
663{
664 JSScope* scope = thisObj->globalObject()->globalScope();
665 VM& vm = *scope->vm();
666 auto throwScope = DECLARE_THROW_SCOPE(vm);
667
668 ProgramExecutable* program = ProgramExecutable::create(callFrame, source);
669 EXCEPTION_ASSERT(throwScope.exception() || program);
670 RETURN_IF_EXCEPTION(throwScope, { });
671
672 throwScope.assertNoException();
673 ASSERT(!vm.isCollectorBusyOnCurrentThread());
674 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
675 if (vm.isCollectorBusyOnCurrentThread())
676 return jsNull();
677
678 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
679 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
680
681 // First check if the "program" is actually just a JSON object. If so,
682 // we'll handle the JSON object here. Else, we'll handle real JS code
683 // below at failedJSONP.
684
685 JSGlobalObject* globalObject = scope->globalObject(vm);
686 Vector<JSONPData> JSONPData;
687 bool parseResult;
688 StringView programSource = program->source().view();
689 if (programSource.isNull())
690 return jsUndefined();
691 if (programSource.is8Bit()) {
692 LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP);
693 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject));
694 } else {
695 LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP);
696 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject));
697 }
698
699 RETURN_IF_EXCEPTION(throwScope, { });
700 if (parseResult) {
701 JSValue result;
702 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
703 Vector<JSONPPathEntry> JSONPPath;
704 JSONPPath.swap(JSONPData[entry].m_path);
705 JSValue JSONPValue = JSONPData[entry].m_value.get();
706 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclareVar) {
707 globalObject->addVar(callFrame, JSONPPath[0].m_pathEntryName);
708 RETURN_IF_EXCEPTION(throwScope, { });
709 PutPropertySlot slot(globalObject);
710 globalObject->methodTable(vm)->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
711 RETURN_IF_EXCEPTION(throwScope, { });
712 result = jsUndefined();
713 continue;
714 }
715 JSValue baseObject(globalObject);
716 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
717 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclareVar);
718 switch (JSONPPath[i].m_type) {
719 case JSONPPathEntryTypeDot: {
720 if (i == 0) {
721 RELEASE_ASSERT(baseObject == globalObject);
722
723 auto doGet = [&] (JSSegmentedVariableObject* scope) {
724 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get);
725 if (scope->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot))
726 return slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
727 return JSValue();
728 };
729
730 JSValue result = doGet(globalObject->globalLexicalEnvironment());
731 RETURN_IF_EXCEPTION(throwScope, JSValue());
732 if (result) {
733 baseObject = result;
734 continue;
735 }
736
737 result = doGet(globalObject);
738 RETURN_IF_EXCEPTION(throwScope, JSValue());
739 if (result) {
740 baseObject = result;
741 continue;
742 }
743
744 if (entry)
745 return throwException(callFrame, throwScope, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName));
746 goto failedJSONP;
747 }
748
749 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
750 RETURN_IF_EXCEPTION(throwScope, JSValue());
751 continue;
752 }
753 case JSONPPathEntryTypeLookup: {
754 baseObject = baseObject.get(callFrame, static_cast<unsigned>(JSONPPath[i].m_pathIndex));
755 RETURN_IF_EXCEPTION(throwScope, JSValue());
756 continue;
757 }
758 default:
759 RELEASE_ASSERT_NOT_REACHED();
760 return jsUndefined();
761 }
762 }
763
764 if (JSONPPath.size() == 1 && JSONPPath.last().m_type != JSONPPathEntryTypeLookup) {
765 RELEASE_ASSERT(baseObject == globalObject);
766 JSGlobalLexicalEnvironment* scope = globalObject->globalLexicalEnvironment();
767 if (scope->hasProperty(callFrame, JSONPPath.last().m_pathEntryName))
768 baseObject = scope;
769 RETURN_IF_EXCEPTION(throwScope, JSValue());
770 }
771
772 PutPropertySlot slot(baseObject);
773 switch (JSONPPath.last().m_type) {
774 case JSONPPathEntryTypeCall: {
775 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
776 RETURN_IF_EXCEPTION(throwScope, JSValue());
777 CallData callData;
778 CallType callType = getCallData(vm, function, callData);
779 if (callType == CallType::None)
780 return throwException(callFrame, throwScope, createNotAFunctionError(callFrame, function));
781 MarkedArgumentBuffer jsonArg;
782 jsonArg.append(JSONPValue);
783 ASSERT(!jsonArg.hasOverflowed());
784 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined() : baseObject;
785 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
786 RETURN_IF_EXCEPTION(throwScope, JSValue());
787 break;
788 }
789 case JSONPPathEntryTypeDot: {
790 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
791 RETURN_IF_EXCEPTION(throwScope, JSValue());
792 break;
793 }
794 case JSONPPathEntryTypeLookup: {
795 baseObject.putByIndex(callFrame, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode());
796 RETURN_IF_EXCEPTION(throwScope, JSValue());
797 break;
798 }
799 default:
800 RELEASE_ASSERT_NOT_REACHED();
801 return jsUndefined();
802 }
803 result = JSONPValue;
804 }
805 return result;
806 }
807failedJSONP:
808 // If we get here, then we have already proven that the script is not a JSON
809 // object.
810
811 VMEntryScope entryScope(vm, globalObject);
812
813 // Compile source to bytecode if necessary:
814 JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope);
815 EXCEPTION_ASSERT(!throwScope.exception() || !error);
816 if (UNLIKELY(error))
817 return checkedReturn(throwException(callFrame, throwScope, error));
818
819 ProgramCodeBlock* codeBlock;
820 {
821 CodeBlock* tempCodeBlock;
822 Exception* error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
823 EXCEPTION_ASSERT(throwScope.exception() == error);
824 if (UNLIKELY(error))
825 return checkedReturn(error);
826 codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
827 }
828
829 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
830 if (UNLIKELY(vm.needTrapHandling(mask))) {
831 vm.handleTraps(callFrame, mask);
832 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
833 }
834
835 if (scope->structure(vm)->isUncacheableDictionary())
836 scope->flattenDictionaryObject(vm);
837
838 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
839
840 ProtoCallFrame protoCallFrame;
841 protoCallFrame.init(codeBlock, JSCallee::create(vm, globalObject, scope), thisObj, 1);
842
843 // Execute the code:
844 throwScope.release();
845 JSValue result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
846 return checkedReturn(result);
847}
848
849JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
850{
851 VM& vm = callFrame->vm();
852 auto throwScope = DECLARE_THROW_SCOPE(vm);
853
854 throwScope.assertNoException();
855 ASSERT(!vm.isCollectorBusyOnCurrentThread());
856 if (vm.isCollectorBusyOnCurrentThread())
857 return jsNull();
858
859 bool isJSCall = (callType == CallType::JS);
860 JSScope* scope = nullptr;
861 CodeBlock* newCodeBlock;
862 size_t argsCount = 1 + args.size(); // implicit "this" parameter
863
864 JSGlobalObject* globalObject;
865
866 if (isJSCall) {
867 scope = callData.js.scope;
868 globalObject = scope->globalObject(vm);
869 } else {
870 ASSERT(callType == CallType::Host);
871 globalObject = function->globalObject(vm);
872 }
873
874 VMEntryScope entryScope(vm, globalObject);
875 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
876 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
877
878 if (isJSCall) {
879 // Compile the callee:
880 Exception* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
881 EXCEPTION_ASSERT(throwScope.exception() == compileError);
882 if (UNLIKELY(!!compileError))
883 return checkedReturn(compileError);
884
885 ASSERT(!!newCodeBlock);
886 newCodeBlock->m_shouldAlwaysBeInlined = false;
887 } else
888 newCodeBlock = 0;
889
890 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
891 if (UNLIKELY(vm.needTrapHandling(mask))) {
892 vm.handleTraps(callFrame, mask);
893 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
894 }
895
896 ProtoCallFrame protoCallFrame;
897 protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data());
898
899 JSValue result;
900 {
901 // Execute the code:
902 if (isJSCall) {
903 throwScope.release();
904 result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
905 } else {
906 result = JSValue::decode(vmEntryToNative(callData.native.function.rawPointer(), &vm, &protoCallFrame));
907 RETURN_IF_EXCEPTION(throwScope, JSValue());
908 }
909 }
910
911 return checkedReturn(result);
912}
913
914JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
915{
916 VM& vm = callFrame->vm();
917 auto throwScope = DECLARE_THROW_SCOPE(vm);
918
919 throwScope.assertNoException();
920 ASSERT(!vm.isCollectorBusyOnCurrentThread());
921 // We throw in this case because we have to return something "valid" but we're
922 // already in an invalid state.
923 if (UNLIKELY(vm.isCollectorBusyOnCurrentThread())) {
924 throwStackOverflowError(callFrame, throwScope);
925 return nullptr;
926 }
927
928 bool isJSConstruct = (constructType == ConstructType::JS);
929 JSScope* scope = nullptr;
930 CodeBlock* newCodeBlock;
931 size_t argsCount = 1 + args.size(); // implicit "this" parameter
932
933 JSGlobalObject* globalObject;
934
935 if (isJSConstruct) {
936 scope = constructData.js.scope;
937 globalObject = scope->globalObject(vm);
938 } else {
939 ASSERT(constructType == ConstructType::Host);
940 globalObject = constructor->globalObject(vm);
941 }
942
943 VMEntryScope entryScope(vm, globalObject);
944 if (UNLIKELY(!vm.isSafeToRecurseSoft())) {
945 throwStackOverflowError(callFrame, throwScope);
946 return nullptr;
947 }
948
949 if (isJSConstruct) {
950 // Compile the callee:
951 Exception* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
952 EXCEPTION_ASSERT(throwScope.exception() == compileError);
953 if (UNLIKELY(!!compileError))
954 return nullptr;
955
956 ASSERT(!!newCodeBlock);
957 newCodeBlock->m_shouldAlwaysBeInlined = false;
958 } else
959 newCodeBlock = 0;
960
961 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
962 if (UNLIKELY(vm.needTrapHandling(mask))) {
963 vm.handleTraps(callFrame, mask);
964 RETURN_IF_EXCEPTION(throwScope, nullptr);
965 }
966
967 ProtoCallFrame protoCallFrame;
968 protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
969
970 JSValue result;
971 {
972 // Execute the code.
973 if (isJSConstruct)
974 result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
975 else {
976 result = JSValue::decode(vmEntryToNative(constructData.native.function.rawPointer(), &vm, &protoCallFrame));
977
978 if (LIKELY(!throwScope.exception()))
979 RELEASE_ASSERT(result.isObject());
980 }
981 }
982
983 RETURN_IF_EXCEPTION(throwScope, 0);
984 ASSERT(result.isObject());
985 return checkedReturn(asObject(result));
986}
987
988CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, const ArgList& args)
989{
990 VM& vm = *scope->vm();
991 auto throwScope = DECLARE_THROW_SCOPE(vm);
992 throwScope.assertNoException();
993
994 if (vm.isCollectorBusyOnCurrentThread())
995 return CallFrameClosure();
996
997 // Compile the callee:
998 CodeBlock* newCodeBlock;
999 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock);
1000 EXCEPTION_ASSERT(throwScope.exception() == error);
1001 if (UNLIKELY(error))
1002 return CallFrameClosure();
1003 newCodeBlock->m_shouldAlwaysBeInlined = false;
1004
1005 size_t argsCount = argumentCountIncludingThis;
1006
1007 protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args.data());
1008 // Return the successful closure:
1009 CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
1010 return result;
1011}
1012
1013JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
1014{
1015 VM& vm = *scope->vm();
1016 auto throwScope = DECLARE_THROW_SCOPE(vm);
1017
1018 ASSERT(&vm == &callFrame->vm());
1019 throwScope.assertNoException();
1020 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1021 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1022 if (vm.isCollectorBusyOnCurrentThread())
1023 return jsNull();
1024
1025 VMEntryScope entryScope(vm, scope->globalObject(vm));
1026 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1027 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
1028
1029 unsigned numVariables = eval->numVariables();
1030 unsigned numTopLevelFunctionDecls = eval->numTopLevelFunctionDecls();
1031 unsigned numFunctionHoistingCandidates = eval->numFunctionHoistingCandidates();
1032
1033 JSScope* variableObject;
1034 if ((numVariables || numTopLevelFunctionDecls) && eval->isStrictMode()) {
1035 scope = StrictEvalActivation::create(vm, callFrame->lexicalGlobalObject()->strictEvalActivationStructure(), scope);
1036 variableObject = scope;
1037 } else {
1038 for (JSScope* node = scope; ; node = node->next()) {
1039 RELEASE_ASSERT(node);
1040 if (node->isGlobalObject()) {
1041 variableObject = node;
1042 break;
1043 }
1044 if (node->isJSLexicalEnvironment()) {
1045 JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(node);
1046 if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) {
1047 variableObject = node;
1048 break;
1049 }
1050 }
1051 }
1052 }
1053
1054 EvalCodeBlock* codeBlock;
1055 {
1056 CodeBlock* tempCodeBlock;
1057 Exception* compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1058 EXCEPTION_ASSERT(throwScope.exception() == compileError);
1059 if (UNLIKELY(!!compileError))
1060 return checkedReturn(compileError);
1061 codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock);
1062 }
1063 UnlinkedEvalCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedEvalCodeBlock();
1064
1065 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
1066 if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numTopLevelFunctionDecls)) {
1067 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment();
1068 for (unsigned i = 0; i < numVariables; ++i) {
1069 const Identifier& ident = unlinkedCodeBlock->variable(i);
1070 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1071 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, ident, slot)) {
1072 return checkedReturn(throwTypeError(callFrame, throwScope, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'")));
1073 }
1074 }
1075
1076 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1077 FunctionExecutable* function = codeBlock->functionDecl(i);
1078 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1079 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, function->name(), slot)) {
1080 return checkedReturn(throwTypeError(callFrame, throwScope, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'")));
1081 }
1082 }
1083 }
1084
1085 if (variableObject->structure(vm)->isUncacheableDictionary())
1086 variableObject->flattenDictionaryObject(vm);
1087
1088 if (numVariables || numTopLevelFunctionDecls || numFunctionHoistingCandidates) {
1089 BatchedTransitionOptimizer optimizer(vm, variableObject);
1090 if (variableObject->next() && !eval->isStrictMode())
1091 variableObject->globalObject(vm)->varInjectionWatchpoint()->fireAll(vm, "Executed eval, fired VarInjection watchpoint");
1092
1093 for (unsigned i = 0; i < numVariables; ++i) {
1094 const Identifier& ident = unlinkedCodeBlock->variable(i);
1095 bool hasProperty = variableObject->hasProperty(callFrame, ident);
1096 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1097 if (!hasProperty) {
1098 PutPropertySlot slot(variableObject);
1099 if (!variableObject->isExtensible(callFrame))
1100 return checkedReturn(throwTypeError(callFrame, throwScope, NonExtensibleObjectPropertyDefineError));
1101 variableObject->methodTable(vm)->put(variableObject, callFrame, ident, jsUndefined(), slot);
1102 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1103 }
1104 }
1105
1106 if (eval->isStrictMode()) {
1107 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1108 FunctionExecutable* function = codeBlock->functionDecl(i);
1109 PutPropertySlot slot(variableObject);
1110 // We need create this variables because it will be used to emits code by bytecode generator
1111 variableObject->methodTable(vm)->put(variableObject, callFrame, function->name(), jsUndefined(), slot);
1112 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1113 }
1114 } else {
1115 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1116 FunctionExecutable* function = codeBlock->functionDecl(i);
1117 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(callFrame, scope, function->name());
1118 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1119 if (resolvedScope.isUndefined())
1120 return checkedReturn(throwSyntaxError(callFrame, throwScope, makeString("Can't create duplicate variable in eval: '", String(function->name().impl()), "'")));
1121 PutPropertySlot slot(variableObject);
1122 // We need create this variables because it will be used to emits code by bytecode generator
1123 variableObject->methodTable(vm)->put(variableObject, callFrame, function->name(), jsUndefined(), slot);
1124 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1125 }
1126
1127 for (unsigned i = 0; i < numFunctionHoistingCandidates; ++i) {
1128 const Identifier& ident = unlinkedCodeBlock->functionHoistingCandidate(i);
1129 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(callFrame, scope, ident);
1130 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1131 if (!resolvedScope.isUndefined()) {
1132 bool hasProperty = variableObject->hasProperty(callFrame, ident);
1133 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1134 if (!hasProperty) {
1135 PutPropertySlot slot(variableObject);
1136 variableObject->methodTable(vm)->put(variableObject, callFrame, ident, jsUndefined(), slot);
1137 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1138 }
1139 }
1140 }
1141 }
1142 }
1143
1144 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
1145 if (UNLIKELY(vm.needTrapHandling(mask))) {
1146 vm.handleTraps(callFrame, mask);
1147 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
1148 }
1149
1150 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1151
1152 ProtoCallFrame protoCallFrame;
1153 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(vm), scope), thisValue, 1);
1154
1155 // Execute the code:
1156 throwScope.release();
1157 JSValue result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
1158
1159 return checkedReturn(result);
1160}
1161
1162JSValue Interpreter::executeModuleProgram(ModuleProgramExecutable* executable, CallFrame* callFrame, JSModuleEnvironment* scope)
1163{
1164 VM& vm = *scope->vm();
1165 auto throwScope = DECLARE_THROW_SCOPE(vm);
1166
1167 ASSERT(&vm == &callFrame->vm());
1168 throwScope.assertNoException();
1169 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1170 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1171 if (vm.isCollectorBusyOnCurrentThread())
1172 return jsNull();
1173
1174 VMEntryScope entryScope(vm, scope->globalObject(vm));
1175 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1176 return checkedReturn(throwStackOverflowError(callFrame, throwScope));
1177
1178 ModuleProgramCodeBlock* codeBlock;
1179 {
1180 CodeBlock* tempCodeBlock;
1181 Exception* compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1182 EXCEPTION_ASSERT(throwScope.exception() == compileError);
1183 if (UNLIKELY(!!compileError))
1184 return checkedReturn(compileError);
1185 codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
1186 }
1187
1188 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
1189 if (UNLIKELY(vm.needTrapHandling(mask))) {
1190 vm.handleTraps(callFrame, mask);
1191 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
1192 }
1193
1194 if (scope->structure(vm)->isUncacheableDictionary())
1195 scope->flattenDictionaryObject(vm);
1196
1197 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1198
1199 // The |this| of the module is always `undefined`.
1200 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding
1201 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding
1202 ProtoCallFrame protoCallFrame;
1203 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(vm), scope), jsUndefined(), 1);
1204
1205 // Execute the code:
1206 throwScope.release();
1207 JSValue result = executable->generatedJITCode()->execute(&vm, &protoCallFrame);
1208
1209 return checkedReturn(result);
1210}
1211
1212NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookType debugHookType)
1213{
1214 VM& vm = callFrame->vm();
1215 auto scope = DECLARE_CATCH_SCOPE(vm);
1216 Debugger* debugger = vm.vmEntryGlobalObject(callFrame)->debugger();
1217 if (!debugger)
1218 return;
1219
1220 ASSERT(callFrame->codeBlock()->hasDebuggerRequests());
1221 scope.assertNoException();
1222
1223 switch (debugHookType) {
1224 case DidEnterCallFrame:
1225 debugger->callEvent(callFrame);
1226 break;
1227 case WillLeaveCallFrame:
1228 debugger->returnEvent(callFrame);
1229 break;
1230 case WillExecuteStatement:
1231 debugger->atStatement(callFrame);
1232 break;
1233 case WillExecuteExpression:
1234 debugger->atExpression(callFrame);
1235 break;
1236 case WillExecuteProgram:
1237 debugger->willExecuteProgram(callFrame);
1238 break;
1239 case DidExecuteProgram:
1240 debugger->didExecuteProgram(callFrame);
1241 break;
1242 case DidReachBreakpoint:
1243 debugger->didReachBreakpoint(callFrame);
1244 break;
1245 }
1246 scope.assertNoException();
1247}
1248
1249} // namespace JSC
1250
1251namespace WTF {
1252
1253void printInternal(PrintStream& out, JSC::DebugHookType type)
1254{
1255 switch (type) {
1256 case JSC::WillExecuteProgram:
1257 out.print("WillExecuteProgram");
1258 return;
1259 case JSC::DidExecuteProgram:
1260 out.print("DidExecuteProgram");
1261 return;
1262 case JSC::DidEnterCallFrame:
1263 out.print("DidEnterCallFrame");
1264 return;
1265 case JSC::DidReachBreakpoint:
1266 out.print("DidReachBreakpoint");
1267 return;
1268 case JSC::WillLeaveCallFrame:
1269 out.print("WillLeaveCallFrame");
1270 return;
1271 case JSC::WillExecuteStatement:
1272 out.print("WillExecuteStatement");
1273 return;
1274 case JSC::WillExecuteExpression:
1275 out.print("WillExecuteExpression");
1276 return;
1277 }
1278}
1279
1280} // namespace WTF
1281