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
27namespace v8 {
28namespace internal {
29struct AssemblerOptions;
30class TurbofanCompilationJob;
31
32namespace compiler {
33// Forward declarations for some compiler data structures.
34class CallDescriptor;
35class Graph;
36class MachineGraph;
37class Node;
38class NodeOriginTable;
39class Operator;
40class SourcePositionTable;
41class WasmDecorator;
42class WasmGraphAssembler;
43enum class TrapId : uint32_t;
44struct Int64LoweringSpecialCase;
45template <size_t VarCount>
46class GraphAssemblerLabel;
47enum class BranchHint : uint8_t;
48}  // namespace compiler
49
50namespace wasm {
51struct DecodeStruct;
52// Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
53using TFNode = compiler::Node;
54using TFGraph = compiler::MachineGraph;
55class WasmCode;
56class WasmFeatures;
57class WireBytesStorage;
58enum class LoadTransformationKind : uint8_t;
59enum Suspend : bool { kSuspend = false, kNoSuspend = true };
60}  // namespace wasm
61
62namespace compiler {
63
64wasm::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.
72enum 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
110constexpr WasmImportCallKind kDefaultImportCallKind =
111    WasmImportCallKind::kJSFunctionArityMatch;
112
113struct 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.
123V8_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.
128V8_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.
133wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::NativeModule*,
134                                           const wasm::FunctionSig*);
135
136// Compiles a wrapper to call a Fast API function from Wasm.
137wasm::WasmCode* CompileWasmJSFastCallWrapper(wasm::NativeModule*,
138                                             const wasm::FunctionSig*,
139                                             Handle<JSFunction> target);
140
141// Returns an TurbofanCompilationJob object for a JS to Wasm wrapper.
142std::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
147MaybeHandle<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.
156MaybeHandle<Code> CompileJSToJSWrapper(Isolate*, const wasm::FunctionSig*,
157                                       const wasm::WasmModule* module);
158
159enum 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.
170V8_EXPORT_PRIVATE Handle<CodeT> CompileCWasmEntry(
171    Isolate*, const wasm::FunctionSig*, const wasm::WasmModule* module);
172
173class JSWasmCallData {
174 public:
175  explicit JSWasmCallData(const wasm::FunctionSig* wasm_signature);
176
177  bool arg_needs_conversion(size_t index) const {
178    DCHECK_LT(index, arg_needs_conversion_.size());
179    return arg_needs_conversion_[index];
180  }
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.)
192struct WasmInstanceCacheNodes {
193  Node* mem_start;
194  Node* mem_size;
195};
196
197struct 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
204  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.
212class 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)
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>
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);
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
434  void set_instance_cache(WasmInstanceCacheNodes* instance_cache) {
435    this->instance_cache_ = instance_cache;
436  }
437
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
544  bool has_simd() const { return has_simd_; }
545
546  wasm::BoundsCheckStrategy bounds_checks() const {
547    return env_->bounds_checks;
548  }
549
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
836enum WasmCallKind { kWasmFunction, kWasmImportWrapper, kWasmCapiFunction };
837
838V8_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
845V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
846    Zone* zone, const wasm::FunctionSig* signature,
847    WasmCallKind kind = kWasmFunction, bool need_frame_state = false);
848
849V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
850    Zone* zone, const CallDescriptor* call_descriptor);
851
852AssemblerOptions WasmAssemblerOptions();
853AssemblerOptions WasmStubAssemblerOptions();
854
855}  // namespace compiler
856}  // namespace internal
857}  // namespace v8
858
859#endif  // V8_COMPILER_WASM_COMPILER_H_
860