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 
18 namespace v8 {
19 namespace internal {
20 
21 namespace compiler {
22 // Forward declarations for some compiler data structures.
23 class Node;
24 class JSGraph;
25 class Graph;
26 class Operator;
27 class SourcePositionTable;
28 }  // namespace compiler
29 
30 namespace wasm {
31 // Forward declarations for some WASM data structures.
32 struct ModuleEnv;
33 struct WasmFunction;
34 class ErrorThrower;
35 struct DecodeStruct;
36 
37 // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
38 typedef compiler::Node TFNode;
39 typedef compiler::JSGraph TFGraph;
40 }  // namespace wasm
41 
42 namespace compiler {
43 class 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 
graph_zone()49   Zone* graph_zone() { return graph_zone_.get(); }
index()50   int index() const { return index_; }
51 
52   void ExecuteCompilation();
53   Handle<Code> FinishCompilation();
54 
CompileWasmFunction(wasm::ErrorThrower * thrower,Isolate * isolate,wasm::ModuleEnv * module_env,const wasm::WasmFunction * function)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.
85 Handle<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.
91 Handle<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.
96 class WasmTrapHelper;
97 typedef ZoneVector<Node*> NodeVector;
98 class WasmGraphBuilder {
99  public:
100   WasmGraphBuilder(
101       Zone* z, JSGraph* g, wasm::FunctionSig* function_signature,
102       compiler::SourcePositionTable* source_position_table = nullptr);
103 
Buffer(size_t count)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 
Control()190   Node* Control() { return *control_; }
Effect()191   Node* Effect() { return *effect_; }
192 
set_module(wasm::ModuleEnv * module)193   void set_module(wasm::ModuleEnv* module) { this->module_ = module; }
194 
set_control_ptr(Node ** control)195   void set_control_ptr(Node** control) { this->control_ = control; }
196 
set_effect_ptr(Node ** effect)197   void set_effect_ptr(Node** effect) { this->effect_ = effect; }
198 
GetFunctionSignature()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.
jsgraph()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 
Realloc(Node ** buffer,size_t old_count,size_t new_count)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