1/*
2 * Copyright (C) 2017-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#pragma once
27
28#if ENABLE(WEBASSEMBLY)
29
30#include "MacroAssemblerCodeRef.h"
31#include "WasmCallee.h"
32#include "WasmEmbedder.h"
33#include <wtf/CrossThreadCopier.h>
34#include <wtf/Lock.h>
35#include <wtf/RefPtr.h>
36#include <wtf/SharedTask.h>
37#include <wtf/ThreadSafeRefCounted.h>
38#include <wtf/text/WTFString.h>
39
40namespace JSC {
41
42namespace Wasm {
43
44struct Context;
45class EntryPlan;
46struct ModuleInformation;
47struct UnlinkedWasmToWasmCall;
48enum class MemoryMode : uint8_t;
49
50// FIXME: Rename this, since it's not a CodeBlock
51// https://bugs.webkit.org/show_bug.cgi?id=203694
52class CodeBlock : public ThreadSafeRefCounted<CodeBlock> {
53public:
54 typedef void CallbackType(Ref<CodeBlock>&&);
55 using AsyncCompilationCallback = RefPtr<WTF::SharedTask<CallbackType>>;
56 static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
57
58 void waitUntilFinished();
59 void compileAsync(Context*, AsyncCompilationCallback&&);
60
61 bool compilationFinished()
62 {
63 return m_compilationFinished.load();
64 }
65 bool runnable() { return compilationFinished() && !m_errorMessage; }
66
67 // Note, we do this copy to ensure it's thread safe to have this
68 // called from multiple threads simultaneously.
69 String errorMessage()
70 {
71 ASSERT(!runnable());
72 return crossThreadCopy(m_errorMessage);
73 }
74
75 unsigned functionImportCount() const { return m_wasmToWasmExitStubs.size(); }
76
77 // These two callee getters are only valid once the callees have been populated.
78
79 Callee& embedderEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
80 {
81 ASSERT(runnable());
82 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
83 unsigned calleeIndex = functionIndexSpace - functionImportCount();
84
85 auto callee = m_embedderCallees.get(calleeIndex);
86 RELEASE_ASSERT(callee);
87 return *callee;
88 }
89 Callee& wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
90 {
91 ASSERT(runnable());
92 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
93 unsigned calleeIndex = functionIndexSpace - functionImportCount();
94 if (m_omgCallees[calleeIndex])
95 return *m_omgCallees[calleeIndex].get();
96 if (m_bbqCallees[calleeIndex])
97 return *m_bbqCallees[calleeIndex].get();
98 return *m_llintCallees[calleeIndex].get();
99 }
100
101 BBQCallee& wasmBBQCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
102 {
103 ASSERT(runnable());
104 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
105 unsigned calleeIndex = functionIndexSpace - functionImportCount();
106 return *m_bbqCallees[calleeIndex].get();
107 }
108
109 MacroAssemblerCodePtr<WasmEntryPtrTag>* entrypointLoadLocationFromFunctionIndexSpace(unsigned functionIndexSpace)
110 {
111 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
112 unsigned calleeIndex = functionIndexSpace - functionImportCount();
113 return &m_wasmIndirectCallEntryPoints[calleeIndex];
114 }
115
116 MacroAssemblerCodePtr<WasmEntryPtrTag> wasmToWasmExitStub(unsigned functionIndex)
117 {
118 return m_wasmToWasmExitStubs[functionIndex].code();
119 }
120
121 bool isSafeToRun(MemoryMode);
122
123 MemoryMode mode() const { return m_mode; }
124
125 ~CodeBlock();
126private:
127 friend class BBQPlan;
128 friend class OMGPlan;
129 friend class OMGForOSREntryPlan;
130
131 CodeBlock(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
132 void setCompilationFinished();
133 unsigned m_calleeCount;
134 MemoryMode m_mode;
135 Vector<RefPtr<OMGCallee>> m_omgCallees;
136 Vector<RefPtr<BBQCallee>> m_bbqCallees;
137 Vector<RefPtr<LLIntCallee>> m_llintCallees;
138 MacroAssemblerCodeRef<B3CompilationPtrTag> m_llintEntryThunks;
139 HashMap<uint32_t, RefPtr<Callee>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderCallees;
140 Vector<MacroAssemblerCodePtr<WasmEntryPtrTag>> m_wasmIndirectCallEntryPoints;
141 Vector<Vector<UnlinkedWasmToWasmCall>> m_wasmToWasmCallsites;
142 Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>> m_wasmToWasmExitStubs;
143 RefPtr<EntryPlan> m_plan;
144 std::atomic<bool> m_compilationFinished { false };
145 String m_errorMessage;
146 Lock m_lock;
147};
148
149} } // namespace JSC::Wasm
150
151#endif // ENABLE(WEBASSEMBLY)
152