1/*
2 * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
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 "ProtoCallFrameInlines.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(JSGlobalObject* globalObject, CallFrame* callFrame)
105{
106 VM& vm = globalObject->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 if (!globalObject->evalEnabled()) {
118 throwException(globalObject, scope, createEvalError(globalObject, globalObject->evalDisabledErrorMessage()));
119 return jsUndefined();
120 }
121 String programSource = asString(program)->value(globalObject);
122 RETURN_IF_EXCEPTION(scope, JSValue());
123
124 CallFrame* callerFrame = callFrame->callerFrame();
125 CallSiteIndex callerCallSiteIndex = callerFrame->callSiteIndex();
126 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
127 JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
128 UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
129
130 bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext();
131
132 DerivedContextType derivedContextType = callerUnlinkedCodeBlock->derivedContextType();
133 if (!isArrowFunctionContext && callerUnlinkedCodeBlock->isClassContext()) {
134 derivedContextType = callerUnlinkedCodeBlock->isConstructor()
135 ? DerivedContextType::DerivedConstructorContext
136 : DerivedContextType::DerivedMethodContext;
137 }
138
139 EvalContextType evalContextType;
140 if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
141 evalContextType = EvalContextType::FunctionEvalContext;
142 else if (callerUnlinkedCodeBlock->codeType() == EvalCode)
143 evalContextType = callerUnlinkedCodeBlock->evalContextType();
144 else
145 evalContextType = EvalContextType::None;
146
147 DirectEvalExecutable* eval = callerCodeBlock->directEvalCodeCache().tryGet(programSource, callerCallSiteIndex);
148 if (!eval) {
149 if (!callerCodeBlock->isStrictMode()) {
150 if (programSource.is8Bit()) {
151 LiteralParser<LChar> preparser(globalObject, programSource.characters8(), programSource.length(), NonStrictJSON, callerCodeBlock);
152 if (JSValue parsedObject = preparser.tryLiteralParse())
153 RELEASE_AND_RETURN(scope, parsedObject);
154
155 } else {
156 LiteralParser<UChar> preparser(globalObject, programSource.characters16(), programSource.length(), NonStrictJSON, callerCodeBlock);
157 if (JSValue parsedObject = preparser.tryLiteralParse())
158 RELEASE_AND_RETURN(scope, parsedObject);
159
160 }
161 RETURN_IF_EXCEPTION(scope, JSValue());
162 }
163
164 VariableEnvironment variablesUnderTDZ;
165 JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ);
166 eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, isArrowFunctionContext, evalContextType, &variablesUnderTDZ);
167 EXCEPTION_ASSERT(!!scope.exception() == !eval);
168 if (!eval)
169 return jsUndefined();
170
171 callerCodeBlock->directEvalCodeCache().set(globalObject, callerCodeBlock, programSource, callerCallSiteIndex, eval);
172 }
173
174 JSValue thisValue = callerFrame->thisValue();
175 Interpreter* interpreter = vm.interpreter;
176 RELEASE_AND_RETURN(scope, interpreter->execute(eval, globalObject, thisValue, callerScopeChain));
177}
178
179unsigned sizeOfVarargs(JSGlobalObject* globalObject, JSValue arguments, uint32_t firstVarArgOffset)
180{
181 VM& vm = globalObject->vm();
182 auto scope = DECLARE_THROW_SCOPE(vm);
183
184 if (UNLIKELY(!arguments.isCell())) {
185 if (arguments.isUndefinedOrNull())
186 return 0;
187
188 throwException(globalObject, scope, createInvalidFunctionApplyParameterError(globalObject, arguments));
189 return 0;
190 }
191
192 JSCell* cell = arguments.asCell();
193 unsigned length;
194 switch (cell->type()) {
195 case DirectArgumentsType:
196 length = jsCast<DirectArguments*>(cell)->length(globalObject);
197 break;
198 case ScopedArgumentsType:
199 length = jsCast<ScopedArguments*>(cell)->length(globalObject);
200 break;
201 case JSFixedArrayType:
202 length = jsCast<JSFixedArray*>(cell)->size();
203 break;
204 case JSImmutableButterflyType:
205 length = jsCast<JSImmutableButterfly*>(cell)->length();
206 break;
207 case StringType:
208 case SymbolType:
209 case BigIntType:
210 throwException(globalObject, scope, createInvalidFunctionApplyParameterError(globalObject, arguments));
211 return 0;
212
213 default:
214 RELEASE_ASSERT(arguments.isObject());
215 length = clampToUnsigned(toLength(globalObject, jsCast<JSObject*>(cell)));
216 break;
217 }
218 RETURN_IF_EXCEPTION(scope, 0);
219
220 if (length >= firstVarArgOffset)
221 length -= firstVarArgOffset;
222 else
223 length = 0;
224
225 return length;
226}
227
228unsigned sizeFrameForForwardArguments(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, unsigned numUsedStackSlots)
229{
230 auto scope = DECLARE_THROW_SCOPE(vm);
231
232 unsigned length = callFrame->argumentCount();
233 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
234 if (UNLIKELY(!vm.ensureStackCapacityFor(calleeFrame->registers())))
235 throwStackOverflowError(globalObject, scope);
236
237 return length;
238}
239
240unsigned sizeFrameForVarargs(JSGlobalObject* globalObject, CallFrame* callFrame, VM& vm, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
241{
242 auto scope = DECLARE_THROW_SCOPE(vm);
243
244 unsigned length = sizeOfVarargs(globalObject, arguments, firstVarArgOffset);
245 RETURN_IF_EXCEPTION(scope, 0);
246
247 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
248 if (UNLIKELY(length > maxArguments || !vm.ensureStackCapacityFor(calleeFrame->registers()))) {
249 throwStackOverflowError(globalObject, scope);
250 return 0;
251 }
252
253 return length;
254}
255
256void loadVarargs(JSGlobalObject* globalObject, CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
257{
258 if (UNLIKELY(!arguments.isCell()) || !length)
259 return;
260
261 VM& vm = globalObject->vm();
262 auto scope = DECLARE_THROW_SCOPE(vm);
263 JSCell* cell = arguments.asCell();
264
265 switch (cell->type()) {
266 case DirectArgumentsType:
267 scope.release();
268 jsCast<DirectArguments*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
269 return;
270 case ScopedArgumentsType:
271 scope.release();
272 jsCast<ScopedArguments*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
273 return;
274 case JSFixedArrayType:
275 scope.release();
276 jsCast<JSFixedArray*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
277 return;
278 case JSImmutableButterflyType:
279 scope.release();
280 jsCast<JSImmutableButterfly*>(cell)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
281 return;
282 default: {
283 ASSERT(arguments.isObject());
284 JSObject* object = jsCast<JSObject*>(cell);
285 if (isJSArray(object)) {
286 scope.release();
287 jsCast<JSArray*>(object)->copyToArguments(globalObject, callFrame, firstElementDest, offset, length);
288 return;
289 }
290 unsigned i;
291 for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i)
292 callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset);
293 for (; i < length; ++i) {
294 JSValue value = object->get(globalObject, i + offset);
295 RETURN_IF_EXCEPTION(scope, void());
296 callFrame->r(firstElementDest + i) = value;
297 }
298 return;
299 } }
300}
301
302void setupVarargsFrame(JSGlobalObject* globalObject, CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
303{
304 VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
305
306 loadVarargs(
307 globalObject,
308 callFrame,
309 calleeFrameOffset + CallFrame::argumentOffset(0),
310 arguments, offset, length);
311
312 newCallFrame->setArgumentCountIncludingThis(length + 1);
313}
314
315void setupVarargsFrameAndSetThis(JSGlobalObject* globalObject, CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
316{
317 setupVarargsFrame(globalObject, callFrame, newCallFrame, arguments, firstVarArgOffset, length);
318 newCallFrame->setThisValue(thisValue);
319}
320
321void setupForwardArgumentsFrame(JSGlobalObject*, 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(JSGlobalObject* globalObject, CallFrame* execCaller, CallFrame* execCallee, JSValue thisValue, uint32_t length)
330{
331 setupForwardArgumentsFrame(globalObject, 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->bytecodeIndex()));
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->bytecodeIndex().offset();
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 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject(vm);
519 auto catchScope = DECLARE_CATCH_SCOPE(vm);
520 if (Debugger* debugger = globalObject->debugger()) {
521 SuspendExceptionScope scope(&vm);
522 if (callFrame->isAnyWasmCallee()
523 || (callFrame->callee().isCell() && callFrame->callee().asCell()->inherits<JSFunction>(vm)))
524 debugger->unwindEvent(callFrame);
525 else
526 debugger->didExecuteProgram(callFrame);
527 catchScope.assertNoException();
528 }
529}
530
531class UnwindFunctor {
532public:
533 UnwindFunctor(VM& vm, CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
534 : m_vm(vm)
535 , m_callFrame(callFrame)
536 , m_isTermination(isTermination)
537 , m_codeBlock(codeBlock)
538 , m_handler(handler)
539 {
540 }
541
542 StackVisitor::Status operator()(StackVisitor& visitor) const
543 {
544 visitor.unwindToMachineCodeBlockFrame();
545 m_callFrame = visitor->callFrame();
546 m_codeBlock = visitor->codeBlock();
547
548 m_handler = nullptr;
549 if (!m_isTermination) {
550 if (m_codeBlock) {
551 m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler);
552 if (m_handler)
553 return StackVisitor::Done;
554 }
555 }
556
557#if ENABLE(WEBASSEMBLY)
558 if (visitor->callee().isCell()) {
559 if (auto* jsToWasmICCallee = jsDynamicCast<JSToWasmICCallee*>(m_vm, visitor->callee().asCell()))
560 m_vm.wasmContext.store(jsToWasmICCallee->function()->previousInstance(m_callFrame), m_vm.softStackLimit());
561 }
562#endif
563
564 notifyDebuggerOfUnwinding(m_vm, m_callFrame);
565
566 copyCalleeSavesToEntryFrameCalleeSavesBuffer(visitor);
567
568 bool shouldStopUnwinding = visitor->callerIsEntryFrame();
569 if (shouldStopUnwinding)
570 return StackVisitor::Done;
571
572 return StackVisitor::Continue;
573 }
574
575private:
576 void copyCalleeSavesToEntryFrameCalleeSavesBuffer(StackVisitor& visitor) const
577 {
578#if ENABLE(ASSEMBLER)
579 Optional<RegisterAtOffsetList> currentCalleeSaves = visitor->calleeSaveRegistersForUnwinding();
580
581 if (!currentCalleeSaves)
582 return;
583
584 RegisterAtOffsetList* allCalleeSaves = RegisterSet::vmCalleeSaveRegisterOffsets();
585 RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
586 CPURegister* frame = reinterpret_cast<CPURegister*>(m_callFrame->registers());
587
588 unsigned registerCount = currentCalleeSaves->size();
589 VMEntryRecord* record = vmEntryRecord(m_vm.topEntryFrame);
590 for (unsigned i = 0; i < registerCount; i++) {
591 RegisterAtOffset currentEntry = currentCalleeSaves->at(i);
592 if (dontCopyRegisters.get(currentEntry.reg()))
593 continue;
594 RegisterAtOffset* calleeSavesEntry = allCalleeSaves->find(currentEntry.reg());
595
596 record->calleeSaveRegistersBuffer[calleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex());
597 }
598#else
599 UNUSED_PARAM(visitor);
600#endif
601 }
602
603 VM& m_vm;
604 CallFrame*& m_callFrame;
605 bool m_isTermination;
606 CodeBlock*& m_codeBlock;
607 HandlerInfo*& m_handler;
608};
609
610NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception)
611{
612 auto scope = DECLARE_CATCH_SCOPE(vm);
613
614 ASSERT(reinterpret_cast<void*>(callFrame) != vm.topEntryFrame);
615 CodeBlock* codeBlock = callFrame->codeBlock();
616
617 JSValue exceptionValue = exception->value();
618 ASSERT(!exceptionValue.isEmpty());
619 ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
620 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
621 // slow cases, so let's harden against it anyway to be safe.
622 if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell()))
623 exceptionValue = jsNull();
624
625 EXCEPTION_ASSERT_UNUSED(scope, scope.exception());
626
627 // Calculate an exception handler vPC, unwinding call frames as necessary.
628 HandlerInfo* handler = nullptr;
629 UnwindFunctor functor(vm, callFrame, isTerminatedExecutionException(vm, exception), codeBlock, handler);
630 StackVisitor::visit<StackVisitor::TerminateIfTopEntryFrameIsEmpty>(callFrame, vm, functor);
631 if (!handler)
632 return nullptr;
633
634 return handler;
635}
636
637void Interpreter::notifyDebuggerOfExceptionToBeThrown(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame, Exception* exception)
638{
639 Debugger* debugger = globalObject->debugger();
640 if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
641 // This code assumes that if the debugger is enabled then there is no inlining.
642 // If that assumption turns out to be false then we'll ignore the inlined call
643 // frames.
644 // https://bugs.webkit.org/show_bug.cgi?id=121754
645
646 bool hasCatchHandler;
647 bool isTermination = isTerminatedExecutionException(vm, exception);
648 if (isTermination)
649 hasCatchHandler = false;
650 else {
651 GetCatchHandlerFunctor functor;
652 StackVisitor::visit(callFrame, vm, functor);
653 HandlerInfo* handler = functor.handler();
654 ASSERT(!handler || handler->isCatchHandler());
655 hasCatchHandler = !!handler;
656 }
657
658 debugger->exception(globalObject, callFrame, exception->value(), hasCatchHandler);
659 }
660 exception->setDidNotifyInspectorOfThrow();
661}
662
663JSValue Interpreter::executeProgram(const SourceCode& source, JSGlobalObject*, JSObject* thisObj)
664{
665 JSScope* scope = thisObj->globalObject()->globalScope();
666 VM& vm = scope->vm();
667 auto throwScope = DECLARE_THROW_SCOPE(vm);
668 JSGlobalObject* globalObject = scope->globalObject(vm);
669
670 ProgramExecutable* program = ProgramExecutable::create(globalObject, source);
671 EXCEPTION_ASSERT(throwScope.exception() || program);
672 RETURN_IF_EXCEPTION(throwScope, { });
673
674 throwScope.assertNoException();
675 ASSERT(!vm.isCollectorBusyOnCurrentThread());
676 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
677 if (vm.isCollectorBusyOnCurrentThread())
678 return jsNull();
679
680 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
681 return checkedReturn(throwStackOverflowError(globalObject, throwScope));
682
683 // First check if the "program" is actually just a JSON object. If so,
684 // we'll handle the JSON object here. Else, we'll handle real JS code
685 // below at failedJSONP.
686
687 Vector<JSONPData> JSONPData;
688 bool parseResult;
689 StringView programSource = program->source().view();
690 if (programSource.isNull())
691 return jsUndefined();
692 if (programSource.is8Bit()) {
693 LiteralParser<LChar> literalParser(globalObject, programSource.characters8(), programSource.length(), JSONP);
694 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject));
695 } else {
696 LiteralParser<UChar> literalParser(globalObject, programSource.characters16(), programSource.length(), JSONP);
697 parseResult = literalParser.tryJSONPParse(JSONPData, globalObject->globalObjectMethodTable()->supportsRichSourceInfo(globalObject));
698 }
699
700 RETURN_IF_EXCEPTION(throwScope, { });
701 if (parseResult) {
702 JSValue result;
703 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
704 Vector<JSONPPathEntry> JSONPPath;
705 JSONPPath.swap(JSONPData[entry].m_path);
706 JSValue JSONPValue = JSONPData[entry].m_value.get();
707 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclareVar) {
708 globalObject->addVar(globalObject, JSONPPath[0].m_pathEntryName);
709 RETURN_IF_EXCEPTION(throwScope, { });
710 PutPropertySlot slot(globalObject);
711 globalObject->methodTable(vm)->put(globalObject, globalObject, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
712 RETURN_IF_EXCEPTION(throwScope, { });
713 result = jsUndefined();
714 continue;
715 }
716 JSValue baseObject(globalObject);
717 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
718 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclareVar);
719 switch (JSONPPath[i].m_type) {
720 case JSONPPathEntryTypeDot: {
721 if (i == 0) {
722 RELEASE_ASSERT(baseObject == globalObject);
723
724 auto doGet = [&] (JSSegmentedVariableObject* scope) {
725 PropertySlot slot(scope, PropertySlot::InternalMethodType::Get);
726 if (scope->getPropertySlot(globalObject, JSONPPath[i].m_pathEntryName, slot))
727 return slot.getValue(globalObject, JSONPPath[i].m_pathEntryName);
728 return JSValue();
729 };
730
731 JSValue result = doGet(globalObject->globalLexicalEnvironment());
732 RETURN_IF_EXCEPTION(throwScope, JSValue());
733 if (result) {
734 baseObject = result;
735 continue;
736 }
737
738 result = doGet(globalObject);
739 RETURN_IF_EXCEPTION(throwScope, JSValue());
740 if (result) {
741 baseObject = result;
742 continue;
743 }
744
745 if (entry)
746 return throwException(globalObject, throwScope, createUndefinedVariableError(globalObject, JSONPPath[i].m_pathEntryName));
747 goto failedJSONP;
748 }
749
750 baseObject = baseObject.get(globalObject, JSONPPath[i].m_pathEntryName);
751 RETURN_IF_EXCEPTION(throwScope, JSValue());
752 continue;
753 }
754 case JSONPPathEntryTypeLookup: {
755 baseObject = baseObject.get(globalObject, static_cast<unsigned>(JSONPPath[i].m_pathIndex));
756 RETURN_IF_EXCEPTION(throwScope, JSValue());
757 continue;
758 }
759 default:
760 RELEASE_ASSERT_NOT_REACHED();
761 return jsUndefined();
762 }
763 }
764
765 if (JSONPPath.size() == 1 && JSONPPath.last().m_type != JSONPPathEntryTypeLookup) {
766 RELEASE_ASSERT(baseObject == globalObject);
767 JSGlobalLexicalEnvironment* scope = globalObject->globalLexicalEnvironment();
768 if (scope->hasProperty(globalObject, JSONPPath.last().m_pathEntryName))
769 baseObject = scope;
770 RETURN_IF_EXCEPTION(throwScope, JSValue());
771 }
772
773 PutPropertySlot slot(baseObject);
774 switch (JSONPPath.last().m_type) {
775 case JSONPPathEntryTypeCall: {
776 JSValue function = baseObject.get(globalObject, JSONPPath.last().m_pathEntryName);
777 RETURN_IF_EXCEPTION(throwScope, JSValue());
778 CallData callData;
779 CallType callType = getCallData(vm, function, callData);
780 if (callType == CallType::None)
781 return throwException(globalObject, throwScope, createNotAFunctionError(globalObject, function));
782 MarkedArgumentBuffer jsonArg;
783 jsonArg.append(JSONPValue);
784 ASSERT(!jsonArg.hasOverflowed());
785 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined() : baseObject;
786 JSONPValue = JSC::call(globalObject, function, callType, callData, thisValue, jsonArg);
787 RETURN_IF_EXCEPTION(throwScope, JSValue());
788 break;
789 }
790 case JSONPPathEntryTypeDot: {
791 baseObject.put(globalObject, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
792 RETURN_IF_EXCEPTION(throwScope, JSValue());
793 break;
794 }
795 case JSONPPathEntryTypeLookup: {
796 baseObject.putByIndex(globalObject, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode());
797 RETURN_IF_EXCEPTION(throwScope, JSValue());
798 break;
799 }
800 default:
801 RELEASE_ASSERT_NOT_REACHED();
802 return jsUndefined();
803 }
804 result = JSONPValue;
805 }
806 return result;
807 }
808failedJSONP:
809 // If we get here, then we have already proven that the script is not a JSON
810 // object.
811
812 VMEntryScope entryScope(vm, globalObject);
813
814 // Compile source to bytecode if necessary:
815 JSObject* error = program->initializeGlobalProperties(vm, globalObject, scope);
816 EXCEPTION_ASSERT(!throwScope.exception() || !error);
817 if (UNLIKELY(error))
818 return checkedReturn(throwException(globalObject, throwScope, error));
819
820 ProgramCodeBlock* codeBlock;
821 {
822 CodeBlock* tempCodeBlock;
823 Exception* error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
824 EXCEPTION_ASSERT(throwScope.exception() == error);
825 if (UNLIKELY(error))
826 return checkedReturn(error);
827 codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
828 }
829
830 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
831 if (UNLIKELY(vm.needTrapHandling(mask))) {
832 vm.handleTraps(globalObject, vm.topCallFrame, mask);
833 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
834 }
835
836 if (scope->structure(vm)->isUncacheableDictionary())
837 scope->flattenDictionaryObject(vm);
838
839 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
840
841 ProtoCallFrame protoCallFrame;
842 protoCallFrame.init(codeBlock, globalObject, JSCallee::create(vm, globalObject, scope), thisObj, 1);
843
844 // Execute the code:
845 throwScope.release();
846 JSValue result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
847 return checkedReturn(result);
848}
849
850JSValue Interpreter::executeCall(JSGlobalObject* lexicalGlobalObject, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
851{
852 VM& vm = lexicalGlobalObject->vm();
853 auto throwScope = DECLARE_THROW_SCOPE(vm);
854
855 throwScope.assertNoException();
856 ASSERT(!vm.isCollectorBusyOnCurrentThread());
857 if (vm.isCollectorBusyOnCurrentThread())
858 return jsNull();
859
860 bool isJSCall = (callType == CallType::JS);
861 JSScope* scope = nullptr;
862 CodeBlock* newCodeBlock;
863 size_t argsCount = 1 + args.size(); // implicit "this" parameter
864
865 JSGlobalObject* globalObject;
866
867 if (isJSCall) {
868 scope = callData.js.scope;
869 globalObject = scope->globalObject(vm);
870 } else {
871 ASSERT(callType == CallType::Host);
872 globalObject = function->globalObject(vm);
873 }
874
875 VMEntryScope entryScope(vm, globalObject);
876 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
877 return checkedReturn(throwStackOverflowError(globalObject, throwScope));
878
879 if (isJSCall) {
880 // Compile the callee:
881 Exception* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
882 EXCEPTION_ASSERT(throwScope.exception() == compileError);
883 if (UNLIKELY(!!compileError))
884 return checkedReturn(compileError);
885
886 ASSERT(!!newCodeBlock);
887 newCodeBlock->m_shouldAlwaysBeInlined = false;
888 } else
889 newCodeBlock = 0;
890
891 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
892 if (UNLIKELY(vm.needTrapHandling(mask))) {
893 vm.handleTraps(globalObject, vm.topCallFrame, mask);
894 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
895 }
896
897 ProtoCallFrame protoCallFrame;
898 protoCallFrame.init(newCodeBlock, globalObject, function, thisValue, argsCount, args.data());
899
900 JSValue result;
901 {
902 // Execute the code:
903 if (isJSCall) {
904 throwScope.release();
905 result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
906 } else {
907 result = JSValue::decode(vmEntryToNative(callData.native.function.rawPointer(), &vm, &protoCallFrame));
908 RETURN_IF_EXCEPTION(throwScope, JSValue());
909 }
910 }
911
912 return checkedReturn(result);
913}
914
915JSObject* Interpreter::executeConstruct(JSGlobalObject* lexicalGlobalObject, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
916{
917 VM& vm = lexicalGlobalObject->vm();
918 auto throwScope = DECLARE_THROW_SCOPE(vm);
919
920 throwScope.assertNoException();
921 ASSERT(!vm.isCollectorBusyOnCurrentThread());
922 // We throw in this case because we have to return something "valid" but we're
923 // already in an invalid state.
924 if (UNLIKELY(vm.isCollectorBusyOnCurrentThread())) {
925 throwStackOverflowError(lexicalGlobalObject, throwScope);
926 return nullptr;
927 }
928
929 bool isJSConstruct = (constructType == ConstructType::JS);
930 JSScope* scope = nullptr;
931 CodeBlock* newCodeBlock;
932 size_t argsCount = 1 + args.size(); // implicit "this" parameter
933
934 JSGlobalObject* globalObject;
935
936 if (isJSConstruct) {
937 scope = constructData.js.scope;
938 globalObject = scope->globalObject(vm);
939 } else {
940 ASSERT(constructType == ConstructType::Host);
941 globalObject = constructor->globalObject(vm);
942 }
943
944 VMEntryScope entryScope(vm, globalObject);
945 if (UNLIKELY(!vm.isSafeToRecurseSoft())) {
946 throwStackOverflowError(globalObject, throwScope);
947 return nullptr;
948 }
949
950 if (isJSConstruct) {
951 // Compile the callee:
952 Exception* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
953 EXCEPTION_ASSERT(throwScope.exception() == compileError);
954 if (UNLIKELY(!!compileError))
955 return nullptr;
956
957 ASSERT(!!newCodeBlock);
958 newCodeBlock->m_shouldAlwaysBeInlined = false;
959 } else
960 newCodeBlock = 0;
961
962 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
963 if (UNLIKELY(vm.needTrapHandling(mask))) {
964 vm.handleTraps(globalObject, vm.topCallFrame, mask);
965 RETURN_IF_EXCEPTION(throwScope, nullptr);
966 }
967
968 ProtoCallFrame protoCallFrame;
969 protoCallFrame.init(newCodeBlock, globalObject, constructor, newTarget, argsCount, args.data());
970
971 JSValue result;
972 {
973 // Execute the code.
974 if (isJSConstruct)
975 result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
976 else {
977 result = JSValue::decode(vmEntryToNative(constructData.native.function.rawPointer(), &vm, &protoCallFrame));
978
979 if (LIKELY(!throwScope.exception()))
980 RELEASE_ASSERT(result.isObject());
981 }
982 }
983
984 RETURN_IF_EXCEPTION(throwScope, 0);
985 ASSERT(result.isObject());
986 return checkedReturn(asObject(result));
987}
988
989CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, const ArgList& args)
990{
991 VM& vm = scope->vm();
992 auto throwScope = DECLARE_THROW_SCOPE(vm);
993 throwScope.assertNoException();
994
995 if (vm.isCollectorBusyOnCurrentThread())
996 return CallFrameClosure();
997
998 // Compile the callee:
999 CodeBlock* newCodeBlock;
1000 Exception* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock);
1001 EXCEPTION_ASSERT(throwScope.exception() == error);
1002 if (UNLIKELY(error))
1003 return CallFrameClosure();
1004 newCodeBlock->m_shouldAlwaysBeInlined = false;
1005
1006 size_t argsCount = argumentCountIncludingThis;
1007
1008 protoCallFrame->init(newCodeBlock, function->globalObject(), function, jsUndefined(), argsCount, args.data());
1009 // Return the successful closure:
1010 CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
1011 return result;
1012}
1013
1014JSValue Interpreter::execute(EvalExecutable* eval, JSGlobalObject* lexicalGlobalObject, JSValue thisValue, JSScope* scope)
1015{
1016 VM& vm = scope->vm();
1017 auto throwScope = DECLARE_THROW_SCOPE(vm);
1018
1019 ASSERT_UNUSED(lexicalGlobalObject, &vm == &lexicalGlobalObject->vm());
1020 throwScope.assertNoException();
1021 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1022 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1023 if (vm.isCollectorBusyOnCurrentThread())
1024 return jsNull();
1025
1026 JSGlobalObject* globalObject = scope->globalObject(vm);
1027 VMEntryScope entryScope(vm, globalObject);
1028 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1029 return checkedReturn(throwStackOverflowError(globalObject, throwScope));
1030
1031 unsigned numVariables = eval->numVariables();
1032 unsigned numTopLevelFunctionDecls = eval->numTopLevelFunctionDecls();
1033 unsigned numFunctionHoistingCandidates = eval->numFunctionHoistingCandidates();
1034
1035 JSScope* variableObject;
1036 if ((numVariables || numTopLevelFunctionDecls) && eval->isStrictMode()) {
1037 scope = StrictEvalActivation::create(vm, globalObject->strictEvalActivationStructure(), scope);
1038 variableObject = scope;
1039 } else {
1040 for (JSScope* node = scope; ; node = node->next()) {
1041 RELEASE_ASSERT(node);
1042 if (node->isGlobalObject()) {
1043 variableObject = node;
1044 break;
1045 }
1046 if (node->isJSLexicalEnvironment()) {
1047 JSLexicalEnvironment* lexicalEnvironment = jsCast<JSLexicalEnvironment*>(node);
1048 if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) {
1049 variableObject = node;
1050 break;
1051 }
1052 }
1053 }
1054 }
1055
1056 EvalCodeBlock* codeBlock;
1057 {
1058 CodeBlock* tempCodeBlock;
1059 Exception* compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1060 EXCEPTION_ASSERT(throwScope.exception() == compileError);
1061 if (UNLIKELY(!!compileError))
1062 return checkedReturn(compileError);
1063 codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock);
1064 }
1065 UnlinkedEvalCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedEvalCodeBlock();
1066
1067 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
1068 if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numTopLevelFunctionDecls)) {
1069 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment();
1070 for (unsigned i = 0; i < numVariables; ++i) {
1071 const Identifier& ident = unlinkedCodeBlock->variable(i);
1072 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1073 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, globalObject, ident, slot)) {
1074 return checkedReturn(throwTypeError(globalObject, throwScope, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'")));
1075 }
1076 }
1077
1078 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1079 FunctionExecutable* function = codeBlock->functionDecl(i);
1080 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1081 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, globalObject, function->name(), slot)) {
1082 return checkedReturn(throwTypeError(globalObject, throwScope, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'")));
1083 }
1084 }
1085 }
1086
1087 if (variableObject->structure(vm)->isUncacheableDictionary())
1088 variableObject->flattenDictionaryObject(vm);
1089
1090 if (numVariables || numTopLevelFunctionDecls || numFunctionHoistingCandidates) {
1091 BatchedTransitionOptimizer optimizer(vm, variableObject);
1092 if (variableObject->next() && !eval->isStrictMode())
1093 variableObject->globalObject(vm)->varInjectionWatchpoint()->fireAll(vm, "Executed eval, fired VarInjection watchpoint");
1094
1095 for (unsigned i = 0; i < numVariables; ++i) {
1096 const Identifier& ident = unlinkedCodeBlock->variable(i);
1097 bool hasProperty = variableObject->hasProperty(globalObject, ident);
1098 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1099 if (!hasProperty) {
1100 PutPropertySlot slot(variableObject);
1101 if (!variableObject->isExtensible(globalObject))
1102 return checkedReturn(throwTypeError(globalObject, throwScope, NonExtensibleObjectPropertyDefineError));
1103 variableObject->methodTable(vm)->put(variableObject, globalObject, ident, jsUndefined(), slot);
1104 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1105 }
1106 }
1107
1108 if (eval->isStrictMode()) {
1109 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1110 FunctionExecutable* function = codeBlock->functionDecl(i);
1111 PutPropertySlot slot(variableObject);
1112 // We need create this variables because it will be used to emits code by bytecode generator
1113 variableObject->methodTable(vm)->put(variableObject, globalObject, function->name(), jsUndefined(), slot);
1114 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1115 }
1116 } else {
1117 for (unsigned i = 0; i < numTopLevelFunctionDecls; ++i) {
1118 FunctionExecutable* function = codeBlock->functionDecl(i);
1119 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(globalObject, scope, function->name());
1120 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1121 if (resolvedScope.isUndefined())
1122 return checkedReturn(throwSyntaxError(globalObject, throwScope, makeString("Can't create duplicate variable in eval: '", String(function->name().impl()), "'")));
1123 PutPropertySlot slot(variableObject);
1124 // We need create this variables because it will be used to emits code by bytecode generator
1125 variableObject->methodTable(vm)->put(variableObject, globalObject, function->name(), jsUndefined(), slot);
1126 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1127 }
1128
1129 for (unsigned i = 0; i < numFunctionHoistingCandidates; ++i) {
1130 const Identifier& ident = unlinkedCodeBlock->functionHoistingCandidate(i);
1131 JSValue resolvedScope = JSScope::resolveScopeForHoistingFuncDeclInEval(globalObject, scope, ident);
1132 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1133 if (!resolvedScope.isUndefined()) {
1134 bool hasProperty = variableObject->hasProperty(globalObject, ident);
1135 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1136 if (!hasProperty) {
1137 PutPropertySlot slot(variableObject);
1138 variableObject->methodTable(vm)->put(variableObject, globalObject, ident, jsUndefined(), slot);
1139 RETURN_IF_EXCEPTION(throwScope, checkedReturn(throwScope.exception()));
1140 }
1141 }
1142 }
1143 }
1144 }
1145
1146 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
1147 if (UNLIKELY(vm.needTrapHandling(mask))) {
1148 vm.handleTraps(globalObject, vm.topCallFrame, mask);
1149 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
1150 }
1151
1152 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1153
1154 ProtoCallFrame protoCallFrame;
1155 protoCallFrame.init(codeBlock, globalObject, JSCallee::create(vm, globalObject, scope), thisValue, 1);
1156
1157 // Execute the code:
1158 throwScope.release();
1159 JSValue result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
1160
1161 return checkedReturn(result);
1162}
1163
1164JSValue Interpreter::executeModuleProgram(ModuleProgramExecutable* executable, JSGlobalObject* lexicalGlobalObject, JSModuleEnvironment* scope)
1165{
1166 VM& vm = scope->vm();
1167 auto throwScope = DECLARE_THROW_SCOPE(vm);
1168
1169 ASSERT_UNUSED(lexicalGlobalObject, &vm == &lexicalGlobalObject->vm());
1170 throwScope.assertNoException();
1171 ASSERT(!vm.isCollectorBusyOnCurrentThread());
1172 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1173 if (vm.isCollectorBusyOnCurrentThread())
1174 return jsNull();
1175
1176 JSGlobalObject* globalObject = scope->globalObject(vm);
1177 VMEntryScope entryScope(vm, scope->globalObject(vm));
1178 if (UNLIKELY(!vm.isSafeToRecurseSoft()))
1179 return checkedReturn(throwStackOverflowError(globalObject, throwScope));
1180
1181 ModuleProgramCodeBlock* codeBlock;
1182 {
1183 CodeBlock* tempCodeBlock;
1184 Exception* compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
1185 EXCEPTION_ASSERT(throwScope.exception() == compileError);
1186 if (UNLIKELY(!!compileError))
1187 return checkedReturn(compileError);
1188 codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
1189 }
1190
1191 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
1192 if (UNLIKELY(vm.needTrapHandling(mask))) {
1193 vm.handleTraps(globalObject, vm.topCallFrame, mask);
1194 RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
1195 }
1196
1197 if (scope->structure(vm)->isUncacheableDictionary())
1198 scope->flattenDictionaryObject(vm);
1199
1200 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1201
1202 // The |this| of the module is always `undefined`.
1203 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding
1204 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding
1205 ProtoCallFrame protoCallFrame;
1206 protoCallFrame.init(codeBlock, globalObject, JSCallee::create(vm, globalObject, scope), jsUndefined(), 1);
1207
1208 // Execute the code:
1209 throwScope.release();
1210 JSValue result = executable->generatedJITCode()->execute(&vm, &protoCallFrame);
1211
1212 return checkedReturn(result);
1213}
1214
1215NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookType debugHookType)
1216{
1217 VM& vm = callFrame->deprecatedVM();
1218 auto scope = DECLARE_CATCH_SCOPE(vm);
1219 Debugger* debugger = callFrame->lexicalGlobalObject(vm)->debugger();
1220 if (!debugger)
1221 return;
1222
1223 ASSERT(callFrame->codeBlock()->hasDebuggerRequests());
1224 scope.assertNoException();
1225
1226 switch (debugHookType) {
1227 case DidEnterCallFrame:
1228 debugger->callEvent(callFrame);
1229 break;
1230 case WillLeaveCallFrame:
1231 debugger->returnEvent(callFrame);
1232 break;
1233 case WillExecuteStatement:
1234 debugger->atStatement(callFrame);
1235 break;
1236 case WillExecuteExpression:
1237 debugger->atExpression(callFrame);
1238 break;
1239 case WillExecuteProgram:
1240 debugger->willExecuteProgram(callFrame);
1241 break;
1242 case DidExecuteProgram:
1243 debugger->didExecuteProgram(callFrame);
1244 break;
1245 case DidReachBreakpoint:
1246 debugger->didReachBreakpoint(callFrame);
1247 break;
1248 }
1249 scope.assertNoException();
1250}
1251
1252} // namespace JSC
1253
1254namespace WTF {
1255
1256void printInternal(PrintStream& out, JSC::DebugHookType type)
1257{
1258 switch (type) {
1259 case JSC::WillExecuteProgram:
1260 out.print("WillExecuteProgram");
1261 return;
1262 case JSC::DidExecuteProgram:
1263 out.print("DidExecuteProgram");
1264 return;
1265 case JSC::DidEnterCallFrame:
1266 out.print("DidEnterCallFrame");
1267 return;
1268 case JSC::DidReachBreakpoint:
1269 out.print("DidReachBreakpoint");
1270 return;
1271 case JSC::WillLeaveCallFrame:
1272 out.print("WillLeaveCallFrame");
1273 return;
1274 case JSC::WillExecuteStatement:
1275 out.print("WillExecuteStatement");
1276 return;
1277 case JSC::WillExecuteExpression:
1278 out.print("WillExecuteExpression");
1279 return;
1280 }
1281}
1282
1283} // namespace WTF
1284