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