function-body-decoder.cc 10 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/flags/flags.h"
8
#include "src/handles/handles.h"
9
#include "src/objects/objects-inl.h"
10
#include "src/utils/ostreams.h"
11
#include "src/wasm/decoder.h"
12 13
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/wasm-limits.h"
14
#include "src/wasm/wasm-linkage.h"
15
#include "src/wasm/wasm-module.h"
16
#include "src/wasm/wasm-opcodes-inl.h"
17 18 19 20 21

namespace v8 {
namespace internal {
namespace wasm {

22 23
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
                      const byte* start, const byte* end) {
24
  WasmFeatures no_features = WasmFeatures::None();
25
  Zone* zone = decls->type_list.get_allocator().zone();
26 27
  WasmDecoder<Decoder::kFullValidation> decoder(
      zone, nullptr, enabled, &no_features, nullptr, start, end, 0);
28
  uint32_t length;
29
  if (!decoder.DecodeLocals(decoder.pc(), &length, 0)) {
30 31
    decls->encoded_size = 0;
    return false;
32
  }
33 34 35 36 37 38
  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;
39
}
40

41
BytecodeIterator::BytecodeIterator(const byte* start, const byte* end,
42
                                   BodyLocalDecls* decls)
43 44
    : Decoder(start, end) {
  if (decls != nullptr) {
45
    if (DecodeLocalDecls(WasmFeatures::All(), decls, start, end)) {
46
      pc_ += decls->encoded_size;
47 48 49 50 51
      if (pc_ > end_) pc_ = end_;
    }
  }
}

52
DecodeResult VerifyWasmCode(AccountingAllocator* allocator,
53 54
                            const WasmFeatures& enabled,
                            const WasmModule* module, WasmFeatures* detected,
55
                            const FunctionBody& body) {
56
  Zone zone(allocator, ZONE_NAME);
57
  WasmFullDecoder<Decoder::kFullValidation, EmptyInterface> decoder(
58
      &zone, module, enabled, detected, body);
59
  decoder.Decode();
60
  return decoder.toResult(nullptr);
61 62
}

63
unsigned OpcodeLength(const byte* pc, const byte* end) {
64
  WasmFeatures no_features = WasmFeatures::None();
65 66 67
  Zone* no_zone = nullptr;
  WasmModule* no_module = nullptr;
  FunctionSig* no_sig = nullptr;
68 69 70
  WasmDecoder<Decoder::kNoValidation> decoder(no_zone, no_module, no_features,
                                              &no_features, no_sig, pc, end, 0);
  return WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, pc);
71 72
}

73
std::pair<uint32_t, uint32_t> StackEffect(const WasmModule* module,
74 75
                                          const FunctionSig* sig,
                                          const byte* pc, const byte* end) {
76
  WasmFeatures unused_detected_features = WasmFeatures::None();
77
  Zone* no_zone = nullptr;
78
  WasmDecoder<Decoder::kNoValidation> decoder(
79 80
      no_zone, module, WasmFeatures::All(), &unused_detected_features, sig, pc,
      end);
81 82 83
  return decoder.StackEffect(pc);
}

84
void PrintRawWasmCode(const byte* start, const byte* end) {
85
  AccountingAllocator allocator;
86 87
  PrintRawWasmCode(&allocator, FunctionBody{nullptr, 0, start, end}, nullptr,
                   kPrintLocals);
88 89 90 91 92 93 94 95 96 97 98 99 100 101
}

namespace {
const char* RawOpcodeName(WasmOpcode opcode) {
  switch (opcode) {
#define DECLARE_NAME_CASE(name, opcode, sig) \
  case kExpr##name:                          \
    return "kExpr" #name;
    FOREACH_OPCODE(DECLARE_NAME_CASE)
#undef DECLARE_NAME_CASE
    default:
      break;
  }
  return "Unknown";
102
}
103 104 105 106 107 108 109 110 111 112 113
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";
  }
}
114
}  // namespace
115

116
bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
117
                      const WasmModule* module, PrintLocals print_locals) {
118
  StdoutStream os;
119 120 121 122
  return PrintRawWasmCode(allocator, body, module, print_locals, os);
}

bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body,
123
                      const WasmModule* module, PrintLocals print_locals,
124
                      std::ostream& os, std::vector<int>* line_numbers) {
125
  Zone zone(allocator, ZONE_NAME);
126
  WasmFeatures unused_detected_features = WasmFeatures::None();
127 128 129
  WasmDecoder<Decoder::kNoValidation> decoder(
      &zone, module, WasmFeatures::All(), &unused_detected_features, body.sig,
      body.start, body.end);
130
  int line_nr = 0;
131
  constexpr int kNoByteCode = -1;
132 133 134 135

  // Print the function signature.
  if (body.sig) {
    os << "// signature: " << *body.sig << std::endl;
136
    if (line_numbers) line_numbers->push_back(kNoByteCode);
137
    ++line_nr;
138 139 140
  }

  // Print the local declarations.
141
  BodyLocalDecls decls(&zone);
142
  BytecodeIterator i(body.start, body.end, &decls);
143
  if (body.start != i.pc() && print_locals == kPrintLocals) {
144
    os << "// locals:";
145 146 147 148 149 150 151
    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 {
152
          os << " " << count << " " << type.name();
153 154 155 156
          type = decls.type_list[pos];
          count = 1;
        }
      }
157
      os << " " << count << " " << type.name();
158 159
    }
    os << std::endl;
160
    if (line_numbers) line_numbers->push_back(kNoByteCode);
161
    ++line_nr;
162

163
    for (const byte* locals = body.start; locals < i.pc(); locals++) {
164
      os << (locals == body.start ? "0x" : " 0x") << AsHex(*locals, 2) << ",";
165
    }
166
    os << std::endl;
167
    if (line_numbers) line_numbers->push_back(kNoByteCode);
168
    ++line_nr;
169 170
  }

171
  os << "// body:" << std::endl;
172
  if (line_numbers) line_numbers->push_back(kNoByteCode);
173 174
  ++line_nr;
  unsigned control_depth = 0;
175
  for (; i.has_next(); i.next()) {
176
    unsigned length =
177
        WasmDecoder<Decoder::kNoValidation>::OpcodeLength(&decoder, i.pc());
178

179
    unsigned offset = 1;
180
    WasmOpcode opcode = i.current();
181 182 183 184
    WasmOpcode prefix = kExprUnreachable;
    bool has_prefix = WasmOpcodes::IsPrefixOpcode(opcode);
    if (has_prefix) {
      prefix = i.current();
185 186 187
      opcode = i.prefixed_opcode();
      offset = 2;
    }
188
    if (line_numbers) line_numbers->push_back(i.position());
189
    if (opcode == kExprElse || opcode == kExprCatch) {
190 191
      control_depth--;
    }
192

193 194 195 196 197 198
    int num_whitespaces = control_depth < 32 ? 2 * control_depth : 64;

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

200 201 202 203
    if (has_prefix) {
      os << PrefixName(prefix) << ", ";
    }

204
    os << RawOpcodeName(opcode) << ",";
205

206 207 208 209
    if (opcode == kExprLoop || opcode == kExprIf || opcode == kExprBlock ||
        opcode == kExprTry) {
      DCHECK_EQ(2, length);

210
      // TODO(7748) Update this for gc and ref types if needed
211 212
      switch (i.pc()[1]) {
#define CASE_LOCAL_TYPE(local_name, type_name) \
213
  case k##local_name##Code:                    \
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    os << " kWasm" #type_name ",";             \
    break;

        CASE_LOCAL_TYPE(I32, I32)
        CASE_LOCAL_TYPE(I64, I64)
        CASE_LOCAL_TYPE(F32, F32)
        CASE_LOCAL_TYPE(F64, F64)
        CASE_LOCAL_TYPE(S128, S128)
        CASE_LOCAL_TYPE(Void, Stmt)
        default:
          os << " 0x" << AsHex(i.pc()[1], 2) << ",";
          break;
      }
#undef CASE_LOCAL_TYPE
    } else {
229
      for (unsigned j = offset; j < length; ++j) {
230 231
        os << " 0x" << AsHex(i.pc()[j], 2) << ",";
      }
232
    }
233

234 235
    os << "  // " << WasmOpcodes::OpcodeName(opcode);

236 237
    switch (opcode) {
      case kExprElse:
238
      case kExprCatch:
239
        os << " @" << i.pc_offset();
240 241
        control_depth++;
        break;
242
      case kExprLoop:
243
      case kExprIf:
244
      case kExprBlock:
245
      case kExprTry: {
246 247
        BlockTypeImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(), &i,
                                                       i.pc() + 1);
248
        os << " @" << i.pc_offset();
249
        if (decoder.Complete(imm)) {
250
          for (uint32_t i = 0; i < imm.out_arity(); i++) {
251
            os << " " << imm.out_type(i).name();
252
          }
253
        }
254 255
        control_depth++;
        break;
256
      }
257
      case kExprEnd:
258
        os << " @" << i.pc_offset();
259 260 261
        control_depth--;
        break;
      case kExprBr: {
262
        BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
263
        os << " depth=" << imm.depth;
264 265 266
        break;
      }
      case kExprBrIf: {
267
        BranchDepthImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
268
        os << " depth=" << imm.depth;
269 270 271
        break;
      }
      case kExprBrTable: {
272
        BranchTableImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
273
        os << " entries=" << imm.table_count;
274 275 276
        break;
      }
      case kExprCallIndirect: {
277 278
        CallIndirectImmediate<Decoder::kNoValidation> imm(WasmFeatures::All(),
                                                          &i, i.pc() + 1);
279
        os << " sig #" << imm.sig_index;
280
        if (decoder.Complete(imm)) {
281
          os << ": " << *imm.sig;
282
        }
283 284 285
        break;
      }
      case kExprCallFunction: {
286
        CallFunctionImmediate<Decoder::kNoValidation> imm(&i, i.pc() + 1);
287
        os << " function #" << imm.index;
288
        if (decoder.Complete(imm)) {
289
          os << ": " << *imm.sig;
290
        }
291 292 293 294
        break;
      }
      default:
        break;
295
    }
296
    os << std::endl;
297
    ++line_nr;
298
  }
299
  DCHECK(!line_numbers || line_numbers->size() == static_cast<size_t>(line_nr));
300 301

  return decoder.ok();
302
}
303

304
BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, uint32_t num_locals,
305
                                           const byte* start, const byte* end) {
306
  WasmFeatures no_features = WasmFeatures::None();
307 308 309
  WasmDecoder<Decoder::kFullValidation> decoder(
      zone, nullptr, no_features, &no_features, nullptr, start, end, 0);
  return WasmDecoder<Decoder::kFullValidation>::AnalyzeLoopAssignment(
310
      &decoder, start, num_locals, zone);
311 312
}

313 314 315
}  // namespace wasm
}  // namespace internal
}  // namespace v8