diff options
Diffstat (limited to 'js/src/wasm/WasmGenerator.h')
-rw-r--r-- | js/src/wasm/WasmGenerator.h | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/js/src/wasm/WasmGenerator.h b/js/src/wasm/WasmGenerator.h new file mode 100644 index 0000000000..775366e215 --- /dev/null +++ b/js/src/wasm/WasmGenerator.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * + * Copyright 2015 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_generator_h +#define wasm_generator_h + +#include "mozilla/Attributes.h" +#include "mozilla/MemoryReporting.h" + +#include "jit/MacroAssembler.h" +#include "threading/ProtectedData.h" +#include "vm/HelperThreadTask.h" +#include "wasm/WasmCompile.h" +#include "wasm/WasmModule.h" +#include "wasm/WasmValidate.h" + +namespace JS { +class OptimizedEncodingListener; +} + +namespace js { +namespace wasm { + +struct CompileTask; +using CompileTaskPtrVector = Vector<CompileTask*, 0, SystemAllocPolicy>; + +// FuncCompileInput contains the input for compiling a single function. + +struct FuncCompileInput { + const uint8_t* begin; + const uint8_t* end; + uint32_t index; + uint32_t lineOrBytecode; + Uint32Vector callSiteLineNums; + + FuncCompileInput(uint32_t index, uint32_t lineOrBytecode, + const uint8_t* begin, const uint8_t* end, + Uint32Vector&& callSiteLineNums) + : begin(begin), + end(end), + index(index), + lineOrBytecode(lineOrBytecode), + callSiteLineNums(std::move(callSiteLineNums)) {} +}; + +using FuncCompileInputVector = Vector<FuncCompileInput, 8, SystemAllocPolicy>; + +// CompiledCode contains the resulting code and metadata for a set of compiled +// input functions or stubs. + +struct CompiledCode { + CompiledCode() : featureUsage(FeatureUsage::None) {} + + Bytes bytes; + CodeRangeVector codeRanges; + CallSiteVector callSites; + CallSiteTargetVector callSiteTargets; + TrapSiteVectorArray trapSites; + SymbolicAccessVector symbolicAccesses; + jit::CodeLabelVector codeLabels; + StackMaps stackMaps; + TryNoteVector tryNotes; + CodeRangeUnwindInfoVector codeRangeUnwindInfos; + FeatureUsage featureUsage; + + [[nodiscard]] bool swap(jit::MacroAssembler& masm); + + void clear() { + bytes.clear(); + codeRanges.clear(); + callSites.clear(); + callSiteTargets.clear(); + trapSites.clear(); + symbolicAccesses.clear(); + codeLabels.clear(); + stackMaps.clear(); + tryNotes.clear(); + codeRangeUnwindInfos.clear(); + featureUsage = FeatureUsage::None; + MOZ_ASSERT(empty()); + } + + bool empty() { + return bytes.empty() && codeRanges.empty() && callSites.empty() && + callSiteTargets.empty() && trapSites.empty() && + symbolicAccesses.empty() && codeLabels.empty() && tryNotes.empty() && + stackMaps.empty() && codeRangeUnwindInfos.empty() && + featureUsage == FeatureUsage::None; + } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; +}; + +// The CompileTaskState of a ModuleGenerator contains the mutable state shared +// between helper threads executing CompileTasks. Each CompileTask started on a +// helper thread eventually either ends up in the 'finished' list or increments +// 'numFailed'. + +struct CompileTaskState { + HelperThreadLockData<CompileTaskPtrVector> finished_; + HelperThreadLockData<uint32_t> numFailed_; + HelperThreadLockData<UniqueChars> errorMessage_; + HelperThreadLockData<ConditionVariable> condVar_; + + CompileTaskState() : numFailed_(0) {} + ~CompileTaskState() { + MOZ_ASSERT(finished_.refNoCheck().empty()); + MOZ_ASSERT(!numFailed_.refNoCheck()); + } + + CompileTaskPtrVector& finished() { return finished_.ref(); } + uint32_t& numFailed() { return numFailed_.ref(); } + UniqueChars& errorMessage() { return errorMessage_.ref(); } + ConditionVariable& condVar() { return condVar_.ref(); } +}; + +// A CompileTask holds a batch of input functions that are to be compiled on a +// helper thread as well as, eventually, the results of compilation. + +struct CompileTask : public HelperThreadTask { + const ModuleEnvironment& moduleEnv; + const CompilerEnvironment& compilerEnv; + + CompileTaskState& state; + LifoAlloc lifo; + FuncCompileInputVector inputs; + CompiledCode output; + + CompileTask(const ModuleEnvironment& moduleEnv, + const CompilerEnvironment& compilerEnv, CompileTaskState& state, + size_t defaultChunkSize) + : moduleEnv(moduleEnv), + compilerEnv(compilerEnv), + state(state), + lifo(defaultChunkSize) {} + + virtual ~CompileTask() = default; + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + void runHelperThreadTask(AutoLockHelperThreadState& locked) override; + ThreadType threadType() override; +}; + +// A ModuleGenerator encapsulates the creation of a wasm module. During the +// lifetime of a ModuleGenerator, a sequence of FunctionGenerators are created +// and destroyed to compile the individual function bodies. After generating all +// functions, ModuleGenerator::finish() must be called to complete the +// compilation and extract the resulting wasm module. + +class MOZ_STACK_CLASS ModuleGenerator { + using CompileTaskVector = Vector<CompileTask, 0, SystemAllocPolicy>; + using CodeOffsetVector = Vector<jit::CodeOffset, 0, SystemAllocPolicy>; + struct CallFarJump { + uint32_t funcIndex; + jit::CodeOffset jump; + CallFarJump(uint32_t fi, jit::CodeOffset j) : funcIndex(fi), jump(j) {} + }; + using CallFarJumpVector = Vector<CallFarJump, 0, SystemAllocPolicy>; + + // Constant parameters + SharedCompileArgs const compileArgs_; + UniqueChars* const error_; + UniqueCharsVector* const warnings_; + const Atomic<bool>* const cancelled_; + ModuleEnvironment* const moduleEnv_; + CompilerEnvironment* const compilerEnv_; + + // Data that is moved into the result of finish() + UniqueLinkData linkData_; + UniqueMetadataTier metadataTier_; + MutableMetadata metadata_; + + // Data scoped to the ModuleGenerator's lifetime + CompileTaskState taskState_; + LifoAlloc lifo_; + jit::TempAllocator masmAlloc_; + jit::WasmMacroAssembler masm_; + Uint32Vector funcToCodeRange_; + uint32_t debugTrapCodeOffset_; + CallFarJumpVector callFarJumps_; + CallSiteTargetVector callSiteTargets_; + uint32_t lastPatchedCallSite_; + uint32_t startOfUnpatchedCallsites_; + + // Parallel compilation + bool parallel_; + uint32_t outstanding_; + CompileTaskVector tasks_; + CompileTaskPtrVector freeTasks_; + CompileTask* currentTask_; + uint32_t batchedBytecode_; + + // Assertions + DebugOnly<bool> finishedFuncDefs_; + + bool allocateInstanceDataBytes(uint32_t bytes, uint32_t align, + uint32_t* instanceDataOffset); + bool allocateInstanceDataBytesN(uint32_t bytes, uint32_t align, + uint32_t count, uint32_t* instanceDataOffset); + + bool funcIsCompiled(uint32_t funcIndex) const; + const CodeRange& funcCodeRange(uint32_t funcIndex) const; + bool linkCallSites(); + void noteCodeRange(uint32_t codeRangeIndex, const CodeRange& codeRange); + bool linkCompiledCode(CompiledCode& code); + bool locallyCompileCurrentTask(); + bool finishTask(CompileTask* task); + bool launchBatchCompile(); + bool finishOutstandingTask(); + bool finishCodegen(); + bool finishMetadataTier(); + UniqueCodeTier finishCodeTier(); + SharedMetadata finishMetadata(const Bytes& bytecode); + + bool isAsmJS() const { return moduleEnv_->isAsmJS(); } + Tier tier() const { return compilerEnv_->tier(); } + CompileMode mode() const { return compilerEnv_->mode(); } + bool debugEnabled() const { return compilerEnv_->debugEnabled(); } + + void warnf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3); + + public: + ModuleGenerator(const CompileArgs& args, ModuleEnvironment* moduleEnv, + CompilerEnvironment* compilerEnv, + const Atomic<bool>* cancelled, UniqueChars* error, + UniqueCharsVector* warnings); + ~ModuleGenerator(); + [[nodiscard]] bool init(Metadata* maybeAsmJSMetadata = nullptr); + + // Before finishFuncDefs() is called, compileFuncDef() must be called once + // for each funcIndex in the range [0, env->numFuncDefs()). + + [[nodiscard]] bool compileFuncDef( + uint32_t funcIndex, uint32_t lineOrBytecode, const uint8_t* begin, + const uint8_t* end, Uint32Vector&& callSiteLineNums = Uint32Vector()); + + // Must be called after the last compileFuncDef() and before finishModule() + // or finishTier2(). + + [[nodiscard]] bool finishFuncDefs(); + + // If env->mode is Once or Tier1, finishModule() must be called to generate + // a new Module. Otherwise, if env->mode is Tier2, finishTier2() must be + // called to augment the given Module with tier 2 code. + + SharedModule finishModule( + const ShareableBytes& bytecode, + JS::OptimizedEncodingListener* maybeTier2Listener = nullptr); + [[nodiscard]] bool finishTier2(const Module& module); +}; + +} // namespace wasm +} // namespace js + +#endif // wasm_generator_h |