1/*
2 * Copyright (C) 2016-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 "CompilationResult.h"
31#include "WasmB3IRGenerator.h"
32#include "WasmModuleInformation.h"
33#include "WasmPlan.h"
34#include "WasmTierUpCount.h"
35#include <wtf/Bag.h>
36#include <wtf/Function.h>
37#include <wtf/SharedTask.h>
38#include <wtf/ThreadSafeRefCounted.h>
39#include <wtf/Vector.h>
40
41namespace JSC {
42
43class CallLinkInfo;
44
45namespace Wasm {
46
47class BBQPlan final : public Plan {
48public:
49 using Base = Plan;
50 enum AsyncWork : uint8_t { FullCompile, Validation };
51
52 // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
53 BBQPlan(Context*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
54 JS_EXPORT_PRIVATE BBQPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
55 BBQPlan(Context*, AsyncWork, CompletionTask&&);
56
57
58 bool parseAndValidateModule()
59 {
60 return parseAndValidateModule(m_source.data(), m_source.size());
61 }
62 bool parseAndValidateModule(const uint8_t*, size_t);
63
64 JS_EXPORT_PRIVATE void prepare();
65 void compileFunctions(CompilationEffort);
66
67 template<typename Functor>
68 void initializeCallees(const Functor&);
69
70 Vector<Export>& exports() const
71 {
72 RELEASE_ASSERT(!failed() && !hasWork());
73 return m_moduleInformation->exports;
74 }
75
76 size_t internalFunctionCount() const
77 {
78 RELEASE_ASSERT(!failed() && !hasWork());
79 return m_moduleInformation->internalFunctionCount();
80 }
81
82 Ref<ModuleInformation>&& takeModuleInformation()
83 {
84 RELEASE_ASSERT(!failed() && !hasWork());
85 return WTFMove(m_moduleInformation);
86 }
87
88 Bag<CallLinkInfo>&& takeCallLinkInfos()
89 {
90 RELEASE_ASSERT(!failed() && !hasWork());
91 return WTFMove(m_callLinkInfos);
92 }
93
94 Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>>&& takeWasmToWasmExitStubs()
95 {
96 RELEASE_ASSERT(!failed() && !hasWork());
97 return WTFMove(m_wasmToWasmExitStubs);
98 }
99
100 Vector<Vector<UnlinkedWasmToWasmCall>> takeWasmToWasmCallsites()
101 {
102 RELEASE_ASSERT(!failed() && !hasWork());
103 return WTFMove(m_unlinkedWasmToWasmCalls);
104 }
105
106 Vector<TierUpCount> takeTierUpCounts()
107 {
108 RELEASE_ASSERT(!failed() && !hasWork());
109 return WTFMove(m_tierUpCounts);
110 }
111
112 enum class State : uint8_t {
113 Initial,
114 Validated,
115 Prepared,
116 Compiled,
117 Completed // We should only move to Completed if we are holding the lock.
118 };
119
120 bool hasWork() const override
121 {
122 if (m_asyncWork == AsyncWork::Validation)
123 return m_state < State::Validated;
124 return m_state < State::Compiled;
125 }
126 void work(CompilationEffort) override;
127 bool hasBeenPrepared() const { return m_state >= State::Prepared; }
128 bool multiThreaded() const override { return hasBeenPrepared(); }
129
130private:
131 class ThreadCountHolder;
132 friend class ThreadCountHolder;
133 // For some reason friendship doesn't extend to parent classes...
134 using Base::m_lock;
135
136 void moveToState(State);
137 bool isComplete() const override { return m_state == State::Completed; }
138 void complete(const AbstractLocker&) override;
139
140 const char* stateString(State);
141
142 Vector<uint8_t> m_source;
143 Bag<CallLinkInfo> m_callLinkInfos;
144 Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>> m_wasmToWasmExitStubs;
145 Vector<std::unique_ptr<InternalFunction>> m_wasmInternalFunctions;
146 HashSet<uint32_t, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_exportedFunctionIndices;
147 HashMap<uint32_t, std::unique_ptr<InternalFunction>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderToWasmInternalFunctions;
148 Vector<CompilationContext> m_compilationContexts;
149 Vector<TierUpCount> m_tierUpCounts;
150
151 Vector<Vector<UnlinkedWasmToWasmCall>> m_unlinkedWasmToWasmCalls;
152 State m_state;
153
154 const AsyncWork m_asyncWork;
155 uint8_t m_numberOfActiveThreads { 0 };
156 uint32_t m_currentIndex { 0 };
157};
158
159
160} } // namespace JSC::Wasm
161
162#endif // ENABLE(WEBASSEMBLY)
163