e11ad51cab32094fe15c4350c7310716959b6caa
[WebKit-https.git] / Source / JavaScriptCore / disassembler / Disassembler.cpp
1 /*
2  * Copyright (C) 2012, 2013, 2015 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 "Disassembler.h"
28
29 #include "MacroAssemblerCodeRef.h"
30 #include <wtf/DataLog.h>
31 #include <wtf/Deque.h>
32 #include <wtf/NeverDestroyed.h>
33 #include <wtf/StringPrintStream.h>
34 #include <wtf/Threading.h>
35 #include <wtf/ThreadingPrimitives.h>
36
37 namespace JSC {
38
39 void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out, InstructionSubsetHint subsetHint)
40 {
41     if (tryToDisassemble(codePtr, size, prefix, out, subsetHint))
42         return;
43     
44     out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size);
45 }
46
47 namespace {
48
49 // This is really a struct, except that it should be a class because that's what the WTF_* macros
50 // expect.
51 class DisassemblyTask {
52     WTF_MAKE_NONCOPYABLE(DisassemblyTask);
53     WTF_MAKE_FAST_ALLOCATED;
54 public:
55     DisassemblyTask()
56     {
57     }
58     
59     ~DisassemblyTask()
60     {
61         if (header)
62             free(header); // free() because it would have been copied by strdup.
63     }
64     
65     char* header { nullptr };
66     MacroAssemblerCodeRef codeRef;
67     size_t size { 0 };
68     const char* prefix { nullptr };
69     InstructionSubsetHint subsetHint { MacroAssemblerSubset };
70 };
71
72 class AsynchronousDisassembler {
73 public:
74     AsynchronousDisassembler()
75     {
76         createThread("Asynchronous Disassembler", [&] () { run(); });
77     }
78     
79     void enqueue(std::unique_ptr<DisassemblyTask> task)
80     {
81         DeprecatedMutexLocker locker(m_lock);
82         m_queue.append(WTF::move(task));
83         m_condition.broadcast();
84     }
85     
86     void waitUntilEmpty()
87     {
88         DeprecatedMutexLocker locker(m_lock);
89         while (!m_queue.isEmpty() || m_working)
90             m_condition.wait(m_lock);
91     }
92     
93 private:
94     NO_RETURN void run()
95     {
96         for (;;) {
97             std::unique_ptr<DisassemblyTask> task;
98             {
99                 DeprecatedMutexLocker locker(m_lock);
100                 m_working = false;
101                 m_condition.broadcast();
102                 while (m_queue.isEmpty())
103                     m_condition.wait(m_lock);
104                 task = m_queue.takeFirst();
105                 m_working = true;
106             }
107
108             dataLog(task->header);
109             disassemble(
110                 task->codeRef.code(), task->size, task->prefix, WTF::dataFile(),
111                 task->subsetHint);
112         }
113     }
114     
115     DeprecatedMutex m_lock;
116     ThreadCondition m_condition;
117     Deque<std::unique_ptr<DisassemblyTask>> m_queue;
118     bool m_working { false };
119 };
120
121 bool hadAnyAsynchronousDisassembly = false;
122
123 AsynchronousDisassembler& asynchronousDisassembler()
124 {
125     static NeverDestroyed<AsynchronousDisassembler> disassembler;
126     hadAnyAsynchronousDisassembly = true;
127     return disassembler.get();
128 }
129
130 } // anonymous namespace
131
132 void disassembleAsynchronously(
133     const CString& header, const MacroAssemblerCodeRef& codeRef, size_t size, const char* prefix,
134     InstructionSubsetHint subsetHint)
135 {
136     std::unique_ptr<DisassemblyTask> task = std::make_unique<DisassemblyTask>();
137     task->header = strdup(header.data()); // Yuck! We need this because CString does racy refcounting.
138     task->codeRef = codeRef;
139     task->size = size;
140     task->prefix = prefix;
141     task->subsetHint = subsetHint;
142     
143     asynchronousDisassembler().enqueue(WTF::move(task));
144 }
145
146 void waitForAsynchronousDisassembly()
147 {
148     if (!hadAnyAsynchronousDisassembly)
149         return;
150     
151     asynchronousDisassembler().waitUntilEmpty();
152 }
153
154 } // namespace JSC
155