V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
function-compiler.cc
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 
5 #include "src/wasm/function-compiler.h"
6 
7 #include "src/compiler/wasm-compiler.h"
8 #include "src/counters.h"
9 #include "src/macro-assembler-inl.h"
10 #include "src/wasm/baseline/liftoff-compiler.h"
11 #include "src/wasm/wasm-code-manager.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace wasm {
16 
17 namespace {
18 
19 const char* GetExecutionTierAsString(ExecutionTier tier) {
20  switch (tier) {
21  case ExecutionTier::kBaseline:
22  return "liftoff";
23  case ExecutionTier::kOptimized:
24  return "turbofan";
25  case ExecutionTier::kInterpreter:
26  return "interpreter";
27  }
28  UNREACHABLE();
29 }
30 
31 } // namespace
32 
33 // static
34 ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier() {
35  return FLAG_liftoff ? ExecutionTier::kBaseline : ExecutionTier::kOptimized;
36 }
37 
38 WasmCompilationUnit::WasmCompilationUnit(WasmEngine* wasm_engine,
39  NativeModule* native_module, int index,
40  ExecutionTier tier)
41  : wasm_engine_(wasm_engine),
42  func_index_(index),
43  native_module_(native_module),
44  tier_(tier) {
45  const WasmModule* module = native_module->module();
46  DCHECK_GE(index, module->num_imported_functions);
47  DCHECK_LT(index, module->functions.size());
48  // Always disable Liftoff for asm.js, for two reasons:
49  // 1) asm-specific opcodes are not implemented, and
50  // 2) tier-up does not work with lazy compilation.
51  if (module->origin == kAsmJsOrigin) tier = ExecutionTier::kOptimized;
52  if (V8_UNLIKELY(FLAG_wasm_tier_mask_for_testing) && index < 32 &&
53  (FLAG_wasm_tier_mask_for_testing & (1 << index))) {
54  tier = ExecutionTier::kOptimized;
55  }
56  SwitchTier(tier);
57 }
58 
59 // Declared here such that {LiftoffCompilationUnit} and
60 // {TurbofanWasmCompilationUnit} can be opaque in the header file.
61 WasmCompilationUnit::~WasmCompilationUnit() = default;
62 
63 void WasmCompilationUnit::ExecuteCompilation(
64  CompilationEnv* env, std::shared_ptr<WireBytesStorage> wire_bytes_storage,
65  Counters* counters, WasmFeatures* detected) {
66  const WasmModule* module = native_module_->module();
67  DCHECK_EQ(module, env->module);
68 
69  auto* func = &env->module->functions[func_index_];
70  Vector<const uint8_t> code = wire_bytes_storage->GetCode(func->code);
71  wasm::FunctionBody func_body{func->sig, func->code.offset(), code.start(),
72  code.end()};
73 
74  auto size_histogram =
75  SELECT_WASM_COUNTER(counters, module->origin, wasm, function_size_bytes);
76  size_histogram->AddSample(static_cast<int>(func_body.end - func_body.start));
77  auto timed_histogram = SELECT_WASM_COUNTER(counters, module->origin,
78  wasm_compile, function_time);
79  TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
80 
81  if (FLAG_trace_wasm_compiler) {
82  PrintF("Compiling wasm function %d with %s\n\n", func_index_,
83  GetExecutionTierAsString(tier_));
84  }
85 
86  switch (tier_) {
87  case ExecutionTier::kBaseline:
88  if (liftoff_unit_->ExecuteCompilation(env, func_body, counters,
89  detected)) {
90  break;
91  }
92  // Otherwise, fall back to turbofan.
93  SwitchTier(ExecutionTier::kOptimized);
94  // TODO(wasm): We could actually stop or remove the tiering unit for this
95  // function to avoid compiling it twice with TurboFan.
96  V8_FALLTHROUGH;
97  case ExecutionTier::kOptimized:
98  turbofan_unit_->ExecuteCompilation(env, func_body, counters, detected);
99  break;
100  case ExecutionTier::kInterpreter:
101  UNREACHABLE(); // TODO(titzer): compile interpreter entry stub.
102  }
103 }
104 
105 void WasmCompilationUnit::SwitchTier(ExecutionTier new_tier) {
106  // This method is being called in the constructor, where neither
107  // {liftoff_unit_} nor {turbofan_unit_} are set, or to switch tier from
108  // kLiftoff to kTurbofan, in which case {liftoff_unit_} is already set.
109  tier_ = new_tier;
110  switch (new_tier) {
111  case ExecutionTier::kBaseline:
112  DCHECK(!turbofan_unit_);
113  DCHECK(!liftoff_unit_);
114  liftoff_unit_.reset(new LiftoffCompilationUnit(this));
115  return;
116  case ExecutionTier::kOptimized:
117  DCHECK(!turbofan_unit_);
118  liftoff_unit_.reset();
119  turbofan_unit_.reset(new compiler::TurbofanWasmCompilationUnit(this));
120  return;
121  case ExecutionTier::kInterpreter:
122  UNREACHABLE(); // TODO(titzer): allow compiling interpreter entry stub.
123  }
124  UNREACHABLE();
125 }
126 
127 // static
128 bool WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
129  NativeModule* native_module,
130  WasmFeatures* detected,
131  const WasmFunction* function,
132  ExecutionTier tier) {
133  ModuleWireBytes wire_bytes(native_module->wire_bytes());
134  FunctionBody function_body{function->sig, function->code.offset(),
135  wire_bytes.start() + function->code.offset(),
136  wire_bytes.start() + function->code.end_offset()};
137 
138  WasmCompilationUnit unit(isolate->wasm_engine(), native_module,
139  function->func_index, tier);
140  CompilationEnv env = native_module->CreateCompilationEnv();
141  unit.ExecuteCompilation(
142  &env, native_module->compilation_state()->GetWireBytesStorage(),
143  isolate->counters(), detected);
144  return !unit.failed();
145 }
146 
147 void WasmCompilationUnit::SetResult(WasmCode* code, Counters* counters) {
148  DCHECK_NULL(result_);
149  result_ = code;
150  native_module()->PublishCode(code);
151 
152  counters->wasm_generated_code_size()->Increment(
153  static_cast<int>(code->instructions().size()));
154  counters->wasm_reloc_size()->Increment(
155  static_cast<int>(code->reloc_info().size()));
156 }
157 
158 } // namespace wasm
159 } // namespace internal
160 } // namespace v8
Definition: libplatform.h:13