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