v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
function-compiler.cc
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <optional>
8
9#include "src/base/fpu.h"
16#include "src/logging/log.h"
22#include "src/wasm/wasm-debug.h"
24
25namespace v8::internal::wasm {
26
28 CompilationEnv* env, const WireBytesStorage* wire_bytes_storage,
29 Counters* counters, WasmDetectedFeatures* detected) {
30 DCHECK_GE(func_index_, static_cast<int>(env->module->num_imported_functions));
31 const WasmFunction* func = &env->module->functions[func_index_];
32 base::Vector<const uint8_t> code = wire_bytes_storage->GetCode(func->code);
33 bool is_shared = env->module->type(func->sig_index).is_shared;
34 wasm::FunctionBody func_body{func->sig, func->code.offset(), code.begin(),
35 code.end(), is_shared};
36
37 std::optional<TimedHistogramScope> wasm_compile_function_time_scope;
38 std::optional<TimedHistogramScope> wasm_compile_huge_function_time_scope;
39 if (counters && base::TimeTicks::IsHighResolution()) {
40 if (func_body.end - func_body.start >= 100 * KB) {
41 auto huge_size_histogram = SELECT_WASM_COUNTER(
42 counters, env->module->origin, wasm, huge_function_size_bytes);
43 huge_size_histogram->AddSample(
44 static_cast<int>(func_body.end - func_body.start));
45 wasm_compile_huge_function_time_scope.emplace(
46 counters->wasm_compile_huge_function_time());
47 }
48 auto timed_histogram = SELECT_WASM_COUNTER(counters, env->module->origin,
49 wasm_compile, function_time);
50 wasm_compile_function_time_scope.emplace(timed_histogram);
51 }
52
53 // Before executing compilation, make sure that the function was validated.
54 // Both Liftoff and TurboFan compilation do not perform validation, so can
55 // only run on valid functions.
56 if (V8_UNLIKELY(!env->module->function_was_validated(func_index_))) {
57 // This code path can only be reached in
58 // - eager compilation mode,
59 // - with lazy validation,
60 // - with PGO (which compiles some functions eagerly), or
61 // - with compilation hints (which also compiles some functions eagerly).
62 DCHECK(!v8_flags.wasm_lazy_compilation || v8_flags.wasm_lazy_validation ||
63 v8_flags.experimental_wasm_pgo_from_file ||
64 v8_flags.experimental_wasm_compilation_hints);
65 Zone validation_zone{GetWasmEngine()->allocator(), ZONE_NAME};
66 if (ValidateFunctionBody(&validation_zone, env->enabled_features,
67 env->module, detected, func_body)
68 .failed()) {
69 return {};
70 }
71 env->module->set_function_validated(func_index_);
72 }
73
74 if (v8_flags.trace_wasm_compiler) {
75 PrintF("Compiling wasm function %d with %s\n", func_index_,
77 }
78
80 int declared_index = declared_function_index(env->module, func_index_);
81
82 switch (tier_) {
84#if V8_ENABLE_DRUMBRAKE
85 case ExecutionTier::kInterpreter:
86#endif // V8_ENABLE_DRUMBRAKE
88
90 // The --wasm-tier-mask-for-testing flag can force functions to be
91 // compiled with TurboFan, and the --wasm-debug-mask-for-testing can force
92 // them to be compiled for debugging, see documentation.
93 bool try_liftoff = true;
94 if (V8_UNLIKELY(v8_flags.wasm_tier_mask_for_testing != 0)) {
95 bool must_use_liftoff =
96 v8_flags.liftoff_only ||
98 bool tiering_requested =
99 declared_index < 32 &&
100 (v8_flags.wasm_tier_mask_for_testing & (1 << declared_index));
101 if (!must_use_liftoff && tiering_requested) try_liftoff = false;
102 }
103
104 if (V8_LIKELY(try_liftoff)) {
105 auto options = LiftoffOptions{}
106 .set_func_index(func_index_)
107 .set_for_debugging(for_debugging_)
108 .set_counters(counters)
109 .set_detected_features(detected);
110 // We do not use the debug side table, we only (optionally) pass it to
111 // cover different code paths in Liftoff for testing.
112 std::unique_ptr<DebugSideTable> unused_debug_sidetable;
113 if (V8_UNLIKELY(declared_index < 32 &&
114 (v8_flags.wasm_debug_mask_for_testing &
115 (1 << declared_index)) != 0)) {
116 options.set_debug_sidetable(&unused_debug_sidetable);
117 if (!for_debugging_) options.set_for_debugging(kForDebugging);
118 }
119 result = ExecuteLiftoffCompilation(env, func_body, options);
120 if (result.succeeded()) break;
121 }
122
123 // If --liftoff-only, do not fall back to turbofan, even if compilation
124 // failed.
125 if (v8_flags.liftoff_only) break;
126
127 // If Liftoff failed, fall back to TurboFan.
128 // TODO(wasm): We could actually stop or remove the tiering unit for this
129 // function to avoid compiling it twice with TurboFan.
130 [[fallthrough]];
131 }
134 data.func_index = func_index_;
135 data.wire_bytes_storage = wire_bytes_storage;
137 env, data, detected, counters);
138 // In exceptional cases it can happen that compilation requests for
139 // debugging end up being executed by Turbofan, e.g. if Liftoff bails out
140 // because of unsupported features or the --wasm-tier-mask-for-testing is
141 // set. In that case we set the for_debugging field for the TurboFan
142 // result to match the requested for_debugging_.
143 result.for_debugging = for_debugging_;
144 break;
145 }
146 }
147
148 DCHECK(result.succeeded());
149 if (counters) {
150 counters->wasm_generated_code_size()->Increment(
151 result.code_desc.instr_size);
152 counters->wasm_reloc_size()->Increment(result.code_desc.reloc_size);
153 counters->wasm_deopt_data_size()->Increment(
154 static_cast<int>(result.deopt_data.size()));
155 }
156
157 result.func_index = func_index_;
158
159 return result;
160}
161
162// static
164 NativeModule* native_module,
165 WasmDetectedFeatures* detected,
166 const WasmFunction* function,
167 ExecutionTier tier) {
168 ModuleWireBytes wire_bytes(native_module->wire_bytes());
169 bool is_shared = native_module->module()->type(function->sig_index).is_shared;
170 FunctionBody function_body{function->sig, function->code.offset(),
171 wire_bytes.start() + function->code.offset(),
172 wire_bytes.start() + function->code.end_offset(),
173 is_shared};
174
175 DCHECK_LE(native_module->num_imported_functions(), function->func_index);
176 DCHECK_LT(function->func_index, native_module->num_functions());
177 WasmCompilationUnit unit(function->func_index, tier, kNotForDebugging);
178 CompilationEnv env = CompilationEnv::ForModule(native_module);
179 base::FlushDenormalsScope disable_denormals(
180 tier == ExecutionTier::kTurbofan &&
181 native_module->compile_imports().contains(
183 WasmCompilationResult result = unit.ExecuteCompilation(
184 &env, native_module->compilation_state()->GetWireBytesStorage().get(),
185 counters, detected);
186 if (result.succeeded()) {
187 WasmCodeRefScope code_ref_scope;
188 native_module->PublishCode(native_module->AddCompiledCode(result));
189 } else {
190 native_module->compilation_state()->SetError();
191 }
192}
193
195 Isolate* isolate, const CanonicalSig* sig, CanonicalTypeIndex sig_index)
196 : isolate_(isolate),
197 sig_(sig),
198 sig_index_(sig_index),
199 job_(v8_flags.wasm_jitless
200 ? nullptr
201 : compiler::NewJSToWasmCompilationJob(isolate, sig)) {
202 if (!v8_flags.wasm_jitless) {
203 OptimizedCompilationInfo* info =
204 static_cast<compiler::turboshaft::TurboshaftCompilationJob*>(job_.get())
205 ->compilation_info();
206 if (info->trace_turbo_graph()) {
207 // Make sure that code tracer is initialized on the main thread if tracing
208 // is enabled.
209 isolate->GetCodeTracer();
210 }
211 }
212}
213
214JSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default;
215
216void JSToWasmWrapperCompilationUnit::Execute() {
217 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
218 "wasm.CompileJSToWasmWrapper");
219 if (!v8_flags.wasm_jitless) {
220 CompilationJob::Status status = job_->ExecuteJob(nullptr);
222 }
223}
224
225DirectHandle<Code> JSToWasmWrapperCompilationUnit::Finalize() {
226#if V8_ENABLE_DRUMBRAKE
227 if (v8_flags.wasm_jitless) {
228 return isolate_->builtins()->code_handle(
229 Builtin::kGenericJSToWasmInterpreterWrapper);
230 }
231#endif // V8_ENABLE_DRUMBRAKE
232
233 CompilationJob::Status status = job_->FinalizeJob(isolate_);
236 static_cast<compiler::turboshaft::TurboshaftCompilationJob*>(job_.get())
238 DirectHandle<Code> code = info->code();
241 info->GetDebugName().get());
242 PROFILE(isolate_, CodeCreateEvent(LogEventListener::CodeTag::kStub,
243 Cast<AbstractCode>(code), name));
244 }
245 // We should always have checked the cache before compiling a wrapper.
246 Tagged<WeakFixedArray> cache = isolate_->heap()->js_to_wasm_wrappers();
247 DCHECK(cache->get(sig_index_.index).IsCleared());
248 // Install the compiled wrapper in the cache now.
249 cache->set(sig_index_.index, MakeWeak(code->wrapper()));
250 Counters* counters = isolate_->counters();
251 counters->wasm_generated_code_size()->Increment(code->body_size());
252 counters->wasm_reloc_size()->Increment(code->relocation_size());
253 counters->wasm_compiled_export_wrapper()->Increment(1);
254 return code;
255}
256
257// static
258DirectHandle<Code> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
259 Isolate* isolate, const CanonicalSig* sig, CanonicalTypeIndex sig_index) {
260 // Run the compilation unit synchronously.
261 JSToWasmWrapperCompilationUnit unit(isolate, sig, sig_index);
262 unit.Execute();
263 return unit.Finalize();
264}
265
266} // namespace v8::internal::wasm
Isolate * isolate_
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
static bool IsHighResolution()
Definition time.cc:763
V8_EXPORT_PRIVATE Handle< Code > code_handle(Builtin builtin)
Definition builtins.cc:154
Handle< String > NewStringFromAsciiChecked(const char *str, AllocationType allocation=AllocationType::kYoung)
bool IsLoggingCodeCreation() const
Definition isolate.cc:6145
Counters * counters()
Definition isolate.h:1180
Builtins * builtins()
Definition isolate.h:1443
v8::internal::Factory * factory()
Definition isolate.h:1527
std::shared_ptr< WireBytesStorage > GetWireBytesStorage() const
JSToWasmWrapperCompilationUnit(Isolate *isolate, const CanonicalSig *sig, CanonicalTypeIndex sig_index)
CompilationState * compilation_state() const
const WasmModule * module() const
base::Vector< const uint8_t > wire_bytes() const
WasmCode * PublishCode(UnpublishedWasmCode)
V8_WARN_UNUSED_RESULT UnpublishedWasmCode AddCompiledCode(WasmCompilationResult &)
const CompileTimeImports & compile_imports() const
WasmCompilationResult ExecuteCompilation(CompilationEnv *, const WireBytesStorage *, Counters *, WasmDetectedFeatures *detected)
static void CompileWasmFunction(Counters *, NativeModule *, WasmDetectedFeatures *detected, const WasmFunction *, ExecutionTier)
AccountingAllocator * allocator()
virtual base::Vector< const uint8_t > GetCode(WireBytesRef) const =0
#define PROFILE(the_isolate, Call)
Definition code-events.h:59
Handle< Code > code
ZoneVector< RpoNumber > & result
wasm::WasmCompilationResult ExecuteTurboshaftWasmCompilation(wasm::CompilationEnv *env, compiler::WasmCompilationData &data, wasm::WasmDetectedFeatures *detected, Counters *counters)
WasmCompilationResult ExecuteLiftoffCompilation(CompilationEnv *env, const FunctionBody &func_body, const LiftoffOptions &compiler_options)
DecodeResult ValidateFunctionBody(Zone *zone, WasmEnabledFeatures enabled, const WasmModule *module, WasmDetectedFeatures *detected, const FunctionBody &body)
WasmEngine * GetWasmEngine()
int declared_function_index(const WasmModule *module, int func_index)
const char * ExecutionTierToString(ExecutionTier tier)
Definition wasm-tier.h:28
void PrintF(const char *format,...)
Definition utils.cc:39
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
V8_EXPORT_PRIVATE FlagValues v8_flags
JSArrayBuffer::IsDetachableBit is_shared
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Definition c-api.cc:87
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
static CompilationEnv ForModule(const NativeModule *native_module)
const uint8_t * start() const
#define TRACE_EVENT0(category_group, name)
#define TRACE_DISABLED_BY_DEFAULT(name)
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
#define SELECT_WASM_COUNTER(counters, origin, prefix, suffix)
#define ZONE_NAME
Definition zone.h:22