1// Copyright 2015 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#ifndef V8_COMPILER_WASM_COMPILER_H_
6#define V8_COMPILER_WASM_COMPILER_H_
7
8#include <memory>
9
10// Clients of this interface shouldn't depend on lots of compiler internals.
11// Do not include anything from src/compiler here!
12#include "src/compilation-info.h"
13#include "src/compiler.h"
14#include "src/trap-handler/trap-handler.h"
15#include "src/wasm/wasm-module.h"
16#include "src/wasm/wasm-opcodes.h"
17#include "src/wasm/wasm-result.h"
18#include "src/zone/zone.h"
19
20namespace v8 {
21namespace internal {
22
23namespace compiler {
24// Forward declarations for some compiler data structures.
25class Node;
26class JSGraph;
27class Graph;
28class Operator;
29class SourcePositionTable;
30}  // namespace compiler
31
32namespace wasm {
33// Forward declarations for some WASM data structures.
34struct ModuleBytesEnv;
35struct ModuleEnv;
36struct WasmFunction;
37struct WasmModule;
38class ErrorThrower;
39struct DecodeStruct;
40
41// Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
42typedef compiler::Node TFNode;
43typedef compiler::JSGraph TFGraph;
44}  // namespace wasm
45
46namespace compiler {
47class WasmCompilationUnit final {
48 public:
49  WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
50                      wasm::ModuleBytesEnv* module_env,
51                      const wasm::WasmFunction* function, uint32_t index);
52
53  Zone* graph_zone() { return graph_zone_.get(); }
54  int index() const { return index_; }
55
56  void ExecuteCompilation();
57  Handle<Code> FinishCompilation();
58
59  static Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower,
60                                          Isolate* isolate,
61                                          wasm::ModuleBytesEnv* module_env,
62                                          const wasm::WasmFunction* function) {
63    WasmCompilationUnit unit(thrower, isolate, module_env, function,
64                             function->func_index);
65    unit.ExecuteCompilation();
66    return unit.FinishCompilation();
67  }
68
69 private:
70  SourcePositionTable* BuildGraphForWasmFunction(double* decode_ms);
71  char* GetTaggedFunctionName(const wasm::WasmFunction* function);
72
73  wasm::ErrorThrower* thrower_;
74  Isolate* isolate_;
75  wasm::ModuleBytesEnv* module_env_;
76  const wasm::WasmFunction* function_;
77  // Function name is tagged with uint32 func_index - wasm#<func_index>
78  char function_name_[16];
79  // The graph zone is deallocated at the end of ExecuteCompilation.
80  std::unique_ptr<Zone> graph_zone_;
81  JSGraph* jsgraph_;
82  Zone compilation_zone_;
83  CompilationInfo info_;
84  std::unique_ptr<CompilationJob> job_;
85  uint32_t index_;
86  wasm::Result<wasm::DecodeStruct*> graph_construction_result_;
87  bool ok_;
88  ZoneVector<trap_handler::ProtectedInstructionData>
89      protected_instructions_;  // Instructions that are protected by the signal
90                                // handler.
91
92  DISALLOW_COPY_AND_ASSIGN(WasmCompilationUnit);
93};
94
95// Wraps a JS function, producing a code object that can be called from WASM.
96Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
97                                    wasm::FunctionSig* sig, uint32_t index,
98                                    Handle<String> module_name,
99                                    MaybeHandle<String> import_name,
100                                    wasm::ModuleOrigin origin);
101
102// Wraps a given wasm code object, producing a code object.
103Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
104                                    const wasm::WasmModule* module,
105                                    Handle<Code> wasm_code, uint32_t index);
106
107// Compiles a stub that redirects a call to a wasm function to the wasm
108// interpreter. It's ABI compatible with the compiled wasm function.
109Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
110                                         wasm::FunctionSig* sig,
111                                         Handle<WasmInstanceObject> instance);
112
113// Abstracts details of building TurboFan graph nodes for WASM to separate
114// the WASM decoder from the internal details of TurboFan.
115class WasmTrapHelper;
116typedef ZoneVector<Node*> NodeVector;
117class WasmGraphBuilder {
118 public:
119  WasmGraphBuilder(
120      wasm::ModuleEnv* module_env, Zone* z, JSGraph* g, wasm::FunctionSig* sig,
121      compiler::SourcePositionTable* source_position_table = nullptr);
122
123  Node** Buffer(size_t count) {
124    if (count > cur_bufsize_) {
125      size_t new_size = count + cur_bufsize_ + 5;
126      cur_buffer_ =
127          reinterpret_cast<Node**>(zone_->New(new_size * sizeof(Node*)));
128      cur_bufsize_ = new_size;
129    }
130    return cur_buffer_;
131  }
132
133  //-----------------------------------------------------------------------
134  // Operations independent of {control} or {effect}.
135  //-----------------------------------------------------------------------
136  Node* Error();
137  Node* Start(unsigned params);
138  Node* Param(unsigned index);
139  Node* Loop(Node* entry);
140  Node* Terminate(Node* effect, Node* control);
141  Node* Merge(unsigned count, Node** controls);
142  Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control);
143  Node* EffectPhi(unsigned count, Node** effects, Node* control);
144  Node* NumberConstant(int32_t value);
145  Node* Uint32Constant(uint32_t value);
146  Node* Int32Constant(int32_t value);
147  Node* Int64Constant(int64_t value);
148  Node* Float32Constant(float value);
149  Node* Float64Constant(double value);
150  Node* HeapConstant(Handle<HeapObject> value);
151  Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
152              wasm::WasmCodePosition position = wasm::kNoCodePosition);
153  Node* Unop(wasm::WasmOpcode opcode, Node* input,
154             wasm::WasmCodePosition position = wasm::kNoCodePosition);
155  Node* GrowMemory(Node* input);
156  Node* Throw(Node* input);
157  Node* Catch(Node* input, wasm::WasmCodePosition position);
158  unsigned InputCount(Node* node);
159  bool IsPhiWithMerge(Node* phi, Node* merge);
160  bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
161  void AppendToMerge(Node* merge, Node* from);
162  void AppendToPhi(Node* phi, Node* from);
163
164  void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr,
165                  Node** control = nullptr);
166
167  //-----------------------------------------------------------------------
168  // Operations that read and/or write {control} and {effect}.
169  //-----------------------------------------------------------------------
170  Node* BranchNoHint(Node* cond, Node** true_node, Node** false_node);
171  Node* BranchExpectTrue(Node* cond, Node** true_node, Node** false_node);
172  Node* BranchExpectFalse(Node* cond, Node** true_node, Node** false_node);
173
174  Node* Switch(unsigned count, Node* key);
175  Node* IfValue(int32_t value, Node* sw);
176  Node* IfDefault(Node* sw);
177  Node* Return(unsigned count, Node** nodes);
178  template <typename... Nodes>
179  Node* Return(Node* fst, Nodes*... more) {
180    Node* arr[] = {fst, more...};
181    return Return(arraysize(arr), arr);
182  }
183  Node* ReturnVoid();
184  Node* Unreachable(wasm::WasmCodePosition position);
185
186  Node* CallDirect(uint32_t index, Node** args, Node*** rets,
187                   wasm::WasmCodePosition position);
188  Node* CallIndirect(uint32_t index, Node** args, Node*** rets,
189                     wasm::WasmCodePosition position);
190
191  void BuildJSToWasmWrapper(Handle<Code> wasm_code, wasm::FunctionSig* sig);
192  void BuildWasmToJSWrapper(Handle<JSReceiver> target, wasm::FunctionSig* sig);
193  void BuildWasmInterpreterEntry(uint32_t func_index, wasm::FunctionSig* sig,
194                                 Handle<WasmInstanceObject> instance);
195
196  Node* ToJS(Node* node, wasm::ValueType type);
197  Node* FromJS(Node* node, Node* context, wasm::ValueType type);
198  Node* Invert(Node* node);
199  void EnsureFunctionTableNodes();
200
201  //-----------------------------------------------------------------------
202  // Operations that concern the linear memory.
203  //-----------------------------------------------------------------------
204  Node* CurrentMemoryPages();
205  Node* GetGlobal(uint32_t index);
206  Node* SetGlobal(uint32_t index, Node* val);
207  Node* LoadMem(wasm::ValueType type, MachineType memtype, Node* index,
208                uint32_t offset, uint32_t alignment,
209                wasm::WasmCodePosition position);
210  Node* StoreMem(MachineType type, Node* index, uint32_t offset,
211                 uint32_t alignment, Node* val,
212                 wasm::WasmCodePosition position);
213
214  static void PrintDebugName(Node* node);
215
216  Node* Control() { return *control_; }
217  Node* Effect() { return *effect_; }
218
219  void set_control_ptr(Node** control) { this->control_ = control; }
220
221  void set_effect_ptr(Node** effect) { this->effect_ = effect; }
222
223  wasm::FunctionSig* GetFunctionSignature() { return sig_; }
224
225  void Int64LoweringForTesting();
226
227  void SimdScalarLoweringForTesting();
228
229  void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
230
231  Node* CreateS128Value(int32_t value);
232
233  Node* SimdOp(wasm::WasmOpcode opcode, const NodeVector& inputs);
234
235  Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
236                   const NodeVector& inputs);
237
238  Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
239                    const NodeVector& inputs);
240
241  Node* SimdSwizzleOp(wasm::WasmOpcode opcode, uint32_t swizzle,
242                      const NodeVector& inputs);
243
244  bool has_simd() const { return has_simd_; }
245
246  wasm::ModuleEnv* module_env() const { return module_; }
247
248 private:
249  static const int kDefaultBufferSize = 16;
250  friend class WasmTrapHelper;
251
252  Zone* zone_;
253  JSGraph* jsgraph_;
254  wasm::ModuleEnv* module_ = nullptr;
255  Node* mem_buffer_ = nullptr;
256  Node* mem_size_ = nullptr;
257  NodeVector signature_tables_;
258  NodeVector function_tables_;
259  NodeVector function_table_sizes_;
260  Node** control_ = nullptr;
261  Node** effect_ = nullptr;
262  Node** cur_buffer_;
263  size_t cur_bufsize_;
264  Node* def_buffer_[kDefaultBufferSize];
265  bool has_simd_ = false;
266
267  WasmTrapHelper* trap_;
268  wasm::FunctionSig* sig_;
269  SetOncePointer<const Operator> allocate_heap_number_operator_;
270
271  compiler::SourcePositionTable* source_position_table_ = nullptr;
272
273  // Internal helper methods.
274  JSGraph* jsgraph() { return jsgraph_; }
275  Graph* graph();
276
277  Node* String(const char* string);
278  Node* MemSize(uint32_t offset);
279  Node* MemBuffer(uint32_t offset);
280  void BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset,
281                      wasm::WasmCodePosition position);
282
283  Node* BuildChangeEndianness(Node* node, MachineType type,
284                              wasm::ValueType wasmtype = wasm::kWasmStmt);
285
286  Node* MaskShiftCount32(Node* node);
287  Node* MaskShiftCount64(Node* node);
288
289  Node* BuildCCall(MachineSignature* sig, Node** args);
290  Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
291                      wasm::WasmCodePosition position);
292
293  Node* BuildF32CopySign(Node* left, Node* right);
294  Node* BuildF64CopySign(Node* left, Node* right);
295  Node* BuildI32SConvertF32(Node* input, wasm::WasmCodePosition position);
296  Node* BuildI32SConvertF64(Node* input, wasm::WasmCodePosition position);
297  Node* BuildI32UConvertF32(Node* input, wasm::WasmCodePosition position);
298  Node* BuildI32UConvertF64(Node* input, wasm::WasmCodePosition position);
299  Node* BuildI32Ctz(Node* input);
300  Node* BuildI32Popcnt(Node* input);
301  Node* BuildI64Ctz(Node* input);
302  Node* BuildI64Popcnt(Node* input);
303  Node* BuildBitCountingCall(Node* input, ExternalReference ref,
304                             MachineRepresentation input_type);
305
306  Node* BuildCFuncInstruction(ExternalReference ref, MachineType type,
307                              Node* input0, Node* input1 = nullptr);
308  Node* BuildF32Trunc(Node* input);
309  Node* BuildF32Floor(Node* input);
310  Node* BuildF32Ceil(Node* input);
311  Node* BuildF32NearestInt(Node* input);
312  Node* BuildF64Trunc(Node* input);
313  Node* BuildF64Floor(Node* input);
314  Node* BuildF64Ceil(Node* input);
315  Node* BuildF64NearestInt(Node* input);
316  Node* BuildI32Rol(Node* left, Node* right);
317  Node* BuildI64Rol(Node* left, Node* right);
318
319  Node* BuildF64Acos(Node* input);
320  Node* BuildF64Asin(Node* input);
321  Node* BuildF64Pow(Node* left, Node* right);
322  Node* BuildF64Mod(Node* left, Node* right);
323
324  Node* BuildIntToFloatConversionInstruction(
325      Node* input, ExternalReference ref,
326      MachineRepresentation parameter_representation,
327      const MachineType result_type);
328  Node* BuildF32SConvertI64(Node* input);
329  Node* BuildF32UConvertI64(Node* input);
330  Node* BuildF64SConvertI64(Node* input);
331  Node* BuildF64UConvertI64(Node* input);
332
333  Node* BuildFloatToIntConversionInstruction(
334      Node* input, ExternalReference ref,
335      MachineRepresentation parameter_representation,
336      const MachineType result_type, wasm::WasmCodePosition position);
337  Node* BuildI64SConvertF32(Node* input, wasm::WasmCodePosition position);
338  Node* BuildI64UConvertF32(Node* input, wasm::WasmCodePosition position);
339  Node* BuildI64SConvertF64(Node* input, wasm::WasmCodePosition position);
340  Node* BuildI64UConvertF64(Node* input, wasm::WasmCodePosition position);
341
342  Node* BuildI32DivS(Node* left, Node* right, wasm::WasmCodePosition position);
343  Node* BuildI32RemS(Node* left, Node* right, wasm::WasmCodePosition position);
344  Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
345  Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
346
347  Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
348  Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
349  Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
350  Node* BuildI64RemU(Node* left, Node* right, wasm::WasmCodePosition position);
351  Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref,
352                       MachineType result_type, int trap_zero,
353                       wasm::WasmCodePosition position);
354
355  Node* BuildJavaScriptToNumber(Node* node, Node* context);
356
357  Node* BuildChangeInt32ToTagged(Node* value);
358  Node* BuildChangeFloat64ToTagged(Node* value);
359  Node* BuildChangeTaggedToFloat64(Node* value);
360
361  Node* BuildChangeInt32ToSmi(Node* value);
362  Node* BuildChangeSmiToInt32(Node* value);
363  Node* BuildChangeUint32ToSmi(Node* value);
364  Node* BuildChangeSmiToFloat64(Node* value);
365  Node* BuildTestNotSmi(Node* value);
366  Node* BuildSmiShiftBitsConstant();
367
368  Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control);
369  Node* BuildLoadHeapNumberValue(Node* value, Node* control);
370  Node* BuildHeapNumberValueIndexConstant();
371
372  // Asm.js specific functionality.
373  Node* BuildI32AsmjsSConvertF32(Node* input);
374  Node* BuildI32AsmjsSConvertF64(Node* input);
375  Node* BuildI32AsmjsUConvertF32(Node* input);
376  Node* BuildI32AsmjsUConvertF64(Node* input);
377  Node* BuildI32AsmjsDivS(Node* left, Node* right);
378  Node* BuildI32AsmjsRemS(Node* left, Node* right);
379  Node* BuildI32AsmjsDivU(Node* left, Node* right);
380  Node* BuildI32AsmjsRemU(Node* left, Node* right);
381  Node* BuildAsmjsLoadMem(MachineType type, Node* index);
382  Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val);
383
384  Node** Realloc(Node** buffer, size_t old_count, size_t new_count) {
385    Node** buf = Buffer(new_count);
386    if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
387    return buf;
388  }
389
390  int AddParameterNodes(Node** args, int pos, int param_count,
391                        wasm::FunctionSig* sig);
392};
393}  // namespace compiler
394}  // namespace internal
395}  // namespace v8
396
397#endif  // V8_COMPILER_WASM_COMPILER_H_
398