• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetExecutionTierAsString(ExecutionTier mode)19 const char* GetExecutionTierAsString(ExecutionTier mode) {
20   switch (mode) {
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 
RecordStats(const WasmCode * code,Counters * counters)31 void RecordStats(const WasmCode* code, Counters* counters) {
32   counters->wasm_generated_code_size()->Increment(
33       static_cast<int>(code->instructions().size()));
34   counters->wasm_reloc_size()->Increment(
35       static_cast<int>(code->reloc_info().size()));
36 }
37 
38 }  // namespace
39 
40 // static
GetDefaultExecutionTier()41 ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier() {
42   return FLAG_liftoff ? ExecutionTier::kBaseline : ExecutionTier::kOptimized;
43 }
44 
WasmCompilationUnit(WasmEngine * wasm_engine,ModuleEnv * env,NativeModule * native_module,FunctionBody body,WasmName name,int index,Counters * counters,ExecutionTier mode)45 WasmCompilationUnit::WasmCompilationUnit(WasmEngine* wasm_engine,
46                                          ModuleEnv* env,
47                                          NativeModule* native_module,
48                                          FunctionBody body, WasmName name,
49                                          int index, Counters* counters,
50                                          ExecutionTier mode)
51     : env_(env),
52       wasm_engine_(wasm_engine),
53       func_body_(body),
54       func_name_(name),
55       counters_(counters),
56       func_index_(index),
57       native_module_(native_module),
58       mode_(mode) {
59   DCHECK_GE(index, env->module->num_imported_functions);
60   DCHECK_LT(index, env->module->functions.size());
61   // Always disable Liftoff for asm.js, for two reasons:
62   //    1) asm-specific opcodes are not implemented, and
63   //    2) tier-up does not work with lazy compilation.
64   if (env->module->origin == kAsmJsOrigin) mode = ExecutionTier::kOptimized;
65   if (V8_UNLIKELY(FLAG_wasm_tier_mask_for_testing) && index < 32 &&
66       (FLAG_wasm_tier_mask_for_testing & (1 << index))) {
67     mode = ExecutionTier::kOptimized;
68   }
69   SwitchMode(mode);
70 }
71 
72 // Declared here such that {LiftoffCompilationUnit} and
73 // {TurbofanWasmCompilationUnit} can be opaque in the header file.
~WasmCompilationUnit()74 WasmCompilationUnit::~WasmCompilationUnit() {}
75 
ExecuteCompilation(WasmFeatures * detected)76 void WasmCompilationUnit::ExecuteCompilation(WasmFeatures* detected) {
77   auto size_histogram = SELECT_WASM_COUNTER(counters_, env_->module->origin,
78                                             wasm, function_size_bytes);
79   size_histogram->AddSample(
80       static_cast<int>(func_body_.end - func_body_.start));
81   auto timed_histogram = SELECT_WASM_COUNTER(counters_, env_->module->origin,
82                                              wasm_compile, function_time);
83   TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
84 
85   if (FLAG_trace_wasm_compiler) {
86     PrintF("Compiling wasm function %d with %s\n\n", func_index_,
87            GetExecutionTierAsString(mode_));
88   }
89 
90   switch (mode_) {
91     case ExecutionTier::kBaseline:
92       if (liftoff_unit_->ExecuteCompilation(detected)) break;
93       // Otherwise, fall back to turbofan.
94       SwitchMode(ExecutionTier::kOptimized);
95       V8_FALLTHROUGH;
96     case ExecutionTier::kOptimized:
97       turbofan_unit_->ExecuteCompilation(detected);
98       break;
99     case ExecutionTier::kInterpreter:
100       UNREACHABLE();  // TODO(titzer): compile interpreter entry stub.
101   }
102 }
103 
FinishCompilation(ErrorThrower * thrower)104 WasmCode* WasmCompilationUnit::FinishCompilation(ErrorThrower* thrower) {
105   WasmCode* ret;
106   switch (mode_) {
107     case ExecutionTier::kBaseline:
108       ret = liftoff_unit_->FinishCompilation(thrower);
109       break;
110     case ExecutionTier::kOptimized:
111       ret = turbofan_unit_->FinishCompilation(thrower);
112       break;
113     case ExecutionTier::kInterpreter:
114       UNREACHABLE();  // TODO(titzer): finish interpreter entry stub.
115   }
116   if (ret == nullptr) {
117     thrower->RuntimeError("Error finalizing code.");
118   } else {
119     RecordStats(ret, counters_);
120   }
121   return ret;
122 }
123 
SwitchMode(ExecutionTier new_mode)124 void WasmCompilationUnit::SwitchMode(ExecutionTier new_mode) {
125   // This method is being called in the constructor, where neither
126   // {liftoff_unit_} nor {turbofan_unit_} are set, or to switch mode from
127   // kLiftoff to kTurbofan, in which case {liftoff_unit_} is already set.
128   mode_ = new_mode;
129   switch (new_mode) {
130     case ExecutionTier::kBaseline:
131       DCHECK(!turbofan_unit_);
132       DCHECK(!liftoff_unit_);
133       liftoff_unit_.reset(new LiftoffCompilationUnit(this));
134       return;
135     case ExecutionTier::kOptimized:
136       DCHECK(!turbofan_unit_);
137       liftoff_unit_.reset();
138       turbofan_unit_.reset(new compiler::TurbofanWasmCompilationUnit(this));
139       return;
140     case ExecutionTier::kInterpreter:
141       UNREACHABLE();  // TODO(titzer): allow compiling interpreter entry stub.
142   }
143   UNREACHABLE();
144 }
145 
146 // static
CompileWasmFunction(Isolate * isolate,NativeModule * native_module,WasmFeatures * detected,ErrorThrower * thrower,ModuleEnv * env,const WasmFunction * function,ExecutionTier mode)147 WasmCode* WasmCompilationUnit::CompileWasmFunction(
148     Isolate* isolate, NativeModule* native_module, WasmFeatures* detected,
149     ErrorThrower* thrower, ModuleEnv* env, const WasmFunction* function,
150     ExecutionTier mode) {
151   ModuleWireBytes wire_bytes(native_module->wire_bytes());
152   FunctionBody function_body{function->sig, function->code.offset(),
153                              wire_bytes.start() + function->code.offset(),
154                              wire_bytes.start() + function->code.end_offset()};
155 
156   WasmCompilationUnit unit(isolate->wasm_engine(), env, native_module,
157                            function_body,
158                            wire_bytes.GetNameOrNull(function, env->module),
159                            function->func_index, isolate->counters(), mode);
160   unit.ExecuteCompilation(detected);
161   return unit.FinishCompilation(thrower);
162 }
163 
164 }  // namespace wasm
165 }  // namespace internal
166 }  // namespace v8
167