• 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 #if !V8_ENABLE_WEBASSEMBLY
6 #error This header should only be included if WebAssembly is enabled.
7 #endif  // !V8_ENABLE_WEBASSEMBLY
8 
9 #ifndef V8_COMPILER_WASM_COMPILER_H_
10 #define V8_COMPILER_WASM_COMPILER_H_
11 
12 #include <memory>
13 #include <utility>
14 
15 // Clients of this interface shouldn't depend on lots of compiler internals.
16 // Do not include anything from src/compiler here!
17 #include "src/base/small-vector.h"
18 #include "src/objects/js-function.h"
19 #include "src/runtime/runtime.h"
20 #include "src/wasm/function-body-decoder.h"
21 #include "src/wasm/function-compiler.h"
22 #include "src/wasm/wasm-module.h"
23 #include "src/wasm/wasm-opcodes.h"
24 #include "src/wasm/wasm-result.h"
25 #include "src/zone/zone.h"
26 
27 namespace v8 {
28 namespace internal {
29 struct AssemblerOptions;
30 class TurbofanCompilationJob;
31 
32 namespace compiler {
33 // Forward declarations for some compiler data structures.
34 class CallDescriptor;
35 class Graph;
36 class MachineGraph;
37 class Node;
38 class NodeOriginTable;
39 class Operator;
40 class SourcePositionTable;
41 class WasmDecorator;
42 class WasmGraphAssembler;
43 enum class TrapId : uint32_t;
44 struct Int64LoweringSpecialCase;
45 template <size_t VarCount>
46 class GraphAssemblerLabel;
47 enum class BranchHint : uint8_t;
48 }  // namespace compiler
49 
50 namespace wasm {
51 struct DecodeStruct;
52 // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
53 using TFNode = compiler::Node;
54 using TFGraph = compiler::MachineGraph;
55 class WasmCode;
56 class WasmFeatures;
57 class WireBytesStorage;
58 enum class LoadTransformationKind : uint8_t;
59 enum Suspend : bool { kSuspend = false, kNoSuspend = true };
60 }  // namespace wasm
61 
62 namespace compiler {
63 
64 wasm::WasmCompilationResult ExecuteTurbofanWasmCompilation(
65     wasm::CompilationEnv*, const wasm::WireBytesStorage* wire_bytes_storage,
66     const wasm::FunctionBody&, int func_index, Counters*,
67     wasm::WasmFeatures* detected);
68 
69 // Calls to Wasm imports are handled in several different ways, depending on the
70 // type of the target function/callable and whether the signature matches the
71 // argument arity.
72 enum class WasmImportCallKind : uint8_t {
73   kLinkError,                // static Wasm->Wasm type error
74   kRuntimeTypeError,         // runtime Wasm->JS type error
75   kWasmToCapi,               // fast Wasm->C-API call
76   kWasmToJSFastApi,          // fast Wasm->JS Fast API C call
77   kWasmToWasm,               // fast Wasm->Wasm call
78   kJSFunctionArityMatch,     // fast Wasm->JS call
79   kJSFunctionArityMismatch,  // Wasm->JS, needs adapter frame
80   // Math functions imported from JavaScript that are intrinsified
81   kFirstMathIntrinsic,
82   kF64Acos = kFirstMathIntrinsic,
83   kF64Asin,
84   kF64Atan,
85   kF64Cos,
86   kF64Sin,
87   kF64Tan,
88   kF64Exp,
89   kF64Log,
90   kF64Atan2,
91   kF64Pow,
92   kF64Ceil,
93   kF64Floor,
94   kF64Sqrt,
95   kF64Min,
96   kF64Max,
97   kF64Abs,
98   kF32Min,
99   kF32Max,
100   kF32Abs,
101   kF32Ceil,
102   kF32Floor,
103   kF32Sqrt,
104   kF32ConvertF64,
105   kLastMathIntrinsic = kF32ConvertF64,
106   // For everything else, there's the call builtin.
107   kUseCallBuiltin
108 };
109 
110 constexpr WasmImportCallKind kDefaultImportCallKind =
111     WasmImportCallKind::kJSFunctionArityMatch;
112 
113 struct WasmImportData {
114   WasmImportCallKind kind;
115   Handle<JSReceiver> callable;
116   Handle<HeapObject> suspender;
117 };
118 // Resolves which import call wrapper is required for the given JS callable.
119 // Returns the kind of wrapper needed, the ultimate target callable, and the
120 // suspender object if applicable. Note that some callables (e.g. a
121 // {WasmExportedFunction} or {WasmJSFunction}) just wrap another target, which
122 // is why the ultimate target is returned as well.
123 V8_EXPORT_PRIVATE WasmImportData ResolveWasmImportCall(
124     Handle<JSReceiver> callable, const wasm::FunctionSig* sig,
125     const wasm::WasmModule* module, const wasm::WasmFeatures& enabled_features);
126 
127 // Compiles an import call wrapper, which allows Wasm to call imports.
128 V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmImportCallWrapper(
129     wasm::CompilationEnv* env, WasmImportCallKind, const wasm::FunctionSig*,
130     bool source_positions, int expected_arity, wasm::Suspend);
131 
132 // Compiles a host call wrapper, which allows Wasm to call host functions.
133 wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::NativeModule*,
134                                            const wasm::FunctionSig*);
135 
136 // Compiles a wrapper to call a Fast API function from Wasm.
137 wasm::WasmCode* CompileWasmJSFastCallWrapper(wasm::NativeModule*,
138                                              const wasm::FunctionSig*,
139                                              Handle<JSFunction> target);
140 
141 // Returns an TurbofanCompilationJob object for a JS to Wasm wrapper.
142 std::unique_ptr<TurbofanCompilationJob> NewJSToWasmCompilationJob(
143     Isolate* isolate, const wasm::FunctionSig* sig,
144     const wasm::WasmModule* module, bool is_import,
145     const wasm::WasmFeatures& enabled_features);
146 
147 MaybeHandle<Code> CompileWasmToJSWrapper(Isolate* isolate,
148                                          const wasm::FunctionSig* sig,
149                                          WasmImportCallKind kind,
150                                          int expected_arity,
151                                          wasm::Suspend suspend);
152 
153 // Compiles a stub with JS linkage that serves as an adapter for function
154 // objects constructed via {WebAssembly.Function}. It performs a round-trip
155 // simulating a JS-to-Wasm-to-JS coercion of parameter and return values.
156 MaybeHandle<Code> CompileJSToJSWrapper(Isolate*, const wasm::FunctionSig*,
157                                        const wasm::WasmModule* module);
158 
159 enum CWasmEntryParameters {
160   kCodeEntry,
161   kObjectRef,
162   kArgumentsBuffer,
163   kCEntryFp,
164   // marker:
165   kNumParameters
166 };
167 
168 // Compiles a stub with C++ linkage, to be called from Execution::CallWasm,
169 // which knows how to feed it its parameters.
170 V8_EXPORT_PRIVATE Handle<CodeT> CompileCWasmEntry(
171     Isolate*, const wasm::FunctionSig*, const wasm::WasmModule* module);
172 
173 class JSWasmCallData {
174  public:
175   explicit JSWasmCallData(const wasm::FunctionSig* wasm_signature);
176 
arg_needs_conversion(size_t index)177   bool arg_needs_conversion(size_t index) const {
178     DCHECK_LT(index, arg_needs_conversion_.size());
179     return arg_needs_conversion_[index];
180   }
result_needs_conversion()181   bool result_needs_conversion() const { return result_needs_conversion_; }
182 
183  private:
184   bool result_needs_conversion_;
185   std::vector<bool> arg_needs_conversion_;
186 };
187 
188 // Values from the instance object are cached between Wasm-level function calls.
189 // This struct allows the SSA environment handling this cache to be defined
190 // and manipulated in wasm-compiler.{h,cc} instead of inside the Wasm decoder.
191 // (Note that currently, the globals base is immutable, so not cached here.)
192 struct WasmInstanceCacheNodes {
193   Node* mem_start;
194   Node* mem_size;
195 };
196 
197 struct WasmLoopInfo {
198   Node* header;
199   uint32_t nesting_depth;
200   // This loop has, to our best knowledge, no other loops nested within it. A
201   // loop can obtain inner loops despite this after inlining.
202   bool can_be_innermost;
203 
WasmLoopInfoWasmLoopInfo204   WasmLoopInfo(Node* header, uint32_t nesting_depth, bool can_be_innermost)
205       : header(header),
206         nesting_depth(nesting_depth),
207         can_be_innermost(can_be_innermost) {}
208 };
209 
210 // Abstracts details of building TurboFan graph nodes for wasm to separate
211 // the wasm decoder from the internal details of TurboFan.
212 class WasmGraphBuilder {
213  public:
214   // The parameter at index 0 in a wasm function has special meaning:
215   // - For normal wasm functions, it points to the function's instance.
216   // - For Wasm-to-JS and C-API wrappers, it points to a {WasmApiFunctionRef}
217   //   object which represents the function's context.
218   // - For JS-to-Wasm and JS-to-JS wrappers (which are JS functions), it does
219   //   not have a special meaning. In these cases, we need access to an isolate
220   //   at compile time, i.e., {isolate_} needs to be non-null.
221   enum Parameter0Mode {
222     kInstanceMode,
223     kWasmApiFunctionRefMode,
224     kNoSpecialParameterMode
225   };
226   struct ObjectReferenceKnowledge {
227     bool object_can_be_null;
228     uint8_t rtt_depth;
229   };
230   enum EnforceBoundsCheck : bool {  // --
231     kNeedsBoundsCheck = true,
232     kCanOmitBoundsCheck = false
233   };
234   enum CheckForNull : bool {  // --
235     kWithNullCheck = true,
236     kWithoutNullCheck = false
237   };
238   enum BoundsCheckResult {
239     // Statically OOB.
240     kOutOfBounds,
241     // Dynamically checked (using 1-2 conditional branches).
242     kDynamicallyChecked,
243     // OOB handled via the trap handler.
244     kTrapHandler,
245     // Statically known to be in bounds.
246     kInBounds
247   };
248 
249   V8_EXPORT_PRIVATE WasmGraphBuilder(
250       wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph,
251       const wasm::FunctionSig* sig,
252       compiler::SourcePositionTable* spt = nullptr)
WasmGraphBuilder(env,zone,mcgraph,sig,spt,kInstanceMode,nullptr)253       : WasmGraphBuilder(env, zone, mcgraph, sig, spt, kInstanceMode, nullptr) {
254   }
255 
256   V8_EXPORT_PRIVATE ~WasmGraphBuilder();
257 
258   //-----------------------------------------------------------------------
259   // Operations independent of {control} or {effect}.
260   //-----------------------------------------------------------------------
261   void Start(unsigned params);
262   Node* Param(int index, const char* debug_name = nullptr);
263   Node* Loop(Node* entry);
264   void TerminateLoop(Node* effect, Node* control);
265   Node* LoopExit(Node* loop_node);
266   // Assumes current control() is the corresponding loop exit.
267   Node* LoopExitValue(Node* value, MachineRepresentation representation);
268   void TerminateThrow(Node* effect, Node* control);
269   Node* Merge(unsigned count, Node** controls);
270   template <typename... Nodes>
271   Node* Merge(Node* fst, Nodes*... args);
272   Node* Phi(wasm::ValueType type, unsigned count, Node** vals_and_control);
273   Node* CreateOrMergeIntoPhi(MachineRepresentation rep, Node* merge,
274                              Node* tnode, Node* fnode);
275   Node* CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode, Node* fnode);
276   Node* EffectPhi(unsigned count, Node** effects_and_control);
277   Node* RefNull();
278   Node* RefFunc(uint32_t function_index);
279   Node* RefAsNonNull(Node* arg, wasm::WasmCodePosition position);
280   Node* Int32Constant(int32_t value);
281   Node* Int64Constant(int64_t value);
282   Node* Float32Constant(float value);
283   Node* Float64Constant(double value);
284   Node* Simd128Constant(const uint8_t value[16]);
285   Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
286               wasm::WasmCodePosition position = wasm::kNoCodePosition);
287   Node* Unop(wasm::WasmOpcode opcode, Node* input,
288              wasm::WasmCodePosition position = wasm::kNoCodePosition);
289   Node* MemoryGrow(Node* input);
290   Node* Throw(uint32_t tag_index, const wasm::WasmTag* tag,
291               const base::Vector<Node*> values,
292               wasm::WasmCodePosition position);
293   Node* Rethrow(Node* except_obj);
294   Node* ExceptionTagEqual(Node* caught_tag, Node* expected_tag);
295   Node* LoadTagFromTable(uint32_t tag_index);
296   Node* GetExceptionTag(Node* except_obj);
297   Node* GetExceptionValues(Node* except_obj, const wasm::WasmTag* tag,
298                            base::Vector<Node*> values_out);
299   bool IsPhiWithMerge(Node* phi, Node* merge);
300   bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
301   void AppendToMerge(Node* merge, Node* from);
302   void AppendToPhi(Node* phi, Node* from);
303 
304   void StackCheck(WasmInstanceCacheNodes* shared_memory_instance_cache,
305                   wasm::WasmCodePosition);
306 
307   void PatchInStackCheckIfNeeded();
308 
309   //-----------------------------------------------------------------------
310   // Operations that read and/or write {control} and {effect}.
311   //-----------------------------------------------------------------------
312   Node* BranchNoHint(Node* cond, Node** true_node, Node** false_node);
313   Node* BranchExpectFalse(Node* cond, Node** true_node, Node** false_node);
314   Node* BranchExpectTrue(Node* cond, Node** true_node, Node** false_node);
315 
316   void TrapIfTrue(wasm::TrapReason reason, Node* cond,
317                   wasm::WasmCodePosition position);
318   void TrapIfFalse(wasm::TrapReason reason, Node* cond,
319                    wasm::WasmCodePosition position);
320   Node* Select(Node *cond, Node* true_node, Node* false_node,
321                wasm::ValueType type);
322 
323   void TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val,
324                   wasm::WasmCodePosition position);
325   void ZeroCheck32(wasm::TrapReason reason, Node* node,
326                    wasm::WasmCodePosition position);
327   void TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val,
328                   wasm::WasmCodePosition position);
329   void ZeroCheck64(wasm::TrapReason reason, Node* node,
330                    wasm::WasmCodePosition position);
331 
332   Node* Switch(unsigned count, Node* key);
333   Node* IfValue(int32_t value, Node* sw);
334   Node* IfDefault(Node* sw);
335   Node* Return(base::Vector<Node*> nodes);
336   template <typename... Nodes>
Return(Node * fst,Nodes * ...more)337   Node* Return(Node* fst, Nodes*... more) {
338     Node* arr[] = {fst, more...};
339     return Return(base::ArrayVector(arr));
340   }
341 
342   void TraceFunctionEntry(wasm::WasmCodePosition position);
343   void TraceFunctionExit(base::Vector<Node*> vals,
344                          wasm::WasmCodePosition position);
345 
346   void Trap(wasm::TrapReason reason, wasm::WasmCodePosition position);
347 
348   // In all six call-related public functions, we pass a signature based on the
349   // real arguments for this call. This signature gets stored in the Call node
350   // and will later help us generate better code if this call gets inlined.
351   Node* CallDirect(uint32_t index, wasm::FunctionSig* real_sig,
352                    base::Vector<Node*> args, base::Vector<Node*> rets,
353                    wasm::WasmCodePosition position);
354   Node* CallIndirect(uint32_t table_index, uint32_t sig_index,
355                      wasm::FunctionSig* real_sig, base::Vector<Node*> args,
356                      base::Vector<Node*> rets, wasm::WasmCodePosition position);
357   Node* CallRef(const wasm::FunctionSig* real_sig, base::Vector<Node*> args,
358                 base::Vector<Node*> rets, CheckForNull null_check,
359                 wasm::WasmCodePosition position);
360 
361   Node* ReturnCall(uint32_t index, const wasm::FunctionSig* real_sig,
362                    base::Vector<Node*> args, wasm::WasmCodePosition position);
363   Node* ReturnCallIndirect(uint32_t table_index, uint32_t sig_index,
364                            wasm::FunctionSig* real_sig,
365                            base::Vector<Node*> args,
366                            wasm::WasmCodePosition position);
367   Node* ReturnCallRef(const wasm::FunctionSig* real_sig,
368                       base::Vector<Node*> args, CheckForNull null_check,
369                       wasm::WasmCodePosition position);
370 
371   void CompareToInternalFunctionAtIndex(Node* func_ref, uint32_t function_index,
372                                         Node** success_control,
373                                         Node** failure_control);
374 
375   void BrOnNull(Node* ref_object, Node** non_null_node, Node** null_node);
376 
377   Node* Invert(Node* node);
378 
379   Node* GlobalGet(uint32_t index);
380   void GlobalSet(uint32_t index, Node* val);
381   Node* TableGet(uint32_t table_index, Node* index,
382                  wasm::WasmCodePosition position);
383   void TableSet(uint32_t table_index, Node* index, Node* val,
384                 wasm::WasmCodePosition position);
385   //-----------------------------------------------------------------------
386   // Operations that concern the linear memory.
387   //-----------------------------------------------------------------------
388   Node* CurrentMemoryPages();
389   void TraceMemoryOperation(bool is_store, MachineRepresentation, Node* index,
390                             uintptr_t offset, wasm::WasmCodePosition);
391   Node* LoadMem(wasm::ValueType type, MachineType memtype, Node* index,
392                 uint64_t offset, uint32_t alignment,
393                 wasm::WasmCodePosition position);
394 #if defined(V8_TARGET_BIG_ENDIAN) || defined(V8_TARGET_ARCH_S390_LE_SIM)
395   Node* LoadTransformBigEndian(wasm::ValueType type, MachineType memtype,
396                                wasm::LoadTransformationKind transform,
397                                Node* index, uint64_t offset, uint32_t alignment,
398                                wasm::WasmCodePosition position);
399 #endif
400   Node* LoadTransform(wasm::ValueType type, MachineType memtype,
401                       wasm::LoadTransformationKind transform, Node* index,
402                       uint64_t offset, uint32_t alignment,
403                       wasm::WasmCodePosition position);
404   Node* LoadLane(wasm::ValueType type, MachineType memtype, Node* value,
405                  Node* index, uint64_t offset, uint32_t alignment,
406                  uint8_t laneidx, wasm::WasmCodePosition position);
407   void StoreMem(MachineRepresentation mem_rep, Node* index, uint64_t offset,
408                 uint32_t alignment, Node* val, wasm::WasmCodePosition position,
409                 wasm::ValueType type);
410   void StoreLane(MachineRepresentation mem_rep, Node* index, uint64_t offset,
411                  uint32_t alignment, Node* val, uint8_t laneidx,
412                  wasm::WasmCodePosition position, wasm::ValueType type);
413   static void PrintDebugName(Node* node);
414 
415   Node* effect();
416   Node* control();
417   Node* SetEffect(Node* node);
418   Node* SetControl(Node* node);
419   void SetEffectControl(Node* effect, Node* control);
SetEffectControl(Node * effect_and_control)420   Node* SetEffectControl(Node* effect_and_control) {
421     SetEffectControl(effect_and_control, effect_and_control);
422     return effect_and_control;
423   }
424 
425   // Utilities to manipulate sets of instance cache nodes.
426   void InitInstanceCache(WasmInstanceCacheNodes* instance_cache);
427   void PrepareInstanceCacheForLoop(WasmInstanceCacheNodes* instance_cache,
428                                    Node* control);
429   void NewInstanceCacheMerge(WasmInstanceCacheNodes* to,
430                              WasmInstanceCacheNodes* from, Node* merge);
431   void MergeInstanceCacheInto(WasmInstanceCacheNodes* to,
432                               WasmInstanceCacheNodes* from, Node* merge);
433 
set_instance_cache(WasmInstanceCacheNodes * instance_cache)434   void set_instance_cache(WasmInstanceCacheNodes* instance_cache) {
435     this->instance_cache_ = instance_cache;
436   }
437 
GetFunctionSignature()438   const wasm::FunctionSig* GetFunctionSignature() { return sig_; }
439 
440   enum CallOrigin { kCalledFromWasm, kCalledFromJS };
441 
442   // Overload for when we want to provide a specific signature, rather than
443   // build one using sig_, for example after scalar lowering.
444   V8_EXPORT_PRIVATE void LowerInt64(Signature<MachineRepresentation>* sig);
445   V8_EXPORT_PRIVATE void LowerInt64(CallOrigin origin);
446 
447   void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
448 
449   Node* S128Zero();
450   Node* S1x4Zero();
451   Node* S1x8Zero();
452   Node* S1x16Zero();
453 
454   Node* SimdOp(wasm::WasmOpcode opcode, Node* const* inputs);
455 
456   Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane, Node* const* inputs);
457 
458   Node* Simd8x16ShuffleOp(const uint8_t shuffle[16], Node* const* inputs);
459 
460   Node* AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs,
461                  uint32_t alignment, uint64_t offset,
462                  wasm::WasmCodePosition position);
463   void AtomicFence();
464 
465   void MemoryInit(uint32_t data_segment_index, Node* dst, Node* src, Node* size,
466                   wasm::WasmCodePosition position);
467   void MemoryCopy(Node* dst, Node* src, Node* size,
468                   wasm::WasmCodePosition position);
469   void DataDrop(uint32_t data_segment_index, wasm::WasmCodePosition position);
470   void MemoryFill(Node* dst, Node* fill, Node* size,
471                   wasm::WasmCodePosition position);
472 
473   void TableInit(uint32_t table_index, uint32_t elem_segment_index, Node* dst,
474                  Node* src, Node* size, wasm::WasmCodePosition position);
475   void ElemDrop(uint32_t elem_segment_index, wasm::WasmCodePosition position);
476   void TableCopy(uint32_t table_dst_index, uint32_t table_src_index, Node* dst,
477                  Node* src, Node* size, wasm::WasmCodePosition position);
478   Node* TableGrow(uint32_t table_index, Node* value, Node* delta);
479   Node* TableSize(uint32_t table_index);
480   void TableFill(uint32_t table_index, Node* start, Node* value, Node* count);
481 
482   Node* StructNewWithRtt(uint32_t struct_index, const wasm::StructType* type,
483                          Node* rtt, base::Vector<Node*> fields);
484   Node* StructGet(Node* struct_object, const wasm::StructType* struct_type,
485                   uint32_t field_index, CheckForNull null_check, bool is_signed,
486                   wasm::WasmCodePosition position);
487   void StructSet(Node* struct_object, const wasm::StructType* struct_type,
488                  uint32_t field_index, Node* value, CheckForNull null_check,
489                  wasm::WasmCodePosition position);
490   Node* ArrayNewWithRtt(uint32_t array_index, const wasm::ArrayType* type,
491                         Node* length, Node* initial_value, Node* rtt,
492                         wasm::WasmCodePosition position);
493   Node* ArrayGet(Node* array_object, const wasm::ArrayType* type, Node* index,
494                  CheckForNull null_check, bool is_signed,
495                  wasm::WasmCodePosition position);
496   void ArraySet(Node* array_object, const wasm::ArrayType* type, Node* index,
497                 Node* value, CheckForNull null_check,
498                 wasm::WasmCodePosition position);
499   Node* ArrayLen(Node* array_object, CheckForNull null_check,
500                  wasm::WasmCodePosition position);
501   void ArrayCopy(Node* dst_array, Node* dst_index, CheckForNull dst_null_check,
502                  Node* src_array, Node* src_index, CheckForNull src_null_check,
503                  Node* length, wasm::WasmCodePosition position);
504   Node* ArrayInit(const wasm::ArrayType* type, Node* rtt,
505                   base::Vector<Node*> elements);
506   Node* ArrayInitFromData(const wasm::ArrayType* type, uint32_t data_segment,
507                           Node* offset, Node* length, Node* rtt,
508                           wasm::WasmCodePosition position);
509   Node* I31New(Node* input);
510   Node* I31GetS(Node* input);
511   Node* I31GetU(Node* input);
512   Node* RttCanon(uint32_t type_index);
513 
514   Node* RefTest(Node* object, Node* rtt, ObjectReferenceKnowledge config);
515   Node* RefCast(Node* object, Node* rtt, ObjectReferenceKnowledge config,
516                 wasm::WasmCodePosition position);
517   void BrOnCast(Node* object, Node* rtt, ObjectReferenceKnowledge config,
518                 Node** match_control, Node** match_effect,
519                 Node** no_match_control, Node** no_match_effect);
520   Node* RefIsData(Node* object, bool object_can_be_null);
521   Node* RefAsData(Node* object, bool object_can_be_null,
522                   wasm::WasmCodePosition position);
523   void BrOnData(Node* object, Node* rtt, ObjectReferenceKnowledge config,
524                 Node** match_control, Node** match_effect,
525                 Node** no_match_control, Node** no_match_effect);
526   Node* RefIsFunc(Node* object, bool object_can_be_null);
527   Node* RefAsFunc(Node* object, bool object_can_be_null,
528                   wasm::WasmCodePosition position);
529   void BrOnFunc(Node* object, Node* rtt, ObjectReferenceKnowledge config,
530                 Node** match_control, Node** match_effect,
531                 Node** no_match_control, Node** no_match_effect);
532   Node* RefIsArray(Node* object, bool object_can_be_null);
533   Node* RefAsArray(Node* object, bool object_can_be_null,
534                    wasm::WasmCodePosition position);
535   void BrOnArray(Node* object, Node* rtt, ObjectReferenceKnowledge config,
536                  Node** match_control, Node** match_effect,
537                  Node** no_match_control, Node** no_match_effect);
538   Node* RefIsI31(Node* object);
539   Node* RefAsI31(Node* object, wasm::WasmCodePosition position);
540   void BrOnI31(Node* object, Node* rtt, ObjectReferenceKnowledge config,
541                Node** match_control, Node** match_effect,
542                Node** no_match_control, Node** no_match_effect);
543 
has_simd()544   bool has_simd() const { return has_simd_; }
545 
bounds_checks()546   wasm::BoundsCheckStrategy bounds_checks() const {
547     return env_->bounds_checks;
548   }
549 
mcgraph()550   MachineGraph* mcgraph() { return mcgraph_; }
551   Graph* graph();
552   Zone* graph_zone();
553 
554   void AddBytecodePositionDecorator(NodeOriginTable* node_origins,
555                                     wasm::Decoder* decoder);
556 
557   void RemoveBytecodePositionDecorator();
558 
559   static const wasm::FunctionSig* Int64LoweredSig(Zone* zone,
560                                                   const wasm::FunctionSig* sig);
561 
562  protected:
563   V8_EXPORT_PRIVATE WasmGraphBuilder(wasm::CompilationEnv* env, Zone* zone,
564                                      MachineGraph* mcgraph,
565                                      const wasm::FunctionSig* sig,
566                                      compiler::SourcePositionTable* spt,
567                                      Parameter0Mode parameter_mode,
568                                      Isolate* isolate);
569 
570   Node* NoContextConstant();
571 
572   Node* GetInstance();
573   Node* BuildLoadIsolateRoot();
574   Node* UndefinedValue();
575 
576   // MemBuffer is only called with valid offsets (after bounds checking), so the
577   // offset fits in a platform-dependent uintptr_t.
578   Node* MemBuffer(uintptr_t offset);
579 
580   // BoundsCheckMem receives a 32/64-bit index (depending on
581   // WasmModule::is_memory64) and returns a ptrsize index and information about
582   // the kind of bounds check performed (or why none was needed).
583   std::pair<Node*, BoundsCheckResult> BoundsCheckMem(uint8_t access_size,
584                                                      Node* index,
585                                                      uint64_t offset,
586                                                      wasm::WasmCodePosition,
587                                                      EnforceBoundsCheck);
588 
589   Node* CheckBoundsAndAlignment(int8_t access_size, Node* index,
590                                 uint64_t offset, wasm::WasmCodePosition);
591 
592   const Operator* GetSafeLoadOperator(int offset, wasm::ValueType type);
593   const Operator* GetSafeStoreOperator(int offset, wasm::ValueType type);
594   Node* BuildChangeEndiannessStore(Node* node, MachineRepresentation rep,
595                                    wasm::ValueType wasmtype = wasm::kWasmVoid);
596   Node* BuildChangeEndiannessLoad(Node* node, MachineType type,
597                                   wasm::ValueType wasmtype = wasm::kWasmVoid);
598 
599   Node* MaskShiftCount32(Node* node);
600   Node* MaskShiftCount64(Node* node);
601 
602   enum IsReturnCall : bool { kReturnCall = true, kCallContinues = false };
603 
604   template <typename... Args>
605   Node* BuildCCall(MachineSignature* sig, Node* function, Args... args);
606   Node* BuildCallNode(const wasm::FunctionSig* sig, base::Vector<Node*> args,
607                       wasm::WasmCodePosition position, Node* instance_node,
608                       const Operator* op, Node* frame_state = nullptr);
609   // Helper function for {BuildIndirectCall}.
610   void LoadIndirectFunctionTable(uint32_t table_index, Node** ift_size,
611                                  Node** ift_sig_ids, Node** ift_targets,
612                                  Node** ift_instances);
613   Node* BuildIndirectCall(uint32_t table_index, uint32_t sig_index,
614                           wasm::FunctionSig* real_sig, base::Vector<Node*> args,
615                           base::Vector<Node*> rets,
616                           wasm::WasmCodePosition position,
617                           IsReturnCall continuation);
618   Node* BuildWasmCall(const wasm::FunctionSig* sig, base::Vector<Node*> args,
619                       base::Vector<Node*> rets, wasm::WasmCodePosition position,
620                       Node* instance_node, Node* frame_state = nullptr);
621   Node* BuildWasmReturnCall(const wasm::FunctionSig* sig,
622                             base::Vector<Node*> args,
623                             wasm::WasmCodePosition position,
624                             Node* instance_node);
625   Node* BuildImportCall(const wasm::FunctionSig* sig, base::Vector<Node*> args,
626                         base::Vector<Node*> rets,
627                         wasm::WasmCodePosition position, int func_index,
628                         IsReturnCall continuation);
629   Node* BuildImportCall(const wasm::FunctionSig* sig, base::Vector<Node*> args,
630                         base::Vector<Node*> rets,
631                         wasm::WasmCodePosition position, Node* func_index,
632                         IsReturnCall continuation);
633   Node* BuildCallRef(const wasm::FunctionSig* real_sig,
634                      base::Vector<Node*> args, base::Vector<Node*> rets,
635                      CheckForNull null_check, IsReturnCall continuation,
636                      wasm::WasmCodePosition position);
637 
638   Node* BuildF32CopySign(Node* left, Node* right);
639   Node* BuildF64CopySign(Node* left, Node* right);
640 
641   Node* BuildIntConvertFloat(Node* input, wasm::WasmCodePosition position,
642                              wasm::WasmOpcode);
643   Node* BuildI32Ctz(Node* input);
644   Node* BuildI32Popcnt(Node* input);
645   Node* BuildI64Ctz(Node* input);
646   Node* BuildI64Popcnt(Node* input);
647   Node* BuildBitCountingCall(Node* input, ExternalReference ref,
648                              MachineRepresentation input_type);
649 
650   Node* BuildCFuncInstruction(ExternalReference ref, MachineType type,
651                               Node* input0, Node* input1 = nullptr);
652   Node* BuildF32Trunc(Node* input);
653   Node* BuildF32Floor(Node* input);
654   Node* BuildF32Ceil(Node* input);
655   Node* BuildF32NearestInt(Node* input);
656   Node* BuildF64Trunc(Node* input);
657   Node* BuildF64Floor(Node* input);
658   Node* BuildF64Ceil(Node* input);
659   Node* BuildF64NearestInt(Node* input);
660   Node* BuildI32Rol(Node* left, Node* right);
661   Node* BuildI64Rol(Node* left, Node* right);
662 
663   Node* BuildF64Acos(Node* input);
664   Node* BuildF64Asin(Node* input);
665   Node* BuildF64Pow(Node* left, Node* right);
666   Node* BuildF64Mod(Node* left, Node* right);
667 
668   Node* BuildIntToFloatConversionInstruction(
669       Node* input, ExternalReference ref,
670       MachineRepresentation parameter_representation,
671       const MachineType result_type);
672   Node* BuildF32SConvertI64(Node* input);
673   Node* BuildF32UConvertI64(Node* input);
674   Node* BuildF64SConvertI64(Node* input);
675   Node* BuildF64UConvertI64(Node* input);
676 
677   Node* BuildCcallConvertFloat(Node* input, wasm::WasmCodePosition position,
678                                wasm::WasmOpcode opcode);
679 
680   Node* BuildI32DivS(Node* left, Node* right, wasm::WasmCodePosition position);
681   Node* BuildI32RemS(Node* left, Node* right, wasm::WasmCodePosition position);
682   Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
683   Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
684 
685   Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
686   Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
687   Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
688   Node* BuildI64RemU(Node* left, Node* right, wasm::WasmCodePosition position);
689   Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref,
690                        MachineType result_type, wasm::TrapReason trap_zero,
691                        wasm::WasmCodePosition position);
692 
693   Node* BuildTruncateIntPtrToInt32(Node* value);
694   Node* BuildChangeInt32ToIntPtr(Node* value);
695   Node* BuildChangeIntPtrToInt64(Node* value);
696   Node* BuildChangeUint32ToUintPtr(Node*);
697   Node* BuildChangeInt32ToSmi(Node* value);
698   Node* BuildChangeUint31ToSmi(Node* value);
699   Node* BuildSmiShiftBitsConstant();
700   Node* BuildSmiShiftBitsConstant32();
701   Node* BuildChangeSmiToInt32(Node* value);
702   Node* BuildChangeSmiToIntPtr(Node* value);
703   // generates {index > max ? Smi(max) : Smi(index)}
704   Node* BuildConvertUint32ToSmiWithSaturation(Node* index, uint32_t maxval);
705 
706   void MemTypeToUintPtrOrOOBTrap(std::initializer_list<Node**> nodes,
707                                  wasm::WasmCodePosition position);
708 
709   Node* IsNull(Node* object);
710 
711   void GetGlobalBaseAndOffset(const wasm::WasmGlobal&, Node** base_node,
712                               Node** offset_node);
713 
714   using BranchBuilder = std::function<void(Node*, BranchHint)>;
715   struct Callbacks {
716     BranchBuilder succeed_if;
717     BranchBuilder fail_if;
718     BranchBuilder fail_if_not;
719   };
720 
721   // This type is used to collect control/effect nodes we need to merge at the
722   // end of BrOn* functions. Nodes are collected in {TypeCheck} etc. by calling
723   // the passed callbacks succeed_if, fail_if and fail_if_not. We have up to 5
724   // control nodes to merge; the EffectPhi needs an additional input.
725   using SmallNodeVector = base::SmallVector<Node*, 6>;
726 
727   Callbacks TestCallbacks(GraphAssemblerLabel<1>* label);
728   Callbacks CastCallbacks(GraphAssemblerLabel<0>* label,
729                           wasm::WasmCodePosition position);
730   Callbacks BranchCallbacks(SmallNodeVector& no_match_controls,
731                             SmallNodeVector& no_match_effects,
732                             SmallNodeVector& match_controls,
733                             SmallNodeVector& match_effects);
734 
735   void TypeCheck(Node* object, Node* rtt, ObjectReferenceKnowledge config,
736                  bool null_succeeds, Callbacks callbacks);
737   void DataCheck(Node* object, bool object_can_be_null, Callbacks callbacks);
738   void ManagedObjectInstanceCheck(Node* object, bool object_can_be_null,
739                                   InstanceType instance_type,
740                                   Callbacks callbacks);
741 
742   void BrOnCastAbs(Node** match_control, Node** match_effect,
743                    Node** no_match_control, Node** no_match_effect,
744                    std::function<void(Callbacks)> type_checker);
745   void BoundsCheckArray(Node* array, Node* index,
746                         wasm::WasmCodePosition position);
747   void BoundsCheckArrayCopy(Node* array, Node* index, Node* length,
748                             wasm::WasmCodePosition position);
749 
750   // Asm.js specific functionality.
751   Node* BuildI32AsmjsSConvertF32(Node* input);
752   Node* BuildI32AsmjsSConvertF64(Node* input);
753   Node* BuildI32AsmjsUConvertF32(Node* input);
754   Node* BuildI32AsmjsUConvertF64(Node* input);
755   Node* BuildI32AsmjsDivS(Node* left, Node* right);
756   Node* BuildI32AsmjsRemS(Node* left, Node* right);
757   Node* BuildI32AsmjsDivU(Node* left, Node* right);
758   Node* BuildI32AsmjsRemU(Node* left, Node* right);
759   Node* BuildAsmjsLoadMem(MachineType type, Node* index);
760   Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val);
761 
762   // Wasm SIMD.
763   Node* BuildF64x2Ceil(Node* input);
764   Node* BuildF64x2Floor(Node* input);
765   Node* BuildF64x2Trunc(Node* input);
766   Node* BuildF64x2NearestInt(Node* input);
767   Node* BuildF32x4Ceil(Node* input);
768   Node* BuildF32x4Floor(Node* input);
769   Node* BuildF32x4Trunc(Node* input);
770   Node* BuildF32x4NearestInt(Node* input);
771 
772   void BuildEncodeException32BitValue(Node* values_array, uint32_t* index,
773                                       Node* value);
774   Node* BuildDecodeException32BitValue(Node* values_array, uint32_t* index);
775   Node* BuildDecodeException64BitValue(Node* values_array, uint32_t* index);
776 
777   Node* BuildMultiReturnFixedArrayFromIterable(const wasm::FunctionSig* sig,
778                                                Node* iterable, Node* context);
779 
780   Node* BuildLoadExternalPointerFromObject(
781       Node* object, int offset,
782       ExternalPointerTag tag = kForeignForeignAddressTag);
783 
784   Node* BuildLoadCallTargetFromExportedFunctionData(Node* function_data);
785 
786   //-----------------------------------------------------------------------
787   // Operations involving the CEntry, a dependency we want to remove
788   // to get off the GC heap.
789   //-----------------------------------------------------------------------
790   Node* BuildCallToRuntime(Runtime::FunctionId f, Node** parameters,
791                            int parameter_count);
792 
793   Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, Node* js_context,
794                                       Node** parameters, int parameter_count);
795   TrapId GetTrapIdForTrap(wasm::TrapReason reason);
796 
797   void AddInt64LoweringReplacement(CallDescriptor* original,
798                                    CallDescriptor* replacement);
799 
800   CallDescriptor* GetI32AtomicWaitCallDescriptor();
801 
802   CallDescriptor* GetI64AtomicWaitCallDescriptor();
803 
804   Node* StoreArgsInStackSlot(
805       std::initializer_list<std::pair<MachineRepresentation, Node*>> args);
806 
807   std::unique_ptr<WasmGraphAssembler> gasm_;
808   Zone* const zone_;
809   MachineGraph* const mcgraph_;
810   wasm::CompilationEnv* const env_;
811 
812   Node** parameters_;
813 
814   WasmInstanceCacheNodes* instance_cache_ = nullptr;
815 
816   SetOncePointer<Node> stack_check_code_node_;
817   SetOncePointer<const Operator> stack_check_call_operator_;
818 
819   bool has_simd_ = false;
820   bool needs_stack_check_ = false;
821 
822   const wasm::FunctionSig* const sig_;
823 
824   compiler::WasmDecorator* decorator_ = nullptr;
825 
826   compiler::SourcePositionTable* const source_position_table_ = nullptr;
827   Parameter0Mode parameter_mode_;
828   Isolate* const isolate_;
829   SetOncePointer<Node> instance_node_;
830 
831   std::unique_ptr<Int64LoweringSpecialCase> lowering_special_case_;
832   CallDescriptor* i32_atomic_wait_descriptor_ = nullptr;
833   CallDescriptor* i64_atomic_wait_descriptor_ = nullptr;
834 };
835 
836 enum WasmCallKind { kWasmFunction, kWasmImportWrapper, kWasmCapiFunction };
837 
838 V8_EXPORT_PRIVATE void BuildInlinedJSToWasmWrapper(
839     Zone* zone, MachineGraph* mcgraph, const wasm::FunctionSig* signature,
840     const wasm::WasmModule* module, Isolate* isolate,
841     compiler::SourcePositionTable* spt, StubCallMode stub_mode,
842     wasm::WasmFeatures features, const JSWasmCallData* js_wasm_call_data,
843     Node* frame_state);
844 
845 V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
846     Zone* zone, const wasm::FunctionSig* signature,
847     WasmCallKind kind = kWasmFunction, bool need_frame_state = false);
848 
849 V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
850     Zone* zone, const CallDescriptor* call_descriptor);
851 
852 AssemblerOptions WasmAssemblerOptions();
853 AssemblerOptions WasmStubAssemblerOptions();
854 
855 }  // namespace compiler
856 }  // namespace internal
857 }  // namespace v8
858 
859 #endif  // V8_COMPILER_WASM_COMPILER_H_
860