• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/runtime/runtime.h"
13 #include "src/wasm/function-body-decoder.h"
14 #include "src/wasm/function-compiler.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 
20 namespace v8 {
21 namespace internal {
22 struct AssemblerOptions;
23 
24 namespace compiler {
25 // Forward declarations for some compiler data structures.
26 class CallDescriptor;
27 class Graph;
28 class MachineGraph;
29 class Node;
30 class NodeOriginTable;
31 class Operator;
32 class SourcePositionTable;
33 class WasmDecorator;
34 enum class TrapId : uint32_t;
35 }  // namespace compiler
36 
37 namespace wasm {
38 struct DecodeStruct;
39 // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
40 typedef compiler::Node TFNode;
41 typedef compiler::MachineGraph TFGraph;
42 class WasmCode;
43 struct WasmFeatures;
44 }  // namespace wasm
45 
46 namespace compiler {
47 
48 class TurbofanWasmCompilationUnit {
49  public:
50   explicit TurbofanWasmCompilationUnit(wasm::WasmCompilationUnit* wasm_unit);
51   ~TurbofanWasmCompilationUnit();
52 
53   SourcePositionTable* BuildGraphForWasmFunction(wasm::WasmFeatures* detected,
54                                                  double* decode_ms,
55                                                  MachineGraph* mcgraph,
56                                                  NodeOriginTable* node_origins);
57 
58   void ExecuteCompilation(wasm::WasmFeatures* detected);
59 
60   wasm::WasmCode* FinishCompilation(wasm::ErrorThrower*);
61 
62  private:
63   wasm::WasmCompilationUnit* const wasm_unit_;
64   bool ok_ = true;
65   wasm::WasmCode* wasm_code_ = nullptr;
66   wasm::Result<wasm::DecodeStruct*> graph_construction_result_;
67 
68   DISALLOW_COPY_AND_ASSIGN(TurbofanWasmCompilationUnit);
69 };
70 
71 // Wraps a JS function, producing a code object that can be called from wasm.
72 MaybeHandle<Code> CompileWasmToJSWrapper(Isolate*, Handle<JSReceiver> target,
73                                          wasm::FunctionSig*, uint32_t index,
74                                          wasm::ModuleOrigin,
75                                          wasm::UseTrapHandler);
76 
77 // Creates a code object calling a wasm function with the given signature,
78 // callable from JS.
79 // TODO(clemensh): Remove the {UseTrapHandler} parameter to make js-to-wasm
80 // wrappers sharable across instances.
81 V8_EXPORT_PRIVATE MaybeHandle<Code> CompileJSToWasmWrapper(
82     Isolate*, const wasm::NativeModule*, wasm::FunctionSig*, bool is_import,
83     wasm::UseTrapHandler);
84 
85 // Compiles a stub that redirects a call to a wasm function to the wasm
86 // interpreter. It's ABI compatible with the compiled wasm function.
87 MaybeHandle<Code> CompileWasmInterpreterEntry(Isolate*, uint32_t func_index,
88                                               wasm::FunctionSig*);
89 
90 // Helper function to get the offset into a fixed array for a given {index}.
91 // TODO(titzer): access-builder.h is not accessible outside compiler. Move?
92 int FixedArrayOffsetMinusTag(uint32_t index);
93 
94 enum CWasmEntryParameters {
95   kCodeObject,
96   kWasmInstance,
97   kArgumentsBuffer,
98   // marker:
99   kNumParameters
100 };
101 
102 // Compiles a stub with JS linkage, taking parameters as described by
103 // {CWasmEntryParameters}. It loads the wasm parameters from the argument
104 // buffer and calls the wasm function given as first parameter.
105 MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig);
106 
107 // Values from the instance object are cached between WASM-level function calls.
108 // This struct allows the SSA environment handling this cache to be defined
109 // and manipulated in wasm-compiler.{h,cc} instead of inside the WASM decoder.
110 // (Note that currently, the globals base is immutable, so not cached here.)
111 struct WasmInstanceCacheNodes {
112   Node* mem_start;
113   Node* mem_size;
114   Node* mem_mask;
115 };
116 
117 // Abstracts details of building TurboFan graph nodes for wasm to separate
118 // the wasm decoder from the internal details of TurboFan.
119 class WasmGraphBuilder {
120  public:
121   enum EnforceBoundsCheck : bool {
122     kNeedsBoundsCheck = true,
123     kCanOmitBoundsCheck = false
124   };
125   enum UseRetpoline : bool { kRetpoline = true, kNoRetpoline = false };
126 
127   WasmGraphBuilder(wasm::ModuleEnv* env, Zone* zone, MachineGraph* mcgraph,
128                    wasm::FunctionSig* sig,
129                    compiler::SourcePositionTable* spt = nullptr);
130 
Buffer(size_t count)131   Node** Buffer(size_t count) {
132     if (count > cur_bufsize_) {
133       size_t new_size = count + cur_bufsize_ + 5;
134       cur_buffer_ =
135           reinterpret_cast<Node**>(zone_->New(new_size * sizeof(Node*)));
136       cur_bufsize_ = new_size;
137     }
138     return cur_buffer_;
139   }
140 
141   //-----------------------------------------------------------------------
142   // Operations independent of {control} or {effect}.
143   //-----------------------------------------------------------------------
144   Node* Error();
145   Node* Start(unsigned params);
146   Node* Param(unsigned index);
147   Node* Loop(Node* entry);
148   Node* Terminate(Node* effect, Node* control);
149   Node* Merge(unsigned count, Node** controls);
150   Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control);
151   Node* CreateOrMergeIntoPhi(MachineRepresentation rep, Node* merge,
152                              Node* tnode, Node* fnode);
153   Node* CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode, Node* fnode);
154   Node* EffectPhi(unsigned count, Node** effects, Node* control);
155   Node* RefNull();
156   Node* Uint32Constant(uint32_t value);
157   Node* Int32Constant(int32_t value);
158   Node* Int64Constant(int64_t value);
159   Node* IntPtrConstant(intptr_t value);
160   Node* Float32Constant(float value);
161   Node* Float64Constant(double value);
162   Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
163               wasm::WasmCodePosition position = wasm::kNoCodePosition);
164   Node* Unop(wasm::WasmOpcode opcode, Node* input,
165              wasm::WasmCodePosition position = wasm::kNoCodePosition);
166   Node* GrowMemory(Node* input);
167   Node* Throw(uint32_t tag, const wasm::WasmException* exception,
168               const Vector<Node*> values);
169   Node* Rethrow();
170   Node* ConvertExceptionTagToRuntimeId(uint32_t tag);
171   Node* GetExceptionRuntimeId();
172   Node** GetExceptionValues(const wasm::WasmException* except_decl);
173   bool IsPhiWithMerge(Node* phi, Node* merge);
174   bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
175   void AppendToMerge(Node* merge, Node* from);
176   void AppendToPhi(Node* phi, Node* from);
177 
178   void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr,
179                   Node** control = nullptr);
180 
181   void PatchInStackCheckIfNeeded();
182 
183   //-----------------------------------------------------------------------
184   // Operations that read and/or write {control} and {effect}.
185   //-----------------------------------------------------------------------
186   Node* BranchNoHint(Node* cond, Node** true_node, Node** false_node);
187   Node* BranchExpectTrue(Node* cond, Node** true_node, Node** false_node);
188   Node* BranchExpectFalse(Node* cond, Node** true_node, Node** false_node);
189 
190   Node* TrapIfTrue(wasm::TrapReason reason, Node* cond,
191                    wasm::WasmCodePosition position);
192   Node* TrapIfFalse(wasm::TrapReason reason, Node* cond,
193                     wasm::WasmCodePosition position);
194   Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
195                    wasm::WasmCodePosition position);
196   Node* ZeroCheck32(wasm::TrapReason reason, Node* node,
197                     wasm::WasmCodePosition position);
198   Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
199                    wasm::WasmCodePosition position);
200   Node* ZeroCheck64(wasm::TrapReason reason, Node* node,
201                     wasm::WasmCodePosition position);
202 
203   Node* Switch(unsigned count, Node* key);
204   Node* IfValue(int32_t value, Node* sw);
205   Node* IfDefault(Node* sw);
206   Node* Return(unsigned count, Node** nodes);
207   template <typename... Nodes>
Return(Node * fst,Nodes * ...more)208   Node* Return(Node* fst, Nodes*... more) {
209     Node* arr[] = {fst, more...};
210     return Return(arraysize(arr), arr);
211   }
212   Node* ReturnVoid();
213   Node* Unreachable(wasm::WasmCodePosition position);
214 
215   Node* CallDirect(uint32_t index, Node** args, Node*** rets,
216                    wasm::WasmCodePosition position);
217   Node* CallIndirect(uint32_t index, Node** args, Node*** rets,
218                      wasm::WasmCodePosition position);
219 
220   Node* Invert(Node* node);
221 
222   //-----------------------------------------------------------------------
223   // Operations that concern the linear memory.
224   //-----------------------------------------------------------------------
225   Node* CurrentMemoryPages();
226   Node* GetGlobal(uint32_t index);
227   Node* SetGlobal(uint32_t index, Node* val);
228   Node* TraceMemoryOperation(bool is_store, MachineRepresentation, Node* index,
229                              uint32_t offset, wasm::WasmCodePosition);
230   Node* LoadMem(wasm::ValueType type, MachineType memtype, Node* index,
231                 uint32_t offset, uint32_t alignment,
232                 wasm::WasmCodePosition position);
233   Node* StoreMem(MachineRepresentation mem_rep, Node* index, uint32_t offset,
234                  uint32_t alignment, Node* val, wasm::WasmCodePosition position,
235                  wasm::ValueType type);
236   static void PrintDebugName(Node* node);
237 
set_instance_node(Node * instance_node)238   void set_instance_node(Node* instance_node) {
239     this->instance_node_ = instance_node;
240   }
241 
Control()242   Node* Control() {
243     DCHECK_NOT_NULL(*control_);
244     return *control_;
245   }
Effect()246   Node* Effect() {
247     DCHECK_NOT_NULL(*effect_);
248     return *effect_;
249   }
SetControl(Node * node)250   Node* SetControl(Node* node) {
251     *control_ = node;
252     return node;
253   }
SetEffect(Node * node)254   Node* SetEffect(Node* node) {
255     *effect_ = node;
256     return node;
257   }
258 
set_control_ptr(Node ** control)259   void set_control_ptr(Node** control) { this->control_ = control; }
260 
set_effect_ptr(Node ** effect)261   void set_effect_ptr(Node** effect) { this->effect_ = effect; }
262 
263   void GetGlobalBaseAndOffset(MachineType mem_type, const wasm::WasmGlobal&,
264                               Node** base_node, Node** offset_node);
265 
266   // Utilities to manipulate sets of instance cache nodes.
267   void InitInstanceCache(WasmInstanceCacheNodes* instance_cache);
268   void PrepareInstanceCacheForLoop(WasmInstanceCacheNodes* instance_cache,
269                                    Node* control);
270   void NewInstanceCacheMerge(WasmInstanceCacheNodes* to,
271                              WasmInstanceCacheNodes* from, Node* merge);
272   void MergeInstanceCacheInto(WasmInstanceCacheNodes* to,
273                               WasmInstanceCacheNodes* from, Node* merge);
274 
set_instance_cache(WasmInstanceCacheNodes * instance_cache)275   void set_instance_cache(WasmInstanceCacheNodes* instance_cache) {
276     this->instance_cache_ = instance_cache;
277   }
278 
GetFunctionSignature()279   wasm::FunctionSig* GetFunctionSignature() { return sig_; }
280 
281   void LowerInt64();
282 
283   void SimdScalarLoweringForTesting();
284 
285   void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
286 
287   Node* S128Zero();
288   Node* S1x4Zero();
289   Node* S1x8Zero();
290   Node* S1x16Zero();
291 
292   Node* SimdOp(wasm::WasmOpcode opcode, Node* const* inputs);
293 
294   Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane, Node* const* inputs);
295 
296   Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
297                     Node* const* inputs);
298 
299   Node* Simd8x16ShuffleOp(const uint8_t shuffle[16], Node* const* inputs);
300 
301   Node* AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs,
302                  uint32_t alignment, uint32_t offset,
303                  wasm::WasmCodePosition position);
304 
has_simd()305   bool has_simd() const { return has_simd_; }
306 
module()307   const wasm::WasmModule* module() { return env_ ? env_->module : nullptr; }
308 
use_trap_handler()309   bool use_trap_handler() const { return env_ && env_->use_trap_handler; }
310 
mcgraph()311   MachineGraph* mcgraph() { return mcgraph_; }
312   Graph* graph();
313 
314   void AddBytecodePositionDecorator(NodeOriginTable* node_origins,
315                                     wasm::Decoder* decoder);
316 
317   void RemoveBytecodePositionDecorator();
318 
319  protected:
320   static const int kDefaultBufferSize = 16;
321 
322   Zone* const zone_;
323   MachineGraph* const mcgraph_;
324   wasm::ModuleEnv* const env_;
325 
326   Node** control_ = nullptr;
327   Node** effect_ = nullptr;
328   WasmInstanceCacheNodes* instance_cache_ = nullptr;
329 
330   SetOncePointer<Node> instance_node_;
331   SetOncePointer<Node> globals_start_;
332   SetOncePointer<Node> imported_mutable_globals_;
333   SetOncePointer<Node> stack_check_code_node_;
334   SetOncePointer<const Operator> stack_check_call_operator_;
335 
336   Node** cur_buffer_;
337   size_t cur_bufsize_;
338   Node* def_buffer_[kDefaultBufferSize];
339   bool has_simd_ = false;
340   bool needs_stack_check_ = false;
341   const bool untrusted_code_mitigations_ = true;
342 
343   wasm::FunctionSig* const sig_;
344 
345   compiler::WasmDecorator* decorator_ = nullptr;
346 
347   compiler::SourcePositionTable* const source_position_table_ = nullptr;
348 
349   Node* NoContextConstant();
350 
351   Node* MemBuffer(uint32_t offset);
352   // BoundsCheckMem receives a uint32 {index} node and returns a ptrsize index.
353   Node* BoundsCheckMem(uint8_t access_size, Node* index, uint32_t offset,
354                        wasm::WasmCodePosition, EnforceBoundsCheck);
355   Node* CheckBoundsAndAlignment(uint8_t access_size, Node* index,
356                                 uint32_t offset, wasm::WasmCodePosition);
357   Node* Uint32ToUintptr(Node*);
358   const Operator* GetSafeLoadOperator(int offset, wasm::ValueType type);
359   const Operator* GetSafeStoreOperator(int offset, wasm::ValueType type);
360   Node* BuildChangeEndiannessStore(Node* node, MachineRepresentation rep,
361                                    wasm::ValueType wasmtype = wasm::kWasmStmt);
362   Node* BuildChangeEndiannessLoad(Node* node, MachineType type,
363                                   wasm::ValueType wasmtype = wasm::kWasmStmt);
364 
365   Node* MaskShiftCount32(Node* node);
366   Node* MaskShiftCount64(Node* node);
367 
368   template <typename... Args>
369   Node* BuildCCall(MachineSignature* sig, Node* function, Args... args);
370   Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
371                       wasm::WasmCodePosition position, Node* instance_node,
372                       UseRetpoline use_retpoline);
373   Node* BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
374                             wasm::WasmCodePosition position, int func_index);
375   Node* BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
376                             wasm::WasmCodePosition position, Node* func_index);
377 
378   Node* BuildF32CopySign(Node* left, Node* right);
379   Node* BuildF64CopySign(Node* left, Node* right);
380 
381   Node* BuildIntConvertFloat(Node* input, wasm::WasmCodePosition position,
382                              wasm::WasmOpcode);
383   Node* BuildI32Ctz(Node* input);
384   Node* BuildI32Popcnt(Node* input);
385   Node* BuildI64Ctz(Node* input);
386   Node* BuildI64Popcnt(Node* input);
387   Node* BuildBitCountingCall(Node* input, ExternalReference ref,
388                              MachineRepresentation input_type);
389 
390   Node* BuildCFuncInstruction(ExternalReference ref, MachineType type,
391                               Node* input0, Node* input1 = nullptr);
392   Node* BuildF32Trunc(Node* input);
393   Node* BuildF32Floor(Node* input);
394   Node* BuildF32Ceil(Node* input);
395   Node* BuildF32NearestInt(Node* input);
396   Node* BuildF64Trunc(Node* input);
397   Node* BuildF64Floor(Node* input);
398   Node* BuildF64Ceil(Node* input);
399   Node* BuildF64NearestInt(Node* input);
400   Node* BuildI32Rol(Node* left, Node* right);
401   Node* BuildI64Rol(Node* left, Node* right);
402 
403   Node* BuildF64Acos(Node* input);
404   Node* BuildF64Asin(Node* input);
405   Node* BuildF64Pow(Node* left, Node* right);
406   Node* BuildF64Mod(Node* left, Node* right);
407 
408   Node* BuildIntToFloatConversionInstruction(
409       Node* input, ExternalReference ref,
410       MachineRepresentation parameter_representation,
411       const MachineType result_type);
412   Node* BuildF32SConvertI64(Node* input);
413   Node* BuildF32UConvertI64(Node* input);
414   Node* BuildF64SConvertI64(Node* input);
415   Node* BuildF64UConvertI64(Node* input);
416 
417   Node* BuildCcallConvertFloat(Node* input, wasm::WasmCodePosition position,
418                                wasm::WasmOpcode opcode);
419 
420   Node* BuildI32DivS(Node* left, Node* right, wasm::WasmCodePosition position);
421   Node* BuildI32RemS(Node* left, Node* right, wasm::WasmCodePosition position);
422   Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
423   Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
424 
425   Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
426   Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
427   Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
428   Node* BuildI64RemU(Node* left, Node* right, wasm::WasmCodePosition position);
429   Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref,
430                        MachineType result_type, wasm::TrapReason trap_zero,
431                        wasm::WasmCodePosition position);
432 
433   Node* BuildChangeInt32ToIntPtr(Node* value);
434   Node* BuildChangeInt32ToSmi(Node* value);
435   Node* BuildChangeUint31ToSmi(Node* value);
436   Node* BuildSmiShiftBitsConstant();
437   Node* BuildChangeSmiToInt32(Node* value);
438 
439   Node* BuildLoadInstanceFromExportedFunction(Node* closure);
440 
441   // Asm.js specific functionality.
442   Node* BuildI32AsmjsSConvertF32(Node* input);
443   Node* BuildI32AsmjsSConvertF64(Node* input);
444   Node* BuildI32AsmjsUConvertF32(Node* input);
445   Node* BuildI32AsmjsUConvertF64(Node* input);
446   Node* BuildI32AsmjsDivS(Node* left, Node* right);
447   Node* BuildI32AsmjsRemS(Node* left, Node* right);
448   Node* BuildI32AsmjsDivU(Node* left, Node* right);
449   Node* BuildI32AsmjsRemU(Node* left, Node* right);
450   Node* BuildAsmjsLoadMem(MachineType type, Node* index);
451   Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val);
452 
453   uint32_t GetExceptionEncodedSize(const wasm::WasmException* exception) const;
454   void BuildEncodeException32BitValue(uint32_t* index, Node* value);
455   Node* BuildDecodeException32BitValue(Node* const* values, uint32_t* index);
456 
Realloc(Node * const * buffer,size_t old_count,size_t new_count)457   Node** Realloc(Node* const* buffer, size_t old_count, size_t new_count) {
458     Node** buf = Buffer(new_count);
459     if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
460     return buf;
461   }
462 
SetNeedsStackCheck()463   void SetNeedsStackCheck() { needs_stack_check_ = true; }
464 
465   //-----------------------------------------------------------------------
466   // Operations involving the CEntry, a dependency we want to remove
467   // to get off the GC heap.
468   //-----------------------------------------------------------------------
469   Node* BuildCallToRuntime(Runtime::FunctionId f, Node** parameters,
470                            int parameter_count);
471 
472   Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, Node* js_context,
473                                       Node** parameters, int parameter_count);
474   Node* BuildCallToRuntimeWithContextFromJS(Runtime::FunctionId f,
475                                             Node* js_context,
476                                             Node* const* parameters,
477                                             int parameter_count);
478   TrapId GetTrapIdForTrap(wasm::TrapReason reason);
479 };
480 
481 V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
482     Zone* zone, wasm::FunctionSig* signature,
483     WasmGraphBuilder::UseRetpoline use_retpoline =
484         WasmGraphBuilder::kNoRetpoline);
485 
486 V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
487     Zone* zone, CallDescriptor* call_descriptor);
488 
489 V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptorForSimd(
490     Zone* zone, CallDescriptor* call_descriptor);
491 
492 AssemblerOptions WasmAssemblerOptions();
493 
494 }  // namespace compiler
495 }  // namespace internal
496 }  // namespace v8
497 
498 #endif  // V8_COMPILER_WASM_COMPILER_H_
499