SamplingProfiler::stackTracesAsJSON() should escape strings.
[WebKit-https.git] / Source / JavaScriptCore / runtime / SamplingProfiler.cpp
1 /*
2  * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "SamplingProfiler.h"
28
29 #if ENABLE(SAMPLING_PROFILER)
30
31 #include "CallFrame.h"
32 #include "CatchScope.h"
33 #include "CodeBlock.h"
34 #include "CodeBlockSet.h"
35 #include "HeapIterationScope.h"
36 #include "HeapUtil.h"
37 #include "InlineCallFrame.h"
38 #include "Interpreter.h"
39 #include "JSCInlines.h"
40 #include "JSFunction.h"
41 #include "LLIntPCRanges.h"
42 #include "MachineContext.h"
43 #include "MarkedBlock.h"
44 #include "MarkedBlockSet.h"
45 #include "MarkedSpaceInlines.h"
46 #include "NativeExecutable.h"
47 #include "PCToCodeOriginMap.h"
48 #include "SlotVisitor.h"
49 #include "StrongInlines.h"
50 #include "VM.h"
51 #include <thread>
52 #include <wtf/FilePrintStream.h>
53 #include <wtf/HashSet.h>
54 #include <wtf/RefPtr.h>
55 #include <wtf/StackTrace.h>
56 #include <wtf/text/StringBuilder.h>
57 #include <wtf/text/StringConcatenateNumbers.h>
58
59 namespace JSC {
60
61 static double sNumTotalStackTraces = 0;
62 static double sNumTotalWalks = 0;
63 static double sNumFailedWalks = 0;
64 static const uint32_t sNumWalkReportingFrequency = 50;
65 static const double sWalkErrorPercentage = .05;
66 static const bool sReportStatsOnlyWhenTheyreAboveThreshold = false;
67 static const bool sReportStats = false;
68
69 using FrameType = SamplingProfiler::FrameType;
70 using UnprocessedStackFrame = SamplingProfiler::UnprocessedStackFrame;
71
72 ALWAYS_INLINE static void reportStats()
73 {
74     if (sReportStats && sNumTotalWalks && static_cast<uint64_t>(sNumTotalWalks) % sNumWalkReportingFrequency == 0) {
75         if (!sReportStatsOnlyWhenTheyreAboveThreshold || (sNumFailedWalks / sNumTotalWalks > sWalkErrorPercentage)) {
76             dataLogF("Num total walks: %llu. Failed walks percent: %lf\n",
77                 static_cast<unsigned long long>(sNumTotalWalks), sNumFailedWalks / sNumTotalWalks);
78         }
79     }
80 }
81
82 class FrameWalker {
83 public:
84     FrameWalker(VM& vm, ExecState* callFrame, const AbstractLocker& codeBlockSetLocker, const AbstractLocker& machineThreadsLocker)
85         : m_vm(vm)
86         , m_callFrame(callFrame)
87         , m_entryFrame(vm.topEntryFrame)
88         , m_codeBlockSetLocker(codeBlockSetLocker)
89         , m_machineThreadsLocker(machineThreadsLocker)
90     {
91     }
92
93     SUPPRESS_ASAN
94     size_t walk(Vector<UnprocessedStackFrame>& stackTrace, bool& didRunOutOfSpace)
95     {
96         if (sReportStats)
97             sNumTotalWalks++;
98         resetAtMachineFrame();
99         size_t maxStackTraceSize = stackTrace.size();
100         while (!isAtTop() && !m_bailingOut && m_depth < maxStackTraceSize) {
101             recordJSFrame(stackTrace);
102             advanceToParentFrame();
103             resetAtMachineFrame();
104         }
105         didRunOutOfSpace = m_depth >= maxStackTraceSize && !isAtTop();
106         reportStats();
107         return m_depth;
108     }
109
110     bool wasValidWalk() const
111     {
112         return !m_bailingOut;
113     }
114
115 protected:
116
117     SUPPRESS_ASAN
118     void recordJSFrame(Vector<UnprocessedStackFrame>& stackTrace)
119     {
120         CallSiteIndex callSiteIndex;
121         CalleeBits unsafeCallee = m_callFrame->unsafeCallee();
122         CodeBlock* codeBlock = m_callFrame->unsafeCodeBlock();
123         if (codeBlock) {
124             ASSERT(isValidCodeBlock(codeBlock));
125             callSiteIndex = m_callFrame->unsafeCallSiteIndex();
126         }
127         stackTrace[m_depth] = UnprocessedStackFrame(codeBlock, unsafeCallee, callSiteIndex);
128         m_depth++;
129     }
130
131     SUPPRESS_ASAN
132     void advanceToParentFrame()
133     {
134         m_callFrame = m_callFrame->unsafeCallerFrame(m_entryFrame);
135     }
136
137     bool isAtTop() const
138     {
139         return !m_callFrame;
140     }
141
142     SUPPRESS_ASAN
143     void resetAtMachineFrame()
144     {
145         if (isAtTop())
146             return;
147
148         if (!isValidFramePointer(m_callFrame)) {
149             // Guard against pausing the process at weird program points.
150             m_bailingOut = true;
151             if (sReportStats)
152                 sNumFailedWalks++;
153             return;
154         }
155
156         CodeBlock* codeBlock = m_callFrame->unsafeCodeBlock();
157         if (!codeBlock)
158             return;
159
160         if (!isValidCodeBlock(codeBlock)) {
161             m_bailingOut = true;
162             if (sReportStats)
163                 sNumFailedWalks++;
164             return;
165         }
166     }
167
168     bool isValidFramePointer(void* exec)
169     {
170         uint8_t* fpCast = bitwise_cast<uint8_t*>(exec);
171         for (auto& thread : m_vm.heap.machineThreads().threads(m_machineThreadsLocker)) {
172             uint8_t* stackBase = static_cast<uint8_t*>(thread->stack().origin());
173             uint8_t* stackLimit = static_cast<uint8_t*>(thread->stack().end());
174             RELEASE_ASSERT(stackBase);
175             RELEASE_ASSERT(stackLimit);
176             RELEASE_ASSERT(stackLimit <= stackBase);
177             if (fpCast < stackBase && fpCast >= stackLimit)
178                 return true;
179         }
180         return false;
181     }
182
183     bool isValidCodeBlock(CodeBlock* codeBlock)
184     {
185         if (!codeBlock)
186             return false;
187         bool result = m_vm.heap.codeBlockSet().contains(m_codeBlockSetLocker, codeBlock);
188         return result;
189     }
190
191     VM& m_vm;
192     ExecState* m_callFrame;
193     EntryFrame* m_entryFrame;
194     const AbstractLocker& m_codeBlockSetLocker;
195     const AbstractLocker& m_machineThreadsLocker;
196     bool m_bailingOut { false };
197     size_t m_depth { 0 };
198 };
199
200 class CFrameWalker : public FrameWalker {
201 public:
202     typedef FrameWalker Base;
203
204     CFrameWalker(VM& vm, void* machineFrame, ExecState* callFrame, const AbstractLocker& codeBlockSetLocker, const AbstractLocker& machineThreadsLocker)
205         : Base(vm, callFrame, codeBlockSetLocker, machineThreadsLocker)
206         , m_machineFrame(machineFrame)
207     {
208     }
209
210     size_t walk(Vector<UnprocessedStackFrame>& stackTrace, bool& didRunOutOfSpace)
211     {
212         if (sReportStats)
213             sNumTotalWalks++;
214         resetAtMachineFrame();
215         size_t maxStackTraceSize = stackTrace.size();
216         // The way the C walker decides if a frame it is about to trace is C or JS is by
217         // ensuring m_callFrame points to some frame above the machineFrame.
218         if (!isAtTop() && !m_bailingOut && m_machineFrame == m_callFrame) {
219             recordJSFrame(stackTrace);
220             Base::advanceToParentFrame();
221             resetAtMachineFrame();
222         }
223
224         while (!isAtTop() && !m_bailingOut && m_depth < maxStackTraceSize) {
225             if (m_machineFrame >= m_callFrame) {
226                 // If we get to this state we probably have an invalid trace.
227                 m_bailingOut = true;
228                 break;
229             }
230
231             if (isCFrame()) {
232                 RELEASE_ASSERT(!LLInt::isLLIntPC(frame()->callerFrame));
233                 stackTrace[m_depth] = UnprocessedStackFrame(frame()->returnPC);
234                 m_depth++;
235             } else
236                 recordJSFrame(stackTrace);
237             advanceToParentFrame();
238             resetAtMachineFrame();
239         }
240         didRunOutOfSpace = m_depth >= maxStackTraceSize && !isAtTop();
241         reportStats();
242         return m_depth;
243     }
244
245 private:
246
247     bool isCFrame()
248     {
249         return frame()->callerFrame != m_callFrame;
250     }
251
252     void advanceToParentFrame()
253     {
254         if (!isCFrame())
255             Base::advanceToParentFrame();
256         m_machineFrame = frame()->callerFrame;
257     }
258
259     void resetAtMachineFrame()
260     {
261         if (!isValidFramePointer(m_machineFrame)) {
262             // Guard against pausing the process at weird program points.
263             m_bailingOut = true;
264             if (sReportStats)
265                 sNumFailedWalks++;
266             return;
267         }
268         Base::resetAtMachineFrame();
269     }
270
271     CallerFrameAndPC* frame()
272     {
273         return reinterpret_cast<CallerFrameAndPC*>(m_machineFrame);
274     }
275
276     void* m_machineFrame;
277 };
278
279 SamplingProfiler::SamplingProfiler(VM& vm, RefPtr<Stopwatch>&& stopwatch)
280     : m_vm(vm)
281     , m_weakRandom()
282     , m_stopwatch(WTFMove(stopwatch))
283     , m_timingInterval(Seconds::fromMicroseconds(Options::sampleInterval()))
284     , m_isPaused(false)
285     , m_isShutDown(false)
286 {
287     if (sReportStats) {
288         sNumTotalWalks = 0;
289         sNumFailedWalks = 0;
290     }
291
292     m_currentFrames.grow(256);
293 }
294
295 SamplingProfiler::~SamplingProfiler()
296 {
297 }
298
299 void SamplingProfiler::createThreadIfNecessary(const AbstractLocker&)
300 {
301     ASSERT(m_lock.isLocked());
302
303     if (m_thread)
304         return;
305
306     RefPtr<SamplingProfiler> profiler = this;
307     m_thread = Thread::create("jsc.sampling-profiler.thread", [profiler] {
308         profiler->timerLoop();
309     });
310 }
311
312 void SamplingProfiler::timerLoop()
313 {
314     while (true) {
315         Seconds stackTraceProcessingTime = 0_s;
316         {
317             LockHolder locker(m_lock);
318             if (UNLIKELY(m_isShutDown))
319                 return;
320
321             if (!m_isPaused && m_jscExecutionThread)
322                 takeSample(locker, stackTraceProcessingTime);
323
324             m_lastTime = m_stopwatch->elapsedTime();
325         }
326
327         // Read section 6.2 of this paper for more elaboration of why we add a random
328         // fluctuation here. The main idea is to prevent our timer from being in sync
329         // with some system process such as a scheduled context switch.
330         // http://plv.colorado.edu/papers/mytkowicz-pldi10.pdf
331         double randomSignedNumber = (m_weakRandom.get() * 2.0) - 1.0; // A random number between [-1, 1).
332         Seconds randomFluctuation = m_timingInterval * 0.2 * randomSignedNumber;
333         WTF::sleep(m_timingInterval - std::min(m_timingInterval, stackTraceProcessingTime) + randomFluctuation);
334     }
335 }
336
337 void SamplingProfiler::takeSample(const AbstractLocker&, Seconds& stackTraceProcessingTime)
338 {
339     ASSERT(m_lock.isLocked());
340     if (m_vm.entryScope) {
341         Seconds nowTime = m_stopwatch->elapsedTime();
342
343         auto machineThreadsLocker = holdLock(m_vm.heap.machineThreads().getLock());
344         LockHolder codeBlockSetLocker(m_vm.heap.codeBlockSet().getLock());
345         LockHolder executableAllocatorLocker(ExecutableAllocator::singleton().getLock());
346
347         auto didSuspend = m_jscExecutionThread->suspend();
348         if (didSuspend) {
349             // While the JSC thread is suspended, we can't do things like malloc because the JSC thread
350             // may be holding the malloc lock.
351             void* machineFrame;
352             ExecState* callFrame;
353             void* machinePC;
354             bool topFrameIsLLInt = false;
355             void* llintPC;
356             {
357                 PlatformRegisters registers;
358                 m_jscExecutionThread->getRegisters(registers);
359                 machineFrame = MachineContext::framePointer(registers);
360                 callFrame = static_cast<ExecState*>(machineFrame);
361                 auto instructionPointer = MachineContext::instructionPointer(registers);
362                 if (instructionPointer)
363                     machinePC = instructionPointer->untaggedExecutableAddress();
364                 else
365                     machinePC = nullptr;
366                 llintPC = removeCodePtrTag(MachineContext::llintInstructionPointer(registers));
367                 assertIsNotTagged(machinePC);
368             }
369             // FIXME: Lets have a way of detecting when we're parsing code.
370             // https://bugs.webkit.org/show_bug.cgi?id=152761
371             if (ExecutableAllocator::singleton().isValidExecutableMemory(executableAllocatorLocker, machinePC)) {
372                 if (m_vm.isExecutingInRegExpJIT) {
373                     // FIXME: We're executing a regexp. Lets gather more intersting data.
374                     // https://bugs.webkit.org/show_bug.cgi?id=152729
375                     callFrame = m_vm.topCallFrame; // We need to do this or else we'd fail our backtrace validation b/c this isn't a JS frame.
376                 }
377             } else if (LLInt::isLLIntPC(machinePC)) {
378                 topFrameIsLLInt = true;
379                 // We're okay to take a normal stack trace when the PC
380                 // is in LLInt code.
381             } else {
382                 // We resort to topCallFrame to see if we can get anything
383                 // useful. We usually get here when we're executing C code.
384                 callFrame = m_vm.topCallFrame;
385             }
386
387             size_t walkSize;
388             bool wasValidWalk;
389             bool didRunOutOfVectorSpace;
390             if (Options::sampleCCode()) {
391                 CFrameWalker walker(m_vm, machineFrame, callFrame, codeBlockSetLocker, machineThreadsLocker);
392                 walkSize = walker.walk(m_currentFrames, didRunOutOfVectorSpace);
393                 wasValidWalk = walker.wasValidWalk();
394             } else {
395                 FrameWalker walker(m_vm, callFrame, codeBlockSetLocker, machineThreadsLocker);
396                 walkSize = walker.walk(m_currentFrames, didRunOutOfVectorSpace);
397                 wasValidWalk = walker.wasValidWalk();
398             }
399
400             m_jscExecutionThread->resume();
401
402             auto startTime = MonotonicTime::now();
403             // We can now use data structures that malloc, and do other interesting things, again.
404
405             // FIXME: It'd be interesting to take data about the program's state when
406             // we fail to take a stack trace: https://bugs.webkit.org/show_bug.cgi?id=152758
407             if (wasValidWalk && walkSize) {
408                 if (sReportStats)
409                     sNumTotalStackTraces++;
410                 Vector<UnprocessedStackFrame> stackTrace;
411                 stackTrace.reserveInitialCapacity(walkSize);
412                 for (size_t i = 0; i < walkSize; i++) {
413                     UnprocessedStackFrame frame = m_currentFrames[i];
414                     stackTrace.uncheckedAppend(frame);
415                 }
416
417                 m_unprocessedStackTraces.append(UnprocessedStackTrace { nowTime, machinePC, topFrameIsLLInt, llintPC, WTFMove(stackTrace) });
418
419                 if (didRunOutOfVectorSpace)
420                     m_currentFrames.grow(m_currentFrames.size() * 1.25);
421             }
422
423             auto endTime = MonotonicTime::now();
424             stackTraceProcessingTime = endTime - startTime;
425         }
426     }
427 }
428
429 static ALWAYS_INLINE unsigned tryGetBytecodeIndex(unsigned llintPC, CodeBlock* codeBlock, bool& isValid)
430 {
431 #if ENABLE(DFG_JIT)
432     RELEASE_ASSERT(!codeBlock->hasCodeOrigins());
433 #endif
434
435 #if USE(JSVALUE64)
436     unsigned bytecodeIndex = llintPC;
437     if (bytecodeIndex < codeBlock->instructionCount()) {
438         isValid = true;
439         return bytecodeIndex;
440     }
441     isValid = false;
442     return 0;
443 #else
444     Instruction* instruction = bitwise_cast<Instruction*>(llintPC);
445
446     if (codeBlock->instructions().contains(instruction)) {
447         isValid = true;
448         return codeBlock->bytecodeOffset(instruction);
449     }
450     isValid = false;
451     return 0;
452 #endif
453 }
454
455 void SamplingProfiler::processUnverifiedStackTraces()
456 {
457     // This function needs to be called from the JSC execution thread.
458     RELEASE_ASSERT(m_lock.isLocked());
459
460     TinyBloomFilter filter = m_vm.heap.objectSpace().blocks().filter();
461
462     for (UnprocessedStackTrace& unprocessedStackTrace : m_unprocessedStackTraces) {
463         m_stackTraces.append(StackTrace());
464         StackTrace& stackTrace = m_stackTraces.last();
465         stackTrace.timestamp = unprocessedStackTrace.timestamp;
466
467         auto populateCodeLocation = [] (CodeBlock* codeBlock, unsigned bytecodeIndex, StackFrame::CodeLocation& location) {
468             if (bytecodeIndex < codeBlock->instructionCount()) {
469                 int divot;
470                 int startOffset;
471                 int endOffset;
472                 codeBlock->expressionRangeForBytecodeOffset(bytecodeIndex, divot, startOffset, endOffset,
473                     location.lineNumber, location.columnNumber);
474                 location.bytecodeIndex = bytecodeIndex;
475             }
476             if (Options::collectSamplingProfilerDataForJSCShell()) {
477                 location.codeBlockHash = codeBlock->hash();
478                 location.jitType = codeBlock->jitType();
479             }
480         };
481
482         auto appendCodeBlock = [&] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
483             stackTrace.frames.append(StackFrame(codeBlock->ownerExecutable()));
484             m_liveCellPointers.add(codeBlock->ownerExecutable());
485             populateCodeLocation(codeBlock, bytecodeIndex, stackTrace.frames.last().semanticLocation);
486         };
487
488         auto appendEmptyFrame = [&] {
489             stackTrace.frames.append(StackFrame());
490         };
491
492         auto storeCalleeIntoLastFrame = [&] (CalleeBits calleeBits) {
493             // Set the callee if it's a valid GC object.
494             StackFrame& stackFrame = stackTrace.frames.last();
495             bool alreadyHasExecutable = !!stackFrame.executable;
496             if (calleeBits.isWasm()) {
497                 stackFrame.frameType = FrameType::Unknown;
498                 return;
499             }
500
501             JSValue callee = calleeBits.asCell();
502             if (!HeapUtil::isValueGCObject(m_vm.heap, filter, callee)) {
503                 if (!alreadyHasExecutable)
504                     stackFrame.frameType = FrameType::Unknown;
505                 return;
506             }
507
508             JSCell* calleeCell = callee.asCell();
509             auto setFallbackFrameType = [&] {
510                 ASSERT(!alreadyHasExecutable);
511                 FrameType result = FrameType::Unknown;
512                 CallData callData;
513                 CallType callType;
514                 callType = getCallData(m_vm, calleeCell, callData);
515                 if (callType == CallType::Host)
516                     result = FrameType::Host;
517
518                 stackFrame.frameType = result;
519             };
520
521             auto addCallee = [&] (JSObject* callee) {
522                 stackFrame.callee = callee;
523                 m_liveCellPointers.add(callee);
524             };
525
526             if (calleeCell->type() != JSFunctionType) {
527                 if (JSObject* object = jsDynamicCast<JSObject*>(*calleeCell->vm(), calleeCell))
528                     addCallee(object);
529
530                 if (!alreadyHasExecutable)
531                     setFallbackFrameType();
532
533                 return;
534             }
535
536             addCallee(jsCast<JSFunction*>(calleeCell));
537
538             if (alreadyHasExecutable)
539                 return;
540
541             ExecutableBase* executable = jsCast<JSFunction*>(calleeCell)->executable();
542             if (!executable) {
543                 setFallbackFrameType();
544                 return;
545             }
546
547             RELEASE_ASSERT(HeapUtil::isPointerGCObjectJSCell(m_vm.heap, filter, executable));
548             stackFrame.frameType = FrameType::Executable;
549             stackFrame.executable = executable;
550             m_liveCellPointers.add(executable);
551         };
552
553         auto appendCodeOrigin = [&] (CodeBlock* machineCodeBlock, CodeOrigin origin) {
554             size_t startIndex = stackTrace.frames.size(); // We want to change stack traces that we're about to append.
555
556             CodeOrigin machineOrigin;
557             origin.walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
558                 machineOrigin = codeOrigin;
559                 appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : machineCodeBlock, codeOrigin.bytecodeIndex);
560             });
561
562             if (Options::collectSamplingProfilerDataForJSCShell()) {
563                 RELEASE_ASSERT(machineOrigin.isSet());
564                 RELEASE_ASSERT(!machineOrigin.inlineCallFrame);
565
566                 StackFrame::CodeLocation machineLocation = stackTrace.frames.last().semanticLocation;
567
568                 // We want to tell each inlined frame about the machine frame
569                 // they were inlined into. Currently, we only use this for dumping
570                 // output on the command line, but we could extend it to the web
571                 // inspector in the future if we find a need for it there.
572                 RELEASE_ASSERT(stackTrace.frames.size());
573                 m_liveCellPointers.add(machineCodeBlock);
574                 for (size_t i = startIndex; i < stackTrace.frames.size() - 1; i++)
575                     stackTrace.frames[i].machineLocation = std::make_pair(machineLocation, machineCodeBlock);
576             }
577         };
578
579         // Prepend the top-most inlined frame if needed and gather
580         // location information about where the top frame is executing.
581         size_t startIndex = 0;
582         if (unprocessedStackTrace.frames.size() && !!unprocessedStackTrace.frames[0].verifiedCodeBlock) {
583             CodeBlock* topCodeBlock = unprocessedStackTrace.frames[0].verifiedCodeBlock;
584             if (unprocessedStackTrace.topFrameIsLLInt) {
585                 // We reuse LLInt CodeBlocks for the baseline JIT, so we need to check for both jit types.
586                 // This might also be false for various reasons (known and unknown), even though
587                 // it's super unlikely. One reason that this can be false is when we throw from a DFG frame,
588                 // and we end up having to unwind past an EntryFrame, we will end up executing
589                 // inside the LLInt's handleUncaughtException. So we just protect against this
590                 // by ignoring it.
591                 unsigned bytecodeIndex = 0;
592                 if (topCodeBlock->jitType() == JITCode::InterpreterThunk || topCodeBlock->jitType() == JITCode::BaselineJIT) {
593                     bool isValidPC;
594                     unsigned bits;
595 #if USE(JSVALUE64)
596                     bits = static_cast<unsigned>(bitwise_cast<uintptr_t>(unprocessedStackTrace.llintPC));
597 #else
598                     bits = bitwise_cast<unsigned>(unprocessedStackTrace.llintPC);
599 #endif
600                     bytecodeIndex = tryGetBytecodeIndex(bits, topCodeBlock, isValidPC);
601
602                     UNUSED_PARAM(isValidPC); // FIXME: do something with this info for the web inspector: https://bugs.webkit.org/show_bug.cgi?id=153455
603
604                     appendCodeBlock(topCodeBlock, bytecodeIndex);
605                     storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
606                     startIndex = 1;
607                 }
608             } else {
609 #if ENABLE(JIT)
610                 if (Optional<CodeOrigin> codeOrigin = topCodeBlock->findPC(unprocessedStackTrace.topPC)) {
611                     appendCodeOrigin(topCodeBlock, *codeOrigin);
612                     storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
613                     startIndex = 1;
614                 }
615 #endif
616                 UNUSED_PARAM(appendCodeOrigin);
617             }
618         }
619
620         for (size_t i = startIndex; i < unprocessedStackTrace.frames.size(); i++) {
621             UnprocessedStackFrame& unprocessedStackFrame = unprocessedStackTrace.frames[i];
622             if (CodeBlock* codeBlock = unprocessedStackFrame.verifiedCodeBlock) {
623                 CallSiteIndex callSiteIndex = unprocessedStackFrame.callSiteIndex;
624
625                 auto appendCodeBlockNoInlining = [&] {
626                     bool isValidPC;
627                     appendCodeBlock(codeBlock, tryGetBytecodeIndex(callSiteIndex.bits(), codeBlock, isValidPC));
628                 };
629
630 #if ENABLE(DFG_JIT)
631                 if (codeBlock->hasCodeOrigins()) {
632                     if (codeBlock->canGetCodeOrigin(callSiteIndex))
633                         appendCodeOrigin(codeBlock, codeBlock->codeOrigin(callSiteIndex));
634                     else
635                         appendCodeBlock(codeBlock, std::numeric_limits<unsigned>::max());
636                 } else
637                     appendCodeBlockNoInlining();
638 #else
639                 appendCodeBlockNoInlining();
640 #endif
641             } else if (unprocessedStackFrame.cCodePC) {
642                 appendEmptyFrame();
643                 stackTrace.frames.last().cCodePC = unprocessedStackFrame.cCodePC;
644                 stackTrace.frames.last().frameType = FrameType::C;
645             } else
646                 appendEmptyFrame();
647
648             // Note that this is okay to do if we walked the inline stack because
649             // the machine frame will be at the top of the processed stack trace.
650             if (!unprocessedStackFrame.cCodePC)
651                 storeCalleeIntoLastFrame(unprocessedStackFrame.unverifiedCallee);
652         }
653     }
654
655     m_unprocessedStackTraces.clear();
656 }
657
658 void SamplingProfiler::visit(SlotVisitor& slotVisitor)
659 {
660     RELEASE_ASSERT(m_lock.isLocked());
661     for (JSCell* cell : m_liveCellPointers)
662         slotVisitor.appendUnbarriered(cell);
663 }
664
665 void SamplingProfiler::shutdown()
666 {
667     LockHolder locker(m_lock);
668     m_isShutDown = true;
669 }
670
671 void SamplingProfiler::start()
672 {
673     LockHolder locker(m_lock);
674     start(locker);
675 }
676
677 void SamplingProfiler::start(const AbstractLocker& locker)
678 {
679     ASSERT(m_lock.isLocked());
680     m_isPaused = false;
681     createThreadIfNecessary(locker);
682 }
683
684 void SamplingProfiler::pause(const AbstractLocker&)
685 {
686     ASSERT(m_lock.isLocked());
687     m_isPaused = true;
688     reportStats();
689 }
690
691 void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread(const AbstractLocker&)
692 {
693     ASSERT(m_lock.isLocked());
694     m_jscExecutionThread = &Thread::current();
695 }
696
697 void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread()
698 {
699     LockHolder locker(m_lock);
700     noticeCurrentThreadAsJSCExecutionThread(locker);
701 }
702
703 void SamplingProfiler::noticeJSLockAcquisition()
704 {
705     LockHolder locker(m_lock);
706     noticeCurrentThreadAsJSCExecutionThread(locker);
707 }
708
709 void SamplingProfiler::noticeVMEntry()
710 {
711     LockHolder locker(m_lock);
712     ASSERT(m_vm.entryScope);
713     noticeCurrentThreadAsJSCExecutionThread(locker);
714     m_lastTime = m_stopwatch->elapsedTime();
715     createThreadIfNecessary(locker);
716 }
717
718 void SamplingProfiler::clearData(const AbstractLocker&)
719 {
720     ASSERT(m_lock.isLocked());
721     m_stackTraces.clear();
722     m_liveCellPointers.clear();
723     m_unprocessedStackTraces.clear();
724 }
725
726 String SamplingProfiler::StackFrame::nameFromCallee(VM& vm)
727 {
728     if (!callee)
729         return String();
730
731     auto scope = DECLARE_CATCH_SCOPE(vm);
732     ExecState* exec = callee->globalObject(vm)->globalExec();
733     auto getPropertyIfPureOperation = [&] (const Identifier& ident) -> String {
734         PropertySlot slot(callee, PropertySlot::InternalMethodType::VMInquiry);
735         PropertyName propertyName(ident);
736         bool hasProperty = callee->getPropertySlot(exec, propertyName, slot);
737         scope.assertNoException();
738         if (hasProperty) {
739             if (slot.isValue()) {
740                 JSValue nameValue = slot.getValue(exec, propertyName);
741                 if (isJSString(nameValue))
742                     return asString(nameValue)->tryGetValue();
743             }
744         }
745         return String();
746     };
747
748     String name = getPropertyIfPureOperation(vm.propertyNames->displayName);
749     if (!name.isEmpty())
750         return name;
751
752     return getPropertyIfPureOperation(vm.propertyNames->name);
753 }
754
755 String SamplingProfiler::StackFrame::displayName(VM& vm)
756 {
757     {
758         String name = nameFromCallee(vm);
759         if (!name.isEmpty())
760             return name;
761     }
762
763     if (frameType == FrameType::Unknown || frameType == FrameType::C) {
764 #if HAVE(DLADDR)
765         if (frameType == FrameType::C) {
766             auto demangled = WTF::StackTrace::demangle(const_cast<void*>(cCodePC));
767             if (demangled)
768                 return String(demangled->demangledName() ? demangled->demangledName() : demangled->mangledName());
769             WTF::dataLog("couldn't get a name");
770         }
771 #endif
772         return "(unknown)"_s;
773     }
774     if (frameType == FrameType::Host)
775         return "(host)"_s;
776
777     if (executable->isHostFunction())
778         return static_cast<NativeExecutable*>(executable)->name();
779
780     if (executable->isFunctionExecutable())
781         return static_cast<FunctionExecutable*>(executable)->inferredName().string();
782     if (executable->isProgramExecutable() || executable->isEvalExecutable())
783         return "(program)"_s;
784     if (executable->isModuleProgramExecutable())
785         return "(module)"_s;
786
787     RELEASE_ASSERT_NOT_REACHED();
788     return String();
789 }
790
791 String SamplingProfiler::StackFrame::displayNameForJSONTests(VM& vm)
792 {
793     {
794         String name = nameFromCallee(vm);
795         if (!name.isEmpty())
796             return name;
797     }
798
799     if (frameType == FrameType::Unknown || frameType == FrameType::C)
800         return "(unknown)"_s;
801     if (frameType == FrameType::Host)
802         return "(host)"_s;
803
804     if (executable->isHostFunction())
805         return static_cast<NativeExecutable*>(executable)->name();
806
807     if (executable->isFunctionExecutable()) {
808         String result = static_cast<FunctionExecutable*>(executable)->inferredName().string();
809         if (result.isEmpty())
810             return "(anonymous function)"_s;
811         return result;
812     }
813     if (executable->isEvalExecutable())
814         return "(eval)"_s;
815     if (executable->isProgramExecutable())
816         return "(program)"_s;
817     if (executable->isModuleProgramExecutable())
818         return "(module)"_s;
819
820     RELEASE_ASSERT_NOT_REACHED();
821     return String();
822 }
823
824 int SamplingProfiler::StackFrame::functionStartLine()
825 {
826     if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
827         return -1;
828
829     if (executable->isHostFunction())
830         return -1;
831     return static_cast<ScriptExecutable*>(executable)->firstLine();
832 }
833
834 unsigned SamplingProfiler::StackFrame::functionStartColumn()
835 {
836     if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
837         return std::numeric_limits<unsigned>::max();
838
839     if (executable->isHostFunction())
840         return std::numeric_limits<unsigned>::max();
841
842     return static_cast<ScriptExecutable*>(executable)->startColumn();
843 }
844
845 intptr_t SamplingProfiler::StackFrame::sourceID()
846 {
847     if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
848         return -1;
849
850     if (executable->isHostFunction())
851         return -1;
852
853     return static_cast<ScriptExecutable*>(executable)->sourceID();
854 }
855
856 String SamplingProfiler::StackFrame::url()
857 {
858     if (frameType == FrameType::Unknown || frameType == FrameType::Host || frameType == FrameType::C)
859         return emptyString();
860
861     if (executable->isHostFunction())
862         return emptyString();
863
864     String url = static_cast<ScriptExecutable*>(executable)->sourceURL();
865     if (url.isEmpty())
866         return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive.
867     return url;
868 }
869
870 Vector<SamplingProfiler::StackTrace> SamplingProfiler::releaseStackTraces(const AbstractLocker& locker)
871 {
872     ASSERT(m_lock.isLocked());
873     {
874         HeapIterationScope heapIterationScope(m_vm.heap);
875         processUnverifiedStackTraces();
876     }
877
878     Vector<StackTrace> result(WTFMove(m_stackTraces));
879     clearData(locker);
880     return result;
881 }
882
883 String SamplingProfiler::stackTracesAsJSON()
884 {
885     DeferGC deferGC(m_vm.heap);
886     LockHolder locker(m_lock);
887
888     {
889         HeapIterationScope heapIterationScope(m_vm.heap);
890         processUnverifiedStackTraces();
891     }
892
893     StringBuilder json;
894     json.append('[');
895
896     bool loopedOnce = false;
897     auto comma = [&] {
898         if (loopedOnce)
899             json.append(',');
900     };
901     for (StackTrace& stackTrace : m_stackTraces) {
902         comma();
903         json.append('[');
904         loopedOnce = false;
905         for (StackFrame& stackFrame : stackTrace.frames) {
906             comma();
907             json.appendQuotedJSONString(stackFrame.displayNameForJSONTests(m_vm));
908             loopedOnce = true;
909         }
910         json.append(']');
911         loopedOnce = true;
912     }
913
914     json.append(']');
915
916     clearData(locker);
917
918     return json.toString();
919 }
920
921 void SamplingProfiler::registerForReportAtExit()
922 {
923     static Lock registrationLock;
924     static HashSet<RefPtr<SamplingProfiler>>* profilesToReport;
925
926     LockHolder holder(registrationLock);
927
928     if (!profilesToReport) {
929         profilesToReport = new HashSet<RefPtr<SamplingProfiler>>();
930         atexit([]() {
931             for (auto profile : *profilesToReport)
932                 profile->reportDataToOptionFile();
933         });
934     }
935
936     profilesToReport->add(adoptRef(this));
937     m_needsReportAtExit = true;
938 }
939
940 void SamplingProfiler::reportDataToOptionFile()
941 {
942     if (m_needsReportAtExit) {
943         m_needsReportAtExit = false;
944         const char* path = Options::samplingProfilerPath();
945         StringPrintStream pathOut;
946         pathOut.print(path, "/");
947         pathOut.print("JSCSampilingProfile-", reinterpret_cast<uintptr_t>(this), ".txt");
948         auto out = FilePrintStream::open(pathOut.toCString().data(), "w");
949         reportTopFunctions(*out);
950         reportTopBytecodes(*out);
951     }
952 }
953
954 void SamplingProfiler::reportTopFunctions()
955 {
956     reportTopFunctions(WTF::dataFile());
957 }
958
959 void SamplingProfiler::reportTopFunctions(PrintStream& out)
960 {
961     LockHolder locker(m_lock);
962     DeferGCForAWhile deferGC(m_vm.heap);
963
964     {
965         HeapIterationScope heapIterationScope(m_vm.heap);
966         processUnverifiedStackTraces();
967     }
968
969
970     HashMap<String, size_t> functionCounts;
971     for (StackTrace& stackTrace : m_stackTraces) {
972         if (!stackTrace.frames.size())
973             continue;
974
975         StackFrame& frame = stackTrace.frames.first();
976         String frameDescription = makeString(frame.displayName(m_vm), ':', frame.sourceID());
977         functionCounts.add(frameDescription, 0).iterator->value++;
978     }
979
980     auto takeMax = [&] () -> std::pair<String, size_t> {
981         String maxFrameDescription;
982         size_t maxFrameCount = 0;
983         for (auto entry : functionCounts) {
984             if (entry.value > maxFrameCount) {
985                 maxFrameCount = entry.value;
986                 maxFrameDescription = entry.key;
987             }
988         }
989         if (!maxFrameDescription.isEmpty())
990             functionCounts.remove(maxFrameDescription);
991         return std::make_pair(maxFrameDescription, maxFrameCount);
992     };
993
994     if (Options::samplingProfilerTopFunctionsCount()) {
995         out.print("\n\nSampling rate: ", m_timingInterval.microseconds(), " microseconds\n");
996         out.print("Top functions as <numSamples  'functionName:sourceID'>\n");
997         for (size_t i = 0; i < Options::samplingProfilerTopFunctionsCount(); i++) {
998             auto pair = takeMax();
999             if (pair.first.isEmpty())
1000                 break;
1001             out.printf("%6zu ", pair.second);
1002             out.print("   '", pair.first, "'\n");
1003         }
1004     }
1005 }
1006
1007 void SamplingProfiler::reportTopBytecodes()
1008 {
1009     reportTopBytecodes(WTF::dataFile());
1010 }
1011
1012 void SamplingProfiler::reportTopBytecodes(PrintStream& out)
1013 {
1014     LockHolder locker(m_lock);
1015     DeferGCForAWhile deferGC(m_vm.heap);
1016
1017     {
1018         HeapIterationScope heapIterationScope(m_vm.heap);
1019         processUnverifiedStackTraces();
1020     }
1021
1022     HashMap<String, size_t> bytecodeCounts;
1023     for (StackTrace& stackTrace : m_stackTraces) {
1024         if (!stackTrace.frames.size())
1025             continue;
1026
1027         auto descriptionForLocation = [&] (StackFrame::CodeLocation location) -> String {
1028             String bytecodeIndex;
1029             String codeBlockHash;
1030             if (location.hasBytecodeIndex())
1031                 bytecodeIndex = String::number(location.bytecodeIndex);
1032             else
1033                 bytecodeIndex = "<nil>";
1034
1035             if (location.hasCodeBlockHash()) {
1036                 StringPrintStream stream;
1037                 location.codeBlockHash.dump(stream);
1038                 codeBlockHash = stream.toString();
1039             } else
1040                 codeBlockHash = "<nil>";
1041
1042             return makeString("#", codeBlockHash, ":", JITCode::typeName(location.jitType), ":", bytecodeIndex);
1043         };
1044
1045         StackFrame& frame = stackTrace.frames.first();
1046         String frameDescription = makeString(frame.displayName(m_vm), descriptionForLocation(frame.semanticLocation));
1047         if (Optional<std::pair<StackFrame::CodeLocation, CodeBlock*>> machineLocation = frame.machineLocation) {
1048             frameDescription = makeString(frameDescription, " <-- ",
1049                 machineLocation->second->inferredName().data(), descriptionForLocation(machineLocation->first));
1050         }
1051         bytecodeCounts.add(frameDescription, 0).iterator->value++;
1052     }
1053
1054     auto takeMax = [&] () -> std::pair<String, size_t> {
1055         String maxFrameDescription;
1056         size_t maxFrameCount = 0;
1057         for (auto entry : bytecodeCounts) {
1058             if (entry.value > maxFrameCount) {
1059                 maxFrameCount = entry.value;
1060                 maxFrameDescription = entry.key;
1061             }
1062         }
1063         if (!maxFrameDescription.isEmpty())
1064             bytecodeCounts.remove(maxFrameDescription);
1065         return std::make_pair(maxFrameDescription, maxFrameCount);
1066     };
1067
1068     if (Options::samplingProfilerTopBytecodesCount()) {
1069         out.print("\n\nSampling rate: ", m_timingInterval.microseconds(), " microseconds\n");
1070         out.print("Hottest bytecodes as <numSamples   'functionName#hash:JITType:bytecodeIndex'>\n");
1071         for (size_t i = 0; i < Options::samplingProfilerTopBytecodesCount(); i++) {
1072             auto pair = takeMax();
1073             if (pair.first.isEmpty())
1074                 break;
1075             out.printf("%6zu ", pair.second);
1076             out.print("   '", pair.first, "'\n");
1077         }
1078     }
1079 }
1080
1081 #if OS(DARWIN)
1082 mach_port_t SamplingProfiler::machThread()
1083 {
1084     if (!m_thread)
1085         return MACH_PORT_NULL;
1086
1087     return m_thread->machThread();
1088 }
1089 #endif
1090
1091 } // namespace JSC
1092
1093 namespace WTF {
1094
1095 using namespace JSC;
1096
1097 void printInternal(PrintStream& out, SamplingProfiler::FrameType frameType)
1098 {
1099     switch (frameType) {
1100     case SamplingProfiler::FrameType::Executable:
1101         out.print("Executable");
1102         break;
1103     case SamplingProfiler::FrameType::Host:
1104         out.print("Host");
1105         break;
1106     case SamplingProfiler::FrameType::C:
1107     case SamplingProfiler::FrameType::Unknown:
1108         out.print("Unknown");
1109         break;
1110     }
1111 }
1112
1113 } // namespace WTF
1114
1115 #endif // ENABLE(SAMPLING_PROFILER)