1/*
2 * Copyright (C) 2008, 2009, 2010, 2012-2015 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 "CallFrameClosure.h"
35#include "ClonedArguments.h"
36#include "CodeBlock.h"
37#include "DirectArguments.h"
38#include "Heap.h"
39#include "Debugger.h"
40#include "DebuggerCallFrame.h"
41#include "ErrorInstance.h"
42#include "EvalCodeCache.h"
43#include "Exception.h"
44#include "ExceptionHelpers.h"
45#include "GetterSetter.h"
46#include "JSArray.h"
47#include "JSBoundFunction.h"
48#include "JSCInlines.h"
49#include "JSLexicalEnvironment.h"
50#include "JSModuleEnvironment.h"
51#include "JSNotAnObject.h"
52#include "JSStackInlines.h"
53#include "JSString.h"
54#include "JSWithScope.h"
55#include "LLIntCLoop.h"
56#include "LLIntThunks.h"
57#include "LegacyProfiler.h"
58#include "LiteralParser.h"
59#include "ObjectPrototype.h"
60#include "Parser.h"
61#include "ProtoCallFrame.h"
62#include "RegExpObject.h"
63#include "RegExpPrototype.h"
64#include "Register.h"
65#include "SamplingTool.h"
66#include "ScopedArguments.h"
67#include "StackAlignment.h"
68#include "StackVisitor.h"
69#include "StrictEvalActivation.h"
70#include "StrongInlines.h"
71#include "Symbol.h"
72#include "VMEntryScope.h"
73#include "VMInlines.h"
74#include "VirtualRegister.h"
75
76#include <limits.h>
77#include <stdio.h>
78#include <wtf/StackStats.h>
79#include <wtf/StdLibExtras.h>
80#include <wtf/StringPrintStream.h>
81#include <wtf/Threading.h>
82#include <wtf/WTFThreadData.h>
83#include <wtf/text/StringBuilder.h>
84
85#if ENABLE(JIT)
86#include "JIT.h"
87#endif
88
89using namespace std;
90
91namespace JSC {
92
93String StackFrame::friendlySourceURL() const
94{
95 String traceLine;
96
97 switch (codeType) {
98 case StackFrameEvalCode:
99 case StackFrameModuleCode:
100 case StackFrameFunctionCode:
101 case StackFrameGlobalCode:
102 if (!sourceURL.isEmpty())
103 traceLine = sourceURL.impl();
104 break;
105 case StackFrameNativeCode:
106 traceLine = "[native code]";
107 break;
108 }
109 return traceLine.isNull() ? emptyString() : traceLine;
110}
111
112String StackFrame::friendlyFunctionName(CallFrame* callFrame) const
113{
114 String traceLine;
115 JSObject* stackFrameCallee = callee.get();
116
117 switch (codeType) {
118 case StackFrameEvalCode:
119 traceLine = "eval code";
120 break;
121 case StackFrameModuleCode:
122 traceLine = "module code";
123 break;
124 case StackFrameNativeCode:
125 if (callee)
126 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
127 break;
128 case StackFrameFunctionCode:
129 traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
130 break;
131 case StackFrameGlobalCode:
132 traceLine = "global code";
133 break;
134 }
135 return traceLine.isNull() ? emptyString() : traceLine;
136}
137
138JSValue eval(CallFrame* callFrame)
139{
140 if (!callFrame->argumentCount())
141 return jsUndefined();
142
143 JSValue program = callFrame->argument(0);
144 if (!program.isString())
145 return program;
146
147 TopCallFrameSetter topCallFrame(callFrame->vm(), callFrame);
148 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();
149 if (!globalObject->evalEnabled()) {
150 callFrame->vm().throwException(callFrame, createEvalError(callFrame, globalObject->evalDisabledErrorMessage()));
151 return jsUndefined();
152 }
153 String programSource = asString(program)->value(callFrame);
154 if (callFrame->hadException())
155 return JSValue();
156
157 CallFrame* callerFrame = callFrame->callerFrame();
158 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
159 JSScope* callerScopeChain = callerFrame->uncheckedR(callerCodeBlock->scopeRegister().offset()).Register::scope();
160 UnlinkedCodeBlock* callerUnlinkedCodeBlock = callerCodeBlock->unlinkedCodeBlock();
161
162 bool isArrowFunctionContext = callerUnlinkedCodeBlock->isArrowFunction() || callerUnlinkedCodeBlock->isArrowFunctionContext();
163 EvalExecutable* eval = callerCodeBlock->evalCodeCache().tryGet(callerCodeBlock->isStrictMode(), programSource, isArrowFunctionContext, callerScopeChain);
164
165 if (!eval) {
166 if (!callerCodeBlock->isStrictMode()) {
167 if (programSource.is8Bit()) {
168 LiteralParser<LChar> preparser(callFrame, programSource.characters8(), programSource.length(), NonStrictJSON);
169 if (JSValue parsedObject = preparser.tryLiteralParse())
170 return parsedObject;
171 } else {
172 LiteralParser<UChar> preparser(callFrame, programSource.characters16(), programSource.length(), NonStrictJSON);
173 if (JSValue parsedObject = preparser.tryLiteralParse())
174 return parsedObject;
175 }
176 }
177
178 // If the literal parser bailed, it should not have thrown exceptions.
179 ASSERT(!callFrame->vm().exception());
180
181 ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded;
182 if (callerUnlinkedCodeBlock->constructorKind() == ConstructorKind::Derived)
183 thisTDZMode = ThisTDZMode::AlwaysCheck;
184
185 eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, callerCodeBlock->unlinkedCodeBlock()->derivedContextType(), callerCodeBlock->unlinkedCodeBlock()->isArrowFunction(), programSource, callerScopeChain);
186 if (!eval)
187 return jsUndefined();
188 }
189
190 JSValue thisValue = callerFrame->thisValue();
191 Interpreter* interpreter = callFrame->vm().interpreter;
192 return interpreter->execute(eval, callFrame, thisValue, callerScopeChain);
193}
194
195unsigned sizeOfVarargs(CallFrame* callFrame, JSValue arguments, uint32_t firstVarArgOffset)
196{
197 if (UNLIKELY(!arguments.isCell())) {
198 if (arguments.isUndefinedOrNull())
199 return 0;
200
201 callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments));
202 return 0;
203 }
204
205 JSCell* cell = arguments.asCell();
206 unsigned length;
207 switch (cell->type()) {
208 case DirectArgumentsType:
209 length = jsCast<DirectArguments*>(cell)->length(callFrame);
210 break;
211 case ScopedArgumentsType:
212 length =jsCast<ScopedArguments*>(cell)->length(callFrame);
213 break;
214 case StringType:
215 callFrame->vm().throwException(callFrame, createInvalidFunctionApplyParameterError(callFrame, arguments));
216 return 0;
217 default:
218 ASSERT(arguments.isObject());
219 if (isJSArray(cell))
220 length = jsCast<JSArray*>(cell)->length();
221 else
222 length = jsCast<JSObject*>(cell)->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
223 break;
224 }
225
226 if (length >= firstVarArgOffset)
227 length -= firstVarArgOffset;
228 else
229 length = 0;
230
231 return length;
232}
233
234unsigned sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arguments, unsigned numUsedStackSlots, uint32_t firstVarArgOffset)
235{
236 unsigned length = sizeOfVarargs(callFrame, arguments, firstVarArgOffset);
237
238 CallFrame* calleeFrame = calleeFrameForVarargs(callFrame, numUsedStackSlots, length + 1);
239 if (length > maxArguments || !stack->ensureCapacityFor(calleeFrame->registers())) {
240 throwStackOverflowError(callFrame);
241 return 0;
242 }
243
244 return length;
245}
246
247void loadVarargs(CallFrame* callFrame, VirtualRegister firstElementDest, JSValue arguments, uint32_t offset, uint32_t length)
248{
249 if (UNLIKELY(!arguments.isCell()) || !length)
250 return;
251
252 JSCell* cell = arguments.asCell();
253 switch (cell->type()) {
254 case DirectArgumentsType:
255 jsCast<DirectArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
256 return;
257 case ScopedArgumentsType:
258 jsCast<ScopedArguments*>(cell)->copyToArguments(callFrame, firstElementDest, offset, length);
259 return;
260 default: {
261 ASSERT(arguments.isObject());
262 JSObject* object = jsCast<JSObject*>(cell);
263 if (isJSArray(object)) {
264 jsCast<JSArray*>(object)->copyToArguments(callFrame, firstElementDest, offset, length);
265 return;
266 }
267 unsigned i;
268 for (i = 0; i < length && object->canGetIndexQuickly(i + offset); ++i)
269 callFrame->r(firstElementDest + i) = object->getIndexQuickly(i + offset);
270 for (; i < length; ++i)
271 callFrame->r(firstElementDest + i) = object->get(callFrame, i + offset);
272 return;
273 } }
274}
275
276void setupVarargsFrame(CallFrame* callFrame, CallFrame* newCallFrame, JSValue arguments, uint32_t offset, uint32_t length)
277{
278 VirtualRegister calleeFrameOffset(newCallFrame - callFrame);
279
280 loadVarargs(
281 callFrame,
282 calleeFrameOffset + CallFrame::argumentOffset(0),
283 arguments, offset, length);
284
285 newCallFrame->setArgumentCountIncludingThis(length + 1);
286}
287
288void setupVarargsFrameAndSetThis(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValue, JSValue arguments, uint32_t firstVarArgOffset, uint32_t length)
289{
290 setupVarargsFrame(callFrame, newCallFrame, arguments, firstVarArgOffset, length);
291 newCallFrame->setThisValue(thisValue);
292}
293
294Interpreter::Interpreter(VM& vm)
295 : m_sampleEntryDepth(0)
296 , m_vm(vm)
297 , m_stack(vm)
298 , m_errorHandlingModeReentry(0)
299#if !ASSERT_DISABLED
300 , m_initialized(false)
301#endif
302{
303}
304
305Interpreter::~Interpreter()
306{
307}
308
309void Interpreter::initialize()
310{
311#if ENABLE(COMPUTED_GOTO_OPCODES)
312 m_opcodeTable = LLInt::opcodeMap();
313 for (int i = 0; i < numOpcodeIDs; ++i)
314 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i));
315#endif
316
317#if !ASSERT_DISABLED
318 m_initialized = true;
319#endif
320
321#if ENABLE(OPCODE_SAMPLING)
322 enableSampler();
323#endif
324}
325
326#ifdef NDEBUG
327
328void Interpreter::dumpCallFrame(CallFrame*)
329{
330}
331
332#else
333
334void Interpreter::dumpCallFrame(CallFrame* callFrame)
335{
336 callFrame->codeBlock()->dumpBytecode();
337 dumpRegisters(callFrame);
338}
339
340class DumpRegisterFunctor {
341public:
342 DumpRegisterFunctor(const Register*& it)
343 : m_hasSkippedFirstFrame(false)
344 , m_it(it)
345 {
346 }
347
348 StackVisitor::Status operator()(StackVisitor& visitor)
349 {
350 if (!m_hasSkippedFirstFrame) {
351 m_hasSkippedFirstFrame = true;
352 return StackVisitor::Continue;
353 }
354
355 unsigned line = 0;
356 unsigned unusedColumn = 0;
357 visitor->computeLineAndColumn(line, unusedColumn);
358 dataLogF("[ReturnVPC] | %10p | %d (line %d)\n", m_it, visitor->bytecodeOffset(), line);
359 --m_it;
360 return StackVisitor::Done;
361 }
362
363private:
364 bool m_hasSkippedFirstFrame;
365 const Register*& m_it;
366};
367
368void Interpreter::dumpRegisters(CallFrame* callFrame)
369{
370 dataLogF("Register frame: \n\n");
371 dataLogF("-----------------------------------------------------------------------------\n");
372 dataLogF(" use | address | value \n");
373 dataLogF("-----------------------------------------------------------------------------\n");
374
375 CodeBlock* codeBlock = callFrame->codeBlock();
376 const Register* it;
377 const Register* end;
378
379 it = callFrame->registers() + JSStack::ThisArgument + callFrame->argumentCount();
380 end = callFrame->registers() + JSStack::ThisArgument - 1;
381 while (it > end) {
382 JSValue v = it->jsValue();
383 int registerNumber = it - callFrame->registers();
384 String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
385 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
386 --it;
387 }
388
389 dataLogF("-----------------------------------------------------------------------------\n");
390 dataLogF("[ArgumentCount] | %10p | %lu \n", it, (unsigned long) callFrame->argumentCount());
391 --it;
392 dataLogF("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
393 --it;
394 dataLogF("[Callee] | %10p | %p \n", it, callFrame->callee());
395 --it;
396 // FIXME: Remove the next decrement when the ScopeChain slot is removed from the call header
397 --it;
398#if ENABLE(JIT)
399 AbstractPC pc = callFrame->abstractReturnPC(callFrame->vm());
400 if (pc.hasJITReturnAddress())
401 dataLogF("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
402#endif
403
404 DumpRegisterFunctor functor(it);
405 callFrame->iterate(functor);
406
407 dataLogF("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
408 --it;
409 dataLogF("-----------------------------------------------------------------------------\n");
410
411 end = it - codeBlock->m_numVars;
412 if (it != end) {
413 do {
414 JSValue v = it->jsValue();
415 int registerNumber = it - callFrame->registers();
416 String name = codeBlock->nameForRegister(VirtualRegister(registerNumber));
417 dataLogF("[r% 3d %14s] | %10p | %-16s 0x%lld \n", registerNumber, name.ascii().data(), it, toCString(v).data(), (long long)JSValue::encode(v));
418 --it;
419 } while (it != end);
420 }
421 dataLogF("-----------------------------------------------------------------------------\n");
422
423 end = it - codeBlock->m_numCalleeLocals + codeBlock->m_numVars;
424 if (it != end) {
425 do {
426 JSValue v = (*it).jsValue();
427 int registerNumber = it - callFrame->registers();
428 dataLogF("[r% 3d] | %10p | %-16s 0x%lld \n", registerNumber, it, toCString(v).data(), (long long)JSValue::encode(v));
429 --it;
430 } while (it != end);
431 }
432 dataLogF("-----------------------------------------------------------------------------\n");
433}
434
435#endif
436
437bool Interpreter::isOpcode(Opcode opcode)
438{
439#if ENABLE(COMPUTED_GOTO_OPCODES)
440 return opcode != HashTraits<Opcode>::emptyValue()
441 && !HashTraits<Opcode>::isDeletedValue(opcode)
442 && m_opcodeIDTable.contains(opcode);
443#else
444 return opcode >= 0 && opcode <= op_end;
445#endif
446}
447
448static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor)
449{
450 switch (visitor->codeType()) {
451 case StackVisitor::Frame::Eval:
452 return StackFrameEvalCode;
453 case StackVisitor::Frame::Module:
454 return StackFrameModuleCode;
455 case StackVisitor::Frame::Function:
456 return StackFrameFunctionCode;
457 case StackVisitor::Frame::Global:
458 return StackFrameGlobalCode;
459 case StackVisitor::Frame::Native:
460 ASSERT_NOT_REACHED();
461 return StackFrameNativeCode;
462 }
463 RELEASE_ASSERT_NOT_REACHED();
464 return StackFrameGlobalCode;
465}
466
467void StackFrame::computeLineAndColumn(unsigned& line, unsigned& column)
468{
469 if (!codeBlock) {
470 line = 0;
471 column = 0;
472 return;
473 }
474
475 int divot = 0;
476 int unusedStartOffset = 0;
477 int unusedEndOffset = 0;
478 unsigned divotLine = 0;
479 unsigned divotColumn = 0;
480 expressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
481
482 line = divotLine + lineOffset;
483 column = divotColumn + (divotLine ? 1 : firstLineColumnOffset);
484
485 if (executable->hasOverrideLineNumber())
486 line = executable->overrideLineNumber();
487}
488
489void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
490{
491 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
492 divot += characterOffset;
493}
494
495String StackFrame::toString(CallFrame* callFrame)
496{
497 StringBuilder traceBuild;
498 String functionName = friendlyFunctionName(callFrame);
499 String sourceURL = friendlySourceURL();
500 traceBuild.append(functionName);
501 if (!sourceURL.isEmpty()) {
502 if (!functionName.isEmpty())
503 traceBuild.append('@');
504 traceBuild.append(sourceURL);
505 if (codeType != StackFrameNativeCode) {
506 unsigned line;
507 unsigned column;
508 computeLineAndColumn(line, column);
509
510 traceBuild.append(':');
511 traceBuild.appendNumber(line);
512 traceBuild.append(':');
513 traceBuild.appendNumber(column);
514 }
515 }
516 return traceBuild.toString().impl();
517}
518
519static inline bool isWebAssemblyExecutable(ExecutableBase* executable)
520{
521#if !ENABLE(WEBASSEMBLY)
522 UNUSED_PARAM(executable);
523 return false;
524#else
525 return executable->isWebAssemblyExecutable();
526#endif
527}
528
529class GetStackTraceFunctor {
530public:
531 GetStackTraceFunctor(VM& vm, Vector<StackFrame>& results, size_t remainingCapacity)
532 : m_vm(vm)
533 , m_results(results)
534 , m_remainingCapacityForFrameCapture(remainingCapacity)
535 {
536 }
537
538 StackVisitor::Status operator()(StackVisitor& visitor)
539 {
540 VM& vm = m_vm;
541 if (m_remainingCapacityForFrameCapture) {
542 if (visitor->isJSFrame()
543 && !isWebAssemblyExecutable(visitor->codeBlock()->ownerExecutable())
544 && !visitor->codeBlock()->unlinkedCodeBlock()->isBuiltinFunction()) {
545 CodeBlock* codeBlock = visitor->codeBlock();
546 StackFrame s = {
547 Strong<JSObject>(vm, visitor->callee()),
548 getStackFrameCodeType(visitor),
549 Strong<ScriptExecutable>(vm, codeBlock->ownerScriptExecutable()),
550 Strong<UnlinkedCodeBlock>(vm, codeBlock->unlinkedCodeBlock()),
551 codeBlock->source(),
552 codeBlock->ownerScriptExecutable()->firstLine(),
553 codeBlock->firstLineColumnOffset(),
554 codeBlock->sourceOffset(),
555 visitor->bytecodeOffset(),
556 visitor->sourceURL()
557 };
558 m_results.append(s);
559 } else {
560 StackFrame s = { Strong<JSObject>(vm, visitor->callee()), StackFrameNativeCode, Strong<ScriptExecutable>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, 0, String()};
561 m_results.append(s);
562 }
563
564 m_remainingCapacityForFrameCapture--;
565 return StackVisitor::Continue;
566 }
567 return StackVisitor::Done;
568 }
569
570private:
571 VM& m_vm;
572 Vector<StackFrame>& m_results;
573 size_t m_remainingCapacityForFrameCapture;
574};
575
576void Interpreter::getStackTrace(Vector<StackFrame>& results, size_t maxStackSize)
577{
578 VM& vm = m_vm;
579 CallFrame* callFrame = vm.topCallFrame;
580 if (!callFrame)
581 return;
582
583 GetStackTraceFunctor functor(vm, results, maxStackSize);
584 callFrame->iterate(functor);
585}
586
587JSString* Interpreter::stackTraceAsString(ExecState* exec, Vector<StackFrame> stackTrace)
588{
589 // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
590 StringBuilder builder;
591 for (unsigned i = 0; i < stackTrace.size(); i++) {
592 builder.append(String(stackTrace[i].toString(exec)));
593 if (i != stackTrace.size() - 1)
594 builder.append('\n');
595 }
596 return jsString(&exec->vm(), builder.toString());
597}
598
599ALWAYS_INLINE static HandlerInfo* findExceptionHandler(StackVisitor& visitor, CodeBlock* codeBlock, CodeBlock::RequiredHandler requiredHandler)
600{
601 ASSERT(codeBlock);
602#if ENABLE(DFG_JIT)
603 ASSERT(!visitor->isInlinedFrame());
604#endif
605
606 CallFrame* callFrame = visitor->callFrame();
607 unsigned exceptionHandlerIndex;
608 if (JITCode::isOptimizingJIT(codeBlock->jitType()))
609 exceptionHandlerIndex = callFrame->callSiteIndex().bits();
610 else
611 exceptionHandlerIndex = callFrame->bytecodeOffset();
612
613 return codeBlock->handlerForIndex(exceptionHandlerIndex, requiredHandler);
614}
615
616class GetCatchHandlerFunctor {
617public:
618 GetCatchHandlerFunctor()
619 : m_handler(0)
620 {
621 }
622
623 HandlerInfo* handler() { return m_handler; }
624
625 StackVisitor::Status operator()(StackVisitor& visitor)
626 {
627 visitor.unwindToMachineCodeBlockFrame();
628
629 CodeBlock* codeBlock = visitor->codeBlock();
630 if (!codeBlock)
631 return StackVisitor::Continue;
632
633 m_handler = findExceptionHandler(visitor, codeBlock, CodeBlock::RequiredHandler::CatchHandler);
634 if (m_handler)
635 return StackVisitor::Done;
636
637 return StackVisitor::Continue;
638 }
639
640private:
641 HandlerInfo* m_handler;
642};
643
644ALWAYS_INLINE static void notifyDebuggerOfUnwinding(CallFrame* callFrame)
645{
646 if (Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger()) {
647 SuspendExceptionScope scope(&callFrame->vm());
648 if (jsDynamicCast<JSFunction*>(callFrame->callee()))
649 debugger->returnEvent(callFrame);
650 else
651 debugger->didExecuteProgram(callFrame);
652 ASSERT(!callFrame->hadException());
653 }
654}
655
656class UnwindFunctor {
657public:
658 UnwindFunctor(CallFrame*& callFrame, bool isTermination, CodeBlock*& codeBlock, HandlerInfo*& handler)
659 : m_callFrame(callFrame)
660 , m_isTermination(isTermination)
661 , m_codeBlock(codeBlock)
662 , m_handler(handler)
663 {
664 }
665
666 StackVisitor::Status operator()(StackVisitor& visitor)
667 {
668 visitor.unwindToMachineCodeBlockFrame();
669 VM& vm = m_callFrame->vm();
670 m_callFrame = visitor->callFrame();
671 m_codeBlock = visitor->codeBlock();
672
673 m_handler = nullptr;
674 if (!m_isTermination) {
675 if (m_codeBlock && !isWebAssemblyExecutable(m_codeBlock->ownerExecutable()))
676 m_handler = findExceptionHandler(visitor, m_codeBlock, CodeBlock::RequiredHandler::AnyHandler);
677 }
678
679 if (m_handler)
680 return StackVisitor::Done;
681
682 notifyDebuggerOfUnwinding(m_callFrame);
683
684 bool shouldStopUnwinding = visitor->callerIsVMEntryFrame();
685 if (shouldStopUnwinding) {
686 if (LegacyProfiler* profiler = vm.enabledProfiler())
687 profiler->exceptionUnwind(m_callFrame);
688
689 copyCalleeSavesToVMCalleeSavesBuffer(visitor);
690
691 return StackVisitor::Done;
692 }
693
694 copyCalleeSavesToVMCalleeSavesBuffer(visitor);
695
696 return StackVisitor::Continue;
697 }
698
699private:
700 void copyCalleeSavesToVMCalleeSavesBuffer(StackVisitor& visitor)
701 {
702#if ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
703
704 if (!visitor->isJSFrame())
705 return;
706
707#if ENABLE(DFG_JIT)
708 if (visitor->inlineCallFrame())
709 return;
710#endif
711 RegisterAtOffsetList* currentCalleeSaves = m_codeBlock ? m_codeBlock->calleeSaveRegisters() : nullptr;
712
713 if (!currentCalleeSaves)
714 return;
715
716 VM& vm = m_callFrame->vm();
717 RegisterAtOffsetList* allCalleeSaves = vm.getAllCalleeSaveRegisterOffsets();
718 RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
719 intptr_t* frame = reinterpret_cast<intptr_t*>(m_callFrame->registers());
720
721 unsigned registerCount = currentCalleeSaves->size();
722 for (unsigned i = 0; i < registerCount; i++) {
723 RegisterAtOffset currentEntry = currentCalleeSaves->at(i);
724 if (dontCopyRegisters.get(currentEntry.reg()))
725 continue;
726 RegisterAtOffset* vmCalleeSavesEntry = allCalleeSaves->find(currentEntry.reg());
727
728 vm.calleeSaveRegistersBuffer[vmCalleeSavesEntry->offsetAsIndex()] = *(frame + currentEntry.offsetAsIndex());
729 }
730#else
731 UNUSED_PARAM(visitor);
732#endif
733 }
734
735 CallFrame*& m_callFrame;
736 bool m_isTermination;
737 CodeBlock*& m_codeBlock;
738 HandlerInfo*& m_handler;
739};
740
741NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception, UnwindStart unwindStart)
742{
743 if (unwindStart == UnwindFromCallerFrame) {
744 if (callFrame->callerFrameOrVMEntryFrame() == vm.topVMEntryFrame)
745 return nullptr;
746
747 callFrame = callFrame->callerFrame();
748 vm.topCallFrame = callFrame;
749 }
750
751 CodeBlock* codeBlock = callFrame->codeBlock();
752
753 JSValue exceptionValue = exception->value();
754 ASSERT(!exceptionValue.isEmpty());
755 ASSERT(!exceptionValue.isCell() || exceptionValue.asCell());
756 // This shouldn't be possible (hence the assertions), but we're already in the slowest of
757 // slow cases, so let's harden against it anyway to be safe.
758 if (exceptionValue.isEmpty() || (exceptionValue.isCell() && !exceptionValue.asCell()))
759 exceptionValue = jsNull();
760
761 ASSERT(vm.exception() && vm.exception()->stack().size());
762
763 // Calculate an exception handler vPC, unwinding call frames as necessary.
764 HandlerInfo* handler = nullptr;
765 UnwindFunctor functor(callFrame, isTerminatedExecutionException(exception), codeBlock, handler);
766 callFrame->iterate(functor);
767 if (!handler)
768 return nullptr;
769
770 return handler;
771}
772
773void Interpreter::notifyDebuggerOfExceptionToBeThrown(CallFrame* callFrame, Exception* exception)
774{
775 Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
776 if (debugger && debugger->needsExceptionCallbacks() && !exception->didNotifyInspectorOfThrow()) {
777 // This code assumes that if the debugger is enabled then there is no inlining.
778 // If that assumption turns out to be false then we'll ignore the inlined call
779 // frames.
780 // https://bugs.webkit.org/show_bug.cgi?id=121754
781
782 bool hasCatchHandler;
783 bool isTermination = isTerminatedExecutionException(exception);
784 if (isTermination)
785 hasCatchHandler = false;
786 else {
787 GetCatchHandlerFunctor functor;
788 callFrame->iterate(functor);
789 HandlerInfo* handler = functor.handler();
790 ASSERT(!handler || handler->isCatchHandler());
791 hasCatchHandler = !!handler;
792 }
793
794 debugger->exception(callFrame, exception->value(), hasCatchHandler);
795 }
796 exception->setDidNotifyInspectorOfThrow();
797}
798
799static inline JSValue checkedReturn(JSValue returnValue)
800{
801 ASSERT(returnValue);
802 return returnValue;
803}
804
805static inline JSObject* checkedReturn(JSObject* returnValue)
806{
807 ASSERT(returnValue);
808 return returnValue;
809}
810
811class SamplingScope {
812public:
813 SamplingScope(Interpreter* interpreter)
814 : m_interpreter(interpreter)
815 {
816 interpreter->startSampling();
817 }
818 ~SamplingScope()
819 {
820 m_interpreter->stopSampling();
821 }
822private:
823 Interpreter* m_interpreter;
824};
825
826JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, JSObject* thisObj)
827{
828 SamplingScope samplingScope(this);
829
830 JSScope* scope = thisObj->globalObject()->globalScope();
831 VM& vm = *scope->vm();
832
833 ASSERT(!vm.exception());
834 ASSERT(!vm.isCollectorBusy());
835 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
836 if (vm.isCollectorBusy())
837 return jsNull();
838
839 if (!vm.isSafeToRecurse())
840 return checkedReturn(throwStackOverflowError(callFrame));
841
842 // First check if the "program" is actually just a JSON object. If so,
843 // we'll handle the JSON object here. Else, we'll handle real JS code
844 // below at failedJSONP.
845
846 Vector<JSONPData> JSONPData;
847 bool parseResult;
848 StringView programSource = program->source().view();
849 if (programSource.isNull())
850 return jsUndefined();
851 if (programSource.is8Bit()) {
852 LiteralParser<LChar> literalParser(callFrame, programSource.characters8(), programSource.length(), JSONP);
853 parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
854 } else {
855 LiteralParser<UChar> literalParser(callFrame, programSource.characters16(), programSource.length(), JSONP);
856 parseResult = literalParser.tryJSONPParse(JSONPData, scope->globalObject()->globalObjectMethodTable()->supportsRichSourceInfo(scope->globalObject()));
857 }
858
859 if (parseResult) {
860 JSGlobalObject* globalObject = scope->globalObject();
861 JSValue result;
862 for (unsigned entry = 0; entry < JSONPData.size(); entry++) {
863 Vector<JSONPPathEntry> JSONPPath;
864 JSONPPath.swap(JSONPData[entry].m_path);
865 JSValue JSONPValue = JSONPData[entry].m_value.get();
866 if (JSONPPath.size() == 1 && JSONPPath[0].m_type == JSONPPathEntryTypeDeclare) {
867 globalObject->addVar(callFrame, JSONPPath[0].m_pathEntryName);
868 PutPropertySlot slot(globalObject);
869 globalObject->methodTable()->put(globalObject, callFrame, JSONPPath[0].m_pathEntryName, JSONPValue, slot);
870 result = jsUndefined();
871 continue;
872 }
873 JSValue baseObject(globalObject);
874 for (unsigned i = 0; i < JSONPPath.size() - 1; i++) {
875 ASSERT(JSONPPath[i].m_type != JSONPPathEntryTypeDeclare);
876 switch (JSONPPath[i].m_type) {
877 case JSONPPathEntryTypeDot: {
878 if (i == 0) {
879 PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get);
880 if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
881 if (entry)
882 return callFrame->vm().throwException(callFrame, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName));
883 goto failedJSONP;
884 }
885 baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);
886 } else
887 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathEntryName);
888 if (callFrame->hadException())
889 return jsUndefined();
890 continue;
891 }
892 case JSONPPathEntryTypeLookup: {
893 baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
894 if (callFrame->hadException())
895 return jsUndefined();
896 continue;
897 }
898 default:
899 RELEASE_ASSERT_NOT_REACHED();
900 return jsUndefined();
901 }
902 }
903 PutPropertySlot slot(baseObject);
904 switch (JSONPPath.last().m_type) {
905 case JSONPPathEntryTypeCall: {
906 JSValue function = baseObject.get(callFrame, JSONPPath.last().m_pathEntryName);
907 if (callFrame->hadException())
908 return jsUndefined();
909 CallData callData;
910 CallType callType = getCallData(function, callData);
911 if (callType == CallTypeNone)
912 return callFrame->vm().throwException(callFrame, createNotAFunctionError(callFrame, function));
913 MarkedArgumentBuffer jsonArg;
914 jsonArg.append(JSONPValue);
915 JSValue thisValue = JSONPPath.size() == 1 ? jsUndefined(): baseObject;
916 JSONPValue = JSC::call(callFrame, function, callType, callData, thisValue, jsonArg);
917 if (callFrame->hadException())
918 return jsUndefined();
919 break;
920 }
921 case JSONPPathEntryTypeDot: {
922 baseObject.put(callFrame, JSONPPath.last().m_pathEntryName, JSONPValue, slot);
923 if (callFrame->hadException())
924 return jsUndefined();
925 break;
926 }
927 case JSONPPathEntryTypeLookup: {
928 baseObject.putByIndex(callFrame, JSONPPath.last().m_pathIndex, JSONPValue, slot.isStrictMode());
929 if (callFrame->hadException())
930 return jsUndefined();
931 break;
932 }
933 default:
934 RELEASE_ASSERT_NOT_REACHED();
935 return jsUndefined();
936 }
937 result = JSONPValue;
938 }
939 return result;
940 }
941failedJSONP:
942 // If we get here, then we have already proven that the script is not a JSON
943 // object.
944
945 VMEntryScope entryScope(vm, scope->globalObject());
946
947 // Compile source to bytecode if necessary:
948 if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope))
949 return checkedReturn(callFrame->vm().throwException(callFrame, error));
950
951 if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall))
952 return checkedReturn(callFrame->vm().throwException(callFrame, error));
953
954 ProgramCodeBlock* codeBlock = program->codeBlock();
955
956 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
957 return throwTerminatedExecutionException(callFrame);
958
959 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
960
961 ProtoCallFrame protoCallFrame;
962 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisObj, 1);
963
964 if (LegacyProfiler* profiler = vm.enabledProfiler())
965 profiler->willExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn());
966
967 // Execute the code:
968 JSValue result;
969 {
970 SamplingTool::CallRecord callRecord(m_sampler.get());
971 result = program->generatedJITCode()->execute(&vm, &protoCallFrame);
972 }
973
974 if (LegacyProfiler* profiler = vm.enabledProfiler())
975 profiler->didExecute(callFrame, program->sourceURL(), program->firstLine(), program->startColumn());
976
977 return checkedReturn(result);
978}
979
980JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
981{
982 VM& vm = callFrame->vm();
983 ASSERT(!callFrame->hadException());
984 ASSERT(!vm.isCollectorBusy());
985 if (vm.isCollectorBusy())
986 return jsNull();
987
988 bool isJSCall = (callType == CallTypeJS);
989 JSScope* scope = nullptr;
990 CodeBlock* newCodeBlock;
991 size_t argsCount = 1 + args.size(); // implicit "this" parameter
992
993 JSGlobalObject* globalObject;
994
995 if (isJSCall) {
996 scope = callData.js.scope;
997 globalObject = scope->globalObject();
998 } else {
999 ASSERT(callType == CallTypeHost);
1000 globalObject = function->globalObject();
1001 }
1002
1003 VMEntryScope entryScope(vm, globalObject);
1004 if (!vm.isSafeToRecurse())
1005 return checkedReturn(throwStackOverflowError(callFrame));
1006
1007 if (isJSCall) {
1008 // Compile the callee:
1009 JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall);
1010 if (UNLIKELY(!!compileError)) {
1011 return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
1012 }
1013 newCodeBlock = callData.js.functionExecutable->codeBlockForCall();
1014 ASSERT(!!newCodeBlock);
1015 newCodeBlock->m_shouldAlwaysBeInlined = false;
1016 } else
1017 newCodeBlock = 0;
1018
1019 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1020 return throwTerminatedExecutionException(callFrame);
1021
1022 ProtoCallFrame protoCallFrame;
1023 protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data());
1024
1025 if (LegacyProfiler* profiler = vm.enabledProfiler())
1026 profiler->willExecute(callFrame, function);
1027
1028 JSValue result;
1029 {
1030 SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSCall);
1031
1032 // Execute the code:
1033 if (isJSCall)
1034 result = callData.js.functionExecutable->generatedJITCodeForCall()->execute(&vm, &protoCallFrame);
1035 else {
1036 result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(callData.native.function), &vm, &protoCallFrame));
1037 if (callFrame->hadException())
1038 result = jsNull();
1039 }
1040 }
1041
1042 if (LegacyProfiler* profiler = vm.enabledProfiler())
1043 profiler->didExecute(callFrame, function);
1044
1045 return checkedReturn(result);
1046}
1047
1048JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
1049{
1050 VM& vm = callFrame->vm();
1051 ASSERT(!callFrame->hadException());
1052 ASSERT(!vm.isCollectorBusy());
1053 // We throw in this case because we have to return something "valid" but we're
1054 // already in an invalid state.
1055 if (vm.isCollectorBusy())
1056 return checkedReturn(throwStackOverflowError(callFrame));
1057
1058 bool isJSConstruct = (constructType == ConstructTypeJS);
1059 JSScope* scope = nullptr;
1060 CodeBlock* newCodeBlock;
1061 size_t argsCount = 1 + args.size(); // implicit "this" parameter
1062
1063 JSGlobalObject* globalObject;
1064
1065 if (isJSConstruct) {
1066 scope = constructData.js.scope;
1067 globalObject = scope->globalObject();
1068 } else {
1069 ASSERT(constructType == ConstructTypeHost);
1070 globalObject = constructor->globalObject();
1071 }
1072
1073 VMEntryScope entryScope(vm, globalObject);
1074 if (!vm.isSafeToRecurse())
1075 return checkedReturn(throwStackOverflowError(callFrame));
1076
1077 if (isJSConstruct) {
1078 // Compile the callee:
1079 JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct);
1080 if (UNLIKELY(!!compileError)) {
1081 return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
1082 }
1083 newCodeBlock = constructData.js.functionExecutable->codeBlockForConstruct();
1084 ASSERT(!!newCodeBlock);
1085 newCodeBlock->m_shouldAlwaysBeInlined = false;
1086 } else
1087 newCodeBlock = 0;
1088
1089 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1090 return throwTerminatedExecutionException(callFrame);
1091
1092 ProtoCallFrame protoCallFrame;
1093 protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
1094
1095 if (LegacyProfiler* profiler = vm.enabledProfiler())
1096 profiler->willExecute(callFrame, constructor);
1097
1098 JSValue result;
1099 {
1100 SamplingTool::CallRecord callRecord(m_sampler.get(), !isJSConstruct);
1101
1102 // Execute the code.
1103 if (isJSConstruct)
1104 result = constructData.js.functionExecutable->generatedJITCodeForConstruct()->execute(&vm, &protoCallFrame);
1105 else {
1106 result = JSValue::decode(vmEntryToNative(reinterpret_cast<void*>(constructData.native.function), &vm, &protoCallFrame));
1107
1108 if (!callFrame->hadException())
1109 RELEASE_ASSERT(result.isObject());
1110 }
1111 }
1112
1113 if (LegacyProfiler* profiler = vm.enabledProfiler())
1114 profiler->didExecute(callFrame, constructor);
1115
1116 if (callFrame->hadException())
1117 return 0;
1118 ASSERT(result.isObject());
1119 return checkedReturn(asObject(result));
1120}
1121
1122CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionExecutable, CallFrame* callFrame, ProtoCallFrame* protoCallFrame, JSFunction* function, int argumentCountIncludingThis, JSScope* scope, JSValue* args)
1123{
1124 VM& vm = *scope->vm();
1125 ASSERT(!vm.exception());
1126
1127 if (vm.isCollectorBusy())
1128 return CallFrameClosure();
1129
1130 // Compile the callee:
1131 JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall);
1132 if (error) {
1133 callFrame->vm().throwException(callFrame, error);
1134 return CallFrameClosure();
1135 }
1136 CodeBlock* newCodeBlock = functionExecutable->codeBlockForCall();
1137 newCodeBlock->m_shouldAlwaysBeInlined = false;
1138
1139 size_t argsCount = argumentCountIncludingThis;
1140
1141 protoCallFrame->init(newCodeBlock, function, jsUndefined(), argsCount, args);
1142 // Return the successful closure:
1143 CallFrameClosure result = { callFrame, protoCallFrame, function, functionExecutable, &vm, scope, newCodeBlock->numParameters(), argumentCountIncludingThis };
1144 return result;
1145}
1146
1147JSValue Interpreter::execute(CallFrameClosure& closure)
1148{
1149 VM& vm = *closure.vm;
1150 SamplingScope samplingScope(this);
1151
1152 ASSERT(!vm.isCollectorBusy());
1153 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1154 if (vm.isCollectorBusy())
1155 return jsNull();
1156
1157 StackStats::CheckPoint stackCheckPoint;
1158
1159 if (LegacyProfiler* profiler = vm.enabledProfiler())
1160 profiler->willExecute(closure.oldCallFrame, closure.function);
1161
1162 if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame)))
1163 return throwTerminatedExecutionException(closure.oldCallFrame);
1164
1165 // Execute the code:
1166 JSValue result;
1167 {
1168 SamplingTool::CallRecord callRecord(m_sampler.get());
1169 result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame);
1170 }
1171
1172 if (LegacyProfiler* profiler = vm.enabledProfiler())
1173 profiler->didExecute(closure.oldCallFrame, closure.function);
1174
1175 return checkedReturn(result);
1176}
1177
1178JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue thisValue, JSScope* scope)
1179{
1180 VM& vm = *scope->vm();
1181 SamplingScope samplingScope(this);
1182
1183 ASSERT(scope->vm() == &callFrame->vm());
1184 ASSERT(!vm.exception());
1185 ASSERT(!vm.isCollectorBusy());
1186 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1187 if (vm.isCollectorBusy())
1188 return jsNull();
1189
1190 VMEntryScope entryScope(vm, scope->globalObject());
1191 if (!vm.isSafeToRecurse())
1192 return checkedReturn(throwStackOverflowError(callFrame));
1193
1194 unsigned numVariables = eval->numVariables();
1195 int numFunctions = eval->numberOfFunctionDecls();
1196
1197 JSScope* variableObject;
1198 if ((numVariables || numFunctions) && eval->isStrictMode()) {
1199 scope = StrictEvalActivation::create(callFrame, scope);
1200 variableObject = scope;
1201 } else {
1202 for (JSScope* node = scope; ; node = node->next()) {
1203 RELEASE_ASSERT(node);
1204 if (node->isGlobalObject()) {
1205 variableObject = node;
1206 break;
1207 }
1208 if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(node)) {
1209 if (lexicalEnvironment->symbolTable()->scopeType() == SymbolTable::ScopeType::VarScope) {
1210 variableObject = node;
1211 break;
1212 }
1213 }
1214 }
1215 }
1216
1217 JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
1218 if (UNLIKELY(!!compileError))
1219 return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
1220 EvalCodeBlock* codeBlock = eval->codeBlock();
1221
1222 // We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
1223 if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numFunctions)) {
1224 JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalObject*>(variableObject)->globalLexicalEnvironment();
1225 for (unsigned i = 0; i < numVariables; ++i) {
1226 const Identifier& ident = codeBlock->variable(i);
1227 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1228 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, ident, slot)) {
1229 return checkedReturn(callFrame->vm().throwException(callFrame,
1230 createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(ident.impl()), "'"))));
1231 }
1232 }
1233
1234 for (int i = 0; i < numFunctions; ++i) {
1235 FunctionExecutable* function = codeBlock->functionDecl(i);
1236 PropertySlot slot(globalLexicalEnvironment, PropertySlot::InternalMethodType::VMInquiry);
1237 if (JSGlobalLexicalEnvironment::getOwnPropertySlot(globalLexicalEnvironment, callFrame, function->name(), slot)) {
1238 return checkedReturn(callFrame->vm().throwException(callFrame,
1239 createTypeError(callFrame, makeString("Can't create duplicate global variable in eval: '", String(function->name().impl()), "'"))));
1240 }
1241 }
1242 }
1243
1244 if (numVariables || numFunctions) {
1245 BatchedTransitionOptimizer optimizer(vm, variableObject);
1246 if (variableObject->next())
1247 variableObject->globalObject()->varInjectionWatchpoint()->fireAll("Executed eval, fired VarInjection watchpoint");
1248
1249 for (unsigned i = 0; i < numVariables; ++i) {
1250 const Identifier& ident = codeBlock->variable(i);
1251 if (!variableObject->hasProperty(callFrame, ident)) {
1252 PutPropertySlot slot(variableObject);
1253 variableObject->methodTable()->put(variableObject, callFrame, ident, jsUndefined(), slot);
1254 }
1255 }
1256
1257 for (int i = 0; i < numFunctions; ++i) {
1258 FunctionExecutable* function = codeBlock->functionDecl(i);
1259 PutPropertySlot slot(variableObject);
1260 variableObject->methodTable()->put(variableObject, callFrame, function->name(), JSFunction::create(vm, function, scope), slot);
1261 }
1262 }
1263
1264 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1265 return throwTerminatedExecutionException(callFrame);
1266
1267 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1268
1269 ProtoCallFrame protoCallFrame;
1270 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), thisValue, 1);
1271
1272 if (LegacyProfiler* profiler = vm.enabledProfiler())
1273 profiler->willExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn());
1274
1275 // Execute the code:
1276 JSValue result;
1277 {
1278 SamplingTool::CallRecord callRecord(m_sampler.get());
1279 result = eval->generatedJITCode()->execute(&vm, &protoCallFrame);
1280 }
1281
1282 if (LegacyProfiler* profiler = vm.enabledProfiler())
1283 profiler->didExecute(callFrame, eval->sourceURL(), eval->firstLine(), eval->startColumn());
1284
1285 return checkedReturn(result);
1286}
1287
1288JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* callFrame, JSModuleEnvironment* scope)
1289{
1290 VM& vm = *scope->vm();
1291 SamplingScope samplingScope(this);
1292
1293 ASSERT(scope->vm() == &callFrame->vm());
1294 ASSERT(!vm.exception());
1295 ASSERT(!vm.isCollectorBusy());
1296 RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
1297 if (vm.isCollectorBusy())
1298 return jsNull();
1299
1300 VMEntryScope entryScope(vm, scope->globalObject());
1301 if (!vm.isSafeToRecurse())
1302 return checkedReturn(throwStackOverflowError(callFrame));
1303
1304 JSObject* compileError = executable->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
1305 if (UNLIKELY(!!compileError))
1306 return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
1307 ModuleProgramCodeBlock* codeBlock = executable->codeBlock();
1308
1309 if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
1310 return throwTerminatedExecutionException(callFrame);
1311
1312 ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
1313
1314 // The |this| of the module is always `undefined`.
1315 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-hasthisbinding
1316 // http://www.ecma-international.org/ecma-262/6.0/#sec-module-environment-records-getthisbinding
1317 ProtoCallFrame protoCallFrame;
1318 protoCallFrame.init(codeBlock, JSCallee::create(vm, scope->globalObject(), scope), jsUndefined(), 1);
1319
1320 if (LegacyProfiler* profiler = vm.enabledProfiler())
1321 profiler->willExecute(callFrame, executable->sourceURL(), executable->firstLine(), executable->startColumn());
1322
1323 // Execute the code:
1324 JSValue result;
1325 {
1326 SamplingTool::CallRecord callRecord(m_sampler.get());
1327 result = executable->generatedJITCode()->execute(&vm, &protoCallFrame);
1328 }
1329
1330 if (LegacyProfiler* profiler = vm.enabledProfiler())
1331 profiler->didExecute(callFrame, executable->sourceURL(), executable->firstLine(), executable->startColumn());
1332
1333 return checkedReturn(result);
1334}
1335
1336NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHookID)
1337{
1338 Debugger* debugger = callFrame->vmEntryGlobalObject()->debugger();
1339 if (!debugger)
1340 return;
1341
1342 ASSERT(callFrame->codeBlock()->hasDebuggerRequests());
1343 ASSERT(!callFrame->hadException());
1344
1345 switch (debugHookID) {
1346 case DidEnterCallFrame:
1347 debugger->callEvent(callFrame);
1348 break;
1349 case WillLeaveCallFrame:
1350 debugger->returnEvent(callFrame);
1351 break;
1352 case WillExecuteStatement:
1353 debugger->atStatement(callFrame);
1354 break;
1355 case WillExecuteProgram:
1356 debugger->willExecuteProgram(callFrame);
1357 break;
1358 case DidExecuteProgram:
1359 debugger->didExecuteProgram(callFrame);
1360 break;
1361 case DidReachBreakpoint:
1362 debugger->didReachBreakpoint(callFrame);
1363 break;
1364 }
1365 ASSERT(!callFrame->hadException());
1366}
1367
1368void Interpreter::enableSampler()
1369{
1370#if ENABLE(OPCODE_SAMPLING)
1371 if (!m_sampler) {
1372 m_sampler = std::make_unique<SamplingTool>(this);
1373 m_sampler->setup();
1374 }
1375#endif
1376}
1377void Interpreter::dumpSampleData(ExecState* exec)
1378{
1379#if ENABLE(OPCODE_SAMPLING)
1380 if (m_sampler)
1381 m_sampler->dump(exec);
1382#else
1383 UNUSED_PARAM(exec);
1384#endif
1385}
1386void Interpreter::startSampling()
1387{
1388#if ENABLE(SAMPLING_THREAD)
1389 if (!m_sampleEntryDepth)
1390 SamplingThread::start();
1391
1392 m_sampleEntryDepth++;
1393#endif
1394}
1395void Interpreter::stopSampling()
1396{
1397#if ENABLE(SAMPLING_THREAD)
1398 m_sampleEntryDepth--;
1399 if (!m_sampleEntryDepth)
1400 SamplingThread::stop();
1401#endif
1402}
1403
1404} // namespace JSC
1405