Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : *
4 : * Copyright 2015 Mozilla Foundation
5 : *
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
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
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.
17 : */
18 :
19 : #ifndef wasm_generator_h
20 : #define wasm_generator_h
21 :
22 : #include "jit/MacroAssembler.h"
23 : #include "wasm/WasmModule.h"
24 : #include "wasm/WasmValidate.h"
25 :
26 : namespace js {
27 : namespace wasm {
28 :
29 : struct ModuleEnvironment;
30 :
31 : typedef Vector<jit::MIRType, 8, SystemAllocPolicy> MIRTypeVector;
32 : typedef jit::ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
33 : typedef jit::ABIArgIter<ValTypeVector> ABIArgValTypeIter;
34 :
35 : struct CompileArgs;
36 :
37 : class FunctionGenerator;
38 :
39 : // The FuncBytes class represents a single, concurrently-compilable function.
40 : // A FuncBytes object is composed of the wasm function body bytes along with the
41 : // ambient metadata describing the function necessary to compile it.
42 :
43 0 : class FuncBytes
44 : {
45 : Bytes bytes_;
46 : uint32_t index_;
47 : const SigWithId* sig_;
48 : uint32_t lineOrBytecode_;
49 : Uint32Vector callSiteLineNums_;
50 :
51 : public:
52 0 : FuncBytes()
53 0 : : index_(UINT32_MAX),
54 : sig_(nullptr),
55 0 : lineOrBytecode_(UINT32_MAX)
56 0 : {}
57 :
58 0 : Bytes& bytes() {
59 0 : return bytes_;
60 : }
61 0 : MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
62 0 : return callSiteLineNums_.append(lineno);
63 : }
64 0 : void setLineOrBytecode(uint32_t lineOrBytecode) {
65 0 : MOZ_ASSERT(lineOrBytecode_ == UINT32_MAX);
66 0 : lineOrBytecode_ = lineOrBytecode;
67 0 : }
68 0 : void setFunc(uint32_t index, const SigWithId* sig) {
69 0 : MOZ_ASSERT(index_ == UINT32_MAX);
70 0 : MOZ_ASSERT(sig_ == nullptr);
71 0 : index_ = index;
72 0 : sig_ = sig;
73 0 : }
74 0 : void reset() {
75 0 : bytes_.clear();
76 0 : index_ = UINT32_MAX;
77 0 : sig_ = nullptr;
78 0 : lineOrBytecode_ = UINT32_MAX;
79 0 : callSiteLineNums_.clear();
80 0 : }
81 :
82 0 : const Bytes& bytes() const { return bytes_; }
83 0 : uint32_t index() const { return index_; }
84 0 : const SigWithId& sig() const { return *sig_; }
85 0 : uint32_t lineOrBytecode() const { return lineOrBytecode_; }
86 0 : const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; }
87 : };
88 :
89 : typedef UniquePtr<FuncBytes> UniqueFuncBytes;
90 : typedef Vector<UniqueFuncBytes, 8, SystemAllocPolicy> UniqueFuncBytesVector;
91 :
92 : // FuncCompileUnit contains all the data necessary to produce and store the
93 : // results of a single function's compilation.
94 :
95 0 : class FuncCompileUnit
96 : {
97 : UniqueFuncBytes func_;
98 : FuncOffsets offsets_;
99 : DebugOnly<bool> finished_;
100 :
101 : public:
102 0 : explicit FuncCompileUnit(UniqueFuncBytes func)
103 0 : : func_(Move(func)),
104 0 : finished_(false)
105 0 : {}
106 :
107 0 : const FuncBytes& func() const { return *func_; }
108 0 : FuncOffsets offsets() const { MOZ_ASSERT(finished_); return offsets_; }
109 :
110 0 : void finish(FuncOffsets offsets) {
111 0 : MOZ_ASSERT(!finished_);
112 0 : offsets_ = offsets;
113 0 : finished_ = true;
114 0 : }
115 :
116 0 : UniqueFuncBytes recycle() {
117 0 : MOZ_ASSERT(finished_);
118 0 : func_->reset();
119 0 : return Move(func_);
120 : }
121 : };
122 :
123 : typedef Vector<FuncCompileUnit, 8, SystemAllocPolicy> FuncCompileUnitVector;
124 :
125 : // A CompileTask represents the task of compiling a batch of functions. It is
126 : // filled with a certain number of function's bodies that are sent off to a
127 : // compilation helper thread, which fills in the resulting code offsets, and
128 : // finally sent back to the validation thread. To save time allocating and
129 : // freeing memory, CompileTasks are reset() and reused.
130 :
131 0 : class CompileTask
132 : {
133 : const ModuleEnvironment& env_;
134 : Tier tier_;
135 : LifoAlloc lifo_;
136 : Maybe<jit::TempAllocator> alloc_;
137 : Maybe<jit::MacroAssembler> masm_;
138 : FuncCompileUnitVector units_;
139 : bool debugEnabled_;
140 :
141 : CompileTask(const CompileTask&) = delete;
142 : CompileTask& operator=(const CompileTask&) = delete;
143 :
144 0 : void init() {
145 0 : alloc_.emplace(&lifo_);
146 0 : masm_.emplace(jit::MacroAssembler::WasmToken(), *alloc_);
147 0 : debugEnabled_ = false;
148 0 : }
149 :
150 : public:
151 0 : CompileTask(const ModuleEnvironment& env, Tier tier, size_t defaultChunkSize)
152 0 : : env_(env),
153 : tier_(tier),
154 0 : lifo_(defaultChunkSize)
155 : {
156 0 : MOZ_ASSERT(tier == Tier::Baseline || tier == Tier::Ion);
157 0 : init();
158 0 : }
159 : LifoAlloc& lifo() {
160 : return lifo_;
161 : }
162 0 : jit::TempAllocator& alloc() {
163 0 : return *alloc_;
164 : }
165 0 : const ModuleEnvironment& env() const {
166 0 : return env_;
167 : }
168 0 : jit::MacroAssembler& masm() {
169 0 : return *masm_;
170 : }
171 0 : FuncCompileUnitVector& units() {
172 0 : return units_;
173 : }
174 0 : Tier tier() const {
175 0 : return tier_;
176 : }
177 0 : bool debugEnabled() const {
178 0 : return debugEnabled_;
179 : }
180 0 : void setDebugEnabled(bool enabled) {
181 0 : debugEnabled_ = enabled;
182 0 : }
183 0 : bool reset(UniqueFuncBytesVector* freeFuncBytes) {
184 0 : for (FuncCompileUnit& unit : units_) {
185 0 : if (!freeFuncBytes->emplaceBack(Move(unit.recycle())))
186 0 : return false;
187 : }
188 :
189 0 : units_.clear();
190 0 : masm_.reset();
191 0 : alloc_.reset();
192 0 : lifo_.releaseAll();
193 :
194 0 : init();
195 0 : return true;
196 : }
197 : };
198 :
199 : // A ModuleGenerator encapsulates the creation of a wasm module. During the
200 : // lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created
201 : // and destroyed to compile the individual function bodies. After generating all
202 : // functions, ModuleGenerator::finish() must be called to complete the
203 : // compilation and extract the resulting wasm module.
204 :
205 : class MOZ_STACK_CLASS ModuleGenerator
206 : {
207 : typedef HashSet<uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> Uint32Set;
208 : typedef Vector<CompileTask, 0, SystemAllocPolicy> CompileTaskVector;
209 : typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
210 : typedef EnumeratedArray<Trap, Trap::Limit, CallableOffsets> TrapExitOffsetArray;
211 :
212 : // Constant parameters
213 : Tier tier_;
214 : UniqueChars* error_;
215 :
216 : // Data that is moved into the result of finish()
217 : Assumptions assumptions_;
218 : LinkDataTier* linkDataTier_; // Owned by linkData_
219 : LinkData linkData_;
220 : MetadataTier* metadataTier_; // Owned by metadata_
221 : MutableMetadata metadata_;
222 :
223 : // Data scoped to the ModuleGenerator's lifetime
224 : UniqueModuleEnvironment env_;
225 : uint32_t numSigs_;
226 : uint32_t numTables_;
227 : LifoAlloc lifo_;
228 : jit::JitContext jcx_;
229 : jit::TempAllocator masmAlloc_;
230 : jit::MacroAssembler masm_;
231 : Uint32Vector funcToCodeRange_;
232 : Uint32Set exportedFuncs_;
233 : uint32_t lastPatchedCallsite_;
234 : uint32_t startOfUnpatchedCallsites_;
235 : Uint32Vector debugTrapFarJumps_;
236 : FuncArgTypesVector debugFuncArgTypes_;
237 : FuncReturnTypesVector debugFuncReturnTypes_;
238 :
239 : // Parallel compilation
240 : bool parallel_;
241 : uint32_t outstanding_;
242 : CompileTaskVector tasks_;
243 : CompileTaskPtrVector freeTasks_;
244 : UniqueFuncBytesVector freeFuncBytes_;
245 : CompileTask* currentTask_;
246 : uint32_t batchedBytecode_;
247 :
248 : // Assertions
249 : DebugOnly<FunctionGenerator*> activeFuncDef_;
250 : DebugOnly<bool> startedFuncDefs_;
251 : DebugOnly<bool> finishedFuncDefs_;
252 : DebugOnly<uint32_t> numFinishedFuncDefs_;
253 :
254 : bool funcIsCompiled(uint32_t funcIndex) const;
255 : const CodeRange& funcCodeRange(uint32_t funcIndex) const;
256 : uint32_t numFuncImports() const;
257 : MOZ_MUST_USE bool patchCallSites();
258 : MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub);
259 : MOZ_MUST_USE bool finishTask(CompileTask* task);
260 : MOZ_MUST_USE bool finishOutstandingTask();
261 : MOZ_MUST_USE bool finishFuncExports();
262 : MOZ_MUST_USE bool finishCodegen();
263 : MOZ_MUST_USE bool finishLinkData();
264 : void generateBytecodeHash(const ShareableBytes& bytecode);
265 : MOZ_MUST_USE bool addFuncImport(const Sig& sig, uint32_t globalDataOffset);
266 : MOZ_MUST_USE bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOff);
267 : MOZ_MUST_USE bool allocateGlobal(GlobalDesc* global);
268 :
269 : MOZ_MUST_USE bool launchBatchCompile();
270 :
271 : MOZ_MUST_USE bool initAsmJS(Metadata* asmJSMetadata);
272 : MOZ_MUST_USE bool initWasm(const CompileArgs& args);
273 :
274 : public:
275 : explicit ModuleGenerator(UniqueChars* error);
276 : ~ModuleGenerator();
277 :
278 : MOZ_MUST_USE bool init(UniqueModuleEnvironment env, const CompileArgs& args,
279 : Metadata* maybeAsmJSMetadata = nullptr);
280 :
281 0 : const ModuleEnvironment& env() const { return *env_; }
282 : ModuleEnvironment& mutableEnv();
283 :
284 0 : bool isAsmJS() const { return metadata_->kind == ModuleKind::AsmJS; }
285 : jit::MacroAssembler& masm() { return masm_; }
286 :
287 : // Memory:
288 : bool usesMemory() const { return env_->usesMemory(); }
289 0 : uint32_t minMemoryLength() const { return env_->minMemoryLength; }
290 :
291 : // Tables:
292 : uint32_t numTables() const { return numTables_; }
293 : const TableDescVector& tables() const { return env_->tables; }
294 :
295 : // Signatures:
296 0 : uint32_t numSigs() const { return numSigs_; }
297 : const SigWithId& sig(uint32_t sigIndex) const;
298 : const SigWithId& funcSig(uint32_t funcIndex) const;
299 : const SigWithIdPtrVector& funcSigs() const { return env_->funcSigs; }
300 :
301 : // Globals:
302 : const GlobalDescVector& globals() const { return env_->globals; }
303 :
304 : // Function definitions:
305 : MOZ_MUST_USE bool startFuncDefs();
306 : MOZ_MUST_USE bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
307 : MOZ_MUST_USE bool finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg);
308 : MOZ_MUST_USE bool finishFuncDefs();
309 :
310 : // asm.js lazy initialization:
311 : void initSig(uint32_t sigIndex, Sig&& sig);
312 : void initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
313 : MOZ_MUST_USE bool initImport(uint32_t funcIndex, uint32_t sigIndex);
314 : MOZ_MUST_USE bool initSigTableLength(uint32_t sigIndex, uint32_t length);
315 : MOZ_MUST_USE bool initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices);
316 : void initMemoryUsage(MemoryUsage memoryUsage);
317 : void bumpMinMemoryLength(uint32_t newMinMemoryLength);
318 : MOZ_MUST_USE bool addGlobal(ValType type, bool isConst, uint32_t* index);
319 : MOZ_MUST_USE bool addExport(CacheableChars&& fieldChars, uint32_t funcIndex);
320 :
321 : // Finish compilation of the given bytecode.
322 : SharedModule finish(const ShareableBytes& bytecode);
323 : };
324 :
325 : // A FunctionGenerator encapsulates the generation of a single function body.
326 : // ModuleGenerator::startFuncDef must be called after construction and before
327 : // doing anything else.
328 : //
329 : // After the body is complete, ModuleGenerator::finishFuncDef must be called
330 : // before the FunctionGenerator is destroyed and the next function is started.
331 :
332 0 : class MOZ_STACK_CLASS FunctionGenerator
333 : {
334 : friend class ModuleGenerator;
335 :
336 : ModuleGenerator* m_;
337 : bool usesSimd_;
338 : bool usesAtomics_;
339 :
340 : UniqueFuncBytes funcBytes_;
341 :
342 : public:
343 0 : FunctionGenerator()
344 0 : : m_(nullptr), usesSimd_(false), usesAtomics_(false), funcBytes_(nullptr)
345 0 : {}
346 :
347 : bool usesSimd() const {
348 : return usesSimd_;
349 : }
350 0 : void setUsesSimd() {
351 0 : usesSimd_ = true;
352 0 : }
353 :
354 : bool usesAtomics() const {
355 : return usesAtomics_;
356 : }
357 0 : void setUsesAtomics() {
358 0 : usesAtomics_ = true;
359 0 : }
360 :
361 : bool isAsmJS() const {
362 : return m_->isAsmJS();
363 : }
364 :
365 0 : Bytes& bytes() {
366 0 : return funcBytes_->bytes();
367 : }
368 0 : MOZ_MUST_USE bool addCallSiteLineNum(uint32_t lineno) {
369 0 : return funcBytes_->addCallSiteLineNum(lineno);
370 : }
371 : };
372 :
373 : } // namespace wasm
374 : } // namespace js
375 :
376 : #endif // wasm_generator_h
|