| Index: src/wasm/ast-decoder.h | 
| diff --git a/src/wasm/ast-decoder.h b/src/wasm/ast-decoder.h | 
| index 395339a268c2a2d5839bc2ad6e88f556898202f0..a6424f75be940e86a251c6d9a064e9e864d47dc7 100644 | 
| --- a/src/wasm/ast-decoder.h | 
| +++ b/src/wasm/ast-decoder.h | 
| @@ -22,7 +22,6 @@ | 
| namespace wasm { | 
|  | 
| const uint32_t kMaxNumWasmLocals = 8000000; | 
| -struct WasmGlobal; | 
|  | 
| // Helpers for decoding different kinds of operands which follow bytecodes. | 
| struct LocalIndexOperand { | 
| @@ -82,111 +81,39 @@ | 
| struct GlobalIndexOperand { | 
| uint32_t index; | 
| LocalType type; | 
| -  const WasmGlobal* global; | 
| unsigned length; | 
|  | 
| inline GlobalIndexOperand(Decoder* decoder, const byte* pc) { | 
| index = decoder->checked_read_u32v(pc, 1, &length, "global index"); | 
| -    global = nullptr; | 
| type = kAstStmt; | 
| -  } | 
| -}; | 
| - | 
| -struct BlockTypeOperand { | 
| -  uint32_t arity; | 
| -  const byte* types;  // pointer to encoded types for the block. | 
| -  unsigned length; | 
| - | 
| -  inline BlockTypeOperand(Decoder* decoder, const byte* pc) { | 
| -    uint8_t val = decoder->checked_read_u8(pc, 1, "block type"); | 
| -    LocalType type = kAstStmt; | 
| -    length = 1; | 
| -    arity = 0; | 
| -    types = nullptr; | 
| -    if (decode_local_type(val, &type)) { | 
| -      arity = type == kAstStmt ? 0 : 1; | 
| -      types = pc + 1; | 
| -    } else { | 
| -      // Handle multi-value blocks. | 
| -      if (!FLAG_wasm_mv_prototype) { | 
| -        decoder->error(pc, pc + 1, "invalid block arity > 1"); | 
| -        return; | 
| -      } | 
| -      if (val != kMultivalBlock) { | 
| -        decoder->error(pc, pc + 1, "invalid block type"); | 
| -        return; | 
| -      } | 
| -      // Decode and check the types vector of the block. | 
| -      unsigned len = 0; | 
| -      uint32_t count = decoder->checked_read_u32v(pc, 2, &len, "block arity"); | 
| -      // {count} is encoded as {arity-2}, so that a {0} count here corresponds | 
| -      // to a block with 2 values. This makes invalid/redundant encodings | 
| -      // impossible. | 
| -      arity = count + 2; | 
| -      length = 1 + len + arity; | 
| -      types = pc + 1 + 1 + len; | 
| - | 
| -      for (uint32_t i = 0; i < arity; i++) { | 
| -        uint32_t offset = 1 + 1 + len + i; | 
| -        val = decoder->checked_read_u8(pc, offset, "block type"); | 
| -        decode_local_type(val, &type); | 
| -        if (type == kAstStmt) { | 
| -          decoder->error(pc, pc + offset, "invalid block type"); | 
| -          return; | 
| -        } | 
| -      } | 
| -    } | 
| -  } | 
| -  // Decode a byte representing a local type. Return {false} if the encoded | 
| -  // byte was invalid or {kMultivalBlock}. | 
| -  bool decode_local_type(uint8_t val, LocalType* result) { | 
| -    switch (static_cast<LocalTypeCode>(val)) { | 
| -      case kLocalVoid: | 
| -        *result = kAstStmt; | 
| -        return true; | 
| -      case kLocalI32: | 
| -        *result = kAstI32; | 
| -        return true; | 
| -      case kLocalI64: | 
| -        *result = kAstI64; | 
| -        return true; | 
| -      case kLocalF32: | 
| -        *result = kAstF32; | 
| -        return true; | 
| -      case kLocalF64: | 
| -        *result = kAstF64; | 
| -        return true; | 
| -      default: | 
| -        *result = kAstStmt; | 
| -        return false; | 
| -    } | 
| -  } | 
| -  LocalType read_entry(unsigned index) { | 
| -    DCHECK_LT(index, arity); | 
| -    LocalType result; | 
| -    CHECK(decode_local_type(types[index], &result)); | 
| -    return result; | 
| } | 
| }; | 
|  | 
| struct Control; | 
| struct BreakDepthOperand { | 
| +  uint32_t arity; | 
| uint32_t depth; | 
| Control* target; | 
| unsigned length; | 
| inline BreakDepthOperand(Decoder* decoder, const byte* pc) { | 
| -    depth = decoder->checked_read_u32v(pc, 1, &length, "break depth"); | 
| +    unsigned len1 = 0; | 
| +    unsigned len2 = 0; | 
| +    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count"); | 
| +    depth = decoder->checked_read_u32v(pc, 1 + len1, &len2, "break depth"); | 
| +    length = len1 + len2; | 
| target = nullptr; | 
| } | 
| }; | 
|  | 
| struct CallIndirectOperand { | 
| +  uint32_t arity; | 
| uint32_t index; | 
| FunctionSig* sig; | 
| unsigned length; | 
| inline CallIndirectOperand(Decoder* decoder, const byte* pc) { | 
| unsigned len1 = 0; | 
| unsigned len2 = 0; | 
| +    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count"); | 
| index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "signature index"); | 
| length = len1 + len2; | 
| sig = nullptr; | 
| @@ -194,74 +121,64 @@ | 
| }; | 
|  | 
| struct CallFunctionOperand { | 
| +  uint32_t arity; | 
| uint32_t index; | 
| FunctionSig* sig; | 
| unsigned length; | 
| inline CallFunctionOperand(Decoder* decoder, const byte* pc) { | 
| unsigned len1 = 0; | 
| unsigned len2 = 0; | 
| +    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count"); | 
| index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "function index"); | 
| length = len1 + len2; | 
| sig = nullptr; | 
| } | 
| }; | 
|  | 
| +struct CallImportOperand { | 
| +  uint32_t arity; | 
| +  uint32_t index; | 
| +  FunctionSig* sig; | 
| +  unsigned length; | 
| +  inline CallImportOperand(Decoder* decoder, const byte* pc) { | 
| +    unsigned len1 = 0; | 
| +    unsigned len2 = 0; | 
| +    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count"); | 
| +    index = decoder->checked_read_u32v(pc, 1 + len1, &len2, "import index"); | 
| +    length = len1 + len2; | 
| +    sig = nullptr; | 
| +  } | 
| +}; | 
| + | 
| struct BranchTableOperand { | 
| +  uint32_t arity; | 
| uint32_t table_count; | 
| -  const byte* start; | 
| const byte* table; | 
| +  unsigned length; | 
| inline BranchTableOperand(Decoder* decoder, const byte* pc) { | 
| -    DCHECK_EQ(kExprBrTable, decoder->checked_read_u8(pc, 0, "opcode")); | 
| -    start = pc + 1; | 
| -    unsigned len1 = 0; | 
| -    table_count = decoder->checked_read_u32v(pc, 1, &len1, "table count"); | 
| +    unsigned len1 = 0; | 
| +    unsigned len2 = 0; | 
| +    arity = decoder->checked_read_u32v(pc, 1, &len1, "argument count"); | 
| +    table_count = | 
| +        decoder->checked_read_u32v(pc, 1 + len1, &len2, "table count"); | 
| if (table_count > (UINT_MAX / sizeof(uint32_t)) - 1 || | 
| -        len1 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) { | 
| +        len1 + len2 > UINT_MAX - (table_count + 1) * sizeof(uint32_t)) { | 
| decoder->error(pc, "branch table size overflow"); | 
| } | 
| -    table = pc + 1 + len1; | 
| +    length = len1 + len2 + (table_count + 1) * sizeof(uint32_t); | 
| + | 
| +    uint32_t table_start = 1 + len1 + len2; | 
| +    if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t), | 
| +                       "expected <table entries>")) { | 
| +      table = pc + table_start; | 
| +    } else { | 
| +      table = nullptr; | 
| +    } | 
| } | 
| inline uint32_t read_entry(Decoder* decoder, unsigned i) { | 
| DCHECK(i <= table_count); | 
| return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0; | 
| } | 
| -}; | 
| - | 
| -// A helper to iterate over a branch table. | 
| -class BranchTableIterator { | 
| - public: | 
| -  unsigned cur_index() { return index_; } | 
| -  bool has_next() { return index_ <= table_count_; } | 
| -  uint32_t next() { | 
| -    DCHECK(has_next()); | 
| -    index_++; | 
| -    unsigned length = 0; | 
| -    uint32_t result = | 
| -        decoder_->checked_read_u32v(pc_, 0, &length, "branch table entry"); | 
| -    pc_ += length; | 
| -    return result; | 
| -  } | 
| -  // length, including the length of the {BranchTableOperand}, but not the | 
| -  // opcode. | 
| -  unsigned length() { | 
| -    while (has_next()) next(); | 
| -    return static_cast<unsigned>(pc_ - start_); | 
| -  } | 
| -  const byte* pc() { return pc_; } | 
| - | 
| -  BranchTableIterator(Decoder* decoder, BranchTableOperand& operand) | 
| -      : decoder_(decoder), | 
| -        start_(operand.start), | 
| -        pc_(operand.table), | 
| -        index_(0), | 
| -        table_count_(operand.table_count) {} | 
| - | 
| - private: | 
| -  Decoder* decoder_; | 
| -  const byte* start_; | 
| -  const byte* pc_; | 
| -  uint32_t index_;        // the current index. | 
| -  uint32_t table_count_;  // the count of entries, not including default. | 
| }; | 
|  | 
| struct MemoryAccessOperand { | 
| @@ -286,6 +203,15 @@ | 
| } | 
| }; | 
|  | 
| +struct ReturnArityOperand { | 
| +  uint32_t arity; | 
| +  unsigned length; | 
| + | 
| +  inline ReturnArityOperand(Decoder* decoder, const byte* pc) { | 
| +    arity = decoder->checked_read_u32v(pc, 1, &length, "return count"); | 
| +  } | 
| +}; | 
| + | 
| typedef compiler::WasmGraphBuilder TFBuilder; | 
| struct ModuleEnv;  // forward declaration of module interface. | 
|  | 
| @@ -357,6 +283,9 @@ | 
|  | 
| // Computes the length of the opcode at the given address. | 
| unsigned OpcodeLength(const byte* pc, const byte* end); | 
| + | 
| +// Computes the arity (number of sub-nodes) of the opcode at the given address. | 
| +unsigned OpcodeArity(const byte* pc, const byte* end); | 
|  | 
| // A simple forward iterator for bytecodes. | 
| class BytecodeIterator : public Decoder { | 
|  |