/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/wasm/function-compiler.cc
274 строки
12 KB
Michaël Zasso
deps: update V8 to 14.3.127.12
13 ноя 2025, 17:08
Не верифицирован
13 ноя 2025, 17:08
53379f3
Код
Авторство
О чём код?
// 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 <optional> #include "src/base/fpu.h" #include "src/codegen/compiler.h" #include "src/codegen/optimized-compilation-info.h" #include "src/compiler/turboshaft/wasm-turboshaft-compiler.h" #include "src/compiler/wasm-compiler.h" #include "src/handles/handles-inl.h" #include "src/logging/counters-scopes.h" #include "src/logging/log.h" #include "src/objects/code-inl.h" #include "src/wasm/baseline/liftoff-compiler.h" #include "src/wasm/compilation-environment-inl.h" #include "src/wasm/turboshaft-graph-interface.h" #include "src/wasm/wasm-code-manager.h" #include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-engine.h" #include "src/wasm/wasm-export-wrapper-cache.h" namespace v8::internal::wasm { WasmCompilationResult WasmCompilationUnit::ExecuteCompilation( CompilationEnv* env, const WireBytesStorage* wire_bytes_storage, DelayedCounterUpdates* counter_updates, WasmDetectedFeatures* detected) { DCHECK_GE(func_index_, static_cast<int>(env->module->num_imported_functions)); const WasmFunction* func = &env->module->functions[func_index_]; base::Vector<const uint8_t> code = wire_bytes_storage->GetCode(func->code); bool is_shared = env->module->type(func->sig_index).is_shared; wasm::FunctionBody func_body{func->sig, func->code.offset(), code.begin(), code.end(), is_shared}; base::ElapsedTimer compile_timer; if (base::TimeTicks::IsHighResolution()) compile_timer.Start(); // Before executing compilation, make sure that the function was validated. // Both Liftoff and TurboFan compilation do not perform validation, so can // only run on valid functions. if (V8_UNLIKELY(!env->module->function_was_validated(func_index_))) { // This code path can only be reached in // - eager compilation mode, // - with lazy validation, // - with PGO (which compiles some functions eagerly), or // - with compilation hints (which compiles some functions eagerly). DCHECK(!v8_flags.wasm_lazy_compilation || v8_flags.wasm_lazy_validation || v8_flags.experimental_wasm_pgo_from_file || v8_flags.experimental_wasm_compilation_hints); Zone validation_zone{GetWasmEngine()->allocator(), ZONE_NAME}; if (ValidateFunctionBody(&validation_zone, env->enabled_features, env->module, detected, func_body) .failed()) { return {}; } env->module->set_function_validated(func_index_); } if (v8_flags.trace_wasm_compiler) { PrintF("Compiling wasm function %d with %s\n", func_index_, ExecutionTierToString(tier_)); } WasmCompilationResult result; int declared_index = declared_function_index(env->module, func_index_); switch (tier_) { case ExecutionTier::kNone: #if V8_ENABLE_DRUMBRAKE case ExecutionTier::kInterpreter: #endif // V8_ENABLE_DRUMBRAKE UNREACHABLE(); case ExecutionTier::kLiftoff: { // The --wasm-tier-mask-for-testing flag can force functions to be // compiled with TurboFan, and the --wasm-debug-mask-for-testing can force // them to be compiled for debugging, see documentation. bool try_liftoff = true; if (V8_UNLIKELY(v8_flags.wasm_tier_mask_for_testing != 0)) { bool must_use_liftoff = v8_flags.liftoff_only || for_debugging_ != ForDebugging::kNotForDebugging; bool tiering_requested = declared_index < 32 && (v8_flags.wasm_tier_mask_for_testing & (1 << declared_index)); if (!must_use_liftoff && tiering_requested) try_liftoff = false; } if (V8_LIKELY(try_liftoff)) { LiftoffOptions options{.func_index = func_index_, .for_debugging = for_debugging_, .counter_updates = counter_updates, .detected_features = detected}; // We do not use the debug side table, we only (optionally) pass it to // cover different code paths in Liftoff for testing. std::unique_ptr<DebugSideTable> unused_debug_sidetable; if (V8_UNLIKELY(declared_index < 32 && (v8_flags.wasm_debug_mask_for_testing & (1 << declared_index)) != 0)) { options.debug_sidetable = &unused_debug_sidetable; if (!for_debugging_) options.for_debugging = kForDebugging; } if (v8_flags.wasm_code_coverage && options.for_debugging == kNotForDebugging) { options.for_debugging = kForDebugging; } result = ExecuteLiftoffCompilation(env, func_body, options); if (result.succeeded()) break; } // If --liftoff-only, do not fall back to turbofan, even if compilation // failed. if (v8_flags.liftoff_only) break; // If Liftoff failed, fall back to TurboFan. // TODO(wasm): We could actually stop or remove the tiering unit for this // function to avoid compiling it twice with TurboFan. [[fallthrough]]; } case ExecutionTier::kTurbofan: { #ifdef V8_ENABLE_TURBOFAN compiler::WasmCompilationData data(func_body); data.func_index = func_index_; data.wire_bytes_storage = wire_bytes_storage; result = compiler::turboshaft::ExecuteTurboshaftWasmCompilation( env, data, detected, counter_updates); // In exceptional cases it can happen that compilation requests for // debugging end up being executed by Turbofan, e.g. if Liftoff bails out // because of unsupported features or the --wasm-tier-mask-for-testing is // set. In that case we set the for_debugging field for the TurboFan // result to match the requested for_debugging_. result.for_debugging = for_debugging_; #endif break; } } DCHECK(result.succeeded()); counter_updates->AddIncrement(&Counters::wasm_generated_code_size, result.code_desc.instr_size); counter_updates->AddIncrement(&Counters::wasm_reloc_size, result.code_desc.reloc_size); counter_updates->AddIncrement(&Counters::wasm_deopt_data_size, static_cast<int>(result.deopt_data.size())); result.func_index = func_index_; if (compile_timer.IsStarted()) { base::TimeDelta compile_time = compile_timer.Elapsed(); if (func_body.end - func_body.start >= 100 * KB) { DelayedCounterUpdates::GetHistogramFn huge_size_histogram = is_asmjs_module(env->module) ? &Counters::wasm_asm_huge_function_size_bytes : &Counters::wasm_wasm_huge_function_size_bytes; counter_updates->AddSample( huge_size_histogram, static_cast<int>(func_body.end - func_body.start)); counter_updates->AddTimedSample( &Counters::wasm_compile_huge_function_time, compile_time); } DelayedCounterUpdates::GetTimedHistogramFn compile_time_histogram = is_asmjs_module(env->module) ? &Counters::wasm_compile_asm_function_time : &Counters::wasm_compile_wasm_function_time; counter_updates->AddTimedSample(compile_time_histogram, compile_time); } return result; } // static void WasmCompilationUnit::CompileWasmFunction(NativeModule* native_module, WasmDetectedFeatures* detected, const WasmFunction* function, ExecutionTier tier) { ModuleWireBytes wire_bytes(native_module->wire_bytes()); bool is_shared = native_module->module()->type(function->sig_index).is_shared; FunctionBody function_body{function->sig, function->code.offset(), wire_bytes.start() + function->code.offset(), wire_bytes.start() + function->code.end_offset(), is_shared}; DCHECK_LE(native_module->num_imported_functions(), function->func_index); DCHECK_LT(function->func_index, native_module->num_functions()); WasmCompilationUnit unit(function->func_index, tier, kNotForDebugging); CompilationEnv env = CompilationEnv::ForModule(native_module); base::FlushDenormalsScope disable_denormals( tier == ExecutionTier::kTurbofan && native_module->compile_imports().contains( CompileTimeImport::kDisableDenormalFloats)); WasmCompilationResult result = unit.ExecuteCompilation( &env, native_module->compilation_state()->GetWireBytesStorage().get(), native_module->counter_updates(), detected); if (result.succeeded()) { WasmCodeRefScope code_ref_scope; native_module->PublishCode(native_module->AddCompiledCode(result)); } else { native_module->compilation_state()->SetError(); } } JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit( Isolate* isolate, const CanonicalSig* sig, bool receiver_is_first_param) : isolate_(isolate), sig_(sig), receiver_is_first_param_(receiver_is_first_param), job_(v8_flags.wasm_jitless ? nullptr : compiler::NewJSToWasmCompilationJob( isolate, sig, receiver_is_first_param)) { if (!v8_flags.wasm_jitless) { OptimizedCompilationInfo* info = static_cast<compiler::turboshaft::TurboshaftCompilationJob*>(job_.get()) ->compilation_info(); if (info->trace_turbo_graph()) { // Make sure that code tracer is initialized on the main thread if tracing // is enabled. isolate->GetCodeTracer(); } } } JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default; void JSToWasmWrapperCompilationUnit::Execute() { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), "wasm.CompileJSToWasmWrapper"); if (!v8_flags.wasm_jitless) { CompilationJob::Status status = job_->ExecuteJob(nullptr); CHECK_EQ(status, CompilationJob::SUCCEEDED); } } DirectHandle<Code> JSToWasmWrapperCompilationUnit::Finalize() { #if V8_ENABLE_DRUMBRAKE if (v8_flags.wasm_jitless) { return isolate_->builtins()->code_handle( Builtin::kGenericJSToWasmInterpreterWrapper); } #endif // V8_ENABLE_DRUMBRAKE CompilationJob::Status status = job_->FinalizeJob(isolate_); CHECK_EQ(status, CompilationJob::SUCCEEDED); OptimizedCompilationInfo* info = static_cast<compiler::turboshaft::TurboshaftCompilationJob*>(job_.get()) ->compilation_info(); DirectHandle<Code> code = info->code(); if (isolate_->IsLoggingCodeCreation()) { DirectHandle<String> name = isolate_->factory()->NewStringFromAsciiChecked( info->GetDebugName().get()); PROFILE(isolate_, CodeCreateEvent(LogEventListener::CodeTag::kStub, Cast<AbstractCode>(code), name)); } // Install the compiled wrapper in the cache now. WasmExportWrapperCache::Put(isolate_, sig_->index(), receiver_is_first_param_, code); Counters* counters = isolate_->counters(); counters->wasm_generated_code_size()->Increment(code->body_size()); counters->wasm_reloc_size()->Increment(code->relocation_size()); counters->wasm_compiled_export_wrapper()->Increment(1); return code; } // static DirectHandle<Code> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( Isolate* isolate, const CanonicalSig* sig, bool receiver_is_first_param) { // Run the compilation unit synchronously. JSToWasmWrapperCompilationUnit unit(isolate, sig, receiver_is_first_param); unit.Execute(); return unit.Finalize(); } } // namespace v8::internal::wasm