Source code

Revision control

Other Tools

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:
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
*
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 "mozilla/MemoryReporting.h"
23
24
#include "jit/MacroAssembler.h"
25
#include "wasm/WasmCompile.h"
26
#include "wasm/WasmModule.h"
27
#include "wasm/WasmValidate.h"
28
29
namespace js {
30
namespace wasm {
31
32
struct CompileTask;
33
typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
34
35
// FuncCompileInput contains the input for compiling a single function.
36
37
struct FuncCompileInput {
38
const uint8_t* begin;
39
const uint8_t* end;
40
uint32_t index;
41
uint32_t lineOrBytecode;
42
Uint32Vector callSiteLineNums;
43
44
FuncCompileInput(uint32_t index, uint32_t lineOrBytecode,
45
const uint8_t* begin, const uint8_t* end,
46
Uint32Vector&& callSiteLineNums)
47
: begin(begin),
48
end(end),
49
index(index),
50
lineOrBytecode(lineOrBytecode),
51
callSiteLineNums(std::move(callSiteLineNums)) {}
52
};
53
54
typedef Vector<FuncCompileInput, 8, SystemAllocPolicy> FuncCompileInputVector;
55
56
// CompiledCode contains the resulting code and metadata for a set of compiled
57
// input functions or stubs.
58
59
struct CompiledCode {
60
Bytes bytes;
61
CodeRangeVector codeRanges;
62
CallSiteVector callSites;
63
CallSiteTargetVector callSiteTargets;
64
TrapSiteVectorArray trapSites;
65
SymbolicAccessVector symbolicAccesses;
66
jit::CodeLabelVector codeLabels;
67
StackMaps stackMaps;
68
69
MOZ_MUST_USE bool swap(jit::MacroAssembler& masm);
70
71
void clear() {
72
bytes.clear();
73
codeRanges.clear();
74
callSites.clear();
75
callSiteTargets.clear();
76
trapSites.clear();
77
symbolicAccesses.clear();
78
codeLabels.clear();
79
stackMaps.clear();
80
MOZ_ASSERT(empty());
81
}
82
83
bool empty() {
84
return bytes.empty() && codeRanges.empty() && callSites.empty() &&
85
callSiteTargets.empty() && trapSites.empty() &&
86
symbolicAccesses.empty() && codeLabels.empty() && stackMaps.empty();
87
}
88
89
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
90
};
91
92
// The CompileTaskState of a ModuleGenerator contains the mutable state shared
93
// between helper threads executing CompileTasks. Each CompileTask started on a
94
// helper thread eventually either ends up in the 'finished' list or increments
95
// 'numFailed'.
96
97
struct CompileTaskState {
98
CompileTaskPtrVector finished;
99
uint32_t numFailed;
100
UniqueChars errorMessage;
101
102
CompileTaskState() : numFailed(0) {}
103
~CompileTaskState() {
104
MOZ_ASSERT(finished.empty());
105
MOZ_ASSERT(!numFailed);
106
}
107
};
108
109
typedef ExclusiveWaitableData<CompileTaskState> ExclusiveCompileTaskState;
110
111
// A CompileTask holds a batch of input functions that are to be compiled on a
112
// helper thread as well as, eventually, the results of compilation.
113
114
struct CompileTask : public RunnableTask {
115
const ModuleEnvironment& env;
116
ExclusiveCompileTaskState& state;
117
LifoAlloc lifo;
118
FuncCompileInputVector inputs;
119
CompiledCode output;
120
121
CompileTask(const ModuleEnvironment& env, ExclusiveCompileTaskState& state,
122
size_t defaultChunkSize)
123
: env(env), state(state), lifo(defaultChunkSize) {}
124
125
virtual ~CompileTask(){};
126
127
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
128
129
void runTask() override;
130
ThreadType threadType() override { return ThreadType::THREAD_TYPE_WASM; }
131
};
132
133
// A ModuleGenerator encapsulates the creation of a wasm module. During the
134
// lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created
135
// and destroyed to compile the individual function bodies. After generating all
136
// functions, ModuleGenerator::finish() must be called to complete the
137
// compilation and extract the resulting wasm module.
138
139
class MOZ_STACK_CLASS ModuleGenerator {
140
typedef Vector<CompileTask, 0, SystemAllocPolicy> CompileTaskVector;
141
typedef Vector<jit::CodeOffset, 0, SystemAllocPolicy> CodeOffsetVector;
142
struct CallFarJump {
143
uint32_t funcIndex;
144
jit::CodeOffset jump;
145
CallFarJump(uint32_t fi, jit::CodeOffset j) : funcIndex(fi), jump(j) {}
146
};
147
typedef Vector<CallFarJump, 0, SystemAllocPolicy> CallFarJumpVector;
148
149
// Constant parameters
150
SharedCompileArgs const compileArgs_;
151
UniqueChars* const error_;
152
const Atomic<bool>* const cancelled_;
153
ModuleEnvironment* const env_;
154
155
// Data that is moved into the result of finish()
156
UniqueLinkData linkData_;
157
UniqueMetadataTier metadataTier_;
158
MutableMetadata metadata_;
159
160
// Data scoped to the ModuleGenerator's lifetime
161
ExclusiveCompileTaskState taskState_;
162
LifoAlloc lifo_;
163
jit::JitContext jcx_;
164
jit::TempAllocator masmAlloc_;
165
jit::WasmMacroAssembler masm_;
166
Uint32Vector funcToCodeRange_;
167
uint32_t debugTrapCodeOffset_;
168
CallFarJumpVector callFarJumps_;
169
CallSiteTargetVector callSiteTargets_;
170
uint32_t lastPatchedCallSite_;
171
uint32_t startOfUnpatchedCallsites_;
172
CodeOffsetVector debugTrapFarJumps_;
173
174
// Parallel compilation
175
bool parallel_;
176
uint32_t outstanding_;
177
CompileTaskVector tasks_;
178
CompileTaskPtrVector freeTasks_;
179
CompileTask* currentTask_;
180
uint32_t batchedBytecode_;
181
182
// Assertions
183
DebugOnly<bool> finishedFuncDefs_;
184
185
bool allocateGlobalBytes(uint32_t bytes, uint32_t align,
186
uint32_t* globalDataOff);
187
188
bool funcIsCompiled(uint32_t funcIndex) const;
189
const CodeRange& funcCodeRange(uint32_t funcIndex) const;
190
bool linkCallSites();
191
void noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRange);
192
bool linkCompiledCode(CompiledCode& code);
193
bool locallyCompileCurrentTask();
194
bool finishTask(CompileTask* task);
195
bool launchBatchCompile();
196
bool finishOutstandingTask();
197
bool finishCodegen();
198
bool finishMetadataTier();
199
UniqueCodeTier finishCodeTier();
200
SharedMetadata finishMetadata(const Bytes& bytecode);
201
202
bool isAsmJS() const { return env_->isAsmJS(); }
203
Tier tier() const { return env_->tier(); }
204
CompileMode mode() const { return env_->mode(); }
205
bool debugEnabled() const { return env_->debugEnabled(); }
206
207
public:
208
ModuleGenerator(const CompileArgs& args, ModuleEnvironment* env,
209
const Atomic<bool>* cancelled, UniqueChars* error);
210
~ModuleGenerator();
211
MOZ_MUST_USE bool init(Metadata* maybeAsmJSMetadata = nullptr);
212
213
// Before finishFuncDefs() is called, compileFuncDef() must be called once
214
// for each funcIndex in the range [0, env->numFuncDefs()).
215
216
MOZ_MUST_USE bool compileFuncDef(
217
uint32_t funcIndex, uint32_t lineOrBytecode, const uint8_t* begin,
218
const uint8_t* end, Uint32Vector&& callSiteLineNums = Uint32Vector());
219
220
// Must be called after the last compileFuncDef() and before finishModule()
221
// or finishTier2().
222
223
MOZ_MUST_USE bool finishFuncDefs();
224
225
// If env->mode is Once or Tier1, finishModule() must be called to generate
226
// a new Module. Otherwise, if env->mode is Tier2, finishTier2() must be
227
// called to augment the given Module with tier 2 code.
228
229
SharedModule finishModule(
230
const ShareableBytes& bytecode,
231
JS::OptimizedEncodingListener* maybeTier2Listener = nullptr);
232
MOZ_MUST_USE bool finishTier2(const Module& module);
233
};
234
235
} // namespace wasm
236
} // namespace js
237
238
#endif // wasm_generator_h