Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .ci/run_test_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
# TestSuite=microsuite
# # 'cpu' or 'check'
# CPU_EXCEPTION_TYPE='cpu'
# # Enable bulk memory operations proposal
# ENABLE_BULK_MEMORY=true

set -e

Expand Down Expand Up @@ -93,6 +95,16 @@ case $CPU_EXCEPTION_TYPE in
;;
esac

# Enable bulk memory operations proposal (default: true)
if [ -z "$ENABLE_BULK_MEMORY" ]; then
ENABLE_BULK_MEMORY=true
fi
if [ ${ENABLE_BULK_MEMORY} = true ]; then
CMAKE_OPTIONS="$CMAKE_OPTIONS -DZEN_ENABLE_BULK_MEMORY=ON"
else
CMAKE_OPTIONS="$CMAKE_OPTIONS -DZEN_ENABLE_BULK_MEMORY=OFF"
fi

STACK_TYPES=("-DZEN_ENABLE_VIRTUAL_STACK=ON" "-DZEN_ENABLE_VIRTUAL_STACK=OFF")
if [[ $RUN_MODE == "interpreter" ]]; then
STACK_TYPES=("-DZEN_ENABLE_VIRTUAL_STACK=OFF")
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/dtvm_wasm_test_x86.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
export TestSuite=microsuite
export CPU_EXCEPTION_TYPE='check'
export ENABLE_GAS_METER=false
export ENABLE_BULK_MEMORY=true

bash .ci/run_test_suite.sh

Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ option(ZEN_ENABLE_MULTIPASS_JIT "Enable multipass JIT" OFF)
option(ZEN_ENABLE_CLI "Enable command line interface" ON)
option(ZEN_ENABLE_BUILTIN_WASI "Enable builtin wasi" ON)
option(ZEN_ENABLE_BUILTIN_LIBC "Enable builtin libc (partial)" ON)

# WebAssembly proposal options
option(ZEN_ENABLE_BULK_MEMORY "Enable bulk memory operations proposal" ON)
option(ZEN_ENABLE_LIBEVM "Enable evmc library build" OFF)

# Feature options
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ if(ZEN_ENABLE_BUILTIN_WASI)
add_definitions(-DZEN_ENABLE_BUILTIN_WASI)
endif()

if(ZEN_ENABLE_BULK_MEMORY)
add_definitions(-DZEN_ENABLE_BULK_MEMORY)
endif()

if(ZEN_ENABLE_BUILTIN_ENV)
add_definitions(-DZEN_ENABLE_BUILTIN_ENV)
endif()
Expand Down
46 changes: 46 additions & 0 deletions src/action/bytecode_visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,52 @@ template <typename IRBuilder> class WASMByteCodeVisitor {
handleIntExtend<WASMType::I64, WASMType::I32, true>();
break;

case common::WASM_PREFIX_FC: { // Bulk memory operations prefix
#ifdef ZEN_ENABLE_BULK_MEMORY
uint32_t SubOpcode;
Ip = readSafeLEBNumber(Ip, SubOpcode);
// Skip operands based on sub-opcode
switch (SubOpcode) {
case common::FC_MEMORY_INIT: // memory.init: dataidx(LEB) + memidx(1
// byte)
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
Ip++; // skip memidx
break;
case common::FC_DATA_DROP: // data.drop: dataidx(LEB)
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
break;
case common::FC_MEMORY_COPY: // memory.copy: 2 bytes
Ip += 2;
break;
case common::FC_MEMORY_FILL: // memory.fill: 1 byte
Ip++;
break;
case common::FC_TABLE_INIT: // table.init: elemidx(LEB) + tableidx(LEB)
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
break;
case common::FC_ELEM_DROP: // elem.drop: elemidx(LEB)
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
break;
case common::FC_TABLE_COPY: // table.copy: dst_tableidx(LEB) +
// src_tableidx(LEB)
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
Ip = utils::skipLEBNumber<uint32_t>(Ip, IpEnd);
break;
default:
break;
}
throw getErrorWithExtraMessage(
ErrorCode::UnsupportedOpcode,
"bulk memory operations not supported in JIT mode");
#else
throw getErrorWithExtraMessage(
ErrorCode::UnsupportedOpcode,
"bulk memory operations not enabled (compile with "
"ZEN_ENABLE_BULK_MEMORY=ON)");
#endif
}

default:
throw getErrorWithExtraMessage(ErrorCode::UnsupportedOpcode,
std::to_string(Opcode));
Expand Down
114 changes: 114 additions & 0 deletions src/action/function_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,120 @@ void FunctionLoader::load() {
case I64_EXTEND32_S:
popAndPushValueType(1, WASMType::I64, WASMType::I64);
break;
case WASM_PREFIX_FC: {
#ifdef ZEN_ENABLE_BULK_MEMORY
// Multi-byte opcode prefix for bulk memory operations
uint32_t SubOpcode = readU32();
switch (SubOpcode) {
case FC_MEMORY_INIT: { // memory.init: dataidx + 0x00
uint32_t DataIdx = readU32();
uint8_t MemIdx = to_underlying(readByte());
if (MemIdx != 0x00) {
throw getError(ErrorCode::ZeroFlagExpected);
}
if (Mod.DataCount == -1u) {
throw getError(ErrorCode::UnknownDataSegment);
}
if (!Mod.isValidDataSegment(DataIdx)) {
throw getError(ErrorCode::UnknownDataSegment);
}
if (!hasMemory()) {
throw getError(ErrorCode::UnknownMemory);
}
popValueType(WASMType::I32); // n
popValueType(WASMType::I32); // s
popValueType(WASMType::I32); // d
FuncCodeEntry.Stats |= Module::SF_memory;
break;
}
case FC_DATA_DROP: { // data.drop: dataidx
uint32_t DataIdx = readU32();
if (Mod.DataCount == -1u) {
throw getError(ErrorCode::UnknownDataSegment);
}
if (!Mod.isValidDataSegment(DataIdx)) {
throw getError(ErrorCode::UnknownDataSegment);
}
break;
}
case FC_MEMORY_COPY: { // memory.copy: 0x00 0x00
uint8_t DstMemIdx = to_underlying(readByte());
uint8_t SrcMemIdx = to_underlying(readByte());
if (DstMemIdx != 0x00 || SrcMemIdx != 0x00) {
throw getError(ErrorCode::ZeroFlagExpected);
}
if (!hasMemory()) {
throw getError(ErrorCode::UnknownMemory);
}
popValueType(WASMType::I32); // n
popValueType(WASMType::I32); // s
popValueType(WASMType::I32); // d
FuncCodeEntry.Stats |= Module::SF_memory;
break;
}
case FC_MEMORY_FILL: { // memory.fill: 0x00
uint8_t MemIdx = to_underlying(readByte());
if (MemIdx != 0x00) {
throw getError(ErrorCode::ZeroFlagExpected);
}
if (!hasMemory()) {
throw getError(ErrorCode::UnknownMemory);
}
popValueType(WASMType::I32); // n
popValueType(WASMType::I32); // val
popValueType(WASMType::I32); // d
FuncCodeEntry.Stats |= Module::SF_memory;
break;
}
case FC_TABLE_INIT: { // table.init: elemidx + tableidx
uint32_t ElemIdx = readU32();
uint32_t TableIdx = readU32();
if (!Mod.isValidElemSegment(ElemIdx)) {
throw getError(ErrorCode::UnknownElemSegment);
}
if (!Mod.isValidTable(TableIdx)) {
throw getError(ErrorCode::UnknownTable);
}
popValueType(WASMType::I32); // n
popValueType(WASMType::I32); // s
popValueType(WASMType::I32); // d
FuncCodeEntry.Stats |= Module::SF_table;
break;
}
case FC_ELEM_DROP: { // elem.drop: elemidx
uint32_t ElemIdx = readU32();
if (!Mod.isValidElemSegment(ElemIdx)) {
throw getError(ErrorCode::UnknownElemSegment);
}
break;
}
case FC_TABLE_COPY: { // table.copy: dst_tableidx + src_tableidx
uint32_t DstTableIdx = readU32();
uint32_t SrcTableIdx = readU32();
if (!Mod.isValidTable(DstTableIdx)) {
throw getError(ErrorCode::UnknownTable);
}
if (!Mod.isValidTable(SrcTableIdx)) {
throw getError(ErrorCode::UnknownTable);
}
popValueType(WASMType::I32); // n
popValueType(WASMType::I32); // s
popValueType(WASMType::I32); // d
FuncCodeEntry.Stats |= Module::SF_table;
break;
}
default:
throw getErrorWithExtraMessage(ErrorCode::UnsupportedOpcode,
"0xFC " + std::to_string(SubOpcode));
}
#else
throw getErrorWithExtraMessage(
ErrorCode::UnsupportedOpcode,
"bulk memory operations not enabled (compile with "
"ZEN_ENABLE_BULK_MEMORY=ON)");
#endif
break;
}
case I32_LOAD:
case I64_LOAD:
case F32_LOAD:
Expand Down
32 changes: 32 additions & 0 deletions src/action/instantiator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ void Instantiator::instantiateTables(Instance &Inst) {

for (uint32_t I = 0; I < Mod.NumElementSegments; ++I) {
const auto &Element = Mod.ElementTable[I];
#ifdef ZEN_ENABLE_BULK_MEMORY
if (Element.Mode != 0)
continue; // skip non-active segments
#endif
TableInstance &TableInst = Inst.Tables[Element.TableIdx];
uint32_t Offset = 0;
if (Element.InitExprKind == GET_GLOBAL) {
Expand Down Expand Up @@ -209,6 +213,10 @@ void Instantiator::initMemoryByDataSegments(Instance &Inst) {
const Module *Mod = Inst.Mod;
for (uint32_t I = 0; I < Mod->NumDataSegments; ++I) {
const auto &DataSeg = Mod->DataTable[I];
#ifdef ZEN_ENABLE_BULK_MEMORY
if (DataSeg.Mode != 0)
continue; // skip non-active segments
#endif
uint32_t MemIdx = DataSeg.MemIdx;
// should checked if MemIndex is valid in loader
MemoryInstance &MemInst = Inst.Memories[MemIdx];
Expand Down Expand Up @@ -349,6 +357,30 @@ void Instantiator::instantiate(Instance &Inst) {

instantiateMemories(Inst);

#ifdef ZEN_ENABLE_BULK_MEMORY
// Initialize dropped segment tracking arrays
if (Mod.NumDataSegments > 0) {
Inst.DroppedDataSegments =
(bool *)Inst.allocateZeros(sizeof(bool) * Mod.NumDataSegments);
// Mark active data segments as dropped after instantiation (per spec)
for (uint32_t I = 0; I < Mod.NumDataSegments; ++I) {
if (Mod.DataTable[I].Mode == 0) {
Inst.DroppedDataSegments[I] = true;
}
}
}
if (Mod.NumElementSegments > 0) {
Inst.DroppedElemSegments =
(bool *)Inst.allocateZeros(sizeof(bool) * Mod.NumElementSegments);
// Mark active element segments as dropped after instantiation (per spec)
for (uint32_t I = 0; I < Mod.NumElementSegments; ++I) {
if (Mod.ElementTable[I].Mode == 0) {
Inst.DroppedElemSegments[I] = true;
}
}
}
#endif

#ifdef ZEN_ENABLE_BUILTIN_WASI
if (!Inst.getRuntime()->getConfig().DisableWASI) {
instantiateWasi(Inst);
Expand Down
Loading
Loading