blob: deda9b97c73f748c02e6c51b54e7ea5d90c564ed [file] [log] [blame]
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/function-compiler.h"
#include "src/compiler/wasm-compiler.h"
#include "src/counters.h"
#include "src/macro-assembler-inl.h"
#include "src/wasm/baseline/liftoff-compiler.h"
#include "src/wasm/wasm-code-manager.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace {
const char* GetExecutionTierAsString(ExecutionTier tier) {
switch (tier) {
case ExecutionTier::kBaseline:
return "liftoff";
case ExecutionTier::kOptimized:
return "turbofan";
case ExecutionTier::kInterpreter:
return "interpreter";
}
UNREACHABLE();
}
} // namespace
// static
ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier(
const WasmModule* module) {
return FLAG_liftoff && module->origin == kWasmOrigin
? ExecutionTier::kBaseline
: ExecutionTier::kOptimized;
}
WasmCompilationUnit::WasmCompilationUnit(WasmEngine* wasm_engine, int index,
ExecutionTier tier)
: wasm_engine_(wasm_engine), func_index_(index), tier_(tier) {
if (V8_UNLIKELY(FLAG_wasm_tier_mask_for_testing) && index < 32 &&
(FLAG_wasm_tier_mask_for_testing & (1 << index))) {
tier = ExecutionTier::kOptimized;
}
SwitchTier(tier);
}
// Declared here such that {LiftoffCompilationUnit} and
// {TurbofanWasmCompilationUnit} can be opaque in the header file.
WasmCompilationUnit::~WasmCompilationUnit() = default;
void WasmCompilationUnit::ExecuteCompilation(
CompilationEnv* env, NativeModule* native_module,
std::shared_ptr<WireBytesStorage> wire_bytes_storage, Counters* counters,
WasmFeatures* detected) {
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, env->module->origin, wasm,
function_size_bytes);
size_histogram->AddSample(static_cast<int>(func_body.end - func_body.start));
auto timed_histogram = SELECT_WASM_COUNTER(counters, env->module->origin,
wasm_compile, function_time);
TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
if (FLAG_trace_wasm_compiler) {
PrintF("Compiling wasm function %d with %s\n\n", func_index_,
GetExecutionTierAsString(tier_));
}
switch (tier_) {
case ExecutionTier::kBaseline:
if (liftoff_unit_->ExecuteCompilation(env, native_module, func_body,
counters, detected)) {
break;
}
// Otherwise, fall back to turbofan.
SwitchTier(ExecutionTier::kOptimized);
// TODO(wasm): We could actually stop or remove the tiering unit for this
// function to avoid compiling it twice with TurboFan.
V8_FALLTHROUGH;
case ExecutionTier::kOptimized:
turbofan_unit_->ExecuteCompilation(env, native_module, func_body,
counters, detected);
break;
case ExecutionTier::kInterpreter:
UNREACHABLE(); // TODO(titzer): compile interpreter entry stub.
}
}
void WasmCompilationUnit::SwitchTier(ExecutionTier new_tier) {
// This method is being called in the constructor, where neither
// {liftoff_unit_} nor {turbofan_unit_} are set, or to switch tier from
// kLiftoff to kTurbofan, in which case {liftoff_unit_} is already set.
tier_ = new_tier;
switch (new_tier) {
case ExecutionTier::kBaseline:
DCHECK(!turbofan_unit_);
DCHECK(!liftoff_unit_);
liftoff_unit_.reset(new LiftoffCompilationUnit(this));
return;
case ExecutionTier::kOptimized:
DCHECK(!turbofan_unit_);
liftoff_unit_.reset();
turbofan_unit_.reset(new compiler::TurbofanWasmCompilationUnit(this));
return;
case ExecutionTier::kInterpreter:
UNREACHABLE(); // TODO(titzer): allow compiling interpreter entry stub.
}
UNREACHABLE();
}
// static
void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
NativeModule* native_module,
WasmFeatures* detected,
const WasmFunction* function,
ExecutionTier tier) {
ModuleWireBytes wire_bytes(native_module->wire_bytes());
FunctionBody function_body{function->sig, function->code.offset(),
wire_bytes.start() + function->code.offset(),
wire_bytes.start() + function->code.end_offset()};
WasmCompilationUnit unit(isolate->wasm_engine(), function->func_index, tier);
CompilationEnv env = native_module->CreateCompilationEnv();
unit.ExecuteCompilation(
&env, native_module,
native_module->compilation_state()->GetWireBytesStorage(),
isolate->counters(), detected);
}
void WasmCompilationUnit::SetResult(WasmCode* code, Counters* counters) {
DCHECK_NULL(result_);
result_ = code;
code->native_module()->PublishCode(code);
counters->wasm_generated_code_size()->Increment(
static_cast<int>(code->instructions().size()));
counters->wasm_reloc_size()->Increment(
static_cast<int>(code->reloc_info().size()));
}
} // namespace wasm
} // namespace internal
} // namespace v8