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