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 : #include "wasm/WasmGenerator.h"
20 :
21 : #include "mozilla/CheckedInt.h"
22 : #include "mozilla/EnumeratedRange.h"
23 : #include "mozilla/SHA1.h"
24 :
25 : #include <algorithm>
26 :
27 : #include "wasm/WasmBaselineCompile.h"
28 : #include "wasm/WasmCompile.h"
29 : #include "wasm/WasmIonCompile.h"
30 : #include "wasm/WasmStubs.h"
31 :
32 : #include "jit/MacroAssembler-inl.h"
33 :
34 : using namespace js;
35 : using namespace js::jit;
36 : using namespace js::wasm;
37 :
38 : using mozilla::CheckedInt;
39 : using mozilla::MakeEnumeratedRange;
40 :
41 : // ****************************************************************************
42 : // ModuleGenerator
43 :
44 : static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
45 : static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
46 : static const uint32_t BAD_CODE_RANGE = UINT32_MAX;
47 :
48 0 : ModuleGenerator::ModuleGenerator(UniqueChars* error)
49 : : tier_(Tier(-1)),
50 : error_(error),
51 : linkDataTier_(nullptr),
52 : metadataTier_(nullptr),
53 : numSigs_(0),
54 : numTables_(0),
55 : lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
56 : masmAlloc_(&lifo_),
57 0 : masm_(MacroAssembler::WasmToken(), masmAlloc_),
58 : lastPatchedCallsite_(0),
59 : startOfUnpatchedCallsites_(0),
60 : parallel_(false),
61 : outstanding_(0),
62 : currentTask_(nullptr),
63 : batchedBytecode_(0),
64 : activeFuncDef_(nullptr),
65 : startedFuncDefs_(false),
66 : finishedFuncDefs_(false),
67 0 : numFinishedFuncDefs_(0)
68 : {
69 0 : MOZ_ASSERT(IsCompilingWasm());
70 0 : }
71 :
72 0 : ModuleGenerator::~ModuleGenerator()
73 : {
74 0 : if (parallel_) {
75 : // Wait for any outstanding jobs to fail or complete.
76 0 : if (outstanding_) {
77 0 : AutoLockHelperThreadState lock;
78 : while (true) {
79 0 : CompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock);
80 0 : MOZ_ASSERT(outstanding_ >= worklist.length());
81 0 : outstanding_ -= worklist.length();
82 0 : worklist.clear();
83 :
84 0 : CompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList(lock);
85 0 : MOZ_ASSERT(outstanding_ >= finished.length());
86 0 : outstanding_ -= finished.length();
87 0 : finished.clear();
88 :
89 0 : uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs(lock);
90 0 : MOZ_ASSERT(outstanding_ >= numFailed);
91 0 : outstanding_ -= numFailed;
92 :
93 0 : if (!outstanding_)
94 0 : break;
95 :
96 0 : HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
97 0 : }
98 : }
99 :
100 0 : MOZ_ASSERT(HelperThreadState().wasmCompilationInProgress);
101 0 : HelperThreadState().wasmCompilationInProgress = false;
102 : } else {
103 0 : MOZ_ASSERT(!outstanding_);
104 : }
105 0 : MOZ_ASSERT_IF(finishedFuncDefs_, !batchedBytecode_);
106 0 : MOZ_ASSERT_IF(finishedFuncDefs_, !currentTask_);
107 0 : }
108 :
109 : bool
110 0 : ModuleGenerator::initAsmJS(Metadata* asmJSMetadata)
111 : {
112 0 : MOZ_ASSERT(env_->isAsmJS());
113 :
114 0 : if (!linkData_.initTier(Tier::Ion))
115 0 : return false;
116 0 : linkDataTier_ = &linkData_.linkData(Tier::Ion);
117 :
118 0 : metadataTier_ = &asmJSMetadata->metadata(Tier::Ion);
119 0 : metadata_ = asmJSMetadata;
120 0 : MOZ_ASSERT(isAsmJS());
121 :
122 : // Enabling debugging requires baseline and baseline is only enabled for
123 : // wasm (since the baseline does not currently support Atomics or SIMD).
124 :
125 0 : metadata_->debugEnabled = false;
126 0 : tier_ = Tier::Ion;
127 :
128 : // For asm.js, the Vectors in ModuleEnvironment are max-sized reservations
129 : // and will be initialized in a linear order via init* functions as the
130 : // module is generated.
131 :
132 0 : MOZ_ASSERT(env_->sigs.length() == AsmJSMaxTypes);
133 0 : MOZ_ASSERT(env_->tables.length() == AsmJSMaxTables);
134 0 : MOZ_ASSERT(env_->asmJSSigToTableIndex.length() == AsmJSMaxTypes);
135 :
136 0 : return true;
137 : }
138 :
139 : bool
140 0 : ModuleGenerator::initWasm(const CompileArgs& args)
141 : {
142 0 : MOZ_ASSERT(!env_->isAsmJS());
143 :
144 0 : bool canBaseline = BaselineCanCompile();
145 0 : bool debugEnabled = args.debugEnabled && canBaseline;
146 0 : tier_ = ((args.alwaysBaseline || debugEnabled) && canBaseline)
147 0 : ? Tier::Baseline
148 : : Tier::Ion;
149 :
150 0 : if (!linkData_.initTier(tier_))
151 0 : return false;
152 0 : linkDataTier_ = &linkData_.linkData(tier_);
153 :
154 0 : auto metadataTier = js::MakeUnique<MetadataTier>(tier_);
155 0 : if (!metadataTier)
156 0 : return false;
157 :
158 0 : metadata_ = js_new<Metadata>(Move(metadataTier));
159 0 : if (!metadata_)
160 0 : return false;
161 :
162 0 : metadataTier_ = &metadata_->metadata(tier_);
163 :
164 0 : MOZ_ASSERT(!isAsmJS());
165 :
166 0 : metadata_->debugEnabled = debugEnabled;
167 :
168 : // For wasm, the Vectors are correctly-sized and already initialized.
169 :
170 0 : numSigs_ = env_->sigs.length();
171 0 : numTables_ = env_->tables.length();
172 :
173 0 : for (size_t i = 0; i < env_->funcImportGlobalDataOffsets.length(); i++) {
174 0 : env_->funcImportGlobalDataOffsets[i] = metadata_->globalDataLength;
175 0 : metadata_->globalDataLength += sizeof(FuncImportTls);
176 0 : if (!addFuncImport(*env_->funcSigs[i], env_->funcImportGlobalDataOffsets[i]))
177 0 : return false;
178 : }
179 :
180 0 : for (TableDesc& table : env_->tables) {
181 0 : if (!allocateGlobalBytes(sizeof(TableTls), sizeof(void*), &table.globalDataOffset))
182 0 : return false;
183 : }
184 :
185 0 : for (uint32_t i = 0; i < numSigs_; i++) {
186 0 : SigWithId& sig = env_->sigs[i];
187 0 : if (SigIdDesc::isGlobal(sig)) {
188 : uint32_t globalDataOffset;
189 0 : if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset))
190 0 : return false;
191 :
192 0 : sig.id = SigIdDesc::global(sig, globalDataOffset);
193 :
194 0 : Sig copy;
195 0 : if (!copy.clone(sig))
196 0 : return false;
197 :
198 0 : if (!metadata_->sigIds.emplaceBack(Move(copy), sig.id))
199 0 : return false;
200 : } else {
201 0 : sig.id = SigIdDesc::immediate(sig);
202 : }
203 : }
204 :
205 0 : for (GlobalDesc& global : env_->globals) {
206 0 : if (global.isConstant())
207 0 : continue;
208 0 : if (!allocateGlobal(&global))
209 0 : return false;
210 : }
211 :
212 0 : for (const Export& exp : env_->exports) {
213 0 : if (exp.kind() == DefinitionKind::Function) {
214 0 : if (!exportedFuncs_.put(exp.funcIndex()))
215 0 : return false;
216 : }
217 : }
218 :
219 0 : if (env_->startFuncIndex) {
220 0 : metadata_->startFuncIndex.emplace(*env_->startFuncIndex);
221 0 : if (!exportedFuncs_.put(*env_->startFuncIndex))
222 0 : return false;
223 : }
224 :
225 0 : if (metadata_->debugEnabled) {
226 0 : if (!debugFuncArgTypes_.resize(env_->funcSigs.length()))
227 0 : return false;
228 0 : if (!debugFuncReturnTypes_.resize(env_->funcSigs.length()))
229 0 : return false;
230 0 : for (size_t i = 0; i < debugFuncArgTypes_.length(); i++) {
231 0 : if (!debugFuncArgTypes_[i].appendAll(env_->funcSigs[i]->args()))
232 0 : return false;
233 0 : debugFuncReturnTypes_[i] = env_->funcSigs[i]->ret();
234 : }
235 : }
236 :
237 0 : return true;
238 : }
239 :
240 : bool
241 0 : ModuleGenerator::init(UniqueModuleEnvironment env, const CompileArgs& args,
242 : Metadata* maybeAsmJSMetadata)
243 : {
244 0 : env_ = Move(env);
245 :
246 0 : if (!funcToCodeRange_.appendN(BAD_CODE_RANGE, env_->funcSigs.length()))
247 0 : return false;
248 :
249 0 : if (!assumptions_.clone(args.assumptions))
250 0 : return false;
251 :
252 0 : if (!exportedFuncs_.init())
253 0 : return false;
254 :
255 0 : if (env_->isAsmJS() ? !initAsmJS(maybeAsmJSMetadata) : !initWasm(args))
256 0 : return false;
257 :
258 0 : if (args.scriptedCaller.filename) {
259 0 : metadata_->filename = DuplicateString(args.scriptedCaller.filename.get());
260 0 : if (!metadata_->filename)
261 0 : return false;
262 : }
263 :
264 0 : return true;
265 : }
266 :
267 : ModuleEnvironment&
268 0 : ModuleGenerator::mutableEnv()
269 : {
270 : // Mutation is not safe during parallel compilation.
271 0 : MOZ_ASSERT(!startedFuncDefs_ || finishedFuncDefs_);
272 0 : return *env_;
273 : }
274 :
275 : bool
276 0 : ModuleGenerator::finishOutstandingTask()
277 : {
278 0 : MOZ_ASSERT(parallel_);
279 :
280 0 : CompileTask* task = nullptr;
281 : {
282 0 : AutoLockHelperThreadState lock;
283 0 : while (true) {
284 0 : MOZ_ASSERT(outstanding_ > 0);
285 :
286 0 : if (HelperThreadState().wasmFailed(lock)) {
287 0 : if (error_) {
288 0 : MOZ_ASSERT(!*error_, "Should have stopped earlier");
289 0 : *error_ = Move(HelperThreadState().harvestWasmError(lock));
290 : }
291 0 : return false;
292 : }
293 :
294 0 : if (!HelperThreadState().wasmFinishedList(lock).empty()) {
295 0 : outstanding_--;
296 0 : task = HelperThreadState().wasmFinishedList(lock).popCopy();
297 0 : break;
298 : }
299 :
300 0 : HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
301 : }
302 : }
303 :
304 0 : return finishTask(task);
305 : }
306 :
307 : bool
308 0 : ModuleGenerator::funcIsCompiled(uint32_t funcIndex) const
309 : {
310 0 : return funcToCodeRange_[funcIndex] != BAD_CODE_RANGE;
311 : }
312 :
313 : const CodeRange&
314 0 : ModuleGenerator::funcCodeRange(uint32_t funcIndex) const
315 : {
316 0 : MOZ_ASSERT(funcIsCompiled(funcIndex));
317 0 : const CodeRange& cr = metadataTier_->codeRanges[funcToCodeRange_[funcIndex]];
318 0 : MOZ_ASSERT(cr.isFunction());
319 0 : return cr;
320 : }
321 :
322 : static uint32_t
323 0 : JumpRange()
324 : {
325 0 : return Min(JitOptions.jumpThreshold, JumpImmediateRange);
326 : }
327 :
328 : typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy> OffsetMap;
329 :
330 : bool
331 0 : ModuleGenerator::patchCallSites()
332 : {
333 0 : masm_.haltingAlign(CodeAlignment);
334 :
335 : // Create far jumps for calls that have relative offsets that may otherwise
336 : // go out of range. Far jumps are created for two cases: direct calls
337 : // between function definitions and calls to trap exits by trap out-of-line
338 : // paths. Far jump code is shared when possible to reduce bloat. This method
339 : // is called both between function bodies (at a frequency determined by the
340 : // ISA's jump range) and once at the very end of a module's codegen after
341 : // all possible calls/traps have been emitted.
342 :
343 0 : OffsetMap existingCallFarJumps;
344 0 : if (!existingCallFarJumps.init())
345 0 : return false;
346 :
347 0 : EnumeratedArray<Trap, Trap::Limit, Maybe<uint32_t>> existingTrapFarJumps;
348 :
349 0 : for (; lastPatchedCallsite_ < masm_.callSites().length(); lastPatchedCallsite_++) {
350 0 : const CallSiteAndTarget& cs = masm_.callSites()[lastPatchedCallsite_];
351 0 : uint32_t callerOffset = cs.returnAddressOffset();
352 0 : MOZ_RELEASE_ASSERT(callerOffset < INT32_MAX);
353 :
354 0 : switch (cs.kind()) {
355 : case CallSiteDesc::Dynamic:
356 : case CallSiteDesc::Symbolic:
357 0 : break;
358 : case CallSiteDesc::Func: {
359 0 : if (funcIsCompiled(cs.funcIndex())) {
360 0 : uint32_t calleeOffset = funcCodeRange(cs.funcIndex()).funcNormalEntry();
361 0 : MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX);
362 :
363 0 : if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) {
364 0 : masm_.patchCall(callerOffset, calleeOffset);
365 0 : break;
366 : }
367 : }
368 :
369 0 : OffsetMap::AddPtr p = existingCallFarJumps.lookupForAdd(cs.funcIndex());
370 0 : if (!p) {
371 0 : Offsets offsets;
372 0 : offsets.begin = masm_.currentOffset();
373 0 : masm_.append(CallFarJump(cs.funcIndex(), masm_.farJumpWithPatch()));
374 0 : offsets.end = masm_.currentOffset();
375 0 : if (masm_.oom())
376 0 : return false;
377 :
378 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::FarJumpIsland, offsets))
379 0 : return false;
380 0 : if (!existingCallFarJumps.add(p, cs.funcIndex(), offsets.begin))
381 0 : return false;
382 : }
383 :
384 0 : masm_.patchCall(callerOffset, p->value());
385 0 : break;
386 : }
387 : case CallSiteDesc::TrapExit: {
388 0 : if (!existingTrapFarJumps[cs.trap()]) {
389 : // See MacroAssembler::wasmEmitTrapOutOfLineCode for why we must
390 : // reload the TLS register on this path.
391 0 : Offsets offsets;
392 0 : offsets.begin = masm_.currentOffset();
393 0 : masm_.loadPtr(Address(FramePointer, offsetof(Frame, tls)), WasmTlsReg);
394 0 : masm_.append(TrapFarJump(cs.trap(), masm_.farJumpWithPatch()));
395 0 : offsets.end = masm_.currentOffset();
396 0 : if (masm_.oom())
397 0 : return false;
398 :
399 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::FarJumpIsland, offsets))
400 0 : return false;
401 0 : existingTrapFarJumps[cs.trap()] = Some(offsets.begin);
402 : }
403 :
404 0 : masm_.patchCall(callerOffset, *existingTrapFarJumps[cs.trap()]);
405 0 : break;
406 : }
407 : case CallSiteDesc::Breakpoint:
408 : case CallSiteDesc::EnterFrame:
409 : case CallSiteDesc::LeaveFrame: {
410 0 : Uint32Vector& jumps = metadataTier_->debugTrapFarJumpOffsets;
411 0 : if (jumps.empty() ||
412 0 : uint32_t(abs(int32_t(jumps.back()) - int32_t(callerOffset))) >= JumpRange())
413 : {
414 : // See BaseCompiler::insertBreakablePoint for why we must
415 : // reload the TLS register on this path.
416 0 : Offsets offsets;
417 0 : offsets.begin = masm_.currentOffset();
418 0 : masm_.loadPtr(Address(FramePointer, offsetof(Frame, tls)), WasmTlsReg);
419 0 : uint32_t jumpOffset = masm_.farJumpWithPatch().offset();
420 0 : offsets.end = masm_.currentOffset();
421 0 : if (masm_.oom())
422 0 : return false;
423 :
424 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::FarJumpIsland, offsets))
425 0 : return false;
426 0 : if (!debugTrapFarJumps_.emplaceBack(jumpOffset))
427 0 : return false;
428 0 : if (!jumps.emplaceBack(offsets.begin))
429 0 : return false;
430 : }
431 0 : break;
432 : }
433 : }
434 : }
435 :
436 0 : masm_.flushBuffer();
437 0 : return true;
438 : }
439 :
440 : bool
441 0 : ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub)
442 : {
443 0 : for (const CallFarJump& farJump : masm_.callFarJumps())
444 0 : masm_.patchFarJump(farJump.jump, funcCodeRange(farJump.funcIndex).funcNormalEntry());
445 :
446 0 : for (const TrapFarJump& farJump : masm_.trapFarJumps())
447 0 : masm_.patchFarJump(farJump.jump, trapExits[farJump.trap].begin);
448 :
449 0 : for (uint32_t debugTrapFarJump : debugTrapFarJumps_)
450 0 : masm_.patchFarJump(CodeOffset(debugTrapFarJump), debugTrapStub.begin);
451 :
452 0 : return true;
453 : }
454 :
455 : bool
456 0 : ModuleGenerator::finishTask(CompileTask* task)
457 : {
458 0 : masm_.haltingAlign(CodeAlignment);
459 :
460 : // Before merging in the new function's code, if calls in a prior function
461 : // body might go out of range, insert far jumps to extend the range.
462 0 : if ((masm_.size() - startOfUnpatchedCallsites_) + task->masm().size() > JumpRange()) {
463 0 : startOfUnpatchedCallsites_ = masm_.size();
464 0 : if (!patchCallSites())
465 0 : return false;
466 : }
467 :
468 0 : uint32_t offsetInWhole = masm_.size();
469 0 : for (const FuncCompileUnit& unit : task->units()) {
470 0 : const FuncBytes& func = unit.func();
471 :
472 : // Offset the recorded FuncOffsets by the offset of the function in the
473 : // whole module's code segment.
474 0 : FuncOffsets offsets = unit.offsets();
475 0 : offsets.offsetBy(offsetInWhole);
476 :
477 : // Add the CodeRange for this function.
478 0 : uint32_t funcCodeRangeIndex = metadataTier_->codeRanges.length();
479 0 : if (!metadataTier_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), offsets))
480 0 : return false;
481 :
482 0 : MOZ_ASSERT(!funcIsCompiled(func.index()));
483 0 : funcToCodeRange_[func.index()] = funcCodeRangeIndex;
484 : }
485 :
486 : // Merge the compiled results into the whole-module masm.
487 0 : mozilla::DebugOnly<size_t> sizeBefore = masm_.size();
488 0 : if (!masm_.asmMergeWith(task->masm()))
489 0 : return false;
490 0 : MOZ_ASSERT(masm_.size() == offsetInWhole + task->masm().size());
491 :
492 0 : if (!task->reset(&freeFuncBytes_))
493 0 : return false;
494 :
495 0 : freeTasks_.infallibleAppend(task);
496 0 : return true;
497 : }
498 :
499 : bool
500 0 : ModuleGenerator::finishFuncExports()
501 : {
502 : // In addition to all the functions that were explicitly exported, any
503 : // element of an exported table is also exported.
504 :
505 0 : for (ElemSegment& elems : env_->elemSegments) {
506 0 : if (env_->tables[elems.tableIndex].external) {
507 0 : for (uint32_t funcIndex : elems.elemFuncIndices) {
508 0 : if (!exportedFuncs_.put(funcIndex))
509 0 : return false;
510 : }
511 : }
512 : }
513 :
514 : // ModuleGenerator::exportedFuncs_ is an unordered HashSet. The
515 : // FuncExportVector stored in Metadata needs to be stored sorted by
516 : // function index to allow O(log(n)) lookup at runtime.
517 :
518 0 : Uint32Vector sorted;
519 0 : if (!sorted.reserve(exportedFuncs_.count()))
520 0 : return false;
521 :
522 0 : for (Uint32Set::Range r = exportedFuncs_.all(); !r.empty(); r.popFront())
523 0 : sorted.infallibleAppend(r.front());
524 :
525 0 : std::sort(sorted.begin(), sorted.end());
526 :
527 0 : MOZ_ASSERT(metadataTier_->funcExports.empty());
528 0 : if (!metadataTier_->funcExports.reserve(sorted.length()))
529 0 : return false;
530 :
531 0 : for (uint32_t funcIndex : sorted) {
532 0 : Sig sig;
533 0 : if (!sig.clone(funcSig(funcIndex)))
534 0 : return false;
535 :
536 0 : uint32_t codeRangeIndex = funcToCodeRange_[funcIndex];
537 0 : metadataTier_->funcExports.infallibleEmplaceBack(Move(sig), funcIndex, codeRangeIndex);
538 : }
539 :
540 0 : return true;
541 : }
542 :
543 : typedef Vector<Offsets, 0, SystemAllocPolicy> OffsetVector;
544 : typedef Vector<CallableOffsets, 0, SystemAllocPolicy> CallableOffsetVector;
545 :
546 : bool
547 0 : ModuleGenerator::finishCodegen()
548 : {
549 0 : masm_.haltingAlign(CodeAlignment);
550 0 : uint32_t offsetInWhole = masm_.size();
551 :
552 0 : uint32_t numFuncExports = metadataTier_->funcExports.length();
553 0 : MOZ_ASSERT(numFuncExports == exportedFuncs_.count());
554 :
555 : // Generate stubs in a separate MacroAssembler since, otherwise, for modules
556 : // larger than the JumpImmediateRange, even local uses of Label will fail
557 : // due to the large absolute offsets temporarily stored by Label::bind().
558 :
559 0 : OffsetVector entries;
560 0 : CallableOffsetVector interpExits;
561 0 : CallableOffsetVector jitExits;
562 0 : TrapExitOffsetArray trapExits;
563 0 : Offsets outOfBoundsExit;
564 0 : Offsets unalignedAccessExit;
565 0 : Offsets interruptExit;
566 0 : Offsets throwStub;
567 0 : Offsets debugTrapStub;
568 :
569 : {
570 0 : TempAllocator alloc(&lifo_);
571 0 : MacroAssembler masm(MacroAssembler::WasmToken(), alloc);
572 0 : Label throwLabel;
573 :
574 0 : if (!entries.resize(numFuncExports))
575 0 : return false;
576 0 : for (uint32_t i = 0; i < numFuncExports; i++)
577 0 : entries[i] = GenerateEntry(masm, metadataTier_->funcExports[i]);
578 :
579 0 : if (!interpExits.resize(numFuncImports()))
580 0 : return false;
581 0 : if (!jitExits.resize(numFuncImports()))
582 0 : return false;
583 0 : for (uint32_t i = 0; i < numFuncImports(); i++) {
584 0 : interpExits[i] = GenerateImportInterpExit(masm, metadataTier_->funcImports[i], i, &throwLabel);
585 0 : jitExits[i] = GenerateImportJitExit(masm, metadataTier_->funcImports[i], &throwLabel);
586 : }
587 :
588 0 : for (Trap trap : MakeEnumeratedRange(Trap::Limit))
589 0 : trapExits[trap] = GenerateTrapExit(masm, trap, &throwLabel);
590 :
591 0 : outOfBoundsExit = GenerateOutOfBoundsExit(masm, &throwLabel);
592 0 : unalignedAccessExit = GenerateUnalignedExit(masm, &throwLabel);
593 0 : interruptExit = GenerateInterruptExit(masm, &throwLabel);
594 0 : throwStub = GenerateThrowStub(masm, &throwLabel);
595 0 : debugTrapStub = GenerateDebugTrapStub(masm, &throwLabel);
596 :
597 0 : if (masm.oom() || !masm_.asmMergeWith(masm))
598 0 : return false;
599 : }
600 :
601 : // Adjust each of the resulting Offsets (to account for being merged into
602 : // masm_) and then create code ranges for all the stubs.
603 :
604 0 : for (uint32_t i = 0; i < numFuncExports; i++) {
605 0 : entries[i].offsetBy(offsetInWhole);
606 0 : metadataTier_->funcExports[i].initEntryOffset(entries[i].begin);
607 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::Entry, entries[i]))
608 0 : return false;
609 : }
610 :
611 0 : for (uint32_t i = 0; i < numFuncImports(); i++) {
612 0 : interpExits[i].offsetBy(offsetInWhole);
613 0 : metadataTier_->funcImports[i].initInterpExitOffset(interpExits[i].begin);
614 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i]))
615 0 : return false;
616 :
617 0 : jitExits[i].offsetBy(offsetInWhole);
618 0 : metadataTier_->funcImports[i].initJitExitOffset(jitExits[i].begin);
619 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i]))
620 0 : return false;
621 : }
622 :
623 0 : for (Trap trap : MakeEnumeratedRange(Trap::Limit)) {
624 0 : trapExits[trap].offsetBy(offsetInWhole);
625 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::TrapExit, trapExits[trap]))
626 0 : return false;
627 : }
628 :
629 0 : outOfBoundsExit.offsetBy(offsetInWhole);
630 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::Inline, outOfBoundsExit))
631 0 : return false;
632 :
633 0 : unalignedAccessExit.offsetBy(offsetInWhole);
634 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::Inline, unalignedAccessExit))
635 0 : return false;
636 :
637 0 : interruptExit.offsetBy(offsetInWhole);
638 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::Interrupt, interruptExit))
639 0 : return false;
640 :
641 0 : throwStub.offsetBy(offsetInWhole);
642 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::Throw, throwStub))
643 0 : return false;
644 :
645 0 : debugTrapStub.offsetBy(offsetInWhole);
646 0 : if (!metadataTier_->codeRanges.emplaceBack(CodeRange::DebugTrap, debugTrapStub))
647 0 : return false;
648 :
649 : // Fill in LinkData with the offsets of these stubs.
650 :
651 0 : linkDataTier_->unalignedAccessOffset = unalignedAccessExit.begin;
652 0 : linkDataTier_->outOfBoundsOffset = outOfBoundsExit.begin;
653 0 : linkDataTier_->interruptOffset = interruptExit.begin;
654 :
655 : // Now that all other code has been emitted, patch all remaining callsites
656 : // then far jumps. Patching callsites can generate far jumps so there is an
657 : // ordering dependency.
658 :
659 0 : if (!patchCallSites())
660 0 : return false;
661 :
662 0 : if (!patchFarJumps(trapExits, debugTrapStub))
663 0 : return false;
664 :
665 : // Code-generation is complete!
666 :
667 0 : masm_.finish();
668 0 : return !masm_.oom();
669 : }
670 :
671 : bool
672 0 : ModuleGenerator::finishLinkData()
673 : {
674 : // Inflate the global bytes up to page size so that the total bytes are a
675 : // page size (as required by the allocator functions).
676 0 : metadata_->globalDataLength = AlignBytes(metadata_->globalDataLength, gc::SystemPageSize());
677 :
678 : // Add links to absolute addresses identified symbolically.
679 0 : for (size_t i = 0; i < masm_.numSymbolicAccesses(); i++) {
680 0 : SymbolicAccess src = masm_.symbolicAccess(i);
681 0 : if (!linkDataTier_->symbolicLinks[src.target].append(src.patchAt.offset()))
682 0 : return false;
683 : }
684 :
685 : // Relative link metadata: absolute addresses that refer to another point within
686 : // the asm.js module.
687 :
688 : // CodeLabels are used for switch cases and loads from floating-point /
689 : // SIMD values in the constant pool.
690 0 : for (size_t i = 0; i < masm_.numCodeLabels(); i++) {
691 0 : CodeLabel cl = masm_.codeLabel(i);
692 0 : LinkDataTier::InternalLink inLink(LinkDataTier::InternalLink::CodeLabel);
693 0 : inLink.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt());
694 0 : inLink.targetOffset = cl.target()->offset();
695 0 : if (!linkDataTier_->internalLinks.append(inLink))
696 0 : return false;
697 : }
698 :
699 0 : return true;
700 : }
701 :
702 : bool
703 0 : ModuleGenerator::addFuncImport(const Sig& sig, uint32_t globalDataOffset)
704 : {
705 0 : MOZ_ASSERT(!finishedFuncDefs_);
706 :
707 0 : Sig copy;
708 0 : if (!copy.clone(sig))
709 0 : return false;
710 :
711 0 : return metadataTier_->funcImports.emplaceBack(Move(copy), globalDataOffset);
712 : }
713 :
714 : bool
715 0 : ModuleGenerator::allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset)
716 : {
717 0 : CheckedInt<uint32_t> newGlobalDataLength(metadata_->globalDataLength);
718 :
719 0 : newGlobalDataLength += ComputeByteAlignment(newGlobalDataLength.value(), align);
720 0 : if (!newGlobalDataLength.isValid())
721 0 : return false;
722 :
723 0 : *globalDataOffset = newGlobalDataLength.value();
724 0 : newGlobalDataLength += bytes;
725 :
726 0 : if (!newGlobalDataLength.isValid())
727 0 : return false;
728 :
729 0 : metadata_->globalDataLength = newGlobalDataLength.value();
730 0 : return true;
731 : }
732 :
733 : bool
734 0 : ModuleGenerator::allocateGlobal(GlobalDesc* global)
735 : {
736 0 : MOZ_ASSERT(!startedFuncDefs_);
737 0 : unsigned width = 0;
738 0 : switch (global->type()) {
739 : case ValType::I32:
740 : case ValType::F32:
741 0 : width = 4;
742 0 : break;
743 : case ValType::I64:
744 : case ValType::F64:
745 0 : width = 8;
746 0 : break;
747 : case ValType::I8x16:
748 : case ValType::I16x8:
749 : case ValType::I32x4:
750 : case ValType::F32x4:
751 : case ValType::B8x16:
752 : case ValType::B16x8:
753 : case ValType::B32x4:
754 0 : width = 16;
755 0 : break;
756 : }
757 :
758 : uint32_t offset;
759 0 : if (!allocateGlobalBytes(width, width, &offset))
760 0 : return false;
761 :
762 0 : global->setOffset(offset);
763 0 : return true;
764 : }
765 :
766 : bool
767 0 : ModuleGenerator::addGlobal(ValType type, bool isConst, uint32_t* index)
768 : {
769 0 : MOZ_ASSERT(isAsmJS());
770 0 : MOZ_ASSERT(!startedFuncDefs_);
771 :
772 0 : *index = env_->globals.length();
773 0 : GlobalDesc global(type, !isConst, *index);
774 0 : if (!allocateGlobal(&global))
775 0 : return false;
776 :
777 0 : return env_->globals.append(global);
778 : }
779 :
780 : bool
781 0 : ModuleGenerator::addExport(CacheableChars&& fieldName, uint32_t funcIndex)
782 : {
783 0 : MOZ_ASSERT(isAsmJS());
784 0 : return env_->exports.emplaceBack(Move(fieldName), funcIndex, DefinitionKind::Function) &&
785 0 : exportedFuncs_.put(funcIndex);
786 : }
787 :
788 : void
789 0 : ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig)
790 : {
791 0 : MOZ_ASSERT(isAsmJS());
792 0 : MOZ_ASSERT(sigIndex == numSigs_);
793 0 : numSigs_++;
794 :
795 0 : MOZ_ASSERT(env_->sigs[sigIndex] == Sig());
796 0 : env_->sigs[sigIndex] = Move(sig);
797 0 : }
798 :
799 : const SigWithId&
800 0 : ModuleGenerator::sig(uint32_t index) const
801 : {
802 0 : MOZ_ASSERT(index < numSigs_);
803 0 : return env_->sigs[index];
804 : }
805 :
806 : void
807 0 : ModuleGenerator::initFuncSig(uint32_t funcIndex, uint32_t sigIndex)
808 : {
809 0 : MOZ_ASSERT(isAsmJS());
810 0 : MOZ_ASSERT(!env_->funcSigs[funcIndex]);
811 :
812 0 : env_->funcSigs[funcIndex] = &env_->sigs[sigIndex];
813 0 : }
814 :
815 : void
816 0 : ModuleGenerator::initMemoryUsage(MemoryUsage memoryUsage)
817 : {
818 0 : MOZ_ASSERT(isAsmJS());
819 0 : MOZ_ASSERT(env_->memoryUsage == MemoryUsage::None);
820 :
821 0 : env_->memoryUsage = memoryUsage;
822 0 : }
823 :
824 : void
825 0 : ModuleGenerator::bumpMinMemoryLength(uint32_t newMinMemoryLength)
826 : {
827 0 : MOZ_ASSERT(isAsmJS());
828 0 : MOZ_ASSERT(newMinMemoryLength >= env_->minMemoryLength);
829 :
830 0 : env_->minMemoryLength = newMinMemoryLength;
831 0 : }
832 :
833 : bool
834 0 : ModuleGenerator::initImport(uint32_t funcIndex, uint32_t sigIndex)
835 : {
836 0 : MOZ_ASSERT(isAsmJS());
837 :
838 0 : MOZ_ASSERT(!env_->funcSigs[funcIndex]);
839 0 : env_->funcSigs[funcIndex] = &env_->sigs[sigIndex];
840 :
841 : uint32_t globalDataOffset;
842 0 : if (!allocateGlobalBytes(sizeof(FuncImportTls), sizeof(void*), &globalDataOffset))
843 0 : return false;
844 :
845 0 : MOZ_ASSERT(!env_->funcImportGlobalDataOffsets[funcIndex]);
846 0 : env_->funcImportGlobalDataOffsets[funcIndex] = globalDataOffset;
847 :
848 0 : MOZ_ASSERT(funcIndex == metadataTier_->funcImports.length());
849 0 : return addFuncImport(sig(sigIndex), globalDataOffset);
850 : }
851 :
852 : uint32_t
853 0 : ModuleGenerator::numFuncImports() const
854 : {
855 : // Until all functions have been validated, asm.js doesn't know the total
856 : // number of imports.
857 0 : MOZ_ASSERT_IF(isAsmJS(), finishedFuncDefs_);
858 0 : return metadataTier_->funcImports.length();
859 : }
860 :
861 : const SigWithId&
862 0 : ModuleGenerator::funcSig(uint32_t funcIndex) const
863 : {
864 0 : MOZ_ASSERT(env_->funcSigs[funcIndex]);
865 0 : return *env_->funcSigs[funcIndex];
866 : }
867 :
868 : bool
869 0 : ModuleGenerator::startFuncDefs()
870 : {
871 0 : MOZ_ASSERT(!startedFuncDefs_);
872 0 : MOZ_ASSERT(!finishedFuncDefs_);
873 :
874 : // The wasmCompilationInProgress atomic ensures that there is only one
875 : // parallel compilation in progress at a time. In the special case of
876 : // asm.js, where the ModuleGenerator itself can be on a helper thread, this
877 : // avoids the possibility of deadlock since at most 1 helper thread will be
878 : // blocking on other helper threads and there are always >1 helper threads.
879 : // With wasm, this restriction could be relaxed by moving the worklist state
880 : // out of HelperThreadState since each independent compilation needs its own
881 : // worklist pair. Alternatively, the deadlock could be avoided by having the
882 : // ModuleGenerator thread make progress (on compile tasks) instead of
883 : // blocking.
884 :
885 0 : GlobalHelperThreadState& threads = HelperThreadState();
886 0 : MOZ_ASSERT(threads.threadCount > 1);
887 :
888 : uint32_t numTasks;
889 0 : if (CanUseExtraThreads() &&
890 0 : threads.cpuCount > 1 &&
891 0 : threads.wasmCompilationInProgress.compareExchange(false, true))
892 : {
893 : #ifdef DEBUG
894 : {
895 0 : AutoLockHelperThreadState lock;
896 0 : MOZ_ASSERT(!HelperThreadState().wasmFailed(lock));
897 0 : MOZ_ASSERT(HelperThreadState().wasmWorklist(lock).empty());
898 0 : MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock).empty());
899 : }
900 : #endif
901 0 : parallel_ = true;
902 0 : numTasks = 2 * threads.maxWasmCompilationThreads();
903 : } else {
904 0 : numTasks = 1;
905 : }
906 :
907 0 : if (!tasks_.initCapacity(numTasks))
908 0 : return false;
909 0 : for (size_t i = 0; i < numTasks; i++)
910 0 : tasks_.infallibleEmplaceBack(*env_, tier_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
911 :
912 0 : if (!freeTasks_.reserve(numTasks))
913 0 : return false;
914 0 : for (size_t i = 0; i < numTasks; i++)
915 0 : freeTasks_.infallibleAppend(&tasks_[i]);
916 :
917 0 : startedFuncDefs_ = true;
918 0 : MOZ_ASSERT(!finishedFuncDefs_);
919 0 : return true;
920 : }
921 :
922 : bool
923 0 : ModuleGenerator::startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg)
924 : {
925 0 : MOZ_ASSERT(startedFuncDefs_);
926 0 : MOZ_ASSERT(!activeFuncDef_);
927 0 : MOZ_ASSERT(!finishedFuncDefs_);
928 :
929 0 : if (!freeFuncBytes_.empty()) {
930 0 : fg->funcBytes_ = Move(freeFuncBytes_.back());
931 0 : freeFuncBytes_.popBack();
932 : } else {
933 0 : fg->funcBytes_ = js::MakeUnique<FuncBytes>();
934 0 : if (!fg->funcBytes_)
935 0 : return false;
936 : }
937 :
938 0 : if (!currentTask_) {
939 0 : if (freeTasks_.empty() && !finishOutstandingTask())
940 0 : return false;
941 0 : currentTask_ = freeTasks_.popCopy();
942 : }
943 :
944 0 : fg->funcBytes_->setLineOrBytecode(lineOrBytecode);
945 0 : fg->m_ = this;
946 0 : activeFuncDef_ = fg;
947 0 : return true;
948 : }
949 :
950 : bool
951 0 : ModuleGenerator::launchBatchCompile()
952 : {
953 0 : MOZ_ASSERT(currentTask_);
954 :
955 0 : currentTask_->setDebugEnabled(metadata_->debugEnabled);
956 :
957 0 : size_t numBatchedFuncs = currentTask_->units().length();
958 0 : MOZ_ASSERT(numBatchedFuncs);
959 :
960 0 : if (parallel_) {
961 0 : if (!StartOffThreadWasmCompile(currentTask_))
962 0 : return false;
963 0 : outstanding_++;
964 : } else {
965 0 : if (!CompileFunction(currentTask_, error_))
966 0 : return false;
967 0 : if (!finishTask(currentTask_))
968 0 : return false;
969 : }
970 :
971 0 : currentTask_ = nullptr;
972 0 : batchedBytecode_ = 0;
973 :
974 0 : numFinishedFuncDefs_ += numBatchedFuncs;
975 0 : return true;
976 : }
977 :
978 : bool
979 0 : ModuleGenerator::finishFuncDef(uint32_t funcIndex, FunctionGenerator* fg)
980 : {
981 0 : MOZ_ASSERT(activeFuncDef_ == fg);
982 :
983 0 : UniqueFuncBytes func = Move(fg->funcBytes_);
984 0 : func->setFunc(funcIndex, &funcSig(funcIndex));
985 0 : uint32_t funcBytecodeLength = func->bytes().length();
986 0 : if (!currentTask_->units().emplaceBack(Move(func)))
987 0 : return false;
988 :
989 : uint32_t threshold;
990 0 : switch (tier_) {
991 0 : case Tier::Baseline: threshold = JitOptions.wasmBatchBaselineThreshold; break;
992 0 : case Tier::Ion: threshold = JitOptions.wasmBatchIonThreshold; break;
993 0 : default: MOZ_CRASH("Invalid tier value"); break;
994 : }
995 :
996 0 : batchedBytecode_ += funcBytecodeLength;
997 0 : MOZ_ASSERT(batchedBytecode_ <= MaxModuleBytes);
998 0 : if (batchedBytecode_ > threshold && !launchBatchCompile())
999 0 : return false;
1000 :
1001 0 : fg->m_ = nullptr;
1002 0 : activeFuncDef_ = nullptr;
1003 0 : return true;
1004 : }
1005 :
1006 : bool
1007 0 : ModuleGenerator::finishFuncDefs()
1008 : {
1009 0 : MOZ_ASSERT(startedFuncDefs_);
1010 0 : MOZ_ASSERT(!activeFuncDef_);
1011 0 : MOZ_ASSERT(!finishedFuncDefs_);
1012 :
1013 0 : if (currentTask_ && !launchBatchCompile())
1014 0 : return false;
1015 :
1016 0 : while (outstanding_ > 0) {
1017 0 : if (!finishOutstandingTask())
1018 0 : return false;
1019 : }
1020 :
1021 0 : linkDataTier_->functionCodeLength = masm_.size();
1022 0 : finishedFuncDefs_ = true;
1023 :
1024 : // Generate wrapper functions for every import. These wrappers turn imports
1025 : // into plain functions so they can be put into tables and re-exported.
1026 : // asm.js cannot do either and so no wrappers are generated.
1027 :
1028 0 : if (!isAsmJS()) {
1029 0 : for (size_t funcIndex = 0; funcIndex < numFuncImports(); funcIndex++) {
1030 0 : const FuncImport& funcImport = metadataTier_->funcImports[funcIndex];
1031 0 : const SigWithId& sig = funcSig(funcIndex);
1032 :
1033 0 : FuncOffsets offsets = GenerateImportFunction(masm_, funcImport, sig.id);
1034 0 : if (masm_.oom())
1035 0 : return false;
1036 :
1037 0 : uint32_t codeRangeIndex = metadataTier_->codeRanges.length();
1038 0 : if (!metadataTier_->codeRanges.emplaceBack(funcIndex, /* bytecodeOffset = */ 0, offsets))
1039 0 : return false;
1040 :
1041 0 : MOZ_ASSERT(!funcIsCompiled(funcIndex));
1042 0 : funcToCodeRange_[funcIndex] = codeRangeIndex;
1043 : }
1044 : }
1045 :
1046 : // All function indices should have an associated code range at this point
1047 : // (except in asm.js, which doesn't have import wrapper functions).
1048 :
1049 : #ifdef DEBUG
1050 0 : if (isAsmJS()) {
1051 0 : MOZ_ASSERT(numFuncImports() < AsmJSFirstDefFuncIndex);
1052 0 : for (uint32_t i = 0; i < AsmJSFirstDefFuncIndex; i++)
1053 0 : MOZ_ASSERT(funcToCodeRange_[i] == BAD_CODE_RANGE);
1054 0 : for (uint32_t i = AsmJSFirstDefFuncIndex; i < numFinishedFuncDefs_; i++)
1055 0 : MOZ_ASSERT(funcCodeRange(i).funcIndex() == i);
1056 : } else {
1057 0 : MOZ_ASSERT(numFinishedFuncDefs_ == env_->numFuncDefs());
1058 0 : for (uint32_t i = 0; i < env_->numFuncs(); i++)
1059 0 : MOZ_ASSERT(funcCodeRange(i).funcIndex() == i);
1060 : }
1061 : #endif
1062 :
1063 : // Complete element segments with the code range index of every element, now
1064 : // that all functions have been compiled.
1065 :
1066 0 : for (ElemSegment& elems : env_->elemSegments) {
1067 0 : Uint32Vector& codeRangeIndices = elems.elemCodeRangeIndices;
1068 :
1069 0 : MOZ_ASSERT(codeRangeIndices.empty());
1070 0 : if (!codeRangeIndices.reserve(elems.elemFuncIndices.length()))
1071 0 : return false;
1072 :
1073 0 : for (uint32_t funcIndex : elems.elemFuncIndices)
1074 0 : codeRangeIndices.infallibleAppend(funcToCodeRange_[funcIndex]);
1075 : }
1076 :
1077 0 : return true;
1078 : }
1079 :
1080 : bool
1081 0 : ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length)
1082 : {
1083 0 : MOZ_ASSERT(isAsmJS());
1084 0 : MOZ_ASSERT(length != 0);
1085 0 : MOZ_ASSERT(length <= MaxTableInitialLength);
1086 :
1087 0 : MOZ_ASSERT(env_->asmJSSigToTableIndex[sigIndex] == 0);
1088 0 : env_->asmJSSigToTableIndex[sigIndex] = numTables_;
1089 :
1090 0 : TableDesc& table = env_->tables[numTables_++];
1091 0 : table.kind = TableKind::TypedFunction;
1092 0 : table.limits.initial = length;
1093 0 : table.limits.maximum = Some(length);
1094 0 : return allocateGlobalBytes(sizeof(TableTls), sizeof(void*), &table.globalDataOffset);
1095 : }
1096 :
1097 : bool
1098 0 : ModuleGenerator::initSigTableElems(uint32_t sigIndex, Uint32Vector&& elemFuncIndices)
1099 : {
1100 0 : MOZ_ASSERT(isAsmJS());
1101 0 : MOZ_ASSERT(finishedFuncDefs_);
1102 :
1103 0 : uint32_t tableIndex = env_->asmJSSigToTableIndex[sigIndex];
1104 0 : MOZ_ASSERT(env_->tables[tableIndex].limits.initial == elemFuncIndices.length());
1105 :
1106 0 : Uint32Vector codeRangeIndices;
1107 0 : if (!codeRangeIndices.resize(elemFuncIndices.length()))
1108 0 : return false;
1109 0 : for (size_t i = 0; i < elemFuncIndices.length(); i++)
1110 0 : codeRangeIndices[i] = funcToCodeRange_[elemFuncIndices[i]];
1111 :
1112 0 : InitExpr offset(Val(uint32_t(0)));
1113 0 : if (!env_->elemSegments.emplaceBack(tableIndex, offset, Move(elemFuncIndices)))
1114 0 : return false;
1115 :
1116 0 : env_->elemSegments.back().elemCodeRangeIndices = Move(codeRangeIndices);
1117 0 : return true;
1118 : }
1119 :
1120 : static_assert(sizeof(ModuleHash) <= sizeof(mozilla::SHA1Sum::Hash),
1121 : "The ModuleHash size shall not exceed the SHA1 hash size.");
1122 :
1123 : void
1124 0 : ModuleGenerator::generateBytecodeHash(const ShareableBytes& bytecode)
1125 : {
1126 : mozilla::SHA1Sum::Hash hash;
1127 0 : mozilla::SHA1Sum sha1Sum;
1128 0 : sha1Sum.update(bytecode.begin(), bytecode.length());
1129 0 : sha1Sum.finish(hash);
1130 0 : memcpy(metadata_->hash, hash, sizeof(ModuleHash));
1131 0 : }
1132 :
1133 : SharedModule
1134 0 : ModuleGenerator::finish(const ShareableBytes& bytecode)
1135 : {
1136 0 : MOZ_ASSERT(!activeFuncDef_);
1137 0 : MOZ_ASSERT(finishedFuncDefs_);
1138 :
1139 0 : if (!finishFuncExports())
1140 0 : return nullptr;
1141 :
1142 0 : if (!finishCodegen())
1143 0 : return nullptr;
1144 :
1145 : // Convert the CallSiteAndTargetVector (needed during generation) to a
1146 : // CallSiteVector (what is stored in the Module).
1147 0 : if (!metadataTier_->callSites.appendAll(masm_.callSites()))
1148 0 : return nullptr;
1149 :
1150 : // The MacroAssembler has accumulated all the memory accesses during codegen.
1151 0 : metadataTier_->memoryAccesses = masm_.extractMemoryAccesses();
1152 :
1153 : // Copy over data from the ModuleEnvironment.
1154 0 : metadata_->memoryUsage = env_->memoryUsage;
1155 0 : metadata_->minMemoryLength = env_->minMemoryLength;
1156 0 : metadata_->maxMemoryLength = env_->maxMemoryLength;
1157 0 : metadata_->tables = Move(env_->tables);
1158 0 : metadata_->globals = Move(env_->globals);
1159 0 : metadata_->funcNames = Move(env_->funcNames);
1160 0 : metadata_->customSections = Move(env_->customSections);
1161 :
1162 : // Additional debug information to copy.
1163 0 : metadata_->debugFuncArgTypes = Move(debugFuncArgTypes_);
1164 0 : metadata_->debugFuncReturnTypes = Move(debugFuncReturnTypes_);
1165 0 : if (metadata_->debugEnabled)
1166 0 : metadataTier_->debugFuncToCodeRange = Move(funcToCodeRange_);
1167 :
1168 : // These Vectors can get large and the excess capacity can be significant,
1169 : // so realloc them down to size.
1170 0 : metadataTier_->memoryAccesses.podResizeToFit();
1171 0 : metadataTier_->codeRanges.podResizeToFit();
1172 0 : metadataTier_->callSites.podResizeToFit();
1173 0 : metadataTier_->debugTrapFarJumpOffsets.podResizeToFit();
1174 0 : metadataTier_->debugFuncToCodeRange.podResizeToFit();
1175 :
1176 : // For asm.js, the tables vector is over-allocated (to avoid resize during
1177 : // parallel copilation). Shrink it back down to fit.
1178 0 : if (isAsmJS() && !metadata_->tables.resize(numTables_))
1179 0 : return nullptr;
1180 :
1181 : // Assert CodeRanges are sorted.
1182 : #ifdef DEBUG
1183 0 : uint32_t lastEnd = 0;
1184 0 : for (const CodeRange& codeRange : metadataTier_->codeRanges) {
1185 0 : MOZ_ASSERT(codeRange.begin() >= lastEnd);
1186 0 : lastEnd = codeRange.end();
1187 : }
1188 : #endif
1189 :
1190 : // Assert debugTrapFarJumpOffsets are sorted.
1191 : #ifdef DEBUG
1192 0 : uint32_t lastOffset = 0;
1193 0 : for (uint32_t debugTrapFarJumpOffset : metadataTier_->debugTrapFarJumpOffsets) {
1194 0 : MOZ_ASSERT(debugTrapFarJumpOffset >= lastOffset);
1195 0 : lastOffset = debugTrapFarJumpOffset;
1196 : }
1197 : #endif
1198 :
1199 0 : if (!finishLinkData())
1200 0 : return nullptr;
1201 :
1202 0 : generateBytecodeHash(bytecode);
1203 :
1204 : UniqueConstCodeSegment codeSegment = CodeSegment::create(tier_,
1205 : masm_,
1206 : bytecode,
1207 0 : *linkDataTier_,
1208 0 : *metadata_);
1209 0 : if (!codeSegment)
1210 0 : return nullptr;
1211 :
1212 0 : UniqueConstBytes maybeDebuggingBytes;
1213 0 : if (metadata_->debugEnabled) {
1214 0 : Bytes bytes;
1215 0 : if (!bytes.resize(masm_.bytesNeeded()))
1216 0 : return nullptr;
1217 0 : masm_.executableCopy(bytes.begin(), /* flushICache = */ false);
1218 0 : maybeDebuggingBytes = js::MakeUnique<Bytes>(Move(bytes));
1219 0 : if (!maybeDebuggingBytes)
1220 0 : return nullptr;
1221 : }
1222 :
1223 0 : SharedCode code = js_new<Code>(Move(codeSegment), *metadata_);
1224 0 : if (!code)
1225 0 : return nullptr;
1226 :
1227 0 : return SharedModule(js_new<Module>(Move(assumptions_),
1228 : *code,
1229 0 : Move(maybeDebuggingBytes),
1230 0 : Move(linkData_),
1231 0 : Move(env_->imports),
1232 0 : Move(env_->exports),
1233 0 : Move(env_->dataSegments),
1234 0 : Move(env_->elemSegments),
1235 0 : bytecode));
1236 : }
1237 :
1238 : bool
1239 0 : wasm::CompileFunction(CompileTask* task, UniqueChars* error)
1240 : {
1241 0 : TraceLoggerThread* logger = TraceLoggerForCurrentThread();
1242 0 : AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation);
1243 :
1244 0 : switch (task->tier()) {
1245 : case Tier::Ion:
1246 0 : for (FuncCompileUnit& unit : task->units()) {
1247 0 : if (!IonCompileFunction(task, &unit, error))
1248 0 : return false;
1249 : }
1250 0 : break;
1251 : case Tier::Baseline:
1252 0 : for (FuncCompileUnit& unit : task->units()) {
1253 0 : if (!BaselineCompileFunction(task, &unit, error))
1254 0 : return false;
1255 : }
1256 0 : break;
1257 : default:
1258 0 : MOZ_CRASH("Invalid tier value");
1259 : }
1260 :
1261 0 : return true;
1262 : }
|