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