Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/loader/serialize/serial_segment.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "loader/serialize.h"
5
6
namespace WasmEdge {
7
namespace Loader {
8
9
// Serialize table segment. See "include/loader/serialize.h".
10
void Serializer::serializeSegment(const AST::TableSegment &Seg,
11
0
                                  std::vector<uint8_t> &OutVec) const noexcept {
12
  // Table segment: tabletype
13
  //               |0x40 + 0x00 + tabletype + expr
14
0
  if (Seg.getExpr().getInstrs().size() > 0) {
15
0
    OutVec.push_back(0x40U);
16
0
    OutVec.push_back(0x00U);
17
0
    serializeType(Seg.getTableType(), OutVec);
18
0
    serializeExpression(Seg.getExpr(), OutVec);
19
0
  } else {
20
0
    serializeType(Seg.getTableType(), OutVec);
21
0
  }
22
0
}
23
24
// Serialize global segment. See "include/loader/serialize.h".
25
void Serializer::serializeSegment(const AST::GlobalSegment &Seg,
26
0
                                  std::vector<uint8_t> &OutVec) const noexcept {
27
  // Global segment: globaltype + expr.
28
0
  serializeType(Seg.getGlobalType(), OutVec);
29
0
  serializeExpression(Seg.getExpr(), OutVec);
30
0
}
31
32
// Serialize element segment. See "include/loader/serialize.h".
33
void Serializer::serializeSegment(const AST::ElementSegment &Seg,
34
0
                                  std::vector<uint8_t> &OutVec) const noexcept {
35
  // Element segment: mode:u32 + tableidx:u32 + offset:expr + elemkind:reftype +
36
  // vec(u32) + vec(expr)
37
  //
38
  // Modes 0x00 to 0x04 only express a nullable funcref element type, and 0x00
39
  // and 0x04 also imply table index 0.
40
0
  const bool IsFuncRef =
41
0
      Seg.getRefType() == ValType(TypeCode::RefNull, TypeCode::FuncRef);
42
  // Modes 0x00 to 0x03 can only express ref.func initialisers.
43
0
  bool AllRefFunc = true;
44
0
  for (const auto &Expr : Seg.getInitExprs()) {
45
0
    const auto &Instrs = Expr.getInstrs();
46
0
    if (Instrs.size() != 2 || Instrs[0].getOpCode() != OpCode::Ref__func ||
47
0
        Instrs[1].getOpCode() != OpCode::End) {
48
0
      AllRefFunc = false;
49
0
      break;
50
0
    }
51
0
  }
52
53
0
  const bool IsPassive =
54
0
      Seg.getMode() == AST::ElementSegment::ElemMode::Passive;
55
0
  const bool IsDeclarative =
56
0
      Seg.getMode() == AST::ElementSegment::ElemMode::Declarative;
57
58
0
  uint8_t Mode;
59
0
  if (!IsFuncRef) {
60
    // Must use mode 0x05, 0x06 or 0x07: an expression form carrying a reftype.
61
0
    Mode = 0x04U | (IsPassive ? 0x01U : IsDeclarative ? 0x03U : 0x02U);
62
0
  } else {
63
0
    Mode = static_cast<uint8_t>(AllRefFunc ? 0x00U : 0x04U) |
64
0
           (IsPassive       ? 0x01U
65
0
            : IsDeclarative ? 0x03U
66
0
                            : (Seg.getIdx() != 0 ? 0x02U : 0x00U));
67
0
  }
68
0
  OutVec.push_back(Mode);
69
70
  // Serialize the table index for the active modes carrying one.
71
0
  if ((Mode & 0x03U) == 0x02U) {
72
0
    serializeU32(Seg.getIdx(), OutVec);
73
0
  }
74
75
  // Serialize the offset expression for the active modes.
76
0
  if (!IsPassive && !IsDeclarative) {
77
0
    serializeExpression(Seg.getExpr(), OutVec);
78
0
  }
79
80
  // Serialize the element kind or the reference type.
81
0
  if (Mode & 0x03U) {
82
0
    if (Mode & 0x04U) {
83
0
      serializeRefType(Seg.getRefType(), OutVec);
84
0
    } else {
85
0
      OutVec.push_back(0x00U);
86
0
    }
87
0
  }
88
89
  // Serialize vec(funcidx) or vec(expr).
90
0
  assuming(Seg.getInitExprs().size() <= UINT32_MAX);
91
0
  serializeU32(static_cast<uint32_t>(Seg.getInitExprs().size()), OutVec);
92
0
  for (const auto &Expr : Seg.getInitExprs()) {
93
0
    if (Mode & 0x04U) {
94
0
      serializeExpression(Expr, OutVec);
95
0
    } else {
96
0
      serializeU32(Expr.getInstrs()[0].getTargetIndex(), OutVec);
97
0
    }
98
0
  }
99
0
}
100
101
// Serialize code segment. See "include/loader/serialize.h".
102
void Serializer::serializeSegment(const AST::CodeSegment &Seg,
103
0
                                  std::vector<uint8_t> &OutVec) const noexcept {
104
  // Code segment: size:u32 + locals:vec(u32 + valtype) + body:expr.
105
0
  assuming(Seg.getLocals().size() <= UINT32_MAX);
106
0
  auto OrgSize = OutVec.size();
107
0
  serializeU32(static_cast<uint32_t>(Seg.getLocals().size()), OutVec);
108
0
  for (auto &Locals : Seg.getLocals()) {
109
0
    serializeU32(Locals.first, OutVec);
110
0
    serializeValType(Locals.second, OutVec);
111
0
  }
112
0
  serializeExpression(Seg.getExpr(), OutVec);
113
  // Backward insert the code segment size.
114
0
  serializeU32(static_cast<uint32_t>(OutVec.size() - OrgSize), OutVec,
115
0
               std::next(OutVec.begin(), static_cast<ptrdiff_t>(OrgSize)));
116
0
}
117
118
// Serialize data segment. See "include/loader/serialize.h".
119
void Serializer::serializeSegment(const AST::DataSegment &Seg,
120
0
                                  std::vector<uint8_t> &OutVec) const noexcept {
121
  // Data segment: mode:u32 + memidx:u32 + expr + vec(byte)
122
0
  switch (Seg.getMode()) {
123
0
  case AST::DataSegment::DataMode::Active:
124
0
    if (Seg.getIdx() != 0) {
125
0
      OutVec.push_back(0x02U);
126
0
      serializeU32(Seg.getIdx(), OutVec);
127
0
    } else {
128
0
      OutVec.push_back(0x00U);
129
0
    }
130
0
    serializeExpression(Seg.getExpr(), OutVec);
131
0
    break;
132
0
  case AST::DataSegment::DataMode::Passive:
133
0
    OutVec.push_back(0x01U);
134
0
    break;
135
0
  default:
136
0
    assumingUnreachable();
137
0
  }
138
139
0
  assuming(Seg.getData().size() <= UINT32_MAX);
140
0
  serializeU32(static_cast<uint32_t>(Seg.getData().size()), OutVec);
141
0
  OutVec.insert(OutVec.end(), Seg.getData().begin(), Seg.getData().end());
142
0
}
143
144
} // namespace Loader
145
} // namespace WasmEdge