1// Copyright 2018 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#include "src/wasm/graph-builder-interface.h"
6
7#include "src/compiler/wasm-compiler.h"
8#include "src/flags/flags.h"
9#include "src/handles/handles.h"
10#include "src/objects/objects-inl.h"
11#include "src/utils/ostreams.h"
12#include "src/wasm/branch-hint-map.h"
13#include "src/wasm/decoder.h"
14#include "src/wasm/function-body-decoder-impl.h"
15#include "src/wasm/function-body-decoder.h"
16#include "src/wasm/value-type.h"
17#include "src/wasm/wasm-limits.h"
18#include "src/wasm/wasm-linkage.h"
19#include "src/wasm/wasm-module.h"
20#include "src/wasm/wasm-opcodes-inl.h"
21
22namespace v8 {
23namespace internal {
24namespace wasm {
25
26namespace {
27
28// An SsaEnv environment carries the current local variable renaming
29// as well as the current effect and control dependency in the TF graph.
30// It maintains a control state that tracks whether the environment
31// is reachable, has reached a control end, or has been merged.
32struct SsaEnv : public ZoneObject {
33  enum State { kUnreachable, kReached, kMerged };
34
35  State state;
36  TFNode* control;
37  TFNode* effect;
38  compiler::WasmInstanceCacheNodes instance_cache;
39  ZoneVector<TFNode*> locals;
40
41  SsaEnv(Zone* zone, State state, TFNode* control, TFNode* effect,
42         uint32_t locals_size)
43      : state(state),
44        control(control),
45        effect(effect),
46        locals(locals_size, zone) {}
47
48  SsaEnv(const SsaEnv& other) V8_NOEXCEPT = default;
49  SsaEnv(SsaEnv&& other) V8_NOEXCEPT : state(other.state),
50                                       control(other.control),
51                                       effect(other.effect),
52                                       instance_cache(other.instance_cache),
53                                       locals(std::move(other.locals)) {
54    other.Kill();
55  }
56
57  void Kill() {
58    state = kUnreachable;
59    for (TFNode*& local : locals) {
60      local = nullptr;
61    }
62    control = nullptr;
63    effect = nullptr;
64    instance_cache = {};
65  }
66  void SetNotMerged() {
67    if (state == kMerged) state = kReached;
68  }
69};
70
71class WasmGraphBuildingInterface {
72 public:
73  static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
74  using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
75  using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
76
77  struct Value : public ValueBase<validate> {
78    TFNode* node = nullptr;
79
80    template <typename... Args>
81    explicit Value(Args&&... args) V8_NOEXCEPT
82        : ValueBase(std::forward<Args>(args)...) {}
83  };
84  using ValueVector = base::SmallVector<Value, 8>;
85  using NodeVector = base::SmallVector<TFNode*, 8>;
86
87  struct TryInfo : public ZoneObject {
88    SsaEnv* catch_env;
89    TFNode* exception = nullptr;
90
91    bool might_throw() const { return exception != nullptr; }
92
93    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TryInfo);
94
95    explicit TryInfo(SsaEnv* c) : catch_env(c) {}
96  };
97
98  struct Control : public ControlBase<Value, validate> {
99    SsaEnv* merge_env = nullptr;  // merge environment for the construct.
100    SsaEnv* false_env = nullptr;  // false environment (only for if).
101    TryInfo* try_info = nullptr;  // information about try statements.
102    int32_t previous_catch = -1;  // previous Control with a catch.
103    BitVector* loop_assignments = nullptr;  // locals assigned in this loop.
104    TFNode* loop_node = nullptr;            // loop header of this loop.
105    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Control);
106
107    template <typename... Args>
108    explicit Control(Args&&... args) V8_NOEXCEPT
109        : ControlBase(std::forward<Args>(args)...) {}
110  };
111
112  WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder,
113                             int func_index, InlinedStatus inlined_status)
114      : builder_(builder),
115        func_index_(func_index),
116        inlined_status_(inlined_status) {}
117
118  void StartFunction(FullDecoder* decoder) {
119    // Get the branch hints map and type feedback for this function (if
120    // available).
121    if (decoder->module_) {
122      auto branch_hints_it = decoder->module_->branch_hints.find(func_index_);
123      if (branch_hints_it != decoder->module_->branch_hints.end()) {
124        branch_hints_ = &branch_hints_it->second;
125      }
126      TypeFeedbackStorage& feedbacks = decoder->module_->type_feedback;
127      base::MutexGuard mutex_guard(&feedbacks.mutex);
128      auto feedback = feedbacks.feedback_for_function.find(func_index_);
129      if (feedback != feedbacks.feedback_for_function.end()) {
130        type_feedback_ = feedback->second.feedback_vector;
131        // We need to keep the feedback in the module to inline later. However,
132        // this means we are stuck with it forever.
133        // TODO(jkummerow): Reconsider our options here.
134      }
135    }
136    // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the
137    // instance parameter.
138    builder_->Start(static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
139    uint32_t num_locals = decoder->num_locals();
140    SsaEnv* ssa_env = decoder->zone()->New<SsaEnv>(
141        decoder->zone(), SsaEnv::kReached, effect(), control(), num_locals);
142    SetEnv(ssa_env);
143
144    // Initialize local variables. Parameters are shifted by 1 because of the
145    // the instance parameter.
146    uint32_t index = 0;
147    for (; index < decoder->sig_->parameter_count(); ++index) {
148      ssa_env->locals[index] = builder_->Param(index + 1);
149    }
150    while (index < num_locals) {
151      ValueType type = decoder->local_type(index);
152      TFNode* node;
153      if ((decoder->enabled_.has_nn_locals() ||
154           decoder->enabled_.has_unsafe_nn_locals()) &&
155          !type.is_defaultable()) {
156        DCHECK(type.is_reference());
157        // TODO(jkummerow): Consider using "the hole" instead, to make any
158        // illegal uses more obvious.
159        node = builder_->RefNull();
160      } else {
161        node = DefaultValue(type);
162      }
163      while (index < num_locals && decoder->local_type(index) == type) {
164        // Do a whole run of like-typed locals at a time.
165        ssa_env->locals[index++] = node;
166      }
167    }
168    LoadContextIntoSsa(ssa_env);
169
170    if (FLAG_trace_wasm && inlined_status_ == kRegularFunction) {
171      builder_->TraceFunctionEntry(decoder->position());
172    }
173  }
174
175  // Reload the instance cache entries into the Ssa Environment.
176  void LoadContextIntoSsa(SsaEnv* ssa_env) {
177    if (ssa_env) builder_->InitInstanceCache(&ssa_env->instance_cache);
178  }
179
180  void StartFunctionBody(FullDecoder* decoder, Control* block) {}
181
182  void FinishFunction(FullDecoder*) {
183    if (inlined_status_ == kRegularFunction) {
184      builder_->PatchInStackCheckIfNeeded();
185    }
186  }
187
188  void OnFirstError(FullDecoder*) {}
189
190  void NextInstruction(FullDecoder*, WasmOpcode) {}
191
192  void Block(FullDecoder* decoder, Control* block) {
193    // The branch environment is the outer environment.
194    block->merge_env = ssa_env_;
195    SetEnv(Steal(decoder->zone(), ssa_env_));
196  }
197
198  void Loop(FullDecoder* decoder, Control* block) {
199    // This is the merge environment at the beginning of the loop.
200    SsaEnv* merge_env = Steal(decoder->zone(), ssa_env_);
201    block->merge_env = merge_env;
202    SetEnv(merge_env);
203
204    ssa_env_->state = SsaEnv::kMerged;
205
206    TFNode* loop_node = builder_->Loop(control());
207
208    if (emit_loop_exits()) {
209      uint32_t nesting_depth = 0;
210      for (uint32_t depth = 1; depth < decoder->control_depth(); depth++) {
211        if (decoder->control_at(depth)->is_loop()) {
212          nesting_depth++;
213        }
214      }
215      // If this loop is nested, the parent loop's can_be_innermost field needs
216      // to be false. If the last loop in loop_infos_ has less depth, it has to
217      // be the parent loop. If it does not, it means another loop has been
218      // found within the parent loop, and that loop will have set the parent's
219      // can_be_innermost to false, so we do not need to do anything.
220      if (nesting_depth > 0 &&
221          loop_infos_.back().nesting_depth < nesting_depth) {
222        loop_infos_.back().can_be_innermost = false;
223      }
224      loop_infos_.emplace_back(loop_node, nesting_depth, true);
225    }
226
227    builder_->SetControl(loop_node);
228    decoder->control_at(0)->loop_node = loop_node;
229
230    TFNode* effect_inputs[] = {effect(), control()};
231    builder_->SetEffect(builder_->EffectPhi(1, effect_inputs));
232    builder_->TerminateLoop(effect(), control());
233    // Doing a preprocessing pass to analyze loop assignments seems to pay off
234    // compared to reallocating Nodes when rearranging Phis in Goto.
235    BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
236        decoder, decoder->pc(), decoder->num_locals(), decoder->zone());
237    if (decoder->failed()) return;
238    int instance_cache_index = decoder->num_locals();
239    // If the module has shared memory, the stack guard might reallocate the
240    // shared memory. We have to assume the instance cache will be updated.
241    if (decoder->module_->has_shared_memory) {
242      assigned->Add(instance_cache_index);
243    }
244    DCHECK_NOT_NULL(assigned);
245    decoder->control_at(0)->loop_assignments = assigned;
246
247    // Only introduce phis for variables assigned in this loop.
248    for (int i = decoder->num_locals() - 1; i >= 0; i--) {
249      if (!assigned->Contains(i)) continue;
250      TFNode* inputs[] = {ssa_env_->locals[i], control()};
251      ssa_env_->locals[i] = builder_->Phi(decoder->local_type(i), 1, inputs);
252    }
253    // Introduce phis for instance cache pointers if necessary.
254    if (assigned->Contains(instance_cache_index)) {
255      builder_->PrepareInstanceCacheForLoop(&ssa_env_->instance_cache,
256                                            control());
257    }
258
259    // Now we setup a new environment for the inside of the loop.
260    SetEnv(Split(decoder->zone(), ssa_env_));
261    builder_->StackCheck(decoder->module_->has_shared_memory
262                             ? &ssa_env_->instance_cache
263                             : nullptr,
264                         decoder->position());
265    ssa_env_->SetNotMerged();
266
267    // Wrap input merge into phis.
268    for (uint32_t i = 0; i < block->start_merge.arity; ++i) {
269      Value& val = block->start_merge[i];
270      TFNode* inputs[] = {val.node, block->merge_env->control};
271      val.node = builder_->Phi(val.type, 1, inputs);
272    }
273  }
274
275  void Try(FullDecoder* decoder, Control* block) {
276    SsaEnv* outer_env = ssa_env_;
277    SsaEnv* catch_env = Split(decoder->zone(), outer_env);
278    // Mark catch environment as unreachable, since only accessable
279    // through catch unwinding (i.e. landing pads).
280    catch_env->state = SsaEnv::kUnreachable;
281    SsaEnv* try_env = Steal(decoder->zone(), outer_env);
282    SetEnv(try_env);
283    TryInfo* try_info = decoder->zone()->New<TryInfo>(catch_env);
284    block->merge_env = outer_env;
285    block->try_info = try_info;
286  }
287
288  void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
289    TFNode* if_true = nullptr;
290    TFNode* if_false = nullptr;
291    WasmBranchHint hint = WasmBranchHint::kNoHint;
292    if (branch_hints_) {
293      hint = branch_hints_->GetHintFor(decoder->pc_relative_offset());
294    }
295    switch (hint) {
296      case WasmBranchHint::kNoHint:
297        builder_->BranchNoHint(cond.node, &if_true, &if_false);
298        break;
299      case WasmBranchHint::kUnlikely:
300        builder_->BranchExpectFalse(cond.node, &if_true, &if_false);
301        break;
302      case WasmBranchHint::kLikely:
303        builder_->BranchExpectTrue(cond.node, &if_true, &if_false);
304        break;
305    }
306    SsaEnv* merge_env = ssa_env_;
307    SsaEnv* false_env = Split(decoder->zone(), ssa_env_);
308    false_env->control = if_false;
309    SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
310    true_env->control = if_true;
311    if_block->merge_env = merge_env;
312    if_block->false_env = false_env;
313    SetEnv(true_env);
314  }
315
316  void FallThruTo(FullDecoder* decoder, Control* c) {
317    DCHECK(!c->is_loop());
318    MergeValuesInto(decoder, c, &c->end_merge);
319  }
320
321  void PopControl(FullDecoder* decoder, Control* block) {
322    // A loop just continues with the end environment. There is no merge.
323    // However, if loop unrolling is enabled, we must create a loop exit and
324    // wrap the fallthru values on the stack.
325    if (block->is_loop()) {
326      if (emit_loop_exits() && block->reachable()) {
327        BuildLoopExits(decoder, block);
328        WrapLocalsAtLoopExit(decoder, block);
329        uint32_t arity = block->end_merge.arity;
330        if (arity > 0) {
331          Value* stack_base = decoder->stack_value(arity);
332          for (uint32_t i = 0; i < arity; i++) {
333            Value* val = stack_base + i;
334            val->node = builder_->LoopExitValue(
335                val->node, val->type.machine_representation());
336          }
337        }
338      }
339      return;
340    }
341    // Any other block falls through to the parent block.
342    if (block->reachable()) FallThruTo(decoder, block);
343    if (block->is_onearmed_if()) {
344      // Merge the else branch into the end merge.
345      SetEnv(block->false_env);
346      DCHECK_EQ(block->start_merge.arity, block->end_merge.arity);
347      Value* values =
348          block->start_merge.arity > 0 ? &block->start_merge[0] : nullptr;
349      MergeValuesInto(decoder, block, &block->end_merge, values);
350    }
351    // Now continue with the merged environment.
352    SetEnv(block->merge_env);
353  }
354
355  void UnOp(FullDecoder* decoder, WasmOpcode opcode, const Value& value,
356            Value* result) {
357    result->node = builder_->Unop(opcode, value.node, decoder->position());
358  }
359
360  void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs,
361             const Value& rhs, Value* result) {
362    TFNode* node =
363        builder_->Binop(opcode, lhs.node, rhs.node, decoder->position());
364    if (result) result->node = node;
365  }
366
367  void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
368    result->node = builder_->Int32Constant(value);
369  }
370
371  void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
372    result->node = builder_->Int64Constant(value);
373  }
374
375  void F32Const(FullDecoder* decoder, Value* result, float value) {
376    result->node = builder_->Float32Constant(value);
377  }
378
379  void F64Const(FullDecoder* decoder, Value* result, double value) {
380    result->node = builder_->Float64Constant(value);
381  }
382
383  void S128Const(FullDecoder* decoder, const Simd128Immediate<validate>& imm,
384                 Value* result) {
385    result->node = builder_->Simd128Constant(imm.value);
386  }
387
388  void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
389    result->node = builder_->RefNull();
390  }
391
392  void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) {
393    result->node = builder_->RefFunc(function_index);
394  }
395
396  void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) {
397    result->node = builder_->RefAsNonNull(arg.node, decoder->position());
398  }
399
400  void Drop(FullDecoder* decoder) {}
401
402  void LocalGet(FullDecoder* decoder, Value* result,
403                const IndexImmediate<validate>& imm) {
404    result->node = ssa_env_->locals[imm.index];
405  }
406
407  void LocalSet(FullDecoder* decoder, const Value& value,
408                const IndexImmediate<validate>& imm) {
409    ssa_env_->locals[imm.index] = value.node;
410  }
411
412  void LocalTee(FullDecoder* decoder, const Value& value, Value* result,
413                const IndexImmediate<validate>& imm) {
414    result->node = value.node;
415    ssa_env_->locals[imm.index] = value.node;
416  }
417
418  void AllocateLocals(FullDecoder* decoder, base::Vector<Value> local_values) {
419    ZoneVector<TFNode*>* locals = &ssa_env_->locals;
420    locals->insert(locals->begin(), local_values.size(), nullptr);
421    for (uint32_t i = 0; i < local_values.size(); i++) {
422      (*locals)[i] = local_values[i].node;
423    }
424  }
425
426  void DeallocateLocals(FullDecoder* decoder, uint32_t count) {
427    ZoneVector<TFNode*>* locals = &ssa_env_->locals;
428    locals->erase(locals->begin(), locals->begin() + count);
429  }
430
431  void GlobalGet(FullDecoder* decoder, Value* result,
432                 const GlobalIndexImmediate<validate>& imm) {
433    result->node = builder_->GlobalGet(imm.index);
434  }
435
436  void GlobalSet(FullDecoder* decoder, const Value& value,
437                 const GlobalIndexImmediate<validate>& imm) {
438    builder_->GlobalSet(imm.index, value.node);
439  }
440
441  void TableGet(FullDecoder* decoder, const Value& index, Value* result,
442                const IndexImmediate<validate>& imm) {
443    result->node =
444        builder_->TableGet(imm.index, index.node, decoder->position());
445  }
446
447  void TableSet(FullDecoder* decoder, const Value& index, const Value& value,
448                const IndexImmediate<validate>& imm) {
449    builder_->TableSet(imm.index, index.node, value.node, decoder->position());
450  }
451
452  void Trap(FullDecoder* decoder, TrapReason reason) {
453    builder_->Trap(reason, decoder->position());
454  }
455
456  void AssertNull(FullDecoder* decoder, const Value& obj, Value* result) {
457    builder_->TrapIfFalse(
458        wasm::TrapReason::kTrapIllegalCast,
459        builder_->Binop(kExprRefEq, obj.node, builder_->RefNull(),
460                        decoder->position()),
461        decoder->position());
462    result->node = obj.node;
463  }
464
465  void NopForTestingUnsupportedInLiftoff(FullDecoder* decoder) {}
466
467  void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
468              const Value& tval, Value* result) {
469    result->node =
470      builder_->Select(cond.node, tval.node, fval.node, result->type);
471  }
472
473  ValueVector CopyStackValues(FullDecoder* decoder, uint32_t count,
474                              uint32_t drop_values) {
475    Value* stack_base =
476        count > 0 ? decoder->stack_value(count + drop_values) : nullptr;
477    ValueVector stack_values(count);
478    for (uint32_t i = 0; i < count; i++) {
479      stack_values[i] = stack_base[i];
480    }
481    return stack_values;
482  }
483
484  void DoReturn(FullDecoder* decoder, uint32_t drop_values) {
485    uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
486    NodeVector values(ret_count);
487    SsaEnv* internal_env = ssa_env_;
488    if (emit_loop_exits()) {
489      SsaEnv* exit_env = Split(decoder->zone(), ssa_env_);
490      SetEnv(exit_env);
491      auto stack_values = CopyStackValues(decoder, ret_count, drop_values);
492      BuildNestedLoopExits(decoder, decoder->control_depth() - 1, false,
493                           stack_values);
494      GetNodes(values.begin(), base::VectorOf(stack_values));
495    } else {
496      Value* stack_base = ret_count == 0
497                              ? nullptr
498                              : decoder->stack_value(ret_count + drop_values);
499      GetNodes(values.begin(), stack_base, ret_count);
500    }
501    if (FLAG_trace_wasm && inlined_status_ == kRegularFunction) {
502      builder_->TraceFunctionExit(base::VectorOf(values), decoder->position());
503    }
504    builder_->Return(base::VectorOf(values));
505    SetEnv(internal_env);
506  }
507
508  void BrOrRet(FullDecoder* decoder, uint32_t depth, uint32_t drop_values) {
509    if (depth == decoder->control_depth() - 1) {
510      DoReturn(decoder, drop_values);
511    } else {
512      Control* target = decoder->control_at(depth);
513      if (emit_loop_exits()) {
514        SsaEnv* internal_env = ssa_env_;
515        SsaEnv* exit_env = Split(decoder->zone(), ssa_env_);
516        SetEnv(exit_env);
517        uint32_t value_count = target->br_merge()->arity;
518        auto stack_values = CopyStackValues(decoder, value_count, drop_values);
519        BuildNestedLoopExits(decoder, depth, true, stack_values);
520        MergeValuesInto(decoder, target, target->br_merge(),
521                        stack_values.data());
522        SetEnv(internal_env);
523      } else {
524        MergeValuesInto(decoder, target, target->br_merge(), drop_values);
525      }
526    }
527  }
528
529  void BrIf(FullDecoder* decoder, const Value& cond, uint32_t depth) {
530    SsaEnv* fenv = ssa_env_;
531    SsaEnv* tenv = Split(decoder->zone(), fenv);
532    fenv->SetNotMerged();
533    WasmBranchHint hint = WasmBranchHint::kNoHint;
534    if (branch_hints_) {
535      hint = branch_hints_->GetHintFor(decoder->pc_relative_offset());
536    }
537    switch (hint) {
538      case WasmBranchHint::kNoHint:
539        builder_->BranchNoHint(cond.node, &tenv->control, &fenv->control);
540        break;
541      case WasmBranchHint::kUnlikely:
542        builder_->BranchExpectFalse(cond.node, &tenv->control, &fenv->control);
543        break;
544      case WasmBranchHint::kLikely:
545        builder_->BranchExpectTrue(cond.node, &tenv->control, &fenv->control);
546        break;
547    }
548    builder_->SetControl(fenv->control);
549    SetEnv(tenv);
550    BrOrRet(decoder, depth, 1);
551    SetEnv(fenv);
552  }
553
554  void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
555               const Value& key) {
556    if (imm.table_count == 0) {
557      // Only a default target. Do the equivalent of br.
558      uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
559      BrOrRet(decoder, target, 1);
560      return;
561    }
562
563    SsaEnv* branch_env = ssa_env_;
564    // Build branches to the various blocks based on the table.
565    TFNode* sw = builder_->Switch(imm.table_count + 1, key.node);
566
567    SsaEnv* copy = Steal(decoder->zone(), branch_env);
568    SetEnv(copy);
569    BranchTableIterator<validate> iterator(decoder, imm);
570    while (iterator.has_next()) {
571      uint32_t i = iterator.cur_index();
572      uint32_t target = iterator.next();
573      SetEnv(Split(decoder->zone(), copy));
574      builder_->SetControl(i == imm.table_count ? builder_->IfDefault(sw)
575                                                : builder_->IfValue(i, sw));
576      BrOrRet(decoder, target, 1);
577    }
578    DCHECK(decoder->ok());
579    SetEnv(branch_env);
580  }
581
582  void Else(FullDecoder* decoder, Control* if_block) {
583    if (if_block->reachable()) {
584      // Merge the if branch into the end merge.
585      MergeValuesInto(decoder, if_block, &if_block->end_merge);
586    }
587    SetEnv(if_block->false_env);
588  }
589
590  void LoadMem(FullDecoder* decoder, LoadType type,
591               const MemoryAccessImmediate<validate>& imm, const Value& index,
592               Value* result) {
593    result->node =
594        builder_->LoadMem(type.value_type(), type.mem_type(), index.node,
595                          imm.offset, imm.alignment, decoder->position());
596  }
597
598  void LoadTransform(FullDecoder* decoder, LoadType type,
599                     LoadTransformationKind transform,
600                     const MemoryAccessImmediate<validate>& imm,
601                     const Value& index, Value* result) {
602    result->node = builder_->LoadTransform(type.value_type(), type.mem_type(),
603                                           transform, index.node, imm.offset,
604                                           imm.alignment, decoder->position());
605  }
606
607  void LoadLane(FullDecoder* decoder, LoadType type, const Value& value,
608                const Value& index, const MemoryAccessImmediate<validate>& imm,
609                const uint8_t laneidx, Value* result) {
610    result->node = builder_->LoadLane(
611        type.value_type(), type.mem_type(), value.node, index.node, imm.offset,
612        imm.alignment, laneidx, decoder->position());
613  }
614
615  void StoreMem(FullDecoder* decoder, StoreType type,
616                const MemoryAccessImmediate<validate>& imm, const Value& index,
617                const Value& value) {
618    builder_->StoreMem(type.mem_rep(), index.node, imm.offset, imm.alignment,
619                       value.node, decoder->position(), type.value_type());
620  }
621
622  void StoreLane(FullDecoder* decoder, StoreType type,
623                 const MemoryAccessImmediate<validate>& imm, const Value& index,
624                 const Value& value, const uint8_t laneidx) {
625    builder_->StoreLane(type.mem_rep(), index.node, imm.offset, imm.alignment,
626                        value.node, laneidx, decoder->position(),
627                        type.value_type());
628  }
629
630  void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
631    result->node = builder_->CurrentMemoryPages();
632  }
633
634  void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) {
635    result->node = builder_->MemoryGrow(value.node);
636    // Always reload the instance cache after growing memory.
637    LoadContextIntoSsa(ssa_env_);
638  }
639
640  void CallDirect(FullDecoder* decoder,
641                  const CallFunctionImmediate<validate>& imm,
642                  const Value args[], Value returns[]) {
643    if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) {
644      DCHECK_LT(feedback_instruction_index_, type_feedback_.size());
645      feedback_instruction_index_++;
646    }
647    DoCall(decoder, CallInfo::CallDirect(imm.index), imm.sig, args, returns);
648  }
649
650  void ReturnCall(FullDecoder* decoder,
651                  const CallFunctionImmediate<validate>& imm,
652                  const Value args[]) {
653    if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) {
654      DCHECK_LT(feedback_instruction_index_, type_feedback_.size());
655      feedback_instruction_index_++;
656    }
657    DoReturnCall(decoder, CallInfo::CallDirect(imm.index), imm.sig, args);
658  }
659
660  void CallIndirect(FullDecoder* decoder, const Value& index,
661                    const CallIndirectImmediate<validate>& imm,
662                    const Value args[], Value returns[]) {
663    DoCall(
664        decoder,
665        CallInfo::CallIndirect(index, imm.table_imm.index, imm.sig_imm.index),
666        imm.sig, args, returns);
667  }
668
669  void ReturnCallIndirect(FullDecoder* decoder, const Value& index,
670                          const CallIndirectImmediate<validate>& imm,
671                          const Value args[]) {
672    DoReturnCall(
673        decoder,
674        CallInfo::CallIndirect(index, imm.table_imm.index, imm.sig_imm.index),
675        imm.sig, args);
676  }
677
678  void CallRef(FullDecoder* decoder, const Value& func_ref,
679               const FunctionSig* sig, uint32_t sig_index, const Value args[],
680               Value returns[]) {
681    int maybe_feedback = -1;
682    if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) {
683      DCHECK_LT(feedback_instruction_index_, type_feedback_.size());
684      maybe_feedback =
685          type_feedback_[feedback_instruction_index_].function_index;
686      feedback_instruction_index_++;
687    }
688    if (maybe_feedback == -1) {
689      DoCall(decoder, CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)),
690             sig, args, returns);
691      return;
692    }
693
694    // Check for equality against a function at a specific index, and if
695    // successful, just emit a direct call.
696    DCHECK_GE(maybe_feedback, 0);
697    const uint32_t expected_function_index = maybe_feedback;
698
699    if (FLAG_trace_wasm_speculative_inlining) {
700      PrintF("[Function #%d call #%d: graph support for inlining target #%d]\n",
701             func_index_, feedback_instruction_index_ - 1,
702             expected_function_index);
703    }
704
705    TFNode* success_control;
706    TFNode* failure_control;
707    builder_->CompareToInternalFunctionAtIndex(
708        func_ref.node, expected_function_index, &success_control,
709        &failure_control);
710    TFNode* initial_effect = effect();
711
712    builder_->SetControl(success_control);
713    ssa_env_->control = success_control;
714    Value* returns_direct =
715        decoder->zone()->NewArray<Value>(sig->return_count());
716    DoCall(decoder, CallInfo::CallDirect(expected_function_index),
717           decoder->module_->signature(sig_index), args, returns_direct);
718    TFNode* control_direct = control();
719    TFNode* effect_direct = effect();
720
721    builder_->SetEffectControl(initial_effect, failure_control);
722    ssa_env_->effect = initial_effect;
723    ssa_env_->control = failure_control;
724    Value* returns_ref = decoder->zone()->NewArray<Value>(sig->return_count());
725    DoCall(decoder, CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)),
726           sig, args, returns_ref);
727
728    TFNode* control_ref = control();
729    TFNode* effect_ref = effect();
730
731    TFNode* control_args[] = {control_direct, control_ref};
732    TFNode* control = builder_->Merge(2, control_args);
733
734    TFNode* effect_args[] = {effect_direct, effect_ref, control};
735    TFNode* effect = builder_->EffectPhi(2, effect_args);
736
737    ssa_env_->control = control;
738    ssa_env_->effect = effect;
739    builder_->SetEffectControl(effect, control);
740
741    for (uint32_t i = 0; i < sig->return_count(); i++) {
742      TFNode* phi_args[] = {returns_direct[i].node, returns_ref[i].node,
743                            control};
744      returns[i].node = builder_->Phi(sig->GetReturn(i), 2, phi_args);
745    }
746  }
747
748  void ReturnCallRef(FullDecoder* decoder, const Value& func_ref,
749                     const FunctionSig* sig, uint32_t sig_index,
750                     const Value args[]) {
751    int maybe_feedback = -1;
752    if (FLAG_wasm_speculative_inlining && type_feedback_.size() > 0) {
753      DCHECK_LT(feedback_instruction_index_, type_feedback_.size());
754      maybe_feedback =
755          type_feedback_[feedback_instruction_index_].function_index;
756      feedback_instruction_index_++;
757    }
758    if (maybe_feedback == -1) {
759      DoReturnCall(decoder,
760                   CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)),
761                   sig, args);
762      return;
763    }
764
765    // Check for equality against a function at a specific index, and if
766    // successful, just emit a direct call.
767    DCHECK_GE(maybe_feedback, 0);
768    const uint32_t expected_function_index = maybe_feedback;
769
770    if (FLAG_trace_wasm_speculative_inlining) {
771      PrintF("[Function #%d call #%d: graph support for inlining target #%d]\n",
772             func_index_, feedback_instruction_index_ - 1,
773             expected_function_index);
774    }
775
776    TFNode* success_control;
777    TFNode* failure_control;
778    builder_->CompareToInternalFunctionAtIndex(
779        func_ref.node, expected_function_index, &success_control,
780        &failure_control);
781    TFNode* initial_effect = effect();
782
783    builder_->SetControl(success_control);
784    ssa_env_->control = success_control;
785    DoReturnCall(decoder, CallInfo::CallDirect(expected_function_index), sig,
786                 args);
787
788    builder_->SetEffectControl(initial_effect, failure_control);
789    ssa_env_->effect = initial_effect;
790    ssa_env_->control = failure_control;
791    DoReturnCall(decoder,
792                 CallInfo::CallRef(func_ref, NullCheckFor(func_ref.type)), sig,
793                 args);
794  }
795
796  void BrOnNull(FullDecoder* decoder, const Value& ref_object, uint32_t depth,
797                bool pass_null_along_branch, Value* result_on_fallthrough) {
798    SsaEnv* false_env = ssa_env_;
799    SsaEnv* true_env = Split(decoder->zone(), false_env);
800    false_env->SetNotMerged();
801    builder_->BrOnNull(ref_object.node, &true_env->control,
802                       &false_env->control);
803    builder_->SetControl(false_env->control);
804    SetEnv(true_env);
805    BrOrRet(decoder, depth, pass_null_along_branch ? 0 : 1);
806    SetEnv(false_env);
807    result_on_fallthrough->node = ref_object.node;
808  }
809
810  void BrOnNonNull(FullDecoder* decoder, const Value& ref_object,
811                   uint32_t depth) {
812    SsaEnv* false_env = ssa_env_;
813    SsaEnv* true_env = Split(decoder->zone(), false_env);
814    false_env->SetNotMerged();
815    builder_->BrOnNull(ref_object.node, &false_env->control,
816                       &true_env->control);
817    builder_->SetControl(false_env->control);
818    SetEnv(true_env);
819    BrOrRet(decoder, depth, 0);
820    SetEnv(false_env);
821  }
822
823  void SimdOp(FullDecoder* decoder, WasmOpcode opcode, base::Vector<Value> args,
824              Value* result) {
825    NodeVector inputs(args.size());
826    GetNodes(inputs.begin(), args);
827    TFNode* node = builder_->SimdOp(opcode, inputs.begin());
828    if (result) result->node = node;
829  }
830
831  void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
832                  const SimdLaneImmediate<validate>& imm,
833                  base::Vector<Value> inputs, Value* result) {
834    NodeVector nodes(inputs.size());
835    GetNodes(nodes.begin(), inputs);
836    result->node = builder_->SimdLaneOp(opcode, imm.lane, nodes.begin());
837  }
838
839  void Simd8x16ShuffleOp(FullDecoder* decoder,
840                         const Simd128Immediate<validate>& imm,
841                         const Value& input0, const Value& input1,
842                         Value* result) {
843    TFNode* input_nodes[] = {input0.node, input1.node};
844    result->node = builder_->Simd8x16ShuffleOp(imm.value, input_nodes);
845  }
846
847  void Throw(FullDecoder* decoder, const TagIndexImmediate<validate>& imm,
848             const base::Vector<Value>& value_args) {
849    int count = value_args.length();
850    ZoneVector<TFNode*> args(count, decoder->zone());
851    for (int i = 0; i < count; ++i) {
852      args[i] = value_args[i].node;
853    }
854    CheckForException(decoder,
855                      builder_->Throw(imm.index, imm.tag, base::VectorOf(args),
856                                      decoder->position()));
857    builder_->TerminateThrow(effect(), control());
858  }
859
860  void Rethrow(FullDecoder* decoder, Control* block) {
861    DCHECK(block->is_try_catchall() || block->is_try_catch());
862    TFNode* exception = block->try_info->exception;
863    DCHECK_NOT_NULL(exception);
864    CheckForException(decoder, builder_->Rethrow(exception));
865    builder_->TerminateThrow(effect(), control());
866  }
867
868  void CatchException(FullDecoder* decoder,
869                      const TagIndexImmediate<validate>& imm, Control* block,
870                      base::Vector<Value> values) {
871    DCHECK(block->is_try_catch());
872    // The catch block is unreachable if no possible throws in the try block
873    // exist. We only build a landing pad if some node in the try block can
874    // (possibly) throw. Otherwise the catch environments remain empty.
875    if (!block->try_info->might_throw()) {
876      block->reachability = kSpecOnlyReachable;
877      return;
878    }
879
880    TFNode* exception = block->try_info->exception;
881    SetEnv(block->try_info->catch_env);
882
883    TFNode* if_catch = nullptr;
884    TFNode* if_no_catch = nullptr;
885
886    // Get the exception tag and see if it matches the expected one.
887    TFNode* caught_tag = builder_->GetExceptionTag(exception);
888    TFNode* exception_tag = builder_->LoadTagFromTable(imm.index);
889    TFNode* compare = builder_->ExceptionTagEqual(caught_tag, exception_tag);
890    builder_->BranchNoHint(compare, &if_catch, &if_no_catch);
891
892    // If the tags don't match we continue with the next tag by setting the
893    // false environment as the new {TryInfo::catch_env} here.
894    SsaEnv* if_no_catch_env = Split(decoder->zone(), ssa_env_);
895    if_no_catch_env->control = if_no_catch;
896    SsaEnv* if_catch_env = Steal(decoder->zone(), ssa_env_);
897    if_catch_env->control = if_catch;
898    block->try_info->catch_env = if_no_catch_env;
899
900    // If the tags match we extract the values from the exception object and
901    // push them onto the operand stack using the passed {values} vector.
902    SetEnv(if_catch_env);
903    NodeVector caught_values(values.size());
904    base::Vector<TFNode*> caught_vector = base::VectorOf(caught_values);
905    builder_->GetExceptionValues(exception, imm.tag, caught_vector);
906    for (size_t i = 0, e = values.size(); i < e; ++i) {
907      values[i].node = caught_values[i];
908    }
909  }
910
911  void Delegate(FullDecoder* decoder, uint32_t depth, Control* block) {
912    DCHECK_EQ(decoder->control_at(0), block);
913    DCHECK(block->is_incomplete_try());
914
915    if (block->try_info->might_throw()) {
916      // Merge the current env into the target handler's env.
917      SetEnv(block->try_info->catch_env);
918      if (depth == decoder->control_depth() - 1) {
919        // We just throw to the caller here, so no need to generate IfSuccess
920        // and IfFailure nodes.
921        builder_->Rethrow(block->try_info->exception);
922        builder_->TerminateThrow(effect(), control());
923        return;
924      }
925      DCHECK(decoder->control_at(depth)->is_try());
926      TryInfo* target_try = decoder->control_at(depth)->try_info;
927      if (emit_loop_exits()) {
928        ValueVector stack_values;
929        BuildNestedLoopExits(decoder, depth, true, stack_values,
930                             &block->try_info->exception);
931      }
932      Goto(decoder, target_try->catch_env);
933
934      // Create or merge the exception.
935      if (target_try->catch_env->state == SsaEnv::kReached) {
936        target_try->exception = block->try_info->exception;
937      } else {
938        DCHECK_EQ(target_try->catch_env->state, SsaEnv::kMerged);
939        target_try->exception = builder_->CreateOrMergeIntoPhi(
940            MachineRepresentation::kTagged, target_try->catch_env->control,
941            target_try->exception, block->try_info->exception);
942      }
943    }
944  }
945
946  void CatchAll(FullDecoder* decoder, Control* block) {
947    DCHECK(block->is_try_catchall() || block->is_try_catch());
948    DCHECK_EQ(decoder->control_at(0), block);
949
950    // The catch block is unreachable if no possible throws in the try block
951    // exist. We only build a landing pad if some node in the try block can
952    // (possibly) throw. Otherwise the catch environments remain empty.
953    if (!block->try_info->might_throw()) {
954      decoder->SetSucceedingCodeDynamicallyUnreachable();
955      return;
956    }
957
958    SetEnv(block->try_info->catch_env);
959  }
960
961  void AtomicOp(FullDecoder* decoder, WasmOpcode opcode,
962                base::Vector<Value> args,
963                const MemoryAccessImmediate<validate>& imm, Value* result) {
964    NodeVector inputs(args.size());
965    GetNodes(inputs.begin(), args);
966    TFNode* node = builder_->AtomicOp(opcode, inputs.begin(), imm.alignment,
967                                      imm.offset, decoder->position());
968    if (result) result->node = node;
969  }
970
971  void AtomicFence(FullDecoder* decoder) { builder_->AtomicFence(); }
972
973  void MemoryInit(FullDecoder* decoder,
974                  const MemoryInitImmediate<validate>& imm, const Value& dst,
975                  const Value& src, const Value& size) {
976    builder_->MemoryInit(imm.data_segment.index, dst.node, src.node, size.node,
977                         decoder->position());
978  }
979
980  void DataDrop(FullDecoder* decoder, const IndexImmediate<validate>& imm) {
981    builder_->DataDrop(imm.index, decoder->position());
982  }
983
984  void MemoryCopy(FullDecoder* decoder,
985                  const MemoryCopyImmediate<validate>& imm, const Value& dst,
986                  const Value& src, const Value& size) {
987    builder_->MemoryCopy(dst.node, src.node, size.node, decoder->position());
988  }
989
990  void MemoryFill(FullDecoder* decoder,
991                  const MemoryIndexImmediate<validate>& imm, const Value& dst,
992                  const Value& value, const Value& size) {
993    builder_->MemoryFill(dst.node, value.node, size.node, decoder->position());
994  }
995
996  void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
997                 base::Vector<Value> args) {
998    builder_->TableInit(imm.table.index, imm.element_segment.index,
999                        args[0].node, args[1].node, args[2].node,
1000                        decoder->position());
1001  }
1002
1003  void ElemDrop(FullDecoder* decoder, const IndexImmediate<validate>& imm) {
1004    builder_->ElemDrop(imm.index, decoder->position());
1005  }
1006
1007  void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
1008                 base::Vector<Value> args) {
1009    builder_->TableCopy(imm.table_dst.index, imm.table_src.index, args[0].node,
1010                        args[1].node, args[2].node, decoder->position());
1011  }
1012
1013  void TableGrow(FullDecoder* decoder, const IndexImmediate<validate>& imm,
1014                 const Value& value, const Value& delta, Value* result) {
1015    result->node = builder_->TableGrow(imm.index, value.node, delta.node);
1016  }
1017
1018  void TableSize(FullDecoder* decoder, const IndexImmediate<validate>& imm,
1019                 Value* result) {
1020    result->node = builder_->TableSize(imm.index);
1021  }
1022
1023  void TableFill(FullDecoder* decoder, const IndexImmediate<validate>& imm,
1024                 const Value& start, const Value& value, const Value& count) {
1025    builder_->TableFill(imm.index, start.node, value.node, count.node);
1026  }
1027
1028  void StructNewWithRtt(FullDecoder* decoder,
1029                        const StructIndexImmediate<validate>& imm,
1030                        const Value& rtt, const Value args[], Value* result) {
1031    uint32_t field_count = imm.struct_type->field_count();
1032    NodeVector arg_nodes(field_count);
1033    for (uint32_t i = 0; i < field_count; i++) {
1034      arg_nodes[i] = args[i].node;
1035    }
1036    result->node = builder_->StructNewWithRtt(
1037        imm.index, imm.struct_type, rtt.node, base::VectorOf(arg_nodes));
1038  }
1039  void StructNewDefault(FullDecoder* decoder,
1040                        const StructIndexImmediate<validate>& imm,
1041                        const Value& rtt, Value* result) {
1042    uint32_t field_count = imm.struct_type->field_count();
1043    NodeVector arg_nodes(field_count);
1044    for (uint32_t i = 0; i < field_count; i++) {
1045      arg_nodes[i] = DefaultValue(imm.struct_type->field(i));
1046    }
1047    result->node = builder_->StructNewWithRtt(
1048        imm.index, imm.struct_type, rtt.node, base::VectorOf(arg_nodes));
1049  }
1050
1051  void StructGet(FullDecoder* decoder, const Value& struct_object,
1052                 const FieldImmediate<validate>& field, bool is_signed,
1053                 Value* result) {
1054    result->node = builder_->StructGet(
1055        struct_object.node, field.struct_imm.struct_type, field.field_imm.index,
1056        NullCheckFor(struct_object.type), is_signed, decoder->position());
1057  }
1058
1059  void StructSet(FullDecoder* decoder, const Value& struct_object,
1060                 const FieldImmediate<validate>& field,
1061                 const Value& field_value) {
1062    builder_->StructSet(struct_object.node, field.struct_imm.struct_type,
1063                        field.field_imm.index, field_value.node,
1064                        NullCheckFor(struct_object.type), decoder->position());
1065  }
1066
1067  void ArrayNewWithRtt(FullDecoder* decoder,
1068                       const ArrayIndexImmediate<validate>& imm,
1069                       const Value& length, const Value& initial_value,
1070                       const Value& rtt, Value* result) {
1071    result->node = builder_->ArrayNewWithRtt(imm.index, imm.array_type,
1072                                             length.node, initial_value.node,
1073                                             rtt.node, decoder->position());
1074    // array.new_with_rtt introduces a loop. Therefore, we have to mark the
1075    // immediately nesting loop (if any) as non-innermost.
1076    if (!loop_infos_.empty()) loop_infos_.back().can_be_innermost = false;
1077  }
1078
1079  void ArrayNewDefault(FullDecoder* decoder,
1080                       const ArrayIndexImmediate<validate>& imm,
1081                       const Value& length, const Value& rtt, Value* result) {
1082    // This will cause the default value to be chosen automatically based
1083    // on the element type.
1084    TFNode* initial_value = nullptr;
1085    result->node =
1086        builder_->ArrayNewWithRtt(imm.index, imm.array_type, length.node,
1087                                  initial_value, rtt.node, decoder->position());
1088  }
1089
1090  void ArrayGet(FullDecoder* decoder, const Value& array_obj,
1091                const ArrayIndexImmediate<validate>& imm, const Value& index,
1092                bool is_signed, Value* result) {
1093    result->node = builder_->ArrayGet(array_obj.node, imm.array_type,
1094                                      index.node, NullCheckFor(array_obj.type),
1095                                      is_signed, decoder->position());
1096  }
1097
1098  void ArraySet(FullDecoder* decoder, const Value& array_obj,
1099                const ArrayIndexImmediate<validate>& imm, const Value& index,
1100                const Value& value) {
1101    builder_->ArraySet(array_obj.node, imm.array_type, index.node, value.node,
1102                       NullCheckFor(array_obj.type), decoder->position());
1103  }
1104
1105  void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) {
1106    result->node = builder_->ArrayLen(
1107        array_obj.node, NullCheckFor(array_obj.type), decoder->position());
1108  }
1109
1110  void ArrayCopy(FullDecoder* decoder, const Value& dst, const Value& dst_index,
1111                 const Value& src, const Value& src_index,
1112                 const Value& length) {
1113    builder_->ArrayCopy(dst.node, dst_index.node, NullCheckFor(dst.type),
1114                        src.node, src_index.node, NullCheckFor(src.type),
1115                        length.node, decoder->position());
1116  }
1117
1118  void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
1119                 const base::Vector<Value>& elements, const Value& rtt,
1120                 Value* result) {
1121    NodeVector element_nodes(elements.size());
1122    for (uint32_t i = 0; i < elements.size(); i++) {
1123      element_nodes[i] = elements[i].node;
1124    }
1125    result->node =
1126        builder_->ArrayInit(imm.array_type, rtt.node, VectorOf(element_nodes));
1127  }
1128
1129  void ArrayInitFromData(FullDecoder* decoder,
1130                         const ArrayIndexImmediate<validate>& array_imm,
1131                         const IndexImmediate<validate>& data_segment,
1132                         const Value& offset, const Value& length,
1133                         const Value& rtt, Value* result) {
1134    result->node = builder_->ArrayInitFromData(
1135        array_imm.array_type, data_segment.index, offset.node, length.node,
1136        rtt.node, decoder->position());
1137  }
1138
1139  void I31New(FullDecoder* decoder, const Value& input, Value* result) {
1140    result->node = builder_->I31New(input.node);
1141  }
1142
1143  void I31GetS(FullDecoder* decoder, const Value& input, Value* result) {
1144    result->node = builder_->I31GetS(input.node);
1145  }
1146
1147  void I31GetU(FullDecoder* decoder, const Value& input, Value* result) {
1148    result->node = builder_->I31GetU(input.node);
1149  }
1150
1151  void RttCanon(FullDecoder* decoder, uint32_t type_index, Value* result) {
1152    result->node = builder_->RttCanon(type_index);
1153  }
1154
1155  using StaticKnowledge = compiler::WasmGraphBuilder::ObjectReferenceKnowledge;
1156
1157  StaticKnowledge ComputeStaticKnowledge(ValueType object_type,
1158                                         ValueType rtt_type,
1159                                         const WasmModule* module) {
1160    StaticKnowledge result;
1161    result.object_can_be_null = object_type.is_nullable();
1162    DCHECK(object_type.is_object_reference());  // Checked by validation.
1163    // In the bottom case, the result is irrelevant.
1164    result.rtt_depth = rtt_type.is_bottom()
1165                           ? 0 /* unused */
1166                           : static_cast<uint8_t>(GetSubtypingDepth(
1167                                 module, rtt_type.ref_index()));
1168    return result;
1169  }
1170
1171  void RefTest(FullDecoder* decoder, const Value& object, const Value& rtt,
1172               Value* result) {
1173    StaticKnowledge config =
1174        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
1175    result->node = builder_->RefTest(object.node, rtt.node, config);
1176  }
1177
1178  void RefCast(FullDecoder* decoder, const Value& object, const Value& rtt,
1179               Value* result) {
1180    StaticKnowledge config =
1181        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
1182    result->node =
1183        builder_->RefCast(object.node, rtt.node, config, decoder->position());
1184  }
1185
1186  template <void (compiler::WasmGraphBuilder::*branch_function)(
1187      TFNode*, TFNode*, StaticKnowledge, TFNode**, TFNode**, TFNode**,
1188      TFNode**)>
1189  void BrOnCastAbs(FullDecoder* decoder, const Value& object, const Value& rtt,
1190                   Value* forwarding_value, uint32_t br_depth,
1191                   bool branch_on_match) {
1192    StaticKnowledge config =
1193        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
1194    SsaEnv* branch_env = Split(decoder->zone(), ssa_env_);
1195    SsaEnv* no_branch_env = Steal(decoder->zone(), ssa_env_);
1196    no_branch_env->SetNotMerged();
1197    SsaEnv* match_env = branch_on_match ? branch_env : no_branch_env;
1198    SsaEnv* no_match_env = branch_on_match ? no_branch_env : branch_env;
1199    (builder_->*branch_function)(object.node, rtt.node, config,
1200                                 &match_env->control, &match_env->effect,
1201                                 &no_match_env->control, &no_match_env->effect);
1202    builder_->SetControl(no_branch_env->control);
1203    SetEnv(branch_env);
1204    forwarding_value->node = object.node;
1205    // Currently, br_on_* instructions modify the value stack before calling
1206    // the interface function, so we don't need to drop any values here.
1207    BrOrRet(decoder, br_depth, 0);
1208    SetEnv(no_branch_env);
1209  }
1210
1211  void BrOnCast(FullDecoder* decoder, const Value& object, const Value& rtt,
1212                Value* value_on_branch, uint32_t br_depth) {
1213    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnCast>(
1214        decoder, object, rtt, value_on_branch, br_depth, true);
1215  }
1216
1217  void BrOnCastFail(FullDecoder* decoder, const Value& object, const Value& rtt,
1218                    Value* value_on_fallthrough, uint32_t br_depth) {
1219    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnCast>(
1220        decoder, object, rtt, value_on_fallthrough, br_depth, false);
1221  }
1222
1223  void RefIsData(FullDecoder* decoder, const Value& object, Value* result) {
1224    result->node = builder_->RefIsData(object.node, object.type.is_nullable());
1225  }
1226
1227  void RefAsData(FullDecoder* decoder, const Value& object, Value* result) {
1228    result->node = builder_->RefAsData(object.node, object.type.is_nullable(),
1229                                       decoder->position());
1230  }
1231
1232  void BrOnData(FullDecoder* decoder, const Value& object,
1233                Value* value_on_branch, uint32_t br_depth) {
1234    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>(
1235        decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
1236        true);
1237  }
1238
1239  void BrOnNonData(FullDecoder* decoder, const Value& object,
1240                   Value* value_on_fallthrough, uint32_t br_depth) {
1241    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnData>(
1242        decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
1243        br_depth, false);
1244  }
1245
1246  void RefIsFunc(FullDecoder* decoder, const Value& object, Value* result) {
1247    result->node = builder_->RefIsFunc(object.node, object.type.is_nullable());
1248  }
1249
1250  void RefAsFunc(FullDecoder* decoder, const Value& object, Value* result) {
1251    result->node = builder_->RefAsFunc(object.node, object.type.is_nullable(),
1252                                       decoder->position());
1253  }
1254
1255  void BrOnFunc(FullDecoder* decoder, const Value& object,
1256                Value* value_on_branch, uint32_t br_depth) {
1257    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnFunc>(
1258        decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
1259        true);
1260  }
1261
1262  void BrOnNonFunc(FullDecoder* decoder, const Value& object,
1263                   Value* value_on_fallthrough, uint32_t br_depth) {
1264    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnFunc>(
1265        decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
1266        br_depth, false);
1267  }
1268
1269  void RefIsArray(FullDecoder* decoder, const Value& object, Value* result) {
1270    result->node = builder_->RefIsArray(object.node, object.type.is_nullable());
1271  }
1272
1273  void RefAsArray(FullDecoder* decoder, const Value& object, Value* result) {
1274    result->node = builder_->RefAsArray(object.node, object.type.is_nullable(),
1275                                        decoder->position());
1276  }
1277
1278  void BrOnArray(FullDecoder* decoder, const Value& object,
1279                 Value* value_on_branch, uint32_t br_depth) {
1280    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>(
1281        decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
1282        true);
1283  }
1284
1285  void BrOnNonArray(FullDecoder* decoder, const Value& object,
1286                    Value* value_on_fallthrough, uint32_t br_depth) {
1287    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnArray>(
1288        decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
1289        br_depth, false);
1290  }
1291
1292  void RefIsI31(FullDecoder* decoder, const Value& object, Value* result) {
1293    result->node = builder_->RefIsI31(object.node);
1294  }
1295
1296  void RefAsI31(FullDecoder* decoder, const Value& object, Value* result) {
1297    result->node = builder_->RefAsI31(object.node, decoder->position());
1298  }
1299
1300  void BrOnI31(FullDecoder* decoder, const Value& object,
1301               Value* value_on_branch, uint32_t br_depth) {
1302    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnI31>(
1303        decoder, object, Value{nullptr, kWasmBottom}, value_on_branch, br_depth,
1304        true);
1305  }
1306
1307  void BrOnNonI31(FullDecoder* decoder, const Value& object,
1308                  Value* value_on_fallthrough, uint32_t br_depth) {
1309    BrOnCastAbs<&compiler::WasmGraphBuilder::BrOnI31>(
1310        decoder, object, Value{nullptr, kWasmBottom}, value_on_fallthrough,
1311        br_depth, false);
1312  }
1313
1314  void Forward(FullDecoder* decoder, const Value& from, Value* to) {
1315    to->node = from.node;
1316  }
1317
1318  std::vector<compiler::WasmLoopInfo> loop_infos() { return loop_infos_; }
1319
1320 private:
1321  SsaEnv* ssa_env_ = nullptr;
1322  compiler::WasmGraphBuilder* builder_;
1323  int func_index_;
1324  const BranchHintMap* branch_hints_ = nullptr;
1325  // Tracks loop data for loop unrolling.
1326  std::vector<compiler::WasmLoopInfo> loop_infos_;
1327  InlinedStatus inlined_status_;
1328  // The entries in {type_feedback_} are indexed by the position of feedback-
1329  // consuming instructions (currently only call_ref).
1330  int feedback_instruction_index_ = 0;
1331  std::vector<CallSiteFeedback> type_feedback_;
1332
1333  TFNode* effect() { return builder_->effect(); }
1334
1335  TFNode* control() { return builder_->control(); }
1336
1337  TryInfo* current_try_info(FullDecoder* decoder) {
1338    DCHECK_LT(decoder->current_catch(), decoder->control_depth());
1339    return decoder->control_at(decoder->control_depth_of_current_catch())
1340        ->try_info;
1341  }
1342
1343  // If {emit_loop_exits()} returns true, we need to emit LoopExit,
1344  // LoopExitEffect, and LoopExit nodes whenever a control resp. effect resp.
1345  // value escapes a loop. We emit loop exits in the following cases:
1346  // - When popping the control of a loop.
1347  // - At some nodes which connect to the graph's end. We do not always need to
1348  //   emit loop exits for such nodes, since the wasm loop analysis algorithm
1349  //   can handle a loop body which connects directly to the graph's end.
1350  //   However, we need to emit them anyway for nodes that may be rewired to
1351  //   different nodes during inlining. These are Return and TailCall nodes.
1352  // - After IfFailure nodes.
1353  // - When exiting a loop through Delegate.
1354  bool emit_loop_exits() {
1355    return FLAG_wasm_loop_unrolling || FLAG_wasm_loop_peeling;
1356  }
1357
1358  void GetNodes(TFNode** nodes, Value* values, size_t count) {
1359    for (size_t i = 0; i < count; ++i) {
1360      nodes[i] = values[i].node;
1361    }
1362  }
1363
1364  void GetNodes(TFNode** nodes, base::Vector<Value> values) {
1365    GetNodes(nodes, values.begin(), values.size());
1366  }
1367
1368  void SetEnv(SsaEnv* env) {
1369    if (FLAG_trace_wasm_decoder) {
1370      char state = 'X';
1371      if (env) {
1372        switch (env->state) {
1373          case SsaEnv::kReached:
1374            state = 'R';
1375            break;
1376          case SsaEnv::kUnreachable:
1377            state = 'U';
1378            break;
1379          case SsaEnv::kMerged:
1380            state = 'M';
1381            break;
1382        }
1383      }
1384      PrintF("{set_env = %p, state = %c", env, state);
1385      if (env && env->control) {
1386        PrintF(", control = ");
1387        compiler::WasmGraphBuilder::PrintDebugName(env->control);
1388      }
1389      PrintF("}\n");
1390    }
1391    if (ssa_env_) {
1392      ssa_env_->control = control();
1393      ssa_env_->effect = effect();
1394    }
1395    ssa_env_ = env;
1396    builder_->SetEffectControl(env->effect, env->control);
1397    builder_->set_instance_cache(&env->instance_cache);
1398  }
1399
1400  TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
1401    DCHECK_NOT_NULL(node);
1402
1403    // We need to emit IfSuccess/IfException nodes if this node throws and has
1404    // an exception handler. An exception handler can either be a try-scope
1405    // around this node, or if this function is being inlined, the IfException
1406    // output of the inlined Call node.
1407    const bool inside_try_scope = decoder->current_catch() != -1;
1408    if (inlined_status_ != kInlinedHandledCall && !inside_try_scope) {
1409      return node;
1410    }
1411
1412    TFNode* if_success = nullptr;
1413    TFNode* if_exception = nullptr;
1414    if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
1415      return node;
1416    }
1417
1418    SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
1419    success_env->control = if_success;
1420
1421    SsaEnv* exception_env = Split(decoder->zone(), success_env);
1422    exception_env->control = if_exception;
1423    exception_env->effect = if_exception;
1424    SetEnv(exception_env);
1425
1426    if (emit_loop_exits()) {
1427      ValueVector values;
1428      BuildNestedLoopExits(decoder,
1429                           inside_try_scope
1430                               ? decoder->control_depth_of_current_catch()
1431                               : decoder->control_depth() - 1,
1432                           true, values, &if_exception);
1433    }
1434    if (inside_try_scope) {
1435      TryInfo* try_info = current_try_info(decoder);
1436      Goto(decoder, try_info->catch_env);
1437      if (try_info->exception == nullptr) {
1438        DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
1439        try_info->exception = if_exception;
1440      } else {
1441        DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
1442        try_info->exception = builder_->CreateOrMergeIntoPhi(
1443            MachineRepresentation::kTaggedPointer, try_info->catch_env->control,
1444            try_info->exception, if_exception);
1445      }
1446    } else {
1447      DCHECK_EQ(inlined_status_, kInlinedHandledCall);
1448      // Leave the IfException/LoopExit node dangling. We will connect it during
1449      // inlining to the handler of the inlined call.
1450      // Note: We have to generate the handler now since we have no way of
1451      // generating a LoopExit if needed in the inlining code.
1452    }
1453
1454    SetEnv(success_env);
1455    return node;
1456  }
1457
1458  TFNode* DefaultValue(ValueType type) {
1459    DCHECK(type.is_defaultable());
1460    switch (type.kind()) {
1461      case kI8:
1462      case kI16:
1463      case kI32:
1464        return builder_->Int32Constant(0);
1465      case kI64:
1466        return builder_->Int64Constant(0);
1467      case kF32:
1468        return builder_->Float32Constant(0);
1469      case kF64:
1470        return builder_->Float64Constant(0);
1471      case kS128:
1472        return builder_->S128Zero();
1473      case kOptRef:
1474        return builder_->RefNull();
1475      case kRtt:
1476      case kVoid:
1477      case kBottom:
1478      case kRef:
1479        UNREACHABLE();
1480    }
1481  }
1482
1483  void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge,
1484                       Value* values) {
1485    DCHECK(merge == &c->start_merge || merge == &c->end_merge);
1486
1487    SsaEnv* target = c->merge_env;
1488    // This has to be computed before calling Goto().
1489    const bool first = target->state == SsaEnv::kUnreachable;
1490
1491    Goto(decoder, target);
1492
1493    if (merge->arity == 0) return;
1494
1495    for (uint32_t i = 0; i < merge->arity; ++i) {
1496      Value& val = values[i];
1497      Value& old = (*merge)[i];
1498      DCHECK_NOT_NULL(val.node);
1499      DCHECK(val.type == kWasmBottom || val.type.machine_representation() ==
1500                                            old.type.machine_representation());
1501      old.node = first ? val.node
1502                       : builder_->CreateOrMergeIntoPhi(
1503                             old.type.machine_representation(), target->control,
1504                             old.node, val.node);
1505    }
1506  }
1507
1508  void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge,
1509                       uint32_t drop_values = 0) {
1510#ifdef DEBUG
1511    uint32_t avail = decoder->stack_size() -
1512                     decoder->control_at(0)->stack_depth - drop_values;
1513    DCHECK_GE(avail, merge->arity);
1514#endif
1515    Value* stack_values = merge->arity > 0
1516                              ? decoder->stack_value(merge->arity + drop_values)
1517                              : nullptr;
1518    MergeValuesInto(decoder, c, merge, stack_values);
1519  }
1520
1521  void Goto(FullDecoder* decoder, SsaEnv* to) {
1522    DCHECK_NOT_NULL(to);
1523    switch (to->state) {
1524      case SsaEnv::kUnreachable: {  // Overwrite destination.
1525        to->state = SsaEnv::kReached;
1526        // There might be an offset in the locals due to a 'let'.
1527        DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
1528        DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
1529        uint32_t local_count_diff =
1530            static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
1531        to->locals = ssa_env_->locals;
1532        to->locals.erase(to->locals.begin(),
1533                         to->locals.begin() + local_count_diff);
1534        to->control = control();
1535        to->effect = effect();
1536        to->instance_cache = ssa_env_->instance_cache;
1537        break;
1538      }
1539      case SsaEnv::kReached: {  // Create a new merge.
1540        to->state = SsaEnv::kMerged;
1541        // Merge control.
1542        TFNode* controls[] = {to->control, control()};
1543        TFNode* merge = builder_->Merge(2, controls);
1544        to->control = merge;
1545        // Merge effects.
1546        TFNode* old_effect = effect();
1547        if (old_effect != to->effect) {
1548          TFNode* inputs[] = {to->effect, old_effect, merge};
1549          to->effect = builder_->EffectPhi(2, inputs);
1550        }
1551        // Merge locals.
1552        // There might be an offset in the locals due to a 'let'.
1553        DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
1554        DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
1555        uint32_t local_count_diff =
1556            static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
1557        for (uint32_t i = 0; i < to->locals.size(); i++) {
1558          TFNode* a = to->locals[i];
1559          TFNode* b = ssa_env_->locals[i + local_count_diff];
1560          if (a != b) {
1561            TFNode* inputs[] = {a, b, merge};
1562            to->locals[i] = builder_->Phi(
1563                decoder->local_type(i + local_count_diff), 2, inputs);
1564          }
1565        }
1566        // Start a new merge from the instance cache.
1567        builder_->NewInstanceCacheMerge(&to->instance_cache,
1568                                        &ssa_env_->instance_cache, merge);
1569        break;
1570      }
1571      case SsaEnv::kMerged: {
1572        TFNode* merge = to->control;
1573        // Extend the existing merge control node.
1574        builder_->AppendToMerge(merge, control());
1575        // Merge effects.
1576        to->effect =
1577            builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, effect());
1578        // Merge locals.
1579        // There might be an offset in the locals due to a 'let'.
1580        DCHECK_EQ(ssa_env_->locals.size(), decoder->num_locals());
1581        DCHECK_GE(ssa_env_->locals.size(), to->locals.size());
1582        uint32_t local_count_diff =
1583            static_cast<uint32_t>(ssa_env_->locals.size() - to->locals.size());
1584        for (uint32_t i = 0; i < to->locals.size(); i++) {
1585          to->locals[i] = builder_->CreateOrMergeIntoPhi(
1586              decoder->local_type(i + local_count_diff)
1587                  .machine_representation(),
1588              merge, to->locals[i], ssa_env_->locals[i + local_count_diff]);
1589        }
1590        // Merge the instance caches.
1591        builder_->MergeInstanceCacheInto(&to->instance_cache,
1592                                         &ssa_env_->instance_cache, merge);
1593        break;
1594      }
1595      default:
1596        UNREACHABLE();
1597    }
1598  }
1599
1600  // Create a complete copy of {from}.
1601  SsaEnv* Split(Zone* zone, SsaEnv* from) {
1602    DCHECK_NOT_NULL(from);
1603    if (from == ssa_env_) {
1604      ssa_env_->control = control();
1605      ssa_env_->effect = effect();
1606    }
1607    SsaEnv* result = zone->New<SsaEnv>(*from);
1608    result->state = SsaEnv::kReached;
1609    return result;
1610  }
1611
1612  // Create a copy of {from} that steals its state and leaves {from}
1613  // unreachable.
1614  SsaEnv* Steal(Zone* zone, SsaEnv* from) {
1615    DCHECK_NOT_NULL(from);
1616    if (from == ssa_env_) {
1617      ssa_env_->control = control();
1618      ssa_env_->effect = effect();
1619    }
1620    SsaEnv* result = zone->New<SsaEnv>(std::move(*from));
1621    // Restore the length of {from->locals} after applying move-constructor.
1622    from->locals.resize(result->locals.size());
1623    result->state = SsaEnv::kReached;
1624    return result;
1625  }
1626
1627  class CallInfo {
1628   public:
1629    enum CallMode { kCallDirect, kCallIndirect, kCallRef };
1630
1631    static CallInfo CallDirect(uint32_t callee_index) {
1632      return {kCallDirect, callee_index, nullptr, 0,
1633              CheckForNull::kWithoutNullCheck};
1634    }
1635
1636    static CallInfo CallIndirect(const Value& index_value, uint32_t table_index,
1637                                 uint32_t sig_index) {
1638      return {kCallIndirect, sig_index, &index_value, table_index,
1639              CheckForNull::kWithoutNullCheck};
1640    }
1641
1642    static CallInfo CallRef(const Value& funcref_value,
1643                            CheckForNull null_check) {
1644      return {kCallRef, 0, &funcref_value, 0, null_check};
1645    }
1646
1647    CallMode call_mode() { return call_mode_; }
1648
1649    uint32_t sig_index() {
1650      DCHECK_EQ(call_mode_, kCallIndirect);
1651      return callee_or_sig_index_;
1652    }
1653
1654    uint32_t callee_index() {
1655      DCHECK_EQ(call_mode_, kCallDirect);
1656      return callee_or_sig_index_;
1657    }
1658
1659    CheckForNull null_check() {
1660      DCHECK_EQ(call_mode_, kCallRef);
1661      return null_check_;
1662    }
1663
1664    const Value* index_or_callee_value() {
1665      DCHECK_NE(call_mode_, kCallDirect);
1666      return index_or_callee_value_;
1667    }
1668
1669    uint32_t table_index() {
1670      DCHECK_EQ(call_mode_, kCallIndirect);
1671      return table_index_;
1672    }
1673
1674   private:
1675    CallInfo(CallMode call_mode, uint32_t callee_or_sig_index,
1676             const Value* index_or_callee_value, uint32_t table_index,
1677             CheckForNull null_check)
1678        : call_mode_(call_mode),
1679          callee_or_sig_index_(callee_or_sig_index),
1680          index_or_callee_value_(index_or_callee_value),
1681          table_index_(table_index),
1682          null_check_(null_check) {}
1683    CallMode call_mode_;
1684    uint32_t callee_or_sig_index_;
1685    const Value* index_or_callee_value_;
1686    uint32_t table_index_;
1687    CheckForNull null_check_;
1688  };
1689
1690  void DoCall(FullDecoder* decoder, CallInfo call_info, const FunctionSig* sig,
1691              const Value args[], Value returns[]) {
1692    size_t param_count = sig->parameter_count();
1693    size_t return_count = sig->return_count();
1694
1695    // Construct a function signature based on the real function parameters.
1696    FunctionSig::Builder real_sig_builder(builder_->graph_zone(), return_count,
1697                                          param_count);
1698    for (size_t i = 0; i < param_count; i++) {
1699      real_sig_builder.AddParam(args[i].type);
1700    }
1701    for (size_t i = 0; i < return_count; i++) {
1702      real_sig_builder.AddReturn(sig->GetReturn(i));
1703    }
1704    FunctionSig* real_sig = real_sig_builder.Build();
1705
1706    NodeVector arg_nodes(param_count + 1);
1707    base::SmallVector<TFNode*, 1> return_nodes(return_count);
1708    arg_nodes[0] = (call_info.call_mode() == CallInfo::kCallDirect)
1709                       ? nullptr
1710                       : call_info.index_or_callee_value()->node;
1711
1712    for (size_t i = 0; i < param_count; ++i) {
1713      arg_nodes[i + 1] = args[i].node;
1714    }
1715    switch (call_info.call_mode()) {
1716      case CallInfo::kCallIndirect:
1717        CheckForException(
1718            decoder, builder_->CallIndirect(
1719                         call_info.table_index(), call_info.sig_index(),
1720                         real_sig, base::VectorOf(arg_nodes),
1721                         base::VectorOf(return_nodes), decoder->position()));
1722        break;
1723      case CallInfo::kCallDirect:
1724        CheckForException(
1725            decoder, builder_->CallDirect(call_info.callee_index(), real_sig,
1726                                          base::VectorOf(arg_nodes),
1727                                          base::VectorOf(return_nodes),
1728                                          decoder->position()));
1729        break;
1730      case CallInfo::kCallRef:
1731        CheckForException(
1732            decoder,
1733            builder_->CallRef(real_sig, base::VectorOf(arg_nodes),
1734                              base::VectorOf(return_nodes),
1735                              call_info.null_check(), decoder->position()));
1736        break;
1737    }
1738    for (size_t i = 0; i < return_count; ++i) {
1739      returns[i].node = return_nodes[i];
1740    }
1741    if (decoder->module_->initial_pages != decoder->module_->maximum_pages) {
1742      // The invoked function could have used grow_memory, so we need to
1743      // reload mem_size and mem_start.
1744      LoadContextIntoSsa(ssa_env_);
1745    }
1746  }
1747
1748  void DoReturnCall(FullDecoder* decoder, CallInfo call_info,
1749                    const FunctionSig* sig, const Value args[]) {
1750    size_t arg_count = sig->parameter_count();
1751
1752    // Construct a function signature based on the real function parameters.
1753    FunctionSig::Builder real_sig_builder(builder_->graph_zone(),
1754                                          sig->return_count(), arg_count);
1755    for (size_t i = 0; i < arg_count; i++) {
1756      real_sig_builder.AddParam(args[i].type);
1757    }
1758    for (size_t i = 0; i < sig->return_count(); i++) {
1759      real_sig_builder.AddReturn(sig->GetReturn(i));
1760    }
1761    FunctionSig* real_sig = real_sig_builder.Build();
1762
1763    ValueVector arg_values(arg_count + 1);
1764    if (call_info.call_mode() == CallInfo::kCallDirect) {
1765      arg_values[0].node = nullptr;
1766    } else {
1767      arg_values[0] = *call_info.index_or_callee_value();
1768      // This is not done by copy assignment.
1769      arg_values[0].node = call_info.index_or_callee_value()->node;
1770    }
1771    if (arg_count > 0) {
1772      std::memcpy(arg_values.data() + 1, args, arg_count * sizeof(Value));
1773    }
1774
1775    if (emit_loop_exits()) {
1776      BuildNestedLoopExits(decoder, decoder->control_depth(), false,
1777                           arg_values);
1778    }
1779
1780    NodeVector arg_nodes(arg_count + 1);
1781    GetNodes(arg_nodes.data(), base::VectorOf(arg_values));
1782
1783    switch (call_info.call_mode()) {
1784      case CallInfo::kCallIndirect:
1785        builder_->ReturnCallIndirect(
1786            call_info.table_index(), call_info.sig_index(), real_sig,
1787            base::VectorOf(arg_nodes), decoder->position());
1788        break;
1789      case CallInfo::kCallDirect:
1790        builder_->ReturnCall(call_info.callee_index(), real_sig,
1791                             base::VectorOf(arg_nodes), decoder->position());
1792        break;
1793      case CallInfo::kCallRef:
1794        builder_->ReturnCallRef(real_sig, base::VectorOf(arg_nodes),
1795                                call_info.null_check(), decoder->position());
1796        break;
1797    }
1798  }
1799
1800  void BuildLoopExits(FullDecoder* decoder, Control* loop) {
1801    builder_->LoopExit(loop->loop_node);
1802    ssa_env_->control = control();
1803    ssa_env_->effect = effect();
1804  }
1805
1806  void WrapLocalsAtLoopExit(FullDecoder* decoder, Control* loop) {
1807    for (uint32_t index = 0; index < decoder->num_locals(); index++) {
1808      if (loop->loop_assignments->Contains(static_cast<int>(index))) {
1809        ssa_env_->locals[index] = builder_->LoopExitValue(
1810            ssa_env_->locals[index],
1811            decoder->local_type(index).machine_representation());
1812      }
1813    }
1814    if (loop->loop_assignments->Contains(decoder->num_locals())) {
1815#define WRAP_CACHE_FIELD(field)                                                \
1816  if (ssa_env_->instance_cache.field != nullptr) {                             \
1817    ssa_env_->instance_cache.field = builder_->LoopExitValue(                  \
1818        ssa_env_->instance_cache.field, MachineType::PointerRepresentation()); \
1819  }
1820
1821      WRAP_CACHE_FIELD(mem_start);
1822      WRAP_CACHE_FIELD(mem_size);
1823#undef WRAP_CACHE_FIELD
1824    }
1825  }
1826
1827  void BuildNestedLoopExits(FullDecoder* decoder, uint32_t depth_limit,
1828                            bool wrap_exit_values, ValueVector& stack_values,
1829                            TFNode** exception_value = nullptr) {
1830    DCHECK(emit_loop_exits());
1831    Control* control = nullptr;
1832    // We are only interested in exits from the innermost loop.
1833    for (uint32_t i = 0; i < depth_limit; i++) {
1834      Control* c = decoder->control_at(i);
1835      if (c->is_loop()) {
1836        control = c;
1837        break;
1838      }
1839    }
1840    if (control != nullptr) {
1841      BuildLoopExits(decoder, control);
1842      for (Value& value : stack_values) {
1843        if (value.node != nullptr) {
1844          value.node = builder_->LoopExitValue(
1845              value.node, value.type.machine_representation());
1846        }
1847      }
1848      if (exception_value != nullptr) {
1849        *exception_value = builder_->LoopExitValue(
1850            *exception_value, MachineRepresentation::kWord32);
1851      }
1852      if (wrap_exit_values) {
1853        WrapLocalsAtLoopExit(decoder, control);
1854      }
1855    }
1856  }
1857
1858  CheckForNull NullCheckFor(ValueType type) {
1859    DCHECK(type.is_object_reference());
1860    return (!FLAG_experimental_wasm_skip_null_checks && type.is_nullable())
1861               ? CheckForNull::kWithNullCheck
1862               : CheckForNull::kWithoutNullCheck;
1863  }
1864};
1865
1866}  // namespace
1867
1868DecodeResult BuildTFGraph(AccountingAllocator* allocator,
1869                          const WasmFeatures& enabled, const WasmModule* module,
1870                          compiler::WasmGraphBuilder* builder,
1871                          WasmFeatures* detected, const FunctionBody& body,
1872                          std::vector<compiler::WasmLoopInfo>* loop_infos,
1873                          compiler::NodeOriginTable* node_origins,
1874                          int func_index, InlinedStatus inlined_status) {
1875  Zone zone(allocator, ZONE_NAME);
1876  WasmFullDecoder<Decoder::kFullValidation, WasmGraphBuildingInterface> decoder(
1877      &zone, module, enabled, detected, body, builder, func_index,
1878      inlined_status);
1879  if (node_origins) {
1880    builder->AddBytecodePositionDecorator(node_origins, &decoder);
1881  }
1882  decoder.Decode();
1883  if (node_origins) {
1884    builder->RemoveBytecodePositionDecorator();
1885  }
1886  *loop_infos = decoder.interface().loop_infos();
1887
1888  return decoder.toResult(nullptr);
1889}
1890
1891}  // namespace wasm
1892}  // namespace internal
1893}  // namespace v8
1894