[wasm] Decouple wire bytes from compilation units
Compilation units currently contain pointers into allocated space that contains the code of the respective function. This requires us to keep the StreamingDecoder alive as long as compilation is still running (including tiering). This CL refactors this by having an additional redirection (WireBytesStorage) which can point to either the StreamingDecoder or the NativeModule. We only keep the code section buffer alive as long as the StreamingWireBytesStorage is still in use. I will further refactor memory ownership in a follow-up CL to not make the AsyncCompileJob keep the StreamingDecoder alive. R=ahaas@chromium.org Bug: v8:8343,v8:7921,v8:8050 Change-Id: I780582c3217abf64000454f2c9c108b9ac9fbff1 Reviewed-on: https://chromium-review.googlesource.com/c/1319588 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#57317}
This commit is contained in:
parent
5e6f91e7c6
commit
014d9e4f32
@ -5211,21 +5211,21 @@ TurbofanWasmCompilationUnit::TurbofanWasmCompilationUnit(
|
||||
TurbofanWasmCompilationUnit::~TurbofanWasmCompilationUnit() = default;
|
||||
|
||||
bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
|
||||
wasm::CompilationEnv* env, wasm::WasmFeatures* detected, double* decode_ms,
|
||||
MachineGraph* mcgraph, NodeOriginTable* node_origins,
|
||||
SourcePositionTable* source_positions) {
|
||||
wasm::CompilationEnv* env, const wasm::FunctionBody& func_body,
|
||||
wasm::WasmFeatures* detected, double* decode_ms, MachineGraph* mcgraph,
|
||||
NodeOriginTable* node_origins, SourcePositionTable* source_positions) {
|
||||
base::ElapsedTimer decode_timer;
|
||||
if (FLAG_trace_wasm_decode_time) {
|
||||
decode_timer.Start();
|
||||
}
|
||||
|
||||
// Create a TF graph during decoding.
|
||||
WasmGraphBuilder builder(env, mcgraph->zone(), mcgraph,
|
||||
wasm_unit_->func_body_.sig, source_positions);
|
||||
WasmGraphBuilder builder(env, mcgraph->zone(), mcgraph, func_body.sig,
|
||||
source_positions);
|
||||
wasm::VoidResult graph_construction_result = wasm::BuildTFGraph(
|
||||
wasm_unit_->wasm_engine_->allocator(),
|
||||
wasm_unit_->native_module_->enabled_features(), env->module, &builder,
|
||||
detected, wasm_unit_->func_body_, node_origins);
|
||||
detected, func_body, node_origins);
|
||||
if (graph_construction_result.failed()) {
|
||||
if (FLAG_trace_wasm_compiler) {
|
||||
StdoutStream{} << "Compilation failed: "
|
||||
@ -5240,16 +5240,15 @@ bool TurbofanWasmCompilationUnit::BuildGraphForWasmFunction(
|
||||
|
||||
if (builder.has_simd() &&
|
||||
(!CpuFeatures::SupportsWasmSimd128() || env->lower_simd)) {
|
||||
SimdScalarLowering(
|
||||
mcgraph,
|
||||
CreateMachineSignature(mcgraph->zone(), wasm_unit_->func_body_.sig))
|
||||
SimdScalarLowering(mcgraph,
|
||||
CreateMachineSignature(mcgraph->zone(), func_body.sig))
|
||||
.LowerGraph();
|
||||
}
|
||||
|
||||
if (wasm_unit_->func_index_ >= FLAG_trace_wasm_ast_start &&
|
||||
wasm_unit_->func_index_ < FLAG_trace_wasm_ast_end) {
|
||||
PrintRawWasmCode(wasm_unit_->wasm_engine_->allocator(),
|
||||
wasm_unit_->func_body_, env->module, wasm::kPrintLocals);
|
||||
PrintRawWasmCode(wasm_unit_->wasm_engine_->allocator(), func_body,
|
||||
env->module, wasm::kPrintLocals);
|
||||
}
|
||||
if (FLAG_trace_wasm_decode_time) {
|
||||
*decode_ms = decode_timer.Elapsed().InMillisecondsF();
|
||||
@ -5273,8 +5272,8 @@ Vector<const char> GetDebugName(Zone* zone, int index) {
|
||||
} // namespace
|
||||
|
||||
void TurbofanWasmCompilationUnit::ExecuteCompilation(
|
||||
wasm::CompilationEnv* env, Counters* counters,
|
||||
wasm::WasmFeatures* detected) {
|
||||
wasm::CompilationEnv* env, const wasm::FunctionBody& func_body,
|
||||
Counters* counters, wasm::WasmFeatures* detected) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
|
||||
"ExecuteTurbofanCompilation");
|
||||
double decode_ms = 0;
|
||||
@ -5305,7 +5304,7 @@ void TurbofanWasmCompilationUnit::ExecuteCompilation(
|
||||
: nullptr;
|
||||
SourcePositionTable* source_positions =
|
||||
new (mcgraph->zone()) SourcePositionTable(mcgraph->graph());
|
||||
if (!BuildGraphForWasmFunction(env, detected, &decode_ms, mcgraph,
|
||||
if (!BuildGraphForWasmFunction(env, func_body, detected, &decode_ms, mcgraph,
|
||||
node_origins, source_positions)) {
|
||||
// Compilation failed.
|
||||
return;
|
||||
@ -5322,16 +5321,15 @@ void TurbofanWasmCompilationUnit::ExecuteCompilation(
|
||||
}
|
||||
|
||||
// Run the compiler pipeline to generate machine code.
|
||||
auto call_descriptor =
|
||||
GetWasmCallDescriptor(&zone, wasm_unit_->func_body_.sig);
|
||||
auto call_descriptor = GetWasmCallDescriptor(&zone, func_body.sig);
|
||||
if (mcgraph->machine()->Is32()) {
|
||||
call_descriptor = GetI32WasmCallDescriptor(&zone, call_descriptor);
|
||||
}
|
||||
|
||||
std::unique_ptr<OptimizedCompilationJob> job(Pipeline::NewWasmCompilationJob(
|
||||
&info, wasm_unit_->wasm_engine_, mcgraph, call_descriptor,
|
||||
source_positions, node_origins, wasm_unit_->func_body_,
|
||||
wasm_unit_->native_module_, wasm_unit_->func_index_));
|
||||
source_positions, node_origins, func_body, wasm_unit_->native_module_,
|
||||
wasm_unit_->func_index_));
|
||||
if (job->ExecuteJob() == CompilationJob::SUCCEEDED) {
|
||||
wasm_unit_->SetResult(info.wasm_code(), counters);
|
||||
}
|
||||
@ -5340,9 +5338,8 @@ void TurbofanWasmCompilationUnit::ExecuteCompilation(
|
||||
PrintF(
|
||||
"wasm-compilation phase 1 ok: %u bytes, %0.3f ms decode, %zu nodes, "
|
||||
"%0.3f ms pipeline\n",
|
||||
static_cast<unsigned>(wasm_unit_->func_body_.end -
|
||||
wasm_unit_->func_body_.start),
|
||||
decode_ms, node_count, pipeline_ms);
|
||||
static_cast<unsigned>(func_body.end - func_body.start), decode_ms,
|
||||
node_count, pipeline_ms);
|
||||
}
|
||||
// TODO(bradnelson): Improve histogram handling of size_t.
|
||||
counters->wasm_compile_function_peak_memory_bytes()->AddSample(
|
||||
|
@ -51,13 +51,14 @@ class TurbofanWasmCompilationUnit {
|
||||
~TurbofanWasmCompilationUnit();
|
||||
|
||||
bool BuildGraphForWasmFunction(wasm::CompilationEnv* env,
|
||||
const wasm::FunctionBody& func_body,
|
||||
wasm::WasmFeatures* detected,
|
||||
double* decode_ms, MachineGraph* mcgraph,
|
||||
NodeOriginTable* node_origins,
|
||||
SourcePositionTable* source_positions);
|
||||
|
||||
void ExecuteCompilation(wasm::CompilationEnv*, Counters*,
|
||||
wasm::WasmFeatures* detected);
|
||||
void ExecuteCompilation(wasm::CompilationEnv*, const wasm::FunctionBody&,
|
||||
Counters*, wasm::WasmFeatures* detected);
|
||||
|
||||
private:
|
||||
wasm::WasmCompilationUnit* const wasm_unit_;
|
||||
|
@ -1875,6 +1875,7 @@ class LiftoffCompiler {
|
||||
} // namespace
|
||||
|
||||
bool LiftoffCompilationUnit::ExecuteCompilation(CompilationEnv* env,
|
||||
const FunctionBody& func_body,
|
||||
Counters* counters,
|
||||
WasmFeatures* detected) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
|
||||
@ -1886,13 +1887,12 @@ bool LiftoffCompilationUnit::ExecuteCompilation(CompilationEnv* env,
|
||||
|
||||
Zone zone(wasm_unit_->wasm_engine_->allocator(), "LiftoffCompilationZone");
|
||||
const WasmModule* module = env ? env->module : nullptr;
|
||||
auto call_descriptor =
|
||||
compiler::GetWasmCallDescriptor(&zone, wasm_unit_->func_body_.sig);
|
||||
auto call_descriptor = compiler::GetWasmCallDescriptor(&zone, func_body.sig);
|
||||
base::Optional<TimedHistogramScope> liftoff_compile_time_scope(
|
||||
base::in_place, counters->liftoff_compile_time());
|
||||
WasmFullDecoder<Decoder::kValidate, LiftoffCompiler> decoder(
|
||||
&zone, module, wasm_unit_->native_module_->enabled_features(), detected,
|
||||
wasm_unit_->func_body_, call_descriptor, env, &zone);
|
||||
func_body, call_descriptor, env, &zone);
|
||||
decoder.Decode();
|
||||
liftoff_compile_time_scope.reset();
|
||||
LiftoffCompiler* compiler = &decoder.interface();
|
||||
@ -1910,9 +1910,7 @@ bool LiftoffCompilationUnit::ExecuteCompilation(CompilationEnv* env,
|
||||
PrintF(
|
||||
"wasm-compilation liftoff phase 1 ok: %u bytes, %0.3f ms decode and "
|
||||
"compile\n",
|
||||
static_cast<unsigned>(wasm_unit_->func_body_.end -
|
||||
wasm_unit_->func_body_.start),
|
||||
compile_ms);
|
||||
static_cast<unsigned>(func_body.end - func_body.start), compile_ms);
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
|
@ -15,6 +15,7 @@ class Counters;
|
||||
namespace wasm {
|
||||
|
||||
struct CompilationEnv;
|
||||
struct FunctionBody;
|
||||
class WasmCompilationUnit;
|
||||
struct WasmFeatures;
|
||||
|
||||
@ -23,7 +24,8 @@ class LiftoffCompilationUnit final {
|
||||
explicit LiftoffCompilationUnit(WasmCompilationUnit* wasm_unit)
|
||||
: wasm_unit_(wasm_unit) {}
|
||||
|
||||
bool ExecuteCompilation(CompilationEnv*, Counters*, WasmFeatures* detected);
|
||||
bool ExecuteCompilation(CompilationEnv*, const FunctionBody&, Counters*,
|
||||
WasmFeatures* detected);
|
||||
|
||||
private:
|
||||
WasmCompilationUnit* const wasm_unit_;
|
||||
|
@ -65,6 +65,14 @@ struct CompilationEnv {
|
||||
lower_simd(lower_simd) {}
|
||||
};
|
||||
|
||||
// The wire bytes are either owned by the StreamingDecoder, or (after streaming)
|
||||
// by the NativeModule. This class abstracts over the storage location.
|
||||
class WireBytesStorage {
|
||||
public:
|
||||
virtual ~WireBytesStorage() = default;
|
||||
virtual Vector<const uint8_t> GetCode(WireBytesRef) const = 0;
|
||||
};
|
||||
|
||||
// The implementation of {CompilationState} lives in module-compiler.cc.
|
||||
// This is the PIMPL interface to that private class.
|
||||
class CompilationState {
|
||||
@ -75,6 +83,10 @@ class CompilationState {
|
||||
|
||||
void SetError(uint32_t func_index, const ResultBase& error_result);
|
||||
|
||||
void SetWireBytesStorage(std::shared_ptr<WireBytesStorage>);
|
||||
|
||||
std::shared_ptr<WireBytesStorage> GetWireBytesStorage();
|
||||
|
||||
private:
|
||||
friend class NativeModule;
|
||||
CompilationState() = delete;
|
||||
|
@ -36,11 +36,9 @@ ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier() {
|
||||
}
|
||||
|
||||
WasmCompilationUnit::WasmCompilationUnit(WasmEngine* wasm_engine,
|
||||
NativeModule* native_module,
|
||||
FunctionBody body, int index,
|
||||
NativeModule* native_module, int index,
|
||||
ExecutionTier mode)
|
||||
: wasm_engine_(wasm_engine),
|
||||
func_body_(body),
|
||||
func_index_(index),
|
||||
native_module_(native_module),
|
||||
mode_(mode) {
|
||||
@ -62,14 +60,20 @@ WasmCompilationUnit::WasmCompilationUnit(WasmEngine* wasm_engine,
|
||||
// {TurbofanWasmCompilationUnit} can be opaque in the header file.
|
||||
WasmCompilationUnit::~WasmCompilationUnit() = default;
|
||||
|
||||
void WasmCompilationUnit::ExecuteCompilation(CompilationEnv* env,
|
||||
Counters* counters,
|
||||
WasmFeatures* detected) {
|
||||
void WasmCompilationUnit::ExecuteCompilation(
|
||||
CompilationEnv* env, std::shared_ptr<WireBytesStorage> wire_bytes_storage,
|
||||
Counters* counters, WasmFeatures* detected) {
|
||||
const WasmModule* module = native_module_->module();
|
||||
DCHECK_EQ(module, env->module);
|
||||
|
||||
auto* func = &env->module->functions[func_index_];
|
||||
Vector<const uint8_t> code = wire_bytes_storage->GetCode(func->code);
|
||||
wasm::FunctionBody func_body{func->sig, func->code.offset(), code.start(),
|
||||
code.end()};
|
||||
|
||||
auto size_histogram =
|
||||
SELECT_WASM_COUNTER(counters, module->origin, wasm, function_size_bytes);
|
||||
size_histogram->AddSample(
|
||||
static_cast<int>(func_body_.end - func_body_.start));
|
||||
size_histogram->AddSample(static_cast<int>(func_body.end - func_body.start));
|
||||
auto timed_histogram = SELECT_WASM_COUNTER(counters, module->origin,
|
||||
wasm_compile, function_time);
|
||||
TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
|
||||
@ -81,12 +85,15 @@ void WasmCompilationUnit::ExecuteCompilation(CompilationEnv* env,
|
||||
|
||||
switch (mode_) {
|
||||
case ExecutionTier::kBaseline:
|
||||
if (liftoff_unit_->ExecuteCompilation(env, counters, detected)) break;
|
||||
if (liftoff_unit_->ExecuteCompilation(env, func_body, counters,
|
||||
detected)) {
|
||||
break;
|
||||
}
|
||||
// Otherwise, fall back to turbofan.
|
||||
SwitchMode(ExecutionTier::kOptimized);
|
||||
V8_FALLTHROUGH;
|
||||
case ExecutionTier::kOptimized:
|
||||
turbofan_unit_->ExecuteCompilation(env, counters, detected);
|
||||
turbofan_unit_->ExecuteCompilation(env, func_body, counters, detected);
|
||||
break;
|
||||
case ExecutionTier::kInterpreter:
|
||||
UNREACHABLE(); // TODO(titzer): compile interpreter entry stub.
|
||||
@ -126,10 +133,12 @@ bool WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
|
||||
wire_bytes.start() + function->code.offset(),
|
||||
wire_bytes.start() + function->code.end_offset()};
|
||||
|
||||
WasmCompilationUnit unit(isolate->wasm_engine(), native_module, function_body,
|
||||
WasmCompilationUnit unit(isolate->wasm_engine(), native_module,
|
||||
function->func_index, mode);
|
||||
CompilationEnv env = native_module->CreateCompilationEnv();
|
||||
unit.ExecuteCompilation(&env, isolate->counters(), detected);
|
||||
unit.ExecuteCompilation(
|
||||
&env, native_module->compilation_state()->GetWireBytesStorage(),
|
||||
isolate->counters(), detected);
|
||||
return !unit.failed();
|
||||
}
|
||||
|
||||
|
@ -37,12 +37,13 @@ class WasmCompilationUnit final {
|
||||
// typically means to hold a std::shared_ptr<Counters>).
|
||||
// If used exclusively from a foreground thread, Isolate::counters() may be
|
||||
// used by callers to pass Counters.
|
||||
WasmCompilationUnit(WasmEngine*, NativeModule*, FunctionBody, int index,
|
||||
WasmCompilationUnit(WasmEngine*, NativeModule*, int index,
|
||||
ExecutionTier = GetDefaultExecutionTier());
|
||||
|
||||
~WasmCompilationUnit();
|
||||
|
||||
void ExecuteCompilation(CompilationEnv*, Counters*, WasmFeatures* detected);
|
||||
void ExecuteCompilation(CompilationEnv*, std::shared_ptr<WireBytesStorage>,
|
||||
Counters*, WasmFeatures* detected);
|
||||
|
||||
NativeModule* native_module() const { return native_module_; }
|
||||
ExecutionTier mode() const { return mode_; }
|
||||
@ -58,10 +59,9 @@ class WasmCompilationUnit final {
|
||||
friend class LiftoffCompilationUnit;
|
||||
friend class compiler::TurbofanWasmCompilationUnit;
|
||||
|
||||
WasmEngine* wasm_engine_;
|
||||
FunctionBody func_body_;
|
||||
int func_index_;
|
||||
NativeModule* native_module_;
|
||||
WasmEngine* const wasm_engine_;
|
||||
const int func_index_;
|
||||
NativeModule* const native_module_;
|
||||
ExecutionTier mode_;
|
||||
WasmCode* result_ = nullptr;
|
||||
|
||||
|
@ -821,7 +821,7 @@ DecodeResult BuildTFGraph(AccountingAllocator* allocator,
|
||||
const WasmFeatures& enabled,
|
||||
const wasm::WasmModule* module,
|
||||
compiler::WasmGraphBuilder* builder,
|
||||
WasmFeatures* detected, FunctionBody& body,
|
||||
WasmFeatures* detected, const FunctionBody& body,
|
||||
compiler::NodeOriginTable* node_origins) {
|
||||
Zone zone(allocator, ZONE_NAME);
|
||||
WasmFullDecoder<Decoder::kValidate, WasmGraphBuildingInterface> decoder(
|
||||
|
@ -26,7 +26,7 @@ struct WasmFeatures;
|
||||
DecodeResult BuildTFGraph(AccountingAllocator* allocator,
|
||||
const WasmFeatures& enabled, const WasmModule* module,
|
||||
compiler::WasmGraphBuilder* builder,
|
||||
WasmFeatures* detected, FunctionBody& body,
|
||||
WasmFeatures* detected, const FunctionBody& body,
|
||||
compiler::NodeOriginTable* node_origins);
|
||||
|
||||
} // namespace wasm
|
||||
|
@ -148,6 +148,23 @@ class CompilationStateImpl {
|
||||
error.str());
|
||||
}
|
||||
|
||||
std::shared_ptr<WireBytesStorage> GetSharedWireBytesStorage() const {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
DCHECK_NOT_NULL(wire_bytes_storage_);
|
||||
return wire_bytes_storage_;
|
||||
}
|
||||
|
||||
void SetWireBytesStorage(
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
wire_bytes_storage_ = wire_bytes_storage;
|
||||
}
|
||||
|
||||
std::shared_ptr<WireBytesStorage> GetWireBytesStorage() {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
return wire_bytes_storage_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct CompilationError {
|
||||
uint32_t const func_index;
|
||||
@ -236,6 +253,11 @@ class CompilationStateImpl {
|
||||
// is currently scheduled.
|
||||
LogCodesTask* log_codes_task_ = nullptr;
|
||||
|
||||
// Abstraction over the storage of the wire bytes. Held in a shared_ptr so
|
||||
// that background compilation jobs can keep the storage alive while
|
||||
// compiling.
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
|
||||
|
||||
// End of fields protected by {mutex_}.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -419,6 +441,15 @@ void CompilationState::SetError(uint32_t func_index,
|
||||
Impl(this)->SetError(func_index, error_result);
|
||||
}
|
||||
|
||||
void CompilationState::SetWireBytesStorage(
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
|
||||
Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
|
||||
}
|
||||
|
||||
std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage() {
|
||||
return Impl(this)->GetWireBytesStorage();
|
||||
}
|
||||
|
||||
CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
|
||||
|
||||
// static
|
||||
@ -456,15 +487,15 @@ WasmCode* LazyCompileFunction(Isolate* isolate, NativeModule* native_module,
|
||||
const uint8_t* module_start = native_module->wire_bytes().start();
|
||||
|
||||
const WasmFunction* func = &native_module->module()->functions[func_index];
|
||||
FunctionBody body{func->sig, func->code.offset(),
|
||||
module_start + func->code.offset(),
|
||||
module_start + func->code.end_offset()};
|
||||
FunctionBody func_body{func->sig, func->code.offset(),
|
||||
module_start + func->code.offset(),
|
||||
module_start + func->code.end_offset()};
|
||||
|
||||
WasmCompilationUnit unit(isolate->wasm_engine(), native_module, body,
|
||||
func_index);
|
||||
WasmCompilationUnit unit(isolate->wasm_engine(), native_module, func_index);
|
||||
CompilationEnv env = native_module->CreateCompilationEnv();
|
||||
unit.ExecuteCompilation(
|
||||
&env, isolate->counters(),
|
||||
&env, native_module->compilation_state()->GetWireBytesStorage(),
|
||||
isolate->counters(),
|
||||
Impl(native_module->compilation_state())->detected_features());
|
||||
|
||||
// If there is a pending error, something really went wrong. The module was
|
||||
@ -519,19 +550,17 @@ class CompilationUnitBuilder {
|
||||
WasmEngine* wasm_engine)
|
||||
: native_module_(native_module), wasm_engine_(wasm_engine) {}
|
||||
|
||||
void AddUnit(const WasmFunction* function, uint32_t buffer_offset,
|
||||
Vector<const uint8_t> bytes) {
|
||||
void AddUnit(uint32_t func_index) {
|
||||
switch (compilation_state()->compile_mode()) {
|
||||
case CompileMode::kTiering:
|
||||
tiering_units_.emplace_back(CreateUnit(function, buffer_offset, bytes,
|
||||
ExecutionTier::kOptimized));
|
||||
baseline_units_.emplace_back(CreateUnit(function, buffer_offset, bytes,
|
||||
ExecutionTier::kBaseline));
|
||||
tiering_units_.emplace_back(
|
||||
CreateUnit(func_index, ExecutionTier::kOptimized));
|
||||
baseline_units_.emplace_back(
|
||||
CreateUnit(func_index, ExecutionTier::kBaseline));
|
||||
return;
|
||||
case CompileMode::kRegular:
|
||||
baseline_units_.emplace_back(
|
||||
CreateUnit(function, buffer_offset, bytes,
|
||||
WasmCompilationUnit::GetDefaultExecutionTier()));
|
||||
baseline_units_.emplace_back(CreateUnit(
|
||||
func_index, WasmCompilationUnit::GetDefaultExecutionTier()));
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
@ -550,14 +579,10 @@ class CompilationUnitBuilder {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<WasmCompilationUnit> CreateUnit(const WasmFunction* function,
|
||||
uint32_t buffer_offset,
|
||||
Vector<const uint8_t> bytes,
|
||||
std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
|
||||
ExecutionTier mode) {
|
||||
return base::make_unique<WasmCompilationUnit>(
|
||||
wasm_engine_, native_module_,
|
||||
FunctionBody{function->sig, buffer_offset, bytes.begin(), bytes.end()},
|
||||
function->func_index, mode);
|
||||
return base::make_unique<WasmCompilationUnit>(wasm_engine_, native_module_,
|
||||
func_index, mode);
|
||||
}
|
||||
|
||||
CompilationStateImpl* compilation_state() const {
|
||||
@ -616,7 +641,8 @@ bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
|
||||
// later as soon as Liftoff can compile any function. Then, we can directly
|
||||
// access {unit->mode()} within {ScheduleUnitForFinishing()}.
|
||||
ExecutionTier mode = unit->mode();
|
||||
unit->ExecuteCompilation(env, counters, detected);
|
||||
unit->ExecuteCompilation(env, compilation_state->GetSharedWireBytesStorage(),
|
||||
counters, detected);
|
||||
if (!unit->failed()) compilation_state->ScheduleCodeLogging(unit->result());
|
||||
compilation_state->ScheduleUnitForFinishing(std::move(unit), mode);
|
||||
|
||||
@ -631,13 +657,7 @@ void InitializeCompilationUnits(NativeModule* native_module,
|
||||
uint32_t start = module->num_imported_functions;
|
||||
uint32_t end = start + module->num_declared_functions;
|
||||
for (uint32_t i = start; i < end; ++i) {
|
||||
const WasmFunction* func = &module->functions[i];
|
||||
uint32_t buffer_offset = func->code.offset();
|
||||
Vector<const uint8_t> bytes(wire_bytes.start() + func->code.offset(),
|
||||
func->code.end_offset() - func->code.offset());
|
||||
|
||||
DCHECK_NOT_NULL(native_module);
|
||||
builder.AddUnit(func, buffer_offset, bytes);
|
||||
builder.AddUnit(i);
|
||||
}
|
||||
builder.Commit();
|
||||
}
|
||||
@ -2283,8 +2303,8 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
|
||||
bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
|
||||
uint32_t offset) override;
|
||||
|
||||
bool ProcessCodeSectionHeader(size_t functions_count,
|
||||
uint32_t offset) override;
|
||||
bool ProcessCodeSectionHeader(size_t functions_count, uint32_t offset,
|
||||
std::shared_ptr<WireBytesStorage>) override;
|
||||
|
||||
bool ProcessFunctionBody(Vector<const uint8_t> bytes,
|
||||
uint32_t offset) override;
|
||||
@ -2810,8 +2830,9 @@ bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
|
||||
}
|
||||
|
||||
// Start the code section.
|
||||
bool AsyncStreamingProcessor::ProcessCodeSectionHeader(size_t functions_count,
|
||||
uint32_t offset) {
|
||||
bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
|
||||
size_t functions_count, uint32_t offset,
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
|
||||
TRACE_STREAMING("Start the code section with %zu functions...\n",
|
||||
functions_count);
|
||||
if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
|
||||
@ -2823,6 +2844,8 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(size_t functions_count,
|
||||
// task.
|
||||
job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
|
||||
decoder_.shared_module(), false);
|
||||
job_->native_module_->compilation_state()->SetWireBytesStorage(
|
||||
std::move(wire_bytes_storage));
|
||||
|
||||
auto* compilation_state = Impl(job_->native_module_->compilation_state());
|
||||
compilation_state->SetNumberOfFunctionsToCompile(functions_count);
|
||||
@ -2844,8 +2867,7 @@ bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
|
||||
next_function_, static_cast<uint32_t>(bytes.length()), offset, false);
|
||||
|
||||
uint32_t index = next_function_ + decoder_.module()->num_imported_functions;
|
||||
const WasmFunction* func = &decoder_.module()->functions[index];
|
||||
compilation_unit_builder_->AddUnit(func, offset, bytes);
|
||||
compilation_unit_builder_->AddUnit(index);
|
||||
++next_function_;
|
||||
// This method always succeeds. The return value is necessary to comply with
|
||||
// the StreamingProcessor interface.
|
||||
@ -2870,12 +2892,12 @@ void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
|
||||
bool needs_finish = job_->DecrementAndCheckFinisherCount();
|
||||
if (job_->native_module_ == nullptr) {
|
||||
// We are processing a WebAssembly module without code section. Create the
|
||||
// runtime objects now (would otherwise happen in {PrepareAndStartCompile}.
|
||||
// runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
|
||||
job_->PrepareRuntimeObjects(std::move(result).value());
|
||||
DCHECK(needs_finish);
|
||||
}
|
||||
job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
|
||||
job_->native_module_->set_wire_bytes(std::move(bytes));
|
||||
job_->native_module_->SetWireBytes(std::move(bytes));
|
||||
if (needs_finish) {
|
||||
HandleScope scope(job_->isolate_);
|
||||
SaveContext saved_context(job_->isolate_);
|
||||
@ -2916,8 +2938,7 @@ bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
|
||||
job_->native_module_ = job_->module_object_->native_module();
|
||||
auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
|
||||
job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
|
||||
job_->native_module_->set_wire_bytes(std::move(owned_wire_bytes));
|
||||
|
||||
job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
|
||||
job_->FinishCompile(false);
|
||||
return true;
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ StreamingDecoder::DecodeNumberOfFunctions::NextWithValue(
|
||||
return base::make_unique<DecodeSectionID>(streaming->module_offset());
|
||||
}
|
||||
|
||||
streaming->StartCodeSection(value_);
|
||||
streaming->StartCodeSection(value_, streaming->section_buffers_.back());
|
||||
if (!streaming->ok()) return nullptr;
|
||||
return base::make_unique<DecodeFunctionLength>(
|
||||
section_buffer_, section_buffer_->payload_offset() + bytes_consumed_,
|
||||
@ -442,6 +442,23 @@ StreamingDecoder::StreamingDecoder(
|
||||
: processor_(std::move(processor)),
|
||||
// A module always starts with a module header.
|
||||
state_(new DecodeModuleHeader()) {}
|
||||
|
||||
StreamingDecoder::SectionBuffer* StreamingDecoder::CreateNewBuffer(
|
||||
uint32_t module_offset, uint8_t section_id, size_t length,
|
||||
Vector<const uint8_t> length_bytes) {
|
||||
// Check the order of sections. Unknown sections can appear at any position.
|
||||
if (section_id != kUnknownSectionCode) {
|
||||
if (section_id < next_section_id_) {
|
||||
Error("Unexpected section");
|
||||
return nullptr;
|
||||
}
|
||||
next_section_id_ = section_id + 1;
|
||||
}
|
||||
section_buffers_.emplace_back(std::make_shared<SectionBuffer>(
|
||||
module_offset, section_id, length, length_bytes));
|
||||
return section_buffers_.back().get();
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/vector.h"
|
||||
#include "src/wasm/compilation-environment.h"
|
||||
#include "src/wasm/wasm-constants.h"
|
||||
#include "src/wasm/wasm-result.h"
|
||||
|
||||
@ -39,8 +40,8 @@ class V8_EXPORT_PRIVATE StreamingProcessor {
|
||||
|
||||
// Process the start of the code section. Returns true if the processing
|
||||
// finished successfully and the decoding should continue.
|
||||
virtual bool ProcessCodeSectionHeader(size_t num_functions,
|
||||
uint32_t offset) = 0;
|
||||
virtual bool ProcessCodeSectionHeader(size_t num_functions, uint32_t offset,
|
||||
std::shared_ptr<WireBytesStorage>) = 0;
|
||||
|
||||
// Process a function body. Returns true if the processing finished
|
||||
// successfully and the decoding should continue.
|
||||
@ -104,7 +105,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
|
||||
// The SectionBuffer is the data object for the content of a single section.
|
||||
// It stores all bytes of the section (including section id and section
|
||||
// length), and the offset where the actual payload starts.
|
||||
class SectionBuffer {
|
||||
class SectionBuffer : public WireBytesStorage {
|
||||
public:
|
||||
// id: The section id.
|
||||
// payload_length: The length of the payload.
|
||||
@ -124,6 +125,13 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
|
||||
return static_cast<SectionCode>(bytes_.start()[0]);
|
||||
}
|
||||
|
||||
Vector<const uint8_t> GetCode(WireBytesRef ref) const final {
|
||||
DCHECK_LE(module_offset_, ref.offset());
|
||||
uint32_t offset_in_code_buffer = ref.offset() - module_offset_;
|
||||
return bytes().SubVector(offset_in_code_buffer,
|
||||
offset_in_code_buffer + ref.length());
|
||||
}
|
||||
|
||||
uint32_t module_offset() const { return module_offset_; }
|
||||
Vector<uint8_t> bytes() const { return bytes_.as_vector(); }
|
||||
Vector<uint8_t> payload() const { return bytes() + payload_offset_; }
|
||||
@ -199,21 +207,9 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
|
||||
class DecodeFunctionBody;
|
||||
|
||||
// Creates a buffer for the next section of the module.
|
||||
SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t id,
|
||||
SectionBuffer* CreateNewBuffer(uint32_t module_offset, uint8_t section_id,
|
||||
size_t length,
|
||||
Vector<const uint8_t> length_bytes) {
|
||||
// Check the order of sections. Unknown sections can appear at any position.
|
||||
if (id != kUnknownSectionCode) {
|
||||
if (id < next_section_id_) {
|
||||
Error("Unexpected section");
|
||||
return nullptr;
|
||||
}
|
||||
next_section_id_ = id + 1;
|
||||
}
|
||||
section_buffers_.emplace_back(
|
||||
new SectionBuffer(module_offset, id, length, length_bytes));
|
||||
return section_buffers_.back().get();
|
||||
}
|
||||
Vector<const uint8_t> length_bytes);
|
||||
|
||||
std::unique_ptr<DecodingState> Error(VoidResult result) {
|
||||
if (ok_) processor_->OnError(std::move(result));
|
||||
@ -242,12 +238,14 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
void StartCodeSection(size_t num_functions) {
|
||||
void StartCodeSection(size_t num_functions,
|
||||
std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
|
||||
if (!ok_) return;
|
||||
// The offset passed to {ProcessCodeSectionHeader} is an error offset and
|
||||
// not the start offset of a buffer. Therefore we need the -1 here.
|
||||
if (!processor_->ProcessCodeSectionHeader(num_functions,
|
||||
module_offset() - 1)) {
|
||||
module_offset() - 1,
|
||||
std::move(wire_bytes_storage))) {
|
||||
ok_ = false;
|
||||
}
|
||||
}
|
||||
@ -267,7 +265,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
|
||||
std::unique_ptr<StreamingProcessor> processor_;
|
||||
bool ok_ = true;
|
||||
std::unique_ptr<DecodingState> state_;
|
||||
std::vector<std::unique_ptr<SectionBuffer>> section_buffers_;
|
||||
std::vector<std::shared_ptr<SectionBuffer>> section_buffers_;
|
||||
uint32_t module_offset_ = 0;
|
||||
size_t total_size_ = 0;
|
||||
uint8_t next_section_id_ = kFirstSectionInModule;
|
||||
|
@ -746,6 +746,30 @@ Vector<byte> NativeModule::AllocateForCode(size_t size) {
|
||||
return {reinterpret_cast<byte*>(code_space.begin()), code_space.size()};
|
||||
}
|
||||
|
||||
namespace {
|
||||
class NativeModuleWireBytesStorage final : public WireBytesStorage {
|
||||
public:
|
||||
explicit NativeModuleWireBytesStorage(NativeModule* native_module)
|
||||
: native_module_(native_module) {}
|
||||
|
||||
Vector<const uint8_t> GetCode(WireBytesRef ref) const final {
|
||||
return native_module_->wire_bytes().SubVector(ref.offset(),
|
||||
ref.end_offset());
|
||||
}
|
||||
|
||||
private:
|
||||
NativeModule* const native_module_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void NativeModule::SetWireBytes(OwnedVector<const byte> wire_bytes) {
|
||||
wire_bytes_ = std::move(wire_bytes);
|
||||
if (!wire_bytes.is_empty()) {
|
||||
compilation_state_->SetWireBytesStorage(
|
||||
std::make_shared<NativeModuleWireBytesStorage>(this));
|
||||
}
|
||||
}
|
||||
|
||||
WasmCode* NativeModule::Lookup(Address pc) const {
|
||||
base::MutexGuard lock(&allocation_mutex_);
|
||||
if (owned_code_.empty()) return nullptr;
|
||||
|
@ -329,11 +329,10 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
||||
void set_lazy_compile_frozen(bool frozen) { lazy_compile_frozen_ = frozen; }
|
||||
bool lazy_compile_frozen() const { return lazy_compile_frozen_; }
|
||||
Vector<const byte> wire_bytes() const { return wire_bytes_.as_vector(); }
|
||||
void set_wire_bytes(OwnedVector<const byte> wire_bytes) {
|
||||
wire_bytes_ = std::move(wire_bytes);
|
||||
}
|
||||
const WasmModule* module() const { return module_.get(); }
|
||||
|
||||
void SetWireBytes(OwnedVector<const byte> wire_bytes);
|
||||
|
||||
WasmCode* Lookup(Address) const;
|
||||
|
||||
WasmImportWrapperCache* import_wrapper_cache() const {
|
||||
|
@ -185,7 +185,7 @@ Handle<WasmModuleObject> WasmModuleObject::New(
|
||||
auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
|
||||
isolate, enabled, native_memory_estimate,
|
||||
wasm::NativeModule::kCanAllocateMoreMemory, std::move(shared_module));
|
||||
native_module->set_wire_bytes(std::move(wire_bytes));
|
||||
native_module->SetWireBytes(std::move(wire_bytes));
|
||||
native_module->SetRuntimeStubs(isolate);
|
||||
|
||||
// Delegate to the shared {WasmModuleObject::New} allocator.
|
||||
|
@ -183,7 +183,7 @@ uint32_t TestingModuleBuilder::AddBytes(Vector<const byte> bytes) {
|
||||
OwnedVector<uint8_t> new_bytes = OwnedVector<uint8_t>::New(new_size);
|
||||
memcpy(new_bytes.start(), old_bytes.start(), old_size);
|
||||
memcpy(new_bytes.start() + bytes_offset, bytes.start(), bytes.length());
|
||||
native_module_->set_wire_bytes(std::move(new_bytes));
|
||||
native_module_->SetWireBytes(std::move(new_bytes));
|
||||
return bytes_offset;
|
||||
}
|
||||
|
||||
@ -419,11 +419,12 @@ void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
|
||||
func_wire_bytes.start(), func_wire_bytes.end()};
|
||||
NativeModule* native_module =
|
||||
builder_->instance_object()->module_object()->native_module();
|
||||
WasmCompilationUnit unit(isolate()->wasm_engine(), native_module, func_body,
|
||||
WasmCompilationUnit unit(isolate()->wasm_engine(), native_module,
|
||||
function_->func_index, tier);
|
||||
WasmFeatures unused_detected_features;
|
||||
unit.ExecuteCompilation(&env, isolate()->counters(),
|
||||
&unused_detected_features);
|
||||
unit.ExecuteCompilation(
|
||||
&env, native_module->compilation_state()->GetWireBytesStorage(),
|
||||
isolate()->counters(), &unused_detected_features);
|
||||
CHECK(!unit.failed());
|
||||
if (WasmCode::ShouldBeLogged(isolate())) unit.result()->LogCode(isolate());
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ class MockStreamingProcessor : public StreamingProcessor {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessCodeSectionHeader(size_t num_functions,
|
||||
uint32_t offset) override {
|
||||
bool ProcessCodeSectionHeader(size_t num_functions, uint32_t offset,
|
||||
std::shared_ptr<WireBytesStorage>) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user