graph-builder-interface.cc 45 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/wasm/graph-builder-interface.h"

#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 13 14
#include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/function-body-decoder.h"
15
#include "src/wasm/value-type.h"
16 17 18
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-module.h"
19
#include "src/wasm/wasm-opcodes-inl.h"
20 21 22 23 24 25 26 27 28 29 30

namespace v8 {
namespace internal {
namespace wasm {

namespace {

// An SsaEnv environment carries the current local variable renaming
// as well as the current effect and control dependency in the TF graph.
// It maintains a control state that tracks whether the environment
// is reachable, has reached a control end, or has been merged.
31
struct SsaEnv : public ZoneObject {
32 33 34 35 36 37
  enum State { kControlEnd, kUnreachable, kReached, kMerged };

  State state;
  TFNode* control;
  TFNode* effect;
  compiler::WasmInstanceCacheNodes instance_cache;
38
  ZoneVector<TFNode*> locals;
39

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
  SsaEnv(Zone* zone, State state, TFNode* control, TFNode* effect,
         uint32_t locals_size)
      : state(state), control(control), effect(effect), locals(zone) {
    if (locals_size > 0) locals.resize(locals_size);
  }

  SsaEnv(const SsaEnv& other) V8_NOEXCEPT = default;
  SsaEnv(SsaEnv&& other) V8_NOEXCEPT : state(other.state),
                                       control(other.control),
                                       effect(other.effect),
                                       instance_cache(other.instance_cache),
                                       locals(std::move(other.locals)) {
    other.Kill(kUnreachable);
  }

55 56
  void Kill(State new_state = kControlEnd) {
    state = new_state;
57
    locals.clear();
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    control = nullptr;
    effect = nullptr;
    instance_cache = {};
  }
  void SetNotMerged() {
    if (state == kMerged) state = kReached;
  }
};

#define BUILD(func, ...)                                            \
  ([&] {                                                            \
    DCHECK(decoder->ok());                                          \
    return CheckForException(decoder, builder_->func(__VA_ARGS__)); \
  })()

constexpr uint32_t kNullCatch = static_cast<uint32_t>(-1);

class WasmGraphBuildingInterface {
 public:
77
  static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
78
  using FullDecoder = WasmFullDecoder<validate, WasmGraphBuildingInterface>;
79
  using CheckForNull = compiler::WasmGraphBuilder::CheckForNull;
80

81
  struct Value : public ValueBase<validate> {
82 83 84 85 86
    TFNode* node = nullptr;

    template <typename... Args>
    explicit Value(Args&&... args) V8_NOEXCEPT
        : ValueBase(std::forward<Args>(args)...) {}
87 88 89 90 91 92
  };

  struct TryInfo : public ZoneObject {
    SsaEnv* catch_env;
    TFNode* exception = nullptr;

93 94
    bool might_throw() const { return exception != nullptr; }

95 96
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TryInfo);

97 98 99
    explicit TryInfo(SsaEnv* c) : catch_env(c) {}
  };

100
  struct Control : public ControlBase<Value, validate> {
101 102 103 104 105 106 107 108 109 110
    SsaEnv* end_env = nullptr;    // end environment for the construct.
    SsaEnv* false_env = nullptr;  // false environment (only for if).
    TryInfo* try_info = nullptr;  // information about try statements.
    int32_t previous_catch = -1;  // previous Control with a catch.

    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Control);

    template <typename... Args>
    explicit Control(Args&&... args) V8_NOEXCEPT
        : ControlBase(std::forward<Args>(args)...) {}
111 112 113 114 115 116 117 118 119 120
  };

  explicit WasmGraphBuildingInterface(compiler::WasmGraphBuilder* builder)
      : builder_(builder) {}

  void StartFunction(FullDecoder* decoder) {
    // The first '+ 1' is needed by TF Start node, the second '+ 1' is for the
    // instance parameter.
    TFNode* start = builder_->Start(
        static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
121
    uint32_t num_locals = decoder->num_locals();
122 123
    SsaEnv* ssa_env = decoder->zone()->New<SsaEnv>(
        decoder->zone(), SsaEnv::kReached, start, start, num_locals);
124

125 126
    // Initialize effect and control before initializing the locals default
    // values (which might require instance loads) or loading the context.
127
    builder_->SetEffectControl(start);
128 129 130 131 132 133 134 135 136
    // Initialize the instance parameter (index 0).
    builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
    // Initialize local variables. Parameters are shifted by 1 because of the
    // the instance parameter.
    uint32_t index = 0;
    for (; index < decoder->sig_->parameter_count(); ++index) {
      ssa_env->locals[index] = builder_->Param(index + 1);
    }
    while (index < num_locals) {
137
      ValueType type = decoder->local_type(index);
138
      TFNode* node = DefaultValue(type);
139
      while (index < num_locals && decoder->local_type(index) == type) {
140 141 142 143 144
        // Do a whole run of like-typed locals at a time.
        ssa_env->locals[index++] = node;
      }
    }
    SetEnv(ssa_env);
145
    LoadContextIntoSsa(ssa_env);
146 147

    if (FLAG_trace_wasm) BUILD(TraceFunctionEntry, decoder->position());
148 149 150 151
  }

  // Reload the instance cache entries into the Ssa Environment.
  void LoadContextIntoSsa(SsaEnv* ssa_env) {
152
    if (ssa_env) builder_->InitInstanceCache(&ssa_env->instance_cache);
153 154
  }

155
  void StartFunctionBody(FullDecoder* decoder, Control* block) {}
156 157 158 159 160 161 162 163

  void FinishFunction(FullDecoder*) { builder_->PatchInStackCheckIfNeeded(); }

  void OnFirstError(FullDecoder*) {}

  void NextInstruction(FullDecoder*, WasmOpcode) {}

  void Block(FullDecoder* decoder, Control* block) {
164
    // The branch environment is the outer environment.
165 166 167 168 169 170 171
    block->end_env = ssa_env_;
    SetEnv(Steal(decoder->zone(), ssa_env_));
  }

  void Loop(FullDecoder* decoder, Control* block) {
    SsaEnv* finish_try_env = Steal(decoder->zone(), ssa_env_);
    block->end_env = finish_try_env;
172
    SetEnv(finish_try_env);
173
    // The continue environment is the inner environment.
174
    PrepareForLoop(decoder);
175 176 177
    ssa_env_->SetNotMerged();
    if (!decoder->ok()) return;
    // Wrap input merge into phis.
178
    for (uint32_t i = 0; i < block->start_merge.arity; ++i) {
179
      Value& val = block->start_merge[i];
180 181
      TFNode* inputs[] = {val.node, block->end_env->control};
      val.node = builder_->Phi(val.type, 1, inputs);
182 183 184 185 186
    }
  }

  void Try(FullDecoder* decoder, Control* block) {
    SsaEnv* outer_env = ssa_env_;
187
    SsaEnv* catch_env = Split(decoder->zone(), outer_env);
188 189 190 191 192
    // Mark catch environment as unreachable, since only accessable
    // through catch unwinding (i.e. landing pads).
    catch_env->state = SsaEnv::kUnreachable;
    SsaEnv* try_env = Steal(decoder->zone(), outer_env);
    SetEnv(try_env);
193
    TryInfo* try_info = decoder->zone()->New<TryInfo>(catch_env);
194 195 196 197 198 199 200 201 202
    block->end_env = outer_env;
    block->try_info = try_info;
    block->previous_catch = current_catch_;
    current_catch_ = static_cast<int32_t>(decoder->control_depth() - 1);
  }

  void If(FullDecoder* decoder, const Value& cond, Control* if_block) {
    TFNode* if_true = nullptr;
    TFNode* if_false = nullptr;
203
    BUILD(BranchNoHint, cond.node, &if_true, &if_false);
204
    SsaEnv* end_env = ssa_env_;
205
    SsaEnv* false_env = Split(decoder->zone(), ssa_env_);
206 207 208 209 210 211 212 213 214 215 216 217 218 219
    false_env->control = if_false;
    SsaEnv* true_env = Steal(decoder->zone(), ssa_env_);
    true_env->control = if_true;
    if_block->end_env = end_env;
    if_block->false_env = false_env;
    SetEnv(true_env);
  }

  void FallThruTo(FullDecoder* decoder, Control* c) {
    DCHECK(!c->is_loop());
    MergeValuesInto(decoder, c, &c->end_merge);
  }

  void PopControl(FullDecoder* decoder, Control* block) {
220 221 222 223
    // A loop just continues with the end environment. There is no merge.
    if (block->is_loop()) return;
    // Any other block falls through to the parent block.
    if (block->reachable()) FallThruTo(decoder, block);
224 225 226
    if (block->is_onearmed_if()) {
      // Merge the else branch into the end merge.
      SetEnv(block->false_env);
227 228 229 230
      DCHECK_EQ(block->start_merge.arity, block->end_merge.arity);
      Value* values =
          block->start_merge.arity > 0 ? &block->start_merge[0] : nullptr;
      MergeValuesInto(decoder, block, &block->end_merge, values);
231
    }
232 233
    // Now continue with the merged environment.
    SetEnv(block->end_env);
234 235 236 237
  }

  void EndControl(FullDecoder* decoder, Control* block) { ssa_env_->Kill(); }

238 239
  void UnOp(FullDecoder* decoder, WasmOpcode opcode, const Value& value,
            Value* result) {
240 241 242
    result->node = BUILD(Unop, opcode, value.node, decoder->position());
  }

243 244
  void BinOp(FullDecoder* decoder, WasmOpcode opcode, const Value& lhs,
             const Value& rhs, Value* result) {
245 246
    TFNode* node =
        BUILD(Binop, opcode, lhs.node, rhs.node, decoder->position());
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    if (result) result->node = node;
  }

  void I32Const(FullDecoder* decoder, Value* result, int32_t value) {
    result->node = builder_->Int32Constant(value);
  }

  void I64Const(FullDecoder* decoder, Value* result, int64_t value) {
    result->node = builder_->Int64Constant(value);
  }

  void F32Const(FullDecoder* decoder, Value* result, float value) {
    result->node = builder_->Float32Constant(value);
  }

  void F64Const(FullDecoder* decoder, Value* result, double value) {
    result->node = builder_->Float64Constant(value);
  }

266 267 268 269 270
  void S128Const(FullDecoder* decoder, const Simd128Immediate<validate>& imm,
                 Value* result) {
    result->node = builder_->Simd128Constant(imm.value);
  }

271
  void RefNull(FullDecoder* decoder, ValueType type, Value* result) {
272 273 274
    result->node = builder_->RefNull();
  }

275 276 277 278
  void RefFunc(FullDecoder* decoder, uint32_t function_index, Value* result) {
    result->node = BUILD(RefFunc, function_index);
  }

279 280 281 282
  void RefAsNonNull(FullDecoder* decoder, const Value& arg, Value* result) {
    result->node = BUILD(RefAsNonNull, arg.node, decoder->position());
  }

283 284
  void Drop(FullDecoder* decoder, const Value& value) {}

285
  void DoReturn(FullDecoder* decoder, Vector<Value> values) {
286 287
    base::SmallVector<TFNode*, 8> nodes(values.size());
    GetNodes(nodes.begin(), values);
288 289 290
    if (FLAG_trace_wasm) {
      BUILD(TraceFunctionExit, VectorOf(nodes), decoder->position());
    }
291
    BUILD(Return, VectorOf(nodes));
292 293
  }

294
  void LocalGet(FullDecoder* decoder, Value* result,
295 296 297 298
                const LocalIndexImmediate<validate>& imm) {
    result->node = ssa_env_->locals[imm.index];
  }

299
  void LocalSet(FullDecoder* decoder, const Value& value,
300 301 302 303
                const LocalIndexImmediate<validate>& imm) {
    ssa_env_->locals[imm.index] = value.node;
  }

304
  void LocalTee(FullDecoder* decoder, const Value& value, Value* result,
305 306 307 308 309
                const LocalIndexImmediate<validate>& imm) {
    result->node = value.node;
    ssa_env_->locals[imm.index] = value.node;
  }

310 311 312 313 314 315 316 317 318 319 320 321 322
  void AllocateLocals(FullDecoder* decoder, Vector<Value> local_values) {
    ZoneVector<TFNode*>* locals = &ssa_env_->locals;
    locals->insert(locals->begin(), local_values.size(), nullptr);
    for (uint32_t i = 0; i < local_values.size(); i++) {
      (*locals)[i] = local_values[i].node;
    }
  }

  void DeallocateLocals(FullDecoder* decoder, uint32_t count) {
    ZoneVector<TFNode*>* locals = &ssa_env_->locals;
    locals->erase(locals->begin(), locals->begin() + count);
  }

323
  void GlobalGet(FullDecoder* decoder, Value* result,
324
                 const GlobalIndexImmediate<validate>& imm) {
325
    result->node = BUILD(GlobalGet, imm.index);
326 327
  }

328
  void GlobalSet(FullDecoder* decoder, const Value& value,
329
                 const GlobalIndexImmediate<validate>& imm) {
330
    BUILD(GlobalSet, imm.index, value.node);
331 332
  }

333
  void TableGet(FullDecoder* decoder, const Value& index, Value* result,
334
                const TableIndexImmediate<validate>& imm) {
335
    result->node = BUILD(TableGet, imm.index, index.node, decoder->position());
336 337
  }

338
  void TableSet(FullDecoder* decoder, const Value& index, const Value& value,
339
                const TableIndexImmediate<validate>& imm) {
340
    BUILD(TableSet, imm.index, index.node, value.node, decoder->position());
341 342
  }

343
  void Unreachable(FullDecoder* decoder) {
344
    BUILD(Trap, wasm::TrapReason::kTrapUnreachable, decoder->position());
345 346 347 348 349 350 351
  }

  void Select(FullDecoder* decoder, const Value& cond, const Value& fval,
              const Value& tval, Value* result) {
    TFNode* controls[2];
    BUILD(BranchNoHint, cond.node, &controls[0], &controls[1]);
    TFNode* merge = BUILD(Merge, 2, controls);
352 353
    TFNode* inputs[] = {tval.node, fval.node, merge};
    TFNode* phi = BUILD(Phi, tval.type, 2, inputs);
354
    result->node = phi;
355
    builder_->SetControl(merge);
356 357
  }

358 359 360
  void BrOrRet(FullDecoder* decoder, uint32_t depth) {
    if (depth == decoder->control_depth() - 1) {
      uint32_t ret_count = static_cast<uint32_t>(decoder->sig_->return_count());
361 362 363 364
      base::SmallVector<TFNode*, 8> values(ret_count);
      if (ret_count > 0) {
        GetNodes(values.begin(), decoder->stack_value(ret_count), ret_count);
      }
365 366 367
      if (FLAG_trace_wasm) {
        BUILD(TraceFunctionExit, VectorOf(values), decoder->position());
      }
368
      BUILD(Return, VectorOf(values));
369
    } else {
370 371
      Control* target = decoder->control_at(depth);
      MergeValuesInto(decoder, target, target->br_merge());
372 373 374 375
    }
  }

  void BrIf(FullDecoder* decoder, const Value& cond, uint32_t depth) {
376
    SsaEnv* fenv = ssa_env_;
377
    SsaEnv* tenv = Split(decoder->zone(), fenv);
378 379
    fenv->SetNotMerged();
    BUILD(BranchNoHint, cond.node, &tenv->control, &fenv->control);
380
    builder_->SetControl(fenv->control);
381 382 383
    SetEnv(tenv);
    BrOrRet(decoder, depth);
    SetEnv(fenv);
384 385 386 387 388 389 390
  }

  void BrTable(FullDecoder* decoder, const BranchTableImmediate<validate>& imm,
               const Value& key) {
    if (imm.table_count == 0) {
      // Only a default target. Do the equivalent of br.
      uint32_t target = BranchTableIterator<validate>(decoder, imm).next();
391
      BrOrRet(decoder, target);
392 393 394
      return;
    }

395
    SsaEnv* branch_env = ssa_env_;
396 397 398
    // Build branches to the various blocks based on the table.
    TFNode* sw = BUILD(Switch, imm.table_count + 1, key.node);

399
    SsaEnv* copy = Steal(decoder->zone(), branch_env);
400
    SetEnv(copy);
401 402 403 404
    BranchTableIterator<validate> iterator(decoder, imm);
    while (iterator.has_next()) {
      uint32_t i = iterator.cur_index();
      uint32_t target = iterator.next();
405
      SetEnv(Split(decoder->zone(), copy));
406 407
      builder_->SetControl(i == imm.table_count ? BUILD(IfDefault, sw)
                                                : BUILD(IfValue, i, sw));
408
      BrOrRet(decoder, target);
409 410
    }
    DCHECK(decoder->ok());
411
    SetEnv(branch_env);
412 413 414
  }

  void Else(FullDecoder* decoder, Control* if_block) {
415 416 417 418
    if (if_block->reachable()) {
      // Merge the if branch into the end merge.
      MergeValuesInto(decoder, if_block, &if_block->end_merge);
    }
419 420 421
    SetEnv(if_block->false_env);
  }

422 423 424 425 426 427
  void Prefetch(FullDecoder* decoder,
                const MemoryAccessImmediate<validate>& imm, const Value& index,
                bool temporal) {
    BUILD(Prefetch, index.node, imm.offset, imm.alignment, temporal);
  }

428 429 430 431 432 433 434 435
  void LoadMem(FullDecoder* decoder, LoadType type,
               const MemoryAccessImmediate<validate>& imm, const Value& index,
               Value* result) {
    result->node =
        BUILD(LoadMem, type.value_type(), type.mem_type(), index.node,
              imm.offset, imm.alignment, decoder->position());
  }

436 437 438 439
  void LoadTransform(FullDecoder* decoder, LoadType type,
                     LoadTransformationKind transform,
                     const MemoryAccessImmediate<validate>& imm,
                     const Value& index, Value* result) {
440 441 442
    result->node =
        BUILD(LoadTransform, type.value_type(), type.mem_type(), transform,
              index.node, imm.offset, imm.alignment, decoder->position());
443 444
  }

445 446 447 448 449 450 451
  void LoadLane(FullDecoder* decoder, LoadType type, const Value& value,
                const Value& index, const MemoryAccessImmediate<validate>& imm,
                const uint8_t laneidx, Value* result) {
    result->node = BUILD(LoadLane, type.mem_type(), value.node, index.node,
                         imm.offset, laneidx, decoder->position());
  }

452 453 454 455 456 457 458
  void StoreMem(FullDecoder* decoder, StoreType type,
                const MemoryAccessImmediate<validate>& imm, const Value& index,
                const Value& value) {
    BUILD(StoreMem, type.mem_rep(), index.node, imm.offset, imm.alignment,
          value.node, decoder->position(), type.value_type());
  }

459 460 461 462 463 464 465
  void StoreLane(FullDecoder* decoder, StoreType type,
                 const MemoryAccessImmediate<validate>& imm, const Value& index,
                 const Value& value, const uint8_t laneidx) {
    BUILD(StoreLane, type.mem_rep(), index.node, imm.offset, imm.alignment,
          value.node, laneidx, decoder->position(), type.value_type());
  }

466 467 468 469
  void CurrentMemoryPages(FullDecoder* decoder, Value* result) {
    result->node = BUILD(CurrentMemoryPages);
  }

470 471
  void MemoryGrow(FullDecoder* decoder, const Value& value, Value* result) {
    result->node = BUILD(MemoryGrow, value.node);
472 473 474 475
    // Always reload the instance cache after growing memory.
    LoadContextIntoSsa(ssa_env_);
  }

476 477
  enum CallMode { kDirect, kIndirect, kRef };

478 479 480
  void CallDirect(FullDecoder* decoder,
                  const CallFunctionImmediate<validate>& imm,
                  const Value args[], Value returns[]) {
481 482
    DoCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
           imm.sig, imm.index, args, returns);
483 484
  }

485 486 487
  void ReturnCall(FullDecoder* decoder,
                  const CallFunctionImmediate<validate>& imm,
                  const Value args[]) {
488 489
    DoReturnCall(decoder, kDirect, 0, CheckForNull::kWithoutNullCheck, nullptr,
                 imm.sig, imm.index, args);
490 491
  }

492 493 494
  void CallIndirect(FullDecoder* decoder, const Value& index,
                    const CallIndirectImmediate<validate>& imm,
                    const Value args[], Value returns[]) {
495 496
    DoCall(decoder, kIndirect, imm.table_index, CheckForNull::kWithoutNullCheck,
           index.node, imm.sig, imm.sig_index, args, returns);
497 498
  }

499 500 501
  void ReturnCallIndirect(FullDecoder* decoder, const Value& index,
                          const CallIndirectImmediate<validate>& imm,
                          const Value args[]) {
502 503 504
    DoReturnCall(decoder, kIndirect, imm.table_index,
                 CheckForNull::kWithoutNullCheck, index.node, imm.sig,
                 imm.sig_index, args);
505 506
  }

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
  void CallRef(FullDecoder* decoder, const Value& func_ref,
               const FunctionSig* sig, uint32_t sig_index, const Value args[],
               Value returns[]) {
    CheckForNull null_check = func_ref.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
    DoCall(decoder, kRef, 0, null_check, func_ref.node, sig, sig_index, args,
           returns);
  }

  void ReturnCallRef(FullDecoder* decoder, const Value& func_ref,
                     const FunctionSig* sig, uint32_t sig_index,
                     const Value args[]) {
    CheckForNull null_check = func_ref.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
    DoReturnCall(decoder, kRef, 0, null_check, func_ref.node, sig, sig_index,
                 args);
  }

527 528
  void BrOnNull(FullDecoder* decoder, const Value& ref_object, uint32_t depth) {
    SsaEnv* non_null_env = ssa_env_;
529
    SsaEnv* null_env = Split(decoder->zone(), non_null_env);
530 531 532 533 534 535 536 537 538
    non_null_env->SetNotMerged();
    BUILD(BrOnNull, ref_object.node, &null_env->control,
          &non_null_env->control);
    builder_->SetControl(non_null_env->control);
    SetEnv(null_env);
    BrOrRet(decoder, depth);
    SetEnv(non_null_env);
  }

539 540
  void SimdOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
              Value* result) {
541 542
    base::SmallVector<TFNode*, 8> inputs(args.size());
    GetNodes(inputs.begin(), args);
543
    TFNode* node = BUILD(SimdOp, opcode, inputs.begin());
544 545 546 547
    if (result) result->node = node;
  }

  void SimdLaneOp(FullDecoder* decoder, WasmOpcode opcode,
548
                  const SimdLaneImmediate<validate>& imm, Vector<Value> inputs,
549
                  Value* result) {
550 551
    base::SmallVector<TFNode*, 8> nodes(inputs.size());
    GetNodes(nodes.begin(), inputs);
552
    result->node = BUILD(SimdLaneOp, opcode, imm.lane, nodes.begin());
553 554 555
  }

  void Simd8x16ShuffleOp(FullDecoder* decoder,
556
                         const Simd128Immediate<validate>& imm,
557 558 559
                         const Value& input0, const Value& input1,
                         Value* result) {
    TFNode* input_nodes[] = {input0.node, input1.node};
560
    result->node = BUILD(Simd8x16ShuffleOp, imm.value, input_nodes);
561 562 563 564 565 566 567 568 569
  }

  void Throw(FullDecoder* decoder, const ExceptionIndexImmediate<validate>& imm,
             const Vector<Value>& value_args) {
    int count = value_args.length();
    ZoneVector<TFNode*> args(count, decoder->zone());
    for (int i = 0; i < count; ++i) {
      args[i] = value_args[i].node;
    }
570
    BUILD(Throw, imm.index, imm.exception, VectorOf(args), decoder->position());
571
    builder_->TerminateThrow(effect(), control());
572 573
  }

574 575
  void Rethrow(FullDecoder* decoder, const Value& exception) {
    BUILD(Rethrow, exception.node);
576
    builder_->TerminateThrow(effect(), control());
577 578
  }

579 580 581 582 583
  void BrOnException(FullDecoder* decoder, const Value& exception,
                     const ExceptionIndexImmediate<validate>& imm,
                     uint32_t depth, Vector<Value> values) {
    TFNode* if_match = nullptr;
    TFNode* if_no_match = nullptr;
584 585

    // Get the exception tag and see if it matches the expected one.
586 587
    TFNode* caught_tag =
        BUILD(GetExceptionTag, exception.node, decoder->position());
588 589
    TFNode* exception_tag = BUILD(LoadExceptionTagFromTable, imm.index);
    TFNode* compare = BUILD(ExceptionTagEqual, caught_tag, exception_tag);
590
    BUILD(BranchNoHint, compare, &if_match, &if_no_match);
591
    SsaEnv* if_no_match_env = Split(decoder->zone(), ssa_env_);
592 593 594
    SsaEnv* if_match_env = Steal(decoder->zone(), ssa_env_);
    if_no_match_env->control = if_no_match;
    if_match_env->control = if_match;
595 596 597

    // If the tags match we extract the values from the exception object and
    // push them onto the operand stack using the passed {values} vector.
598
    SetEnv(if_match_env);
599 600 601
    base::SmallVector<TFNode*, 8> caught_values(values.size());
    Vector<TFNode*> caught_vector = VectorOf(caught_values);
    BUILD(GetExceptionValues, exception.node, imm.exception, caught_vector);
602
    for (size_t i = 0, e = values.size(); i < e; ++i) {
603
      values[i].node = caught_vector[i];
604
    }
605 606 607 608
    BrOrRet(decoder, depth);

    // If the tags don't match we fall-through here.
    SetEnv(if_no_match_env);
609 610
  }

611 612
  void Catch(FullDecoder* decoder, Control* block, Value* exception) {
    DCHECK(block->is_try_catch());
613
    DCHECK_EQ(decoder->control_at(0), block);
614

615 616 617 618 619
    current_catch_ = block->previous_catch;  // Pop try scope.

    // The catch block is unreachable if no possible throws in the try block
    // exist. We only build a landing pad if some node in the try block can
    // (possibly) throw. Otherwise the catch environments remain empty.
620
    if (!block->try_info->might_throw()) {
621
      decoder->SetSucceedingCodeDynamicallyUnreachable();
622 623
      return;
    }
624 625

    SetEnv(block->try_info->catch_env);
626 627
    DCHECK_NOT_NULL(block->try_info->exception);
    exception->node = block->try_info->exception;
628 629 630 631
  }

  void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, Vector<Value> args,
                const MemoryAccessImmediate<validate>& imm, Value* result) {
632 633
    base::SmallVector<TFNode*, 8> inputs(args.size());
    GetNodes(inputs.begin(), args);
634 635
    TFNode* node = BUILD(AtomicOp, opcode, inputs.begin(), imm.alignment,
                         imm.offset, decoder->position());
636 637 638
    if (result) result->node = node;
  }

639 640
  void AtomicFence(FullDecoder* decoder) { BUILD(AtomicFence); }

641
  void MemoryInit(FullDecoder* decoder,
642 643 644 645
                  const MemoryInitImmediate<validate>& imm, const Value& dst,
                  const Value& src, const Value& size) {
    BUILD(MemoryInit, imm.data_segment_index, dst.node, src.node, size.node,
          decoder->position());
646
  }
647

648 649
  void DataDrop(FullDecoder* decoder, const DataDropImmediate<validate>& imm) {
    BUILD(DataDrop, imm.index, decoder->position());
650
  }
651

652
  void MemoryCopy(FullDecoder* decoder,
653
                  const MemoryCopyImmediate<validate>& imm, const Value& dst,
654 655
                  const Value& src, const Value& size) {
    BUILD(MemoryCopy, dst.node, src.node, size.node, decoder->position());
656
  }
657

658
  void MemoryFill(FullDecoder* decoder,
659 660 661
                  const MemoryIndexImmediate<validate>& imm, const Value& dst,
                  const Value& value, const Value& size) {
    BUILD(MemoryFill, dst.node, value.node, size.node, decoder->position());
662
  }
663

664 665
  void TableInit(FullDecoder* decoder, const TableInitImmediate<validate>& imm,
                 Vector<Value> args) {
666 667
    BUILD(TableInit, imm.table.index, imm.elem_segment_index, args[0].node,
          args[1].node, args[2].node, decoder->position());
668
  }
669

670 671
  void ElemDrop(FullDecoder* decoder, const ElemDropImmediate<validate>& imm) {
    BUILD(ElemDrop, imm.index, decoder->position());
672
  }
673

674
  void TableCopy(FullDecoder* decoder, const TableCopyImmediate<validate>& imm,
675
                 Vector<Value> args) {
676
    BUILD(TableCopy, imm.table_dst.index, imm.table_src.index, args[0].node,
677
          args[1].node, args[2].node, decoder->position());
678 679
  }

680
  void TableGrow(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
681
                 const Value& value, const Value& delta, Value* result) {
682 683 684
    result->node = BUILD(TableGrow, imm.index, value.node, delta.node);
  }

685 686 687 688 689
  void TableSize(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
                 Value* result) {
    result->node = BUILD(TableSize, imm.index);
  }

690
  void TableFill(FullDecoder* decoder, const TableIndexImmediate<validate>& imm,
691
                 const Value& start, const Value& value, const Value& count) {
692 693 694
    BUILD(TableFill, imm.index, start.node, value.node, count.node);
  }

695 696 697 698 699 700 701 702 703 704 705
  void StructNewWithRtt(FullDecoder* decoder,
                        const StructIndexImmediate<validate>& imm,
                        const Value& rtt, const Value args[], Value* result) {
    uint32_t field_count = imm.struct_type->field_count();
    base::SmallVector<TFNode*, 16> arg_nodes(field_count);
    for (uint32_t i = 0; i < field_count; i++) {
      arg_nodes[i] = args[i].node;
    }
    result->node = BUILD(StructNewWithRtt, imm.index, imm.struct_type, rtt.node,
                         VectorOf(arg_nodes));
  }
706 707 708 709 710 711 712 713 714 715 716
  void StructNewDefault(FullDecoder* decoder,
                        const StructIndexImmediate<validate>& imm,
                        const Value& rtt, Value* result) {
    uint32_t field_count = imm.struct_type->field_count();
    base::SmallVector<TFNode*, 16> arg_nodes(field_count);
    for (uint32_t i = 0; i < field_count; i++) {
      arg_nodes[i] = DefaultValue(imm.struct_type->field(i));
    }
    result->node = BUILD(StructNewWithRtt, imm.index, imm.struct_type, rtt.node,
                         VectorOf(arg_nodes));
  }
717

718
  void StructGet(FullDecoder* decoder, const Value& struct_object,
719 720
                 const FieldIndexImmediate<validate>& field, bool is_signed,
                 Value* result) {
721 722 723
    CheckForNull null_check = struct_object.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
724 725
    result->node =
        BUILD(StructGet, struct_object.node, field.struct_index.struct_type,
726
              field.index, null_check, is_signed, decoder->position());
727 728 729 730 731
  }

  void StructSet(FullDecoder* decoder, const Value& struct_object,
                 const FieldIndexImmediate<validate>& field,
                 const Value& field_value) {
732 733 734
    CheckForNull null_check = struct_object.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
735
    BUILD(StructSet, struct_object.node, field.struct_index.struct_type,
736
          field.index, field_value.node, null_check, decoder->position());
737 738
  }

739 740 741 742
  void ArrayNewWithRtt(FullDecoder* decoder,
                       const ArrayIndexImmediate<validate>& imm,
                       const Value& length, const Value& initial_value,
                       const Value& rtt, Value* result) {
743 744 745
    result->node =
        BUILD(ArrayNewWithRtt, imm.index, imm.array_type, length.node,
              initial_value.node, rtt.node, decoder->position());
746 747
  }

748 749 750 751
  void ArrayNewDefault(FullDecoder* decoder,
                       const ArrayIndexImmediate<validate>& imm,
                       const Value& length, const Value& rtt, Value* result) {
    TFNode* initial_value = DefaultValue(imm.array_type->element_type());
752 753 754
    result->node =
        BUILD(ArrayNewWithRtt, imm.index, imm.array_type, length.node,
              initial_value, rtt.node, decoder->position());
755 756
  }

757 758
  void ArrayGet(FullDecoder* decoder, const Value& array_obj,
                const ArrayIndexImmediate<validate>& imm, const Value& index,
759
                bool is_signed, Value* result) {
760 761 762
    CheckForNull null_check = array_obj.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
763
    result->node = BUILD(ArrayGet, array_obj.node, imm.array_type, index.node,
764
                         null_check, is_signed, decoder->position());
765 766 767 768 769
  }

  void ArraySet(FullDecoder* decoder, const Value& array_obj,
                const ArrayIndexImmediate<validate>& imm, const Value& index,
                const Value& value) {
770 771 772
    CheckForNull null_check = array_obj.type.is_nullable()
                                  ? CheckForNull::kWithNullCheck
                                  : CheckForNull::kWithoutNullCheck;
773
    BUILD(ArraySet, array_obj.node, imm.array_type, index.node, value.node,
774
          null_check, decoder->position());
775 776
  }

777 778 779 780
  void ArrayLen(FullDecoder* decoder, const Value& array_obj, Value* result) {
    result->node = BUILD(ArrayLen, array_obj.node, decoder->position());
  }

781 782 783 784 785 786 787 788 789 790 791 792
  void I31New(FullDecoder* decoder, const Value& input, Value* result) {
    result->node = BUILD(I31New, input.node);
  }

  void I31GetS(FullDecoder* decoder, const Value& input, Value* result) {
    result->node = BUILD(I31GetS, input.node);
  }

  void I31GetU(FullDecoder* decoder, const Value& input, Value* result) {
    result->node = BUILD(I31GetU, input.node);
  }

793
  void RttCanon(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
794
                Value* result) {
795
    result->node = BUILD(RttCanon, imm.type);
796 797
  }

798 799 800 801 802
  void RttSub(FullDecoder* decoder, const HeapTypeImmediate<validate>& imm,
              const Value& parent, Value* result) {
    result->node = BUILD(RttSub, imm.type, parent.node);
  }

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
  using StaticKnowledge = compiler::WasmGraphBuilder::ObjectReferenceKnowledge;

  StaticKnowledge ComputeStaticKnowledge(ValueType object_type,
                                         ValueType rtt_type,
                                         const WasmModule* module) {
    StaticKnowledge result;
    result.object_can_be_null = object_type.is_nullable();
    result.object_must_be_data_ref = false;
    DCHECK(object_type.is_object_reference_type());  // Checked by validation.
    if (object_type.has_index()) {
      uint32_t reftype = object_type.ref_index();
      // TODO(7748): When we implement dataref (=any struct or array), add it
      // to this list.
      if (module->has_struct(reftype) || module->has_array(reftype)) {
        result.object_must_be_data_ref = true;
      }
    }
    result.object_can_be_i31 = IsSubtypeOf(kWasmI31Ref, object_type, module);
    result.rtt_is_i31 = rtt_type.heap_representation() == HeapType::kI31;
    result.rtt_depth = rtt_type.depth();
    return result;
  }

826 827
  void RefTest(FullDecoder* decoder, const Value& object, const Value& rtt,
               Value* result) {
828 829 830
    StaticKnowledge config =
        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
    result->node = BUILD(RefTest, object.node, rtt.node, config);
831 832 833 834
  }

  void RefCast(FullDecoder* decoder, const Value& object, const Value& rtt,
               Value* result) {
835 836 837 838
    StaticKnowledge config =
        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
    result->node =
        BUILD(RefCast, object.node, rtt.node, config, decoder->position());
839 840
  }

841
  void BrOnCast(FullDecoder* decoder, const Value& object, const Value& rtt,
842
                Value* value_on_branch, uint32_t br_depth) {
843 844
    StaticKnowledge config =
        ComputeStaticKnowledge(object.type, rtt.type, decoder->module_);
845 846 847
    SsaEnv* match_env = Split(decoder->zone(), ssa_env_);
    SsaEnv* no_match_env = Steal(decoder->zone(), ssa_env_);
    no_match_env->SetNotMerged();
848 849
    BUILD(BrOnCast, object.node, rtt.node, config, &match_env->control,
          &match_env->effect, &no_match_env->control, &no_match_env->effect);
850 851 852
    builder_->SetControl(no_match_env->control);
    SetEnv(match_env);
    value_on_branch->node = object.node;
853
    BrOrRet(decoder, br_depth);
854 855 856
    SetEnv(no_match_env);
  }

857 858 859 860
  void PassThrough(FullDecoder* decoder, const Value& from, Value* to) {
    to->node = from.node;
  }

861
 private:
862
  SsaEnv* ssa_env_ = nullptr;
863 864 865
  compiler::WasmGraphBuilder* builder_;
  uint32_t current_catch_ = kNullCatch;

866
  TFNode* effect() { return builder_->effect(); }
867

868
  TFNode* control() { return builder_->control(); }
869

870 871 872 873 874
  TryInfo* current_try_info(FullDecoder* decoder) {
    return decoder->control_at(decoder->control_depth() - 1 - current_catch_)
        ->try_info;
  }

875
  void GetNodes(TFNode** nodes, Value* values, size_t count) {
876 877 878 879 880
    for (size_t i = 0; i < count; ++i) {
      nodes[i] = values[i].node;
    }
  }

881 882
  void GetNodes(TFNode** nodes, Vector<Value> values) {
    GetNodes(nodes, values.begin(), values.size());
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
  }

  void SetEnv(SsaEnv* env) {
    if (FLAG_trace_wasm_decoder) {
      char state = 'X';
      if (env) {
        switch (env->state) {
          case SsaEnv::kReached:
            state = 'R';
            break;
          case SsaEnv::kUnreachable:
            state = 'U';
            break;
          case SsaEnv::kMerged:
            state = 'M';
            break;
          case SsaEnv::kControlEnd:
            state = 'E';
            break;
        }
      }
904
      PrintF("{set_env = %p, state = %c", env, state);
905 906 907 908 909 910
      if (env && env->control) {
        PrintF(", control = ");
        compiler::WasmGraphBuilder::PrintDebugName(env->control);
      }
      PrintF("}\n");
    }
911 912 913 914
    if (ssa_env_) {
      ssa_env_->control = control();
      ssa_env_->effect = effect();
    }
915
    ssa_env_ = env;
916
    builder_->SetEffectControl(env->effect, env->control);
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
    builder_->set_instance_cache(&env->instance_cache);
  }

  TFNode* CheckForException(FullDecoder* decoder, TFNode* node) {
    if (node == nullptr) return nullptr;

    const bool inside_try_scope = current_catch_ != kNullCatch;

    if (!inside_try_scope) return node;

    TFNode* if_success = nullptr;
    TFNode* if_exception = nullptr;
    if (!builder_->ThrowsException(node, &if_success, &if_exception)) {
      return node;
    }

    SsaEnv* success_env = Steal(decoder->zone(), ssa_env_);
    success_env->control = if_success;

936
    SsaEnv* exception_env = Split(decoder->zone(), success_env);
937
    exception_env->control = if_exception;
938
    exception_env->effect = if_exception;
939
    SetEnv(exception_env);
940
    TryInfo* try_info = current_try_info(decoder);
941
    Goto(decoder, try_info->catch_env);
942
    if (try_info->exception == nullptr) {
943 944 945 946 947 948 949 950 951 952 953 954 955 956
      DCHECK_EQ(SsaEnv::kReached, try_info->catch_env->state);
      try_info->exception = if_exception;
    } else {
      DCHECK_EQ(SsaEnv::kMerged, try_info->catch_env->state);
      try_info->exception = builder_->CreateOrMergeIntoPhi(
          MachineRepresentation::kWord32, try_info->catch_env->control,
          try_info->exception, if_exception);
    }

    SetEnv(success_env);
    return node;
  }

  TFNode* DefaultValue(ValueType type) {
957
    DCHECK(type.is_defaultable());
958
    switch (type.kind()) {
959 960
      case ValueType::kI8:
      case ValueType::kI16:
961
      case ValueType::kI32:
962
        return builder_->Int32Constant(0);
963
      case ValueType::kI64:
964
        return builder_->Int64Constant(0);
965
      case ValueType::kF32:
966
        return builder_->Float32Constant(0);
967
      case ValueType::kF64:
968
        return builder_->Float64Constant(0);
969
      case ValueType::kS128:
970
        return builder_->S128Zero();
971
      case ValueType::kOptRef:
972
        return builder_->RefNull();
973
      case ValueType::kRtt:
974 975 976
      case ValueType::kStmt:
      case ValueType::kBottom:
      case ValueType::kRef:
977 978 979 980
        UNREACHABLE();
    }
  }

981 982
  void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge,
                       Value* values) {
983 984 985 986
    DCHECK(merge == &c->start_merge || merge == &c->end_merge);

    SsaEnv* target = c->end_env;
    const bool first = target->state == SsaEnv::kUnreachable;
987
    Goto(decoder, target);
988

989 990
    if (merge->arity == 0) return;

991 992
    for (uint32_t i = 0; i < merge->arity; ++i) {
      Value& val = values[i];
993
      Value& old = (*merge)[i];
994
      DCHECK_NOT_NULL(val.node);
995 996
      DCHECK(val.type == kWasmBottom || val.type.machine_representation() ==
                                            old.type.machine_representation());
997 998
      old.node = first ? val.node
                       : builder_->CreateOrMergeIntoPhi(
999 1000
                             old.type.machine_representation(), target->control,
                             old.node, val.node);
1001 1002 1003
    }
  }

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
  void MergeValuesInto(FullDecoder* decoder, Control* c, Merge<Value>* merge) {
#ifdef DEBUG
    uint32_t avail =
        decoder->stack_size() - decoder->control_at(0)->stack_depth;
    DCHECK_GE(avail, merge->arity);
#endif
    Value* stack_values =
        merge->arity > 0 ? decoder->stack_value(merge->arity) : nullptr;
    MergeValuesInto(decoder, c, merge, stack_values);
  }

1015
  void Goto(FullDecoder* decoder, SsaEnv* to) {
1016 1017 1018 1019
    DCHECK_NOT_NULL(to);
    switch (to->state) {
      case SsaEnv::kUnreachable: {  // Overwrite destination.
        to->state = SsaEnv::kReached;
1020 1021 1022 1023
        to->locals = ssa_env_->locals;
        to->control = control();
        to->effect = effect();
        to->instance_cache = ssa_env_->instance_cache;
1024 1025 1026 1027 1028
        break;
      }
      case SsaEnv::kReached: {  // Create a new merge.
        to->state = SsaEnv::kMerged;
        // Merge control.
1029
        TFNode* controls[] = {to->control, control()};
1030 1031 1032
        TFNode* merge = builder_->Merge(2, controls);
        to->control = merge;
        // Merge effects.
1033 1034 1035
        TFNode* old_effect = effect();
        if (old_effect != to->effect) {
          TFNode* inputs[] = {to->effect, old_effect, merge};
1036
          to->effect = builder_->EffectPhi(2, inputs);
1037 1038
        }
        // Merge SSA values.
1039
        for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1040
          TFNode* a = to->locals[i];
1041
          TFNode* b = ssa_env_->locals[i];
1042
          if (a != b) {
1043
            TFNode* inputs[] = {a, b, merge};
1044
            to->locals[i] = builder_->Phi(decoder->local_type(i), 2, inputs);
1045 1046 1047 1048
          }
        }
        // Start a new merge from the instance cache.
        builder_->NewInstanceCacheMerge(&to->instance_cache,
1049
                                        &ssa_env_->instance_cache, merge);
1050 1051 1052 1053 1054
        break;
      }
      case SsaEnv::kMerged: {
        TFNode* merge = to->control;
        // Extend the existing merge control node.
1055
        builder_->AppendToMerge(merge, control());
1056
        // Merge effects.
1057 1058
        to->effect =
            builder_->CreateOrMergeIntoEffectPhi(merge, to->effect, effect());
1059
        // Merge locals.
1060
        for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1061
          to->locals[i] = builder_->CreateOrMergeIntoPhi(
1062
              decoder->local_type(i).machine_representation(), merge,
1063
              to->locals[i], ssa_env_->locals[i]);
1064 1065 1066
        }
        // Merge the instance caches.
        builder_->MergeInstanceCacheInto(&to->instance_cache,
1067
                                         &ssa_env_->instance_cache, merge);
1068 1069 1070 1071 1072
        break;
      }
      default:
        UNREACHABLE();
    }
1073
    return ssa_env_->Kill();
1074 1075
  }

1076 1077
  void PrepareForLoop(FullDecoder* decoder) {
    ssa_env_->state = SsaEnv::kMerged;
1078

1079 1080 1081 1082
    builder_->SetControl(builder_->Loop(control()));
    TFNode* effect_inputs[] = {effect(), control()};
    builder_->SetEffect(builder_->EffectPhi(1, effect_inputs));
    builder_->TerminateLoop(effect(), control());
1083
    BitVector* assigned = WasmDecoder<validate>::AnalyzeLoopAssignment(
1084
        decoder, decoder->pc(), decoder->num_locals(), decoder->zone());
1085
    if (decoder->failed()) return;
1086
    DCHECK_NOT_NULL(assigned);
1087

1088 1089
    // Only introduce phis for variables assigned in this loop.
    int instance_cache_index = decoder->num_locals();
1090
    for (int i = decoder->num_locals() - 1; i >= 0; i--) {
1091
      if (!assigned->Contains(i)) continue;
1092
      TFNode* inputs[] = {ssa_env_->locals[i], control()};
1093
      ssa_env_->locals[i] = builder_->Phi(decoder->local_type(i), 1, inputs);
1094
    }
1095 1096 1097 1098 1099
    // Introduce phis for instance cache pointers if necessary.
    if (assigned->Contains(instance_cache_index)) {
      builder_->PrepareInstanceCacheForLoop(&ssa_env_->instance_cache,
                                            control());
    }
1100

1101
    SetEnv(Split(decoder->zone(), ssa_env_));
1102
    builder_->StackCheck(decoder->position());
1103 1104 1105
  }

  // Create a complete copy of {from}.
1106
  SsaEnv* Split(Zone* zone, SsaEnv* from) {
1107
    DCHECK_NOT_NULL(from);
1108 1109 1110 1111
    if (from == ssa_env_) {
      ssa_env_->control = control();
      ssa_env_->effect = effect();
    }
1112
    SsaEnv* result = zone->New<SsaEnv>(*from);
1113
    result->state = SsaEnv::kReached;
1114 1115 1116 1117 1118 1119 1120
    return result;
  }

  // Create a copy of {from} that steals its state and leaves {from}
  // unreachable.
  SsaEnv* Steal(Zone* zone, SsaEnv* from) {
    DCHECK_NOT_NULL(from);
1121 1122 1123 1124
    if (from == ssa_env_) {
      ssa_env_->control = control();
      ssa_env_->effect = effect();
    }
1125
    SsaEnv* result = zone->New<SsaEnv>(std::move(*from));
1126 1127 1128 1129 1130 1131
    result->state = SsaEnv::kReached;
    return result;
  }

  // Create an unreachable environment.
  SsaEnv* UnreachableEnv(Zone* zone) {
1132
    return zone->New<SsaEnv>(zone, SsaEnv::kUnreachable, nullptr, nullptr, 0);
1133 1134
  }

1135 1136
  void DoCall(FullDecoder* decoder, CallMode call_mode, uint32_t table_index,
              CheckForNull null_check, TFNode* caller_node,
1137
              const FunctionSig* sig, uint32_t sig_index, const Value args[],
1138
              Value returns[]) {
1139 1140 1141 1142
    size_t param_count = sig->parameter_count();
    size_t return_count = sig->return_count();
    base::SmallVector<TFNode*, 16> arg_nodes(param_count + 1);
    base::SmallVector<TFNode*, 1> return_nodes(return_count);
1143
    arg_nodes[0] = caller_node;
1144
    for (size_t i = 0; i < param_count; ++i) {
1145 1146
      arg_nodes[i + 1] = args[i].node;
    }
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
    switch (call_mode) {
      case kIndirect:
        BUILD(CallIndirect, table_index, sig_index, VectorOf(arg_nodes),
              VectorOf(return_nodes), decoder->position());
        break;
      case kDirect:
        BUILD(CallDirect, sig_index, VectorOf(arg_nodes),
              VectorOf(return_nodes), decoder->position());
        break;
      case kRef:
1157 1158 1159
        BUILD(CallRef, sig_index, VectorOf(arg_nodes), VectorOf(return_nodes),
              null_check, decoder->position());
        break;
1160
    }
1161
    for (size_t i = 0; i < return_count; ++i) {
1162 1163 1164 1165 1166 1167
      returns[i].node = return_nodes[i];
    }
    // The invoked function could have used grow_memory, so we need to
    // reload mem_size and mem_start.
    LoadContextIntoSsa(ssa_env_);
  }
1168

1169 1170
  void DoReturnCall(FullDecoder* decoder, CallMode call_mode,
                    uint32_t table_index, CheckForNull null_check,
1171 1172
                    TFNode* index_node, const FunctionSig* sig,
                    uint32_t sig_index, const Value args[]) {
1173 1174
    size_t arg_count = sig->parameter_count();
    base::SmallVector<TFNode*, 16> arg_nodes(arg_count + 1);
1175
    arg_nodes[0] = index_node;
1176
    for (size_t i = 0; i < arg_count; ++i) {
1177 1178
      arg_nodes[i + 1] = args[i].node;
    }
1179 1180 1181 1182 1183 1184 1185 1186 1187
    switch (call_mode) {
      case kIndirect:
        BUILD(ReturnCallIndirect, table_index, sig_index, VectorOf(arg_nodes),
              decoder->position());
        break;
      case kDirect:
        BUILD(ReturnCall, sig_index, VectorOf(arg_nodes), decoder->position());
        break;
      case kRef:
1188 1189
        BUILD(ReturnCallRef, sig_index, VectorOf(arg_nodes), null_check,
              decoder->position());
1190 1191
    }
  }
1192 1193 1194 1195 1196
};

}  // namespace

DecodeResult BuildTFGraph(AccountingAllocator* allocator,
1197
                          const WasmFeatures& enabled, const WasmModule* module,
1198
                          compiler::WasmGraphBuilder* builder,
1199
                          WasmFeatures* detected, const FunctionBody& body,
1200 1201
                          compiler::NodeOriginTable* node_origins) {
  Zone zone(allocator, ZONE_NAME);
1202
  WasmFullDecoder<Decoder::kFullValidation, WasmGraphBuildingInterface> decoder(
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
      &zone, module, enabled, detected, body, builder);
  if (node_origins) {
    builder->AddBytecodePositionDecorator(node_origins, &decoder);
  }
  decoder.Decode();
  if (node_origins) {
    builder->RemoveBytecodePositionDecorator();
  }
  return decoder.toResult(nullptr);
}

#undef BUILD

}  // namespace wasm
}  // namespace internal
}  // namespace v8