1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
4 * Copyright 2015 Mozilla Foundation
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #ifndef wasm_generator_h
20 #define wasm_generator_h
22 #include "mozilla/Attributes.h"
23 #include "mozilla/MemoryReporting.h"
25 #include "jit/MacroAssembler.h"
26 #include "threading/ProtectedData.h"
27 #include "vm/HelperThreadTask.h"
28 #include "wasm/WasmCompile.h"
29 #include "wasm/WasmModule.h"
30 #include "wasm/WasmValidate.h"
33 class OptimizedEncodingListener
;
40 using CompileTaskPtrVector
= Vector
<CompileTask
*, 0, SystemAllocPolicy
>;
42 // FuncCompileInput contains the input for compiling a single function.
44 struct FuncCompileInput
{
48 uint32_t lineOrBytecode
;
49 Uint32Vector callSiteLineNums
;
51 FuncCompileInput(uint32_t index
, uint32_t lineOrBytecode
,
52 const uint8_t* begin
, const uint8_t* end
,
53 Uint32Vector
&& callSiteLineNums
)
57 lineOrBytecode(lineOrBytecode
),
58 callSiteLineNums(std::move(callSiteLineNums
)) {}
61 using FuncCompileInputVector
= Vector
<FuncCompileInput
, 8, SystemAllocPolicy
>;
63 // CompiledCode contains the resulting code and metadata for a set of compiled
64 // input functions or stubs.
67 CompiledCode() : featureUsage(FeatureUsage::None
) {}
70 CodeRangeVector codeRanges
;
71 CallSiteVector callSites
;
72 CallSiteTargetVector callSiteTargets
;
73 TrapSiteVectorArray trapSites
;
74 SymbolicAccessVector symbolicAccesses
;
75 jit::CodeLabelVector codeLabels
;
77 TryNoteVector tryNotes
;
78 CodeRangeUnwindInfoVector codeRangeUnwindInfos
;
79 FeatureUsage featureUsage
;
81 [[nodiscard
]] bool swap(jit::MacroAssembler
& masm
);
87 callSiteTargets
.clear();
89 symbolicAccesses
.clear();
93 codeRangeUnwindInfos
.clear();
94 featureUsage
= FeatureUsage::None
;
99 return bytes
.empty() && codeRanges
.empty() && callSites
.empty() &&
100 callSiteTargets
.empty() && trapSites
.empty() &&
101 symbolicAccesses
.empty() && codeLabels
.empty() && tryNotes
.empty() &&
102 stackMaps
.empty() && codeRangeUnwindInfos
.empty() &&
103 featureUsage
== FeatureUsage::None
;
106 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
109 // The CompileTaskState of a ModuleGenerator contains the mutable state shared
110 // between helper threads executing CompileTasks. Each CompileTask started on a
111 // helper thread eventually either ends up in the 'finished' list or increments
114 struct CompileTaskState
{
115 HelperThreadLockData
<CompileTaskPtrVector
> finished_
;
116 HelperThreadLockData
<uint32_t> numFailed_
;
117 HelperThreadLockData
<UniqueChars
> errorMessage_
;
118 HelperThreadLockData
<ConditionVariable
> condVar_
;
120 CompileTaskState() : numFailed_(0) {}
121 ~CompileTaskState() {
122 MOZ_ASSERT(finished_
.refNoCheck().empty());
123 MOZ_ASSERT(!numFailed_
.refNoCheck());
126 CompileTaskPtrVector
& finished() { return finished_
.ref(); }
127 uint32_t& numFailed() { return numFailed_
.ref(); }
128 UniqueChars
& errorMessage() { return errorMessage_
.ref(); }
129 ConditionVariable
& condVar() { return condVar_
.ref(); }
132 // A CompileTask holds a batch of input functions that are to be compiled on a
133 // helper thread as well as, eventually, the results of compilation.
135 struct CompileTask
: public HelperThreadTask
{
136 const ModuleEnvironment
& moduleEnv
;
137 const CompilerEnvironment
& compilerEnv
;
139 CompileTaskState
& state
;
141 FuncCompileInputVector inputs
;
144 CompileTask(const ModuleEnvironment
& moduleEnv
,
145 const CompilerEnvironment
& compilerEnv
, CompileTaskState
& state
,
146 size_t defaultChunkSize
)
147 : moduleEnv(moduleEnv
),
148 compilerEnv(compilerEnv
),
150 lifo(defaultChunkSize
) {}
152 virtual ~CompileTask() = default;
154 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
156 void runHelperThreadTask(AutoLockHelperThreadState
& locked
) override
;
157 ThreadType
threadType() override
;
160 // A ModuleGenerator encapsulates the creation of a wasm module. During the
161 // lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created
162 // and destroyed to compile the individual function bodies. After generating all
163 // functions, ModuleGenerator::finish() must be called to complete the
164 // compilation and extract the resulting wasm module.
166 class MOZ_STACK_CLASS ModuleGenerator
{
167 using CompileTaskVector
= Vector
<CompileTask
, 0, SystemAllocPolicy
>;
168 using CodeOffsetVector
= Vector
<jit::CodeOffset
, 0, SystemAllocPolicy
>;
171 jit::CodeOffset jump
;
172 CallFarJump(uint32_t fi
, jit::CodeOffset j
) : funcIndex(fi
), jump(j
) {}
174 using CallFarJumpVector
= Vector
<CallFarJump
, 0, SystemAllocPolicy
>;
176 // Constant parameters
177 SharedCompileArgs
const compileArgs_
;
178 UniqueChars
* const error_
;
179 UniqueCharsVector
* const warnings_
;
180 const Atomic
<bool>* const cancelled_
;
181 ModuleEnvironment
* const moduleEnv_
;
182 CompilerEnvironment
* const compilerEnv_
;
184 // Data that is moved into the result of finish()
185 UniqueLinkData linkData_
;
186 UniqueMetadataTier metadataTier_
;
187 MutableMetadata metadata_
;
189 // Data scoped to the ModuleGenerator's lifetime
190 CompileTaskState taskState_
;
192 jit::TempAllocator masmAlloc_
;
193 jit::WasmMacroAssembler masm_
;
194 Uint32Vector funcToCodeRange_
;
195 uint32_t debugTrapCodeOffset_
;
196 CallFarJumpVector callFarJumps_
;
197 CallSiteTargetVector callSiteTargets_
;
198 uint32_t lastPatchedCallSite_
;
199 uint32_t startOfUnpatchedCallsites_
;
201 // Parallel compilation
203 uint32_t outstanding_
;
204 CompileTaskVector tasks_
;
205 CompileTaskPtrVector freeTasks_
;
206 CompileTask
* currentTask_
;
207 uint32_t batchedBytecode_
;
210 DebugOnly
<bool> finishedFuncDefs_
;
212 bool allocateInstanceDataBytes(uint32_t bytes
, uint32_t align
,
213 uint32_t* instanceDataOffset
);
214 bool allocateInstanceDataBytesN(uint32_t bytes
, uint32_t align
,
215 uint32_t count
, uint32_t* instanceDataOffset
);
217 bool funcIsCompiled(uint32_t funcIndex
) const;
218 const CodeRange
& funcCodeRange(uint32_t funcIndex
) const;
219 bool linkCallSites();
220 void noteCodeRange(uint32_t codeRangeIndex
, const CodeRange
& codeRange
);
221 bool linkCompiledCode(CompiledCode
& code
);
222 bool locallyCompileCurrentTask();
223 bool finishTask(CompileTask
* task
);
224 bool launchBatchCompile();
225 bool finishOutstandingTask();
226 bool finishCodegen();
227 bool finishMetadataTier();
228 UniqueCodeTier
finishCodeTier();
229 SharedMetadata
finishMetadata(const Bytes
& bytecode
);
231 bool isAsmJS() const { return moduleEnv_
->isAsmJS(); }
232 Tier
tier() const { return compilerEnv_
->tier(); }
233 CompileMode
mode() const { return compilerEnv_
->mode(); }
234 bool debugEnabled() const { return compilerEnv_
->debugEnabled(); }
236 void warnf(const char* msg
, ...) MOZ_FORMAT_PRINTF(2, 3);
239 ModuleGenerator(const CompileArgs
& args
, ModuleEnvironment
* moduleEnv
,
240 CompilerEnvironment
* compilerEnv
,
241 const Atomic
<bool>* cancelled
, UniqueChars
* error
,
242 UniqueCharsVector
* warnings
);
244 [[nodiscard
]] bool init(Metadata
* maybeAsmJSMetadata
= nullptr);
246 // Before finishFuncDefs() is called, compileFuncDef() must be called once
247 // for each funcIndex in the range [0, env->numFuncDefs()).
249 [[nodiscard
]] bool compileFuncDef(
250 uint32_t funcIndex
, uint32_t lineOrBytecode
, const uint8_t* begin
,
251 const uint8_t* end
, Uint32Vector
&& callSiteLineNums
= Uint32Vector());
253 // Must be called after the last compileFuncDef() and before finishModule()
256 [[nodiscard
]] bool finishFuncDefs();
258 // If env->mode is Once or Tier1, finishModule() must be called to generate
259 // a new Module. Otherwise, if env->mode is Tier2, finishTier2() must be
260 // called to augment the given Module with tier 2 code.
262 SharedModule
finishModule(
263 const ShareableBytes
& bytecode
,
264 JS::OptimizedEncodingListener
* maybeTier2Listener
= nullptr);
265 [[nodiscard
]] bool finishTier2(const Module
& module
);
271 #endif // wasm_generator_h