11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/wasm/function-compiler.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/base/platform/time.h" 81cb0ef41Sopenharmony_ci#include "src/base/strings.h" 91cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h" 101cb0ef41Sopenharmony_ci#include "src/codegen/macro-assembler-inl.h" 111cb0ef41Sopenharmony_ci#include "src/codegen/optimized-compilation-info.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/wasm-compiler.h" 131cb0ef41Sopenharmony_ci#include "src/diagnostics/code-tracer.h" 141cb0ef41Sopenharmony_ci#include "src/logging/counters-scopes.h" 151cb0ef41Sopenharmony_ci#include "src/logging/log.h" 161cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h" 171cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-compiler.h" 181cb0ef41Sopenharmony_ci#include "src/wasm/wasm-code-manager.h" 191cb0ef41Sopenharmony_ci#include "src/wasm/wasm-debug.h" 201cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h" 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cinamespace v8 { 231cb0ef41Sopenharmony_cinamespace internal { 241cb0ef41Sopenharmony_cinamespace wasm { 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci// static 271cb0ef41Sopenharmony_ciExecutionTier WasmCompilationUnit::GetBaselineExecutionTier( 281cb0ef41Sopenharmony_ci const WasmModule* module) { 291cb0ef41Sopenharmony_ci // Liftoff does not support the special asm.js opcodes, thus always compile 301cb0ef41Sopenharmony_ci // asm.js modules with TurboFan. 311cb0ef41Sopenharmony_ci if (is_asmjs_module(module)) return ExecutionTier::kTurbofan; 321cb0ef41Sopenharmony_ci return FLAG_liftoff ? ExecutionTier::kLiftoff : ExecutionTier::kTurbofan; 331cb0ef41Sopenharmony_ci} 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciWasmCompilationResult WasmCompilationUnit::ExecuteCompilation( 361cb0ef41Sopenharmony_ci CompilationEnv* env, const WireBytesStorage* wire_bytes_storage, 371cb0ef41Sopenharmony_ci Counters* counters, WasmFeatures* detected) { 381cb0ef41Sopenharmony_ci WasmCompilationResult result; 391cb0ef41Sopenharmony_ci if (func_index_ < static_cast<int>(env->module->num_imported_functions)) { 401cb0ef41Sopenharmony_ci result = ExecuteImportWrapperCompilation(env); 411cb0ef41Sopenharmony_ci } else { 421cb0ef41Sopenharmony_ci result = 431cb0ef41Sopenharmony_ci ExecuteFunctionCompilation(env, wire_bytes_storage, counters, detected); 441cb0ef41Sopenharmony_ci } 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci if (result.succeeded() && counters) { 471cb0ef41Sopenharmony_ci counters->wasm_generated_code_size()->Increment( 481cb0ef41Sopenharmony_ci result.code_desc.instr_size); 491cb0ef41Sopenharmony_ci counters->wasm_reloc_size()->Increment(result.code_desc.reloc_size); 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci result.func_index = func_index_; 531cb0ef41Sopenharmony_ci result.requested_tier = tier_; 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci return result; 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ciWasmCompilationResult WasmCompilationUnit::ExecuteImportWrapperCompilation( 591cb0ef41Sopenharmony_ci CompilationEnv* env) { 601cb0ef41Sopenharmony_ci const FunctionSig* sig = env->module->functions[func_index_].sig; 611cb0ef41Sopenharmony_ci // Assume the wrapper is going to be a JS function with matching arity at 621cb0ef41Sopenharmony_ci // instantiation time. 631cb0ef41Sopenharmony_ci auto kind = compiler::kDefaultImportCallKind; 641cb0ef41Sopenharmony_ci bool source_positions = is_asmjs_module(env->module); 651cb0ef41Sopenharmony_ci WasmCompilationResult result = compiler::CompileWasmImportCallWrapper( 661cb0ef41Sopenharmony_ci env, kind, sig, source_positions, 671cb0ef41Sopenharmony_ci static_cast<int>(sig->parameter_count()), wasm::kNoSuspend); 681cb0ef41Sopenharmony_ci return result; 691cb0ef41Sopenharmony_ci} 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ciWasmCompilationResult WasmCompilationUnit::ExecuteFunctionCompilation( 721cb0ef41Sopenharmony_ci CompilationEnv* env, const WireBytesStorage* wire_bytes_storage, 731cb0ef41Sopenharmony_ci Counters* counters, WasmFeatures* detected) { 741cb0ef41Sopenharmony_ci auto* func = &env->module->functions[func_index_]; 751cb0ef41Sopenharmony_ci base::Vector<const uint8_t> code = wire_bytes_storage->GetCode(func->code); 761cb0ef41Sopenharmony_ci wasm::FunctionBody func_body{func->sig, func->code.offset(), code.begin(), 771cb0ef41Sopenharmony_ci code.end()}; 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci base::Optional<TimedHistogramScope> wasm_compile_function_time_scope; 801cb0ef41Sopenharmony_ci base::Optional<TimedHistogramScope> wasm_compile_huge_function_time_scope; 811cb0ef41Sopenharmony_ci if (counters) { 821cb0ef41Sopenharmony_ci if (func_body.end - func_body.start >= 100 * KB) { 831cb0ef41Sopenharmony_ci auto huge_size_histogram = SELECT_WASM_COUNTER( 841cb0ef41Sopenharmony_ci counters, env->module->origin, wasm, huge_function_size_bytes); 851cb0ef41Sopenharmony_ci huge_size_histogram->AddSample( 861cb0ef41Sopenharmony_ci static_cast<int>(func_body.end - func_body.start)); 871cb0ef41Sopenharmony_ci wasm_compile_huge_function_time_scope.emplace( 881cb0ef41Sopenharmony_ci counters->wasm_compile_huge_function_time()); 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci auto timed_histogram = SELECT_WASM_COUNTER(counters, env->module->origin, 911cb0ef41Sopenharmony_ci wasm_compile, function_time); 921cb0ef41Sopenharmony_ci wasm_compile_function_time_scope.emplace(timed_histogram); 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci if (FLAG_trace_wasm_compiler) { 961cb0ef41Sopenharmony_ci PrintF("Compiling wasm function %d with %s\n", func_index_, 971cb0ef41Sopenharmony_ci ExecutionTierToString(tier_)); 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci WasmCompilationResult result; 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci switch (tier_) { 1031cb0ef41Sopenharmony_ci case ExecutionTier::kNone: 1041cb0ef41Sopenharmony_ci UNREACHABLE(); 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci case ExecutionTier::kLiftoff: 1071cb0ef41Sopenharmony_ci // The --wasm-tier-mask-for-testing flag can force functions to be 1081cb0ef41Sopenharmony_ci // compiled with TurboFan, and the --wasm-debug-mask-for-testing can force 1091cb0ef41Sopenharmony_ci // them to be compiled for debugging, see documentation. 1101cb0ef41Sopenharmony_ci if (V8_LIKELY(FLAG_wasm_tier_mask_for_testing == 0) || 1111cb0ef41Sopenharmony_ci func_index_ >= 32 || 1121cb0ef41Sopenharmony_ci ((FLAG_wasm_tier_mask_for_testing & (1 << func_index_)) == 0) || 1131cb0ef41Sopenharmony_ci FLAG_liftoff_only) { 1141cb0ef41Sopenharmony_ci // We do not use the debug side table, we only (optionally) pass it to 1151cb0ef41Sopenharmony_ci // cover different code paths in Liftoff for testing. 1161cb0ef41Sopenharmony_ci std::unique_ptr<DebugSideTable> unused_debug_sidetable; 1171cb0ef41Sopenharmony_ci std::unique_ptr<DebugSideTable>* debug_sidetable_ptr = nullptr; 1181cb0ef41Sopenharmony_ci if (V8_UNLIKELY(func_index_ < 32 && (FLAG_wasm_debug_mask_for_testing & 1191cb0ef41Sopenharmony_ci (1 << func_index_)) != 0)) { 1201cb0ef41Sopenharmony_ci debug_sidetable_ptr = &unused_debug_sidetable; 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci result = ExecuteLiftoffCompilation( 1231cb0ef41Sopenharmony_ci env, func_body, func_index_, for_debugging_, 1241cb0ef41Sopenharmony_ci LiftoffOptions{} 1251cb0ef41Sopenharmony_ci .set_counters(counters) 1261cb0ef41Sopenharmony_ci .set_detected_features(detected) 1271cb0ef41Sopenharmony_ci .set_debug_sidetable(debug_sidetable_ptr)); 1281cb0ef41Sopenharmony_ci if (result.succeeded()) break; 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci // If --liftoff-only, do not fall back to turbofan, even if compilation 1321cb0ef41Sopenharmony_ci // failed. 1331cb0ef41Sopenharmony_ci if (FLAG_liftoff_only) break; 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci // If Liftoff failed, fall back to turbofan. 1361cb0ef41Sopenharmony_ci // TODO(wasm): We could actually stop or remove the tiering unit for this 1371cb0ef41Sopenharmony_ci // function to avoid compiling it twice with TurboFan. 1381cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci case ExecutionTier::kTurbofan: 1411cb0ef41Sopenharmony_ci result = compiler::ExecuteTurbofanWasmCompilation( 1421cb0ef41Sopenharmony_ci env, wire_bytes_storage, func_body, func_index_, counters, detected); 1431cb0ef41Sopenharmony_ci result.for_debugging = for_debugging_; 1441cb0ef41Sopenharmony_ci break; 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci return result; 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci// static 1511cb0ef41Sopenharmony_civoid WasmCompilationUnit::CompileWasmFunction(Isolate* isolate, 1521cb0ef41Sopenharmony_ci NativeModule* native_module, 1531cb0ef41Sopenharmony_ci WasmFeatures* detected, 1541cb0ef41Sopenharmony_ci const WasmFunction* function, 1551cb0ef41Sopenharmony_ci ExecutionTier tier) { 1561cb0ef41Sopenharmony_ci ModuleWireBytes wire_bytes(native_module->wire_bytes()); 1571cb0ef41Sopenharmony_ci FunctionBody function_body{function->sig, function->code.offset(), 1581cb0ef41Sopenharmony_ci wire_bytes.start() + function->code.offset(), 1591cb0ef41Sopenharmony_ci wire_bytes.start() + function->code.end_offset()}; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci DCHECK_LE(native_module->num_imported_functions(), function->func_index); 1621cb0ef41Sopenharmony_ci DCHECK_LT(function->func_index, native_module->num_functions()); 1631cb0ef41Sopenharmony_ci WasmCompilationUnit unit(function->func_index, tier, kNoDebugging); 1641cb0ef41Sopenharmony_ci CompilationEnv env = native_module->CreateCompilationEnv(); 1651cb0ef41Sopenharmony_ci WasmCompilationResult result = unit.ExecuteCompilation( 1661cb0ef41Sopenharmony_ci &env, native_module->compilation_state()->GetWireBytesStorage().get(), 1671cb0ef41Sopenharmony_ci isolate->counters(), detected); 1681cb0ef41Sopenharmony_ci if (result.succeeded()) { 1691cb0ef41Sopenharmony_ci WasmCodeRefScope code_ref_scope; 1701cb0ef41Sopenharmony_ci native_module->PublishCode( 1711cb0ef41Sopenharmony_ci native_module->AddCompiledCode(std::move(result))); 1721cb0ef41Sopenharmony_ci } else { 1731cb0ef41Sopenharmony_ci native_module->compilation_state()->SetError(); 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci} 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_cinamespace { 1781cb0ef41Sopenharmony_cibool UseGenericWrapper(const FunctionSig* sig) { 1791cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_X64 1801cb0ef41Sopenharmony_ci if (sig->returns().size() > 1) { 1811cb0ef41Sopenharmony_ci return false; 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci if (sig->returns().size() == 1) { 1841cb0ef41Sopenharmony_ci ValueType ret = sig->GetReturn(0); 1851cb0ef41Sopenharmony_ci if (ret.kind() == kS128) return false; 1861cb0ef41Sopenharmony_ci if (ret.is_reference()) { 1871cb0ef41Sopenharmony_ci if (ret.heap_representation() != wasm::HeapType::kAny && 1881cb0ef41Sopenharmony_ci ret.heap_representation() != wasm::HeapType::kFunc) { 1891cb0ef41Sopenharmony_ci return false; 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci for (ValueType type : sig->parameters()) { 1941cb0ef41Sopenharmony_ci if (type.kind() != kI32 && type.kind() != kI64 && type.kind() != kF32 && 1951cb0ef41Sopenharmony_ci type.kind() != kF64 && 1961cb0ef41Sopenharmony_ci !(type.is_reference() && 1971cb0ef41Sopenharmony_ci type.heap_representation() == wasm::HeapType::kAny)) { 1981cb0ef41Sopenharmony_ci return false; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci return FLAG_wasm_generic_wrapper; 2021cb0ef41Sopenharmony_ci#else 2031cb0ef41Sopenharmony_ci return false; 2041cb0ef41Sopenharmony_ci#endif 2051cb0ef41Sopenharmony_ci} 2061cb0ef41Sopenharmony_ci} // namespace 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ciJSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit( 2091cb0ef41Sopenharmony_ci Isolate* isolate, const FunctionSig* sig, const WasmModule* module, 2101cb0ef41Sopenharmony_ci bool is_import, const WasmFeatures& enabled_features, 2111cb0ef41Sopenharmony_ci AllowGeneric allow_generic) 2121cb0ef41Sopenharmony_ci : isolate_(isolate), 2131cb0ef41Sopenharmony_ci is_import_(is_import), 2141cb0ef41Sopenharmony_ci sig_(sig), 2151cb0ef41Sopenharmony_ci use_generic_wrapper_(allow_generic && UseGenericWrapper(sig) && 2161cb0ef41Sopenharmony_ci !is_import), 2171cb0ef41Sopenharmony_ci job_(use_generic_wrapper_ 2181cb0ef41Sopenharmony_ci ? nullptr 2191cb0ef41Sopenharmony_ci : compiler::NewJSToWasmCompilationJob( 2201cb0ef41Sopenharmony_ci isolate, sig, module, is_import, enabled_features)) {} 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ciJSToWasmWrapperCompilationUnit::~JSToWasmWrapperCompilationUnit() = default; 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_civoid JSToWasmWrapperCompilationUnit::Execute() { 2251cb0ef41Sopenharmony_ci TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"), 2261cb0ef41Sopenharmony_ci "wasm.CompileJSToWasmWrapper"); 2271cb0ef41Sopenharmony_ci if (!use_generic_wrapper_) { 2281cb0ef41Sopenharmony_ci CompilationJob::Status status = job_->ExecuteJob(nullptr); 2291cb0ef41Sopenharmony_ci CHECK_EQ(status, CompilationJob::SUCCEEDED); 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ciHandle<Code> JSToWasmWrapperCompilationUnit::Finalize() { 2341cb0ef41Sopenharmony_ci if (use_generic_wrapper_) { 2351cb0ef41Sopenharmony_ci return FromCodeT( 2361cb0ef41Sopenharmony_ci isolate_->builtins()->code_handle(Builtin::kGenericJSToWasmWrapper), 2371cb0ef41Sopenharmony_ci isolate_); 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci CompilationJob::Status status = job_->FinalizeJob(isolate_); 2411cb0ef41Sopenharmony_ci CHECK_EQ(status, CompilationJob::SUCCEEDED); 2421cb0ef41Sopenharmony_ci Handle<Code> code = job_->compilation_info()->code(); 2431cb0ef41Sopenharmony_ci if (isolate_->logger()->is_listening_to_code_events() || 2441cb0ef41Sopenharmony_ci isolate_->is_profiling()) { 2451cb0ef41Sopenharmony_ci Handle<String> name = isolate_->factory()->NewStringFromAsciiChecked( 2461cb0ef41Sopenharmony_ci job_->compilation_info()->GetDebugName().get()); 2471cb0ef41Sopenharmony_ci PROFILE(isolate_, CodeCreateEvent(CodeEventListener::STUB_TAG, 2481cb0ef41Sopenharmony_ci Handle<AbstractCode>::cast(code), name)); 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci return code; 2511cb0ef41Sopenharmony_ci} 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ci// static 2541cb0ef41Sopenharmony_ciHandle<Code> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( 2551cb0ef41Sopenharmony_ci Isolate* isolate, const FunctionSig* sig, const WasmModule* module, 2561cb0ef41Sopenharmony_ci bool is_import) { 2571cb0ef41Sopenharmony_ci // Run the compilation unit synchronously. 2581cb0ef41Sopenharmony_ci WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate); 2591cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit unit(isolate, sig, module, is_import, 2601cb0ef41Sopenharmony_ci enabled_features, kAllowGeneric); 2611cb0ef41Sopenharmony_ci unit.Execute(); 2621cb0ef41Sopenharmony_ci return unit.Finalize(); 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci// static 2661cb0ef41Sopenharmony_ciHandle<Code> JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper( 2671cb0ef41Sopenharmony_ci Isolate* isolate, const FunctionSig* sig, const WasmModule* module) { 2681cb0ef41Sopenharmony_ci // Run the compilation unit synchronously. 2691cb0ef41Sopenharmony_ci const bool is_import = false; 2701cb0ef41Sopenharmony_ci WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate); 2711cb0ef41Sopenharmony_ci JSToWasmWrapperCompilationUnit unit(isolate, sig, module, is_import, 2721cb0ef41Sopenharmony_ci enabled_features, kDontAllowGeneric); 2731cb0ef41Sopenharmony_ci unit.Execute(); 2741cb0ef41Sopenharmony_ci return unit.Finalize(); 2751cb0ef41Sopenharmony_ci} 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci} // namespace wasm 2781cb0ef41Sopenharmony_ci} // namespace internal 2791cb0ef41Sopenharmony_ci} // namespace v8 280