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