aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/test/unittests/wasm/wasm-text-unittest.cc
blob: e960b730a5fecf0ee7beead36420ce55e3c8c0cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2019 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 <sstream>

#include "test/unittests/test-utils.h"

#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-module-builder.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-text.h"
#include "test/common/wasm/test-signatures.h"

namespace v8 {
namespace internal {
namespace wasm {

class WasmTextTest : public TestWithIsolateAndZone {
 public:
  TestSignatures sigs;
  WasmFeatures enabled_features_;

  void TestInstruction(const byte* func_start, size_t func_size) {
    WasmModuleBuilder mb(zone());
    auto* fb = mb.AddFunction(sigs.v_v());
    fb->EmitCode(func_start, static_cast<uint32_t>(func_size));
    fb->Emit(kExprEnd);

    ZoneBuffer buffer(zone());
    mb.WriteTo(&buffer);

    ModuleWireBytes wire_bytes(
        Vector<const byte>(buffer.begin(), buffer.size()));

    ModuleResult result = DecodeWasmModule(
        enabled_features_, buffer.begin(), buffer.end(), false, kWasmOrigin,
        isolate()->counters(), isolate()->wasm_engine()->allocator());
    EXPECT_TRUE(result.ok());

    std::stringstream ss;
    PrintWasmText(result.value().get(), wire_bytes, 0, ss, nullptr);
  }
};

TEST_F(WasmTextTest, EveryOpcodeCanBeDecoded) {
  static const struct {
    WasmOpcode opcode;
    const char* debug_name;
  } kValues[] = {
#define DECLARE_ELEMENT(name, opcode, sig) {kExpr##name, "kExpr" #name},
      FOREACH_OPCODE(DECLARE_ELEMENT)};
#undef DECLARE_ELEMENT

  for (const auto& value : kValues) {
    // Pad with 0 for any immediate values. If they're not needed, they'll be
    // interpreted as unreachable.
    byte data[20] = {0};

    printf("%s\n", value.debug_name);
    switch (value.opcode) {
      // Instructions that have a special case because they affect the control
      // depth.
      case kExprBlock:
      case kExprLoop:
      case kExprIf:
      case kExprTry:
        data[0] = value.opcode;
        data[1] = kLocalVoid;
        data[2] = kExprEnd;
        break;
      case kExprElse:
        data[0] = kExprIf;
        data[1] = value.opcode;
        data[2] = kExprEnd;
        break;
      case kExprCatch:
        data[0] = kExprTry;
        data[1] = value.opcode;
        data[2] = kExprEnd;
        break;
      case kExprEnd:
        break;

      // Instructions with special requirements for immediates.
      case kExprSelectWithType:
        data[0] = kExprSelectWithType;
        data[1] = 1;
        data[2] = kLocalI32;
        break;

      default: {
        if (value.opcode >= 0x100) {
          data[0] = value.opcode >> 8;        // Prefix byte.
          byte opcode = value.opcode & 0xff;  // Actual opcode.
          if (opcode >= 0x80) {
            // Opcode with prefix, and needs to be LEB encoded (3 bytes).
            // For now, this can only be in the range [0x80, 0xff], which means
            // that the third byte is always 1.
            data[1] = (opcode & 0x7f) | 0x80;
            data[2] = 1;
          } else {
            // Opcode with prefix (2 bytes).
            data[1] = opcode;
          }
        } else {
          // Single-byte opcode.
          data[0] = value.opcode;
        }
        break;
      }
    }

    TestInstruction(data, arraysize(data));
  }
}

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