function-body-decoder.cc 10.7 KB
Newer Older
1 2 3 4
// Copyright 2015 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.

5
#include "src/wasm/function-body-decoder.h"
6

7
#include "src/codegen/assembler-inl.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/decoder.h"
13 14
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/wasm-limits.h"
15
#include "src/wasm/wasm-linkage.h"
16
#include "src/wasm/wasm-module.h"
17
#include "src/wasm/wasm-opcodes-inl.h"
18 19 20 21 22

namespace v8 {
namespace internal {
namespace wasm {

23 24 25 26 27 28 29 30 31 32 33
namespace value_type_reader {
HeapType consume_heap_type(Decoder* decoder, const WasmModule* module,
                           const WasmFeatures& enabled) {
  uint32_t length;
  HeapType result = value_type_reader::read_heap_type<Decoder::kFullValidation>(
      decoder, decoder->pc(), &length, module, enabled);
  decoder->consume_bytes(length, "heap type");
  return result;
}
}  // namespace value_type_reader

34
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
35 36
                      const WasmModule* module, const byte* start,
                      const byte* end) {
37
  WasmFeatures no_features = WasmFeatures::None();
38
  Zone* zone = decls->type_list.get_allocator().zone();
39
  WasmDecoder<Decoder::kFullValidation> decoder(
40
      zone, module, enabled, &no_features, nullptr, start, end, 0);
41
  uint32_t length;
42
  if (decoder.DecodeLocals(decoder.pc(), &length, 0) < 0) {
43 44
    decls->encoded_size = 0;
    return false;
45
  }
46 47 48 49 50 51
  DCHECK(decoder.ok());
  decls->encoded_size = length;
  // Copy the decoded locals types into {decls->type_list}.
  DCHECK(decls->type_list.empty());
  decls->type_list = std::move(decoder.local_types_);
  return true;
52
}
53

54
BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
55
                                   BodyLocalDecls* decls)
56 57
    : Decoder(start, end) {
  if (decls != nullptr) {
58
    if (DecodeLocalDecls(WasmFeatures::All(), decls, nullptr, start, end)) {
59
      pc_ += decls->encoded_size;
60 61 62 63 64
      if (pc_ > end_) pc_ = end_;
    }
  }
}

65
DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
66 67
                            const WasmFeatures& enabled,
                            const WasmModule* module, WasmFeatures* detected,
68
                            const FunctionBody& body) {
69
  Zone zone(allocator, ZONE_NAME);
70
  WasmFullDecoder<Decoder::kFullValidation, EmptyInterface> decoder(
71
      &zone, module, enabled, detected, body);
72
  decoder.Decode();
73
  return decoder.toResult(nullptr);
74 75
}

76
unsigned OpcodeLength(const byte* pc, const byte* end) {
77
  WasmFeatures unused_detected_features;
78 79 80
  Zone* no_zone = nullptr;
  WasmModule* no_module = nullptr;
  FunctionSig* no_sig = nullptr;
81 82 83
  WasmDecoder<Decoder::kNoValidation> decoder(
      no_zone, no_module, WasmFeatures::All(), &unused_detected_features,
      no_sig, pc, end, 0);
84
  return WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, pc);
85 86
}

87 88
bool CheckHardwareSupportsSimd() { return CpuFeatures::SupportsWasmSimd128(); }

89
std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
90 91
                                          const FunctionSig* sig,
                                          const byte* pc, const byte* end) {
92
  WasmFeatures unused_detected_features = WasmFeatures::None();
93
  Zone* no_zone = nullptr;
94
  WasmDecoder<Decoder::kNoValidation> decoder(
95 96
      no_zone, module, WasmFeatures::All(), &unused_detected_features, sig, pc,
      end);
97 98 99
  return decoder.StackEffect(pc);
}

100
void PrintRawWasmCode(const byte* start, const byte* end) {
101
  AccountingAllocator allocator;
102 103
  PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr,
                   kPrintLocals);
104 105 106 107 108
}

namespace {
const char* RawOpcodeName(WasmOpcode opcode) {
  switch (opcode) {
109 110
#define DECLARE_NAME_CASE(name, ...) \
  case kExpr##name:                  \
111 112 113 114 115 116 117
    return "kExpr" #name;
    FOREACH_OPCODE(DECLARE_NAME_CASE)
#undef DECLARE_NAME_CASE
    default:
      break;
  }
  return "Unknown";
118
}
119 120 121 122 123 124 125 126 127 128 129
const char* PrefixName(WasmOpcode prefix_opcode) {
  switch (prefix_opcode) {
#define DECLARE_PREFIX_CASE(name, opcode) \
  case k##name##Prefix:                   \
    return "k" #name "Prefix";
    FOREACH_PREFIX(DECLARE_PREFIX_CASE)
#undef DECLARE_PREFIX_CASE
    default:
      return "Unknown prefix";
  }
}
130
}  // namespace
131

132
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
133
                      const WasmModule* module, PrintLocals print_locals) {
134
  StdoutStream os;
135 136 137 138
  return PrintRawWasmCode(allocator, body, module, print_locals, os);
}

bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
139
                      const WasmModule* module, PrintLocals print_locals,
140
                      std::ostream& os, std::vector<int>* line_numbers) {
141
  Zone zone(allocator, ZONE_NAME);
142
  WasmFeatures unused_detected_features = WasmFeatures::None();
143 144 145
  WasmDecoder<Decoder::kNoValidation> decoder(
      &zone, module, WasmFeatures::All(), &unused_detected_features, body.sig,
      body.start, body.end);
146
  int line_nr = 0;
147
  constexpr int kNoByteCode = -1;
148 149 150 151

  // Print the function signature.
  if (body.sig) {
    os << "// signature: " << *body.sig << std::endl;
152
    if (line_numbers) line_numbers->push_back(kNoByteCode);
153
    ++line_nr;
154 155 156
  }

  // Print the local declarations.
157
  BodyLocalDecls decls(&zone);
158
  BytecodeIterator i(body.start, body.end, &decls);
159
  if (body.start != i.pc() && print_locals == kPrintLocals) {
160
    os << "// locals:";
161 162 163 164 165 166 167
    if (!decls.type_list.empty()) {
      ValueType type = decls.type_list[0];
      uint32_t count = 0;
      for (size_t pos = 0; pos < decls.type_list.size(); ++pos) {
        if (decls.type_list[pos] == type) {
          ++count;
        } else {
168
          os << " " << count << " " << type.name();
169 170 171 172
          type = decls.type_list[pos];
          count = 1;
        }
      }
173
      os << " " << count << " " << type.name();
174 175
    }
    os << std::endl;
176
    if (line_numbers) line_numbers->push_back(kNoByteCode);
177
    ++line_nr;
178

179
    for (const byte* locals = body.start; locals < i.pc(); locals++) {
180
      os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ",";
181
    }
182
    os << std::endl;
183
    if (line_numbers) line_numbers->push_back(kNoByteCode);
184
    ++line_nr;
185 186
  }

187
  os << "// body:" << std::endl;
188
  if (line_numbers) line_numbers->push_back(kNoByteCode);
189 190
  ++line_nr;
  unsigned control_depth = 0;
191
  for (; i.has_next(); i.next()) {
192
    unsigned length =
193
        WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, i.pc());
194

195
    unsigned offset = 1;
196
    WasmOpcode opcode = i.current();
197 198 199 200
    WasmOpcode prefix = kExprUnreachable;
    bool has_prefix = WasmOpcodes::IsPrefixOpcode(opcode);
    if (has_prefix) {
      prefix = i.current();
201 202 203
      opcode = i.prefixed_opcode();
      offset = 2;
    }
204
    if (line_numbers) line_numbers->push_back(i.position());
205
    if (opcode == kExprElse || opcode == kExprCatch ||
206
        opcode == kExprCatchAll) {
207 208
      control_depth--;
    }
209

210 211 212 213 214 215
    int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;

    // 64 whitespaces
    const char* padding =
        "                                                                ";
    os.write(padding, num_whitespaces);
216

217 218 219 220
    if (has_prefix) {
      os << PrefixName(prefix) << ", ";
    }

221
    os << RawOpcodeName(opcode) << ",";
222

223
    if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock ||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
        opcode == kExprTry || opcode == kExprLet) {
      if (i.pc()[1] & 0x80) {
        uint32_t temp_length;
        ValueType type =
            value_type_reader::read_value_type<Decoder::kNoValidation>(
                &decoder, i.pc() + 1, &temp_length, module,
                WasmFeatures::All());
        if (temp_length == 1) {
          os << type.name() << ",";
        } else {
          // TODO(manoskouk): Improve this for rtts and (nullable) refs.
          for (unsigned j = offset; j < length; ++j) {
            os << " 0x" << AsHex(i.pc()[j], 2) << ",";
          }
        }
      } else {
        for (unsigned j = offset; j < length; ++j) {
          os << " 0x" << AsHex(i.pc()[j], 2) << ",";
        }
243 244
      }
    } else {
245
      for (unsigned j = offset; j < length; ++j) {
246 247
        os << " 0x" << AsHex(i.pc()[j], 2) << ",";
      }
248
    }
249

250 251
    os << "  // " << WasmOpcodes::OpcodeName(opcode);

252 253
    switch (opcode) {
      case kExprElse:
254
      case kExprCatch:
255
      case kExprCatchAll:
256
        os << " @" << i.pc_offset();
257 258
        control_depth++;
        break;
259
      case kExprLoop:
260
      case kExprIf:
261
      case kExprBlock:
262 263
      case kExprTry:
      case kExprLet: {
264
        BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(), &i,
265
                                                       i.pc() + 1, module);
266
        os << " @" << i.pc_offset();
267
        CHECK(decoder.Validate(i.pc() + 1, imm));
268 269
        for (uint32_t j = 0; j < imm.out_arity(); j++) {
          os << " " << imm.out_type(j).name();
270
        }
271 272
        control_depth++;
        break;
273
      }
274
      case kExprEnd:
275
        os << " @" << i.pc_offset();
276 277 278
        control_depth--;
        break;
      case kExprBr: {
279
        BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
280
        os << " depth=" << imm.depth;
281 282 283
        break;
      }
      case kExprBrIf: {
284
        BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
285
        os << " depth=" << imm.depth;
286 287 288
        break;
      }
      case kExprBrTable: {
289
        BranchTableImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
290
        os << " entries=" << imm.table_count;
291 292 293
        break;
      }
      case kExprCallIndirect: {
294 295 296
        CallIndirectImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
        os << " sig #" << imm.sig_imm.index;
        CHECK(decoder.Validate(i.pc() + 1, imm));
297
        os << ": " << *imm.sig;
298 299 300
        break;
      }
      case kExprCallFunction: {
301
        CallFunctionImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
302
        os << " function #" << imm.index;
303
        CHECK(decoder.Validate(i.pc() + 1, imm));
304
        os << ": " << *imm.sig;
305 306 307 308
        break;
      }
      default:
        break;
309
    }
310
    os << std::endl;
311
    ++line_nr;
312
  }
313
  DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr));
314
  USE(line_nr);
315 316

  return decoder.ok();
317
}
318

319
BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, uint32_t num_locals,
320
                                           const byte* start, const byte* end) {
321
  WasmFeatures no_features = WasmFeatures::None();
322 323 324
  WasmDecoder<Decoder::kFullValidation> decoder(
      zone, nullptr, no_features, &no_features, nullptr, start, end, 0);
  return WasmDecoder<Decoder::kFullValidation>::AnalyzeLoopAssignment(
325
      &decoder, start, num_locals, zone);
326 327
}

328 329 330
}  // namespace wasm
}  // namespace internal
}  // namespace v8