Coverage Report

Created: 2025-07-01 06:18

/src/WasmEdge/lib/loader/serialize/serial_segment.cpp
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
#include "loader/serialize.h"
5
6
namespace WasmEdge {
7
namespace Loader {
8
9
// Serialize table segment. See "include/loader/serialize.h".
10
Expect<void>
11
Serializer::serializeSegment(const AST::TableSegment &Seg,
12
0
                             std::vector<uint8_t> &OutVec) const noexcept {
13
  // Table segment: tabletype + expr.
14
0
  if (Seg.getExpr().getInstrs().size() > 0) {
15
0
    if (!Conf.hasProposal(Proposal::FunctionReferences)) {
16
0
      return logNeedProposal(ErrCode::Value::MalformedTable,
17
0
                             Proposal::FunctionReferences,
18
0
                             ASTNodeAttr::Seg_Table);
19
0
    }
20
0
    OutVec.push_back(0x40);
21
0
    OutVec.push_back(0x00);
22
0
  }
23
0
  return Expect<void>{}
24
0
      .and_then([&]() { return serializeType(Seg.getTableType(), OutVec); })
25
0
      .and_then([&]() { return serializeExpression(Seg.getExpr(), OutVec); })
26
0
      .map_error([](auto E) {
27
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Table));
28
0
        return E;
29
0
      });
30
0
}
31
32
// Serialize global segment. See "include/loader/serialize.h".
33
Expect<void>
34
Serializer::serializeSegment(const AST::GlobalSegment &Seg,
35
0
                             std::vector<uint8_t> &OutVec) const noexcept {
36
  // Global segment: globaltype + expr.
37
0
  return Expect<void>{}
38
0
      .and_then([&]() { return serializeType(Seg.getGlobalType(), OutVec); })
39
0
      .and_then([&]() { return serializeExpression(Seg.getExpr(), OutVec); })
40
0
      .map_error([](auto E) {
41
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Global));
42
0
        return E;
43
0
      });
44
0
}
45
46
// Serialize element segment. See "include/loader/serialize.h".
47
Expect<void>
48
Serializer::serializeSegment(const AST::ElementSegment &Seg,
49
0
                             std::vector<uint8_t> &OutVec) const noexcept {
50
  // Element segment: mode:u32 + tableidx:u32 + offset:expr + elemkind:reftype +
51
  // vec(u32) + vec(expr)
52
0
  if (!Conf.hasProposal(Proposal::BulkMemoryOperations) &&
53
0
      !Conf.hasProposal(Proposal::ReferenceTypes) &&
54
0
      (Seg.getMode() != AST::ElementSegment::ElemMode::Passive ||
55
0
       Seg.getIdx() != 0)) {
56
0
    return logNeedProposal(ErrCode::Value::ExpectedZeroByte,
57
0
                           Proposal::BulkMemoryOperations,
58
0
                           ASTNodeAttr::Seg_Element);
59
0
  }
60
61
0
  uint8_t Mode = 0x00;
62
0
  auto ModeIdx = OutVec.size();
63
0
  OutVec.push_back(Mode);
64
0
  switch (Seg.getMode()) {
65
0
  case AST::ElementSegment::ElemMode::Passive:
66
0
    Mode |= 0x01;
67
0
    break;
68
0
  case AST::ElementSegment::ElemMode::Declarative:
69
0
    Mode |= 0x03;
70
0
    break;
71
0
  default:
72
0
    break;
73
0
  }
74
75
0
  auto ReportError = [](auto E) {
76
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Element));
77
0
    return E;
78
0
  };
79
80
  // Serialize idx.
81
0
  if (Seg.getIdx() != 0) {
82
0
    Mode |= 0x02;
83
0
    serializeU32(Seg.getIdx(), OutVec);
84
0
  }
85
86
  // Serialize OffExpr.
87
0
  if (Seg.getMode() == AST::ElementSegment::ElemMode::Active) {
88
0
    EXPECTED_TRY(
89
0
        serializeExpression(Seg.getExpr(), OutVec).map_error(ReportError));
90
0
  }
91
92
  // Distinguish between FuncIdx and Expr.
93
0
  if (Seg.getInitExprs().size() != 0) {
94
0
    auto IsInitExpr = false;
95
0
    for (auto &Expr : Seg.getInitExprs()) {
96
0
      if (Expr.getInstrs().size() != 2 ||
97
0
          Expr.getInstrs()[0].getOpCode() != OpCode::Ref__func ||
98
0
          Expr.getInstrs()[1].getOpCode() != OpCode::End) {
99
0
        IsInitExpr = true;
100
0
        break;
101
0
      }
102
0
    }
103
0
    if (IsInitExpr) {
104
0
      Mode |= 0x04;
105
0
    }
106
0
  }
107
108
  // Serialize ElemKind or RefType.
109
0
  if (Mode & 0x03) {
110
0
    if (Mode & 0x04) {
111
      // Serialize RefType.
112
0
      EXPECTED_TRY(
113
0
          serializeRefType(Seg.getRefType(), ASTNodeAttr::Seg_Element, OutVec));
114
0
    } else {
115
      // Serialize ElemKind.
116
0
      OutVec.push_back(0x00);
117
0
    }
118
0
  }
119
120
  // Serialize vec(FuncIdx) or vec(expr).
121
0
  serializeU32(static_cast<uint32_t>(Seg.getInitExprs().size()), OutVec);
122
0
  for (auto &Expr : Seg.getInitExprs()) {
123
0
    if (Mode & 0x04) {
124
      // Serialize vec(expr).
125
0
      EXPECTED_TRY(serializeExpression(Expr, OutVec).map_error(ReportError));
126
0
    } else {
127
      // Serialize vec(FuncIdx).
128
0
      serializeU32(Expr.getInstrs()[0].getTargetIndex(), OutVec);
129
0
    }
130
0
  }
131
132
0
  OutVec[ModeIdx] = Mode;
133
0
  return {};
134
0
}
135
136
// Serialize code segment. See "include/loader/serialize.h".
137
Expect<void>
138
Serializer::serializeSegment(const AST::CodeSegment &Seg,
139
0
                             std::vector<uint8_t> &OutVec) const noexcept {
140
  // Code segment: size:u32 + locals:vec(u32 + valtype) + body:expr.
141
0
  auto OrgSize = OutVec.size();
142
0
  serializeU32(static_cast<uint32_t>(Seg.getLocals().size()), OutVec);
143
0
  for (auto &Locals : Seg.getLocals()) {
144
0
    serializeU32(Locals.first, OutVec);
145
0
    EXPECTED_TRY(
146
0
        serializeValType(Locals.second, ASTNodeAttr::Seg_Code, OutVec));
147
0
  }
148
0
  EXPECTED_TRY(serializeExpression(Seg.getExpr(), OutVec).map_error([](auto E) {
149
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Expression));
150
0
    return E;
151
0
  }));
152
  // Backward insert the section size.
153
0
  serializeU32(static_cast<uint32_t>(OutVec.size() - OrgSize), OutVec,
154
0
               std::next(OutVec.begin(), static_cast<ptrdiff_t>(OrgSize)));
155
0
  return {};
156
0
}
157
158
// Serialize data segment. See "include/loader/serialize.h".
159
Expect<void>
160
Serializer::serializeSegment(const AST::DataSegment &Seg,
161
0
                             std::vector<uint8_t> &OutVec) const noexcept {
162
  // Data segment: mode:u32 + memidx:u32 + expr + vec(byte)
163
0
  if (!Conf.hasProposal(Proposal::BulkMemoryOperations) &&
164
0
      !Conf.hasProposal(Proposal::ReferenceTypes) &&
165
0
      (Seg.getMode() != AST::DataSegment::DataMode::Active ||
166
0
       Seg.getIdx() != 0)) {
167
0
    return logNeedProposal(ErrCode::Value::ExpectedZeroByte,
168
0
                           Proposal::BulkMemoryOperations,
169
0
                           ASTNodeAttr::Seg_Data);
170
0
  }
171
172
0
  switch (Seg.getMode()) {
173
0
  case AST::DataSegment::DataMode::Active:
174
0
    if (Seg.getIdx() != 0) {
175
0
      OutVec.push_back(0x02);
176
0
      serializeU32(Seg.getIdx(), OutVec);
177
0
    } else {
178
0
      OutVec.push_back(0x00);
179
0
    }
180
0
    EXPECTED_TRY(
181
0
        serializeExpression(Seg.getExpr(), OutVec).map_error([](auto E) {
182
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Seg_Data));
183
0
          return E;
184
0
        }));
185
0
    break;
186
187
0
  case AST::DataSegment::DataMode::Passive:
188
0
    OutVec.push_back(0x01);
189
0
    break;
190
191
0
  default:
192
0
    assumingUnreachable();
193
0
  }
194
195
0
  serializeU32(static_cast<uint32_t>(Seg.getData().size()), OutVec);
196
0
  OutVec.insert(OutVec.end(), Seg.getData().begin(), Seg.getData().end());
197
0
  return {};
198
0
}
199
200
} // namespace Loader
201
} // namespace WasmEdge