Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/include/runtime/instance/table.h
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
//===-- wasmedge/runtime/instance/table.h - Table Instance definition -----===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the table instance definition in store manager.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#include "ast/segment.h"
17
#include "ast/type.h"
18
#include "common/errcode.h"
19
#include "common/errinfo.h"
20
#include "common/spdlog.h"
21
22
#include <algorithm>
23
#include <cstdint>
24
#include <vector>
25
26
namespace WasmEdge {
27
namespace Runtime {
28
namespace Instance {
29
30
class TableInstance {
31
public:
32
  TableInstance() = delete;
33
  TableInstance(const AST::TableType &TType) noexcept
34
0
      : TabType(TType),
35
0
        Refs(TType.getLimit().getMin(), RefVariant(TType.getRefType())),
36
0
        InitValue(RefVariant(TType.getRefType())) {
37
    // The reftype should a nullable reference because of no init ref.
38
0
    assuming(TType.getRefType().isNullableRefType());
39
0
  }
40
  TableInstance(const AST::TableType &TType, const RefVariant &InitVal) noexcept
41
0
      : TabType(TType), Refs(TType.getLimit().getMin(), InitVal),
42
0
        InitValue(InitVal) {
43
    // If the reftype is not a nullable reference, the init ref is required.
44
0
    assuming(TType.getRefType().isNullableRefType() || !InitVal.isNull());
45
0
  }
46
47
  /// Get size of table.refs
48
0
  uint32_t getSize() const noexcept {
49
    // The table size is binded with the limit in table type.
50
0
    return TabType.getLimit().getMin();
51
0
  }
52
53
  /// Getter of table type.
54
0
  const AST::TableType &getTableType() const noexcept { return TabType; }
55
56
  /// Check is out of bound.
57
0
  bool checkAccessBound(uint32_t Offset, uint32_t Length) const noexcept {
58
0
    const uint64_t AccessLen =
59
0
        static_cast<uint64_t>(Offset) + static_cast<uint64_t>(Length);
60
0
    return AccessLen <= Refs.size();
61
0
  }
62
63
  /// Get boundary index.
64
0
  uint32_t getBoundIdx() const noexcept {
65
0
    return std::max(static_cast<uint32_t>(Refs.size()), UINT32_C(1)) -
66
0
           UINT32_C(1);
67
0
  }
68
69
  /// Grow table with initialization value.
70
0
  bool growTable(uint32_t Count, const RefVariant &Val) noexcept {
71
0
    uint32_t MaxSizeCaped = std::numeric_limits<uint32_t>::max();
72
0
    uint32_t Min = TabType.getLimit().getMin();
73
0
    uint32_t Max = TabType.getLimit().getMax();
74
0
    if (TabType.getLimit().hasMax()) {
75
0
      MaxSizeCaped = std::min(Max, MaxSizeCaped);
76
0
    }
77
0
    if (Count > MaxSizeCaped - Refs.size()) {
78
0
      return false;
79
0
    }
80
0
    Refs.resize(Refs.size() + Count);
81
0
    std::fill_n(Refs.end() - Count, Count, Val);
82
0
    TabType.getLimit().setMin(Min + Count);
83
0
    return true;
84
0
  }
85
0
  bool growTable(uint32_t Count) noexcept {
86
0
    return growTable(Count, InitValue);
87
0
  }
88
89
  /// Get slice of Refs[Offset : Offset + Length - 1]
90
  Expect<Span<const RefVariant>> getRefs(uint32_t Offset,
91
0
                                         uint32_t Length) const noexcept {
92
    // Check the accessing boundary.
93
0
    if (!checkAccessBound(Offset, Length)) {
94
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
95
0
      spdlog::error(ErrInfo::InfoBoundary(Offset, Length, getBoundIdx()));
96
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
97
0
    }
98
0
    return Span<const RefVariant>(Refs.begin() + Offset, Length);
99
0
  }
100
101
  /// Replace the Refs[Dst :] by Slice[Src : Src + Length)
102
  Expect<void> setRefs(Span<const RefVariant> Slice, uint32_t Dst, uint32_t Src,
103
0
                       uint32_t Length) noexcept {
104
    // Check the accessing boundary.
105
0
    if (!checkAccessBound(Dst, Length)) {
106
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
107
0
      spdlog::error(ErrInfo::InfoBoundary(Dst, Length, getBoundIdx()));
108
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
109
0
    }
110
111
    // Check the input data validation.
112
0
    if (static_cast<uint64_t>(Src) + static_cast<uint64_t>(Length) >
113
0
        Slice.size()) {
114
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
115
0
      spdlog::error(ErrInfo::InfoBoundary(
116
0
          Src, Length, std::max(static_cast<uint32_t>(Slice.size()), 1U) - 1U));
117
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
118
0
    }
119
120
    // Copy the references.
121
0
    if (Dst <= Src) {
122
0
      std::copy(Slice.begin() + Src, Slice.begin() + Src + Length,
123
0
                Refs.begin() + Dst);
124
0
    } else {
125
0
      std::copy(std::make_reverse_iterator(Slice.begin() + Src + Length),
126
0
                std::make_reverse_iterator(Slice.begin() + Src),
127
0
                std::make_reverse_iterator(Refs.begin() + Dst + Length));
128
0
    }
129
0
    return {};
130
0
  }
131
132
  /// Fill the Refs[Offset : Offset + Length - 1] by Val.
133
  Expect<void> fillRefs(const RefVariant &Val, uint32_t Offset,
134
0
                        uint32_t Length) noexcept {
135
    // Check the accessing boundary.
136
0
    if (!checkAccessBound(Offset, Length)) {
137
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
138
0
      spdlog::error(ErrInfo::InfoBoundary(Offset, Length, getBoundIdx()));
139
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
140
0
    }
141
142
    // Fill the references.
143
0
    std::fill_n(Refs.begin() + Offset, Length, Val);
144
0
    return {};
145
0
  }
146
147
  /// Get the elem address.
148
0
  Expect<RefVariant> getRefAddr(uint32_t Idx) const noexcept {
149
0
    if (Idx >= Refs.size()) {
150
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
151
0
      spdlog::error(ErrInfo::InfoBoundary(Idx, 1, getBoundIdx()));
152
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
153
0
    }
154
0
    return Refs[Idx];
155
0
  }
156
157
  /// Set the elem address.
158
0
  Expect<void> setRefAddr(uint32_t Idx, const RefVariant &Val) {
159
0
    if (Idx >= Refs.size()) {
160
0
      spdlog::error(ErrCode::Value::TableOutOfBounds);
161
0
      spdlog::error(ErrInfo::InfoBoundary(Idx, 1, getBoundIdx()));
162
0
      return Unexpect(ErrCode::Value::TableOutOfBounds);
163
0
    }
164
0
    Refs[Idx] = Val;
165
0
    return {};
166
0
  }
167
168
private:
169
  /// \name Data of table instance.
170
  /// @{
171
  AST::TableType TabType;
172
  std::vector<RefVariant> Refs;
173
  RefVariant InitValue;
174
  /// @}
175
};
176
177
} // namespace Instance
178
} // namespace Runtime
179
} // namespace WasmEdge