Skip to content

Commit

Permalink
Memory64: support 64-bit data init-expr (#1656)
Browse files Browse the repository at this point in the history
  • Loading branch information
aardappel authored Apr 5, 2021
1 parent 15a5156 commit 3c79f17
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 26 deletions.
22 changes: 11 additions & 11 deletions src/binary-reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ class BinaryReader {

Index NumTotalFuncs();

Result ReadI32InitExpr(Index index) WABT_WARN_UNUSED;
Result ReadInitExpr(Index index, bool require_i32 = false) WABT_WARN_UNUSED;
Result ReadInitExpr(Index index, Type required = Type::Any) WABT_WARN_UNUSED;
Result ReadTable(Type* out_elem_type,
Limits* out_elem_limits) WABT_WARN_UNUSED;
Result ReadMemory(Limits* out_page_limits) WABT_WARN_UNUSED;
Expand Down Expand Up @@ -468,11 +467,7 @@ Index BinaryReader::NumTotalFuncs() {
return num_func_imports_ + num_function_signatures_;
}

Result BinaryReader::ReadI32InitExpr(Index index) {
return ReadInitExpr(index, true);
}

Result BinaryReader::ReadInitExpr(Index index, bool require_i32) {
Result BinaryReader::ReadInitExpr(Index index, Type required) {
Opcode opcode;
CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
ERROR_UNLESS_OPCODE_ENABLED(opcode);
Expand Down Expand Up @@ -542,11 +537,16 @@ Result BinaryReader::ReadInitExpr(Index index, bool require_i32) {
return ReportUnexpectedOpcode(opcode, "in initializer expression");
}

if (require_i32 && opcode != Opcode::I32Const &&
opcode != Opcode::GlobalGet) {
if (required == Type::I32 && opcode != Opcode::I32Const &&
opcode != Opcode::GlobalGet) {
PrintError("expected i32 init_expr");
return Result::Error;
}
if (required == Type::I64 && opcode != Opcode::I64Const &&
opcode != Opcode::GlobalGet) {
PrintError("expected i64 init_expr");
return Result::Error;
}

CHECK_RESULT(ReadOpcode(&opcode, "opcode"));
ERROR_UNLESS(opcode == Opcode::End,
Expand Down Expand Up @@ -2443,7 +2443,7 @@ Result BinaryReader::ReadElemSection(Offset section_size) {

if (!(flags & SegPassive)) {
CALLBACK(BeginElemSegmentInitExpr, i);
CHECK_RESULT(ReadI32InitExpr(i));
CHECK_RESULT(ReadInitExpr(i, Type::I32));
CALLBACK(EndElemSegmentInitExpr, i);
}

Expand Down Expand Up @@ -2559,7 +2559,7 @@ Result BinaryReader::ReadDataSection(Offset section_size) {
CALLBACK(BeginDataSegment, i, memory_index, flags);
if (!(flags & SegPassive)) {
CALLBACK(BeginDataSegmentInitExpr, i);
CHECK_RESULT(ReadI32InitExpr(i));
CHECK_RESULT(ReadInitExpr(i, memories[0].IndexType()));
CALLBACK(EndDataSegmentInitExpr, i);
}

Expand Down
1 change: 1 addition & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ struct Limits {
has_max(true),
is_shared(is_shared),
is_64(is_64) {}
Type IndexType() const { return is_64 ? Type::I64 : Type::I32; }

uint64_t initial = 0;
uint64_t max = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/interp/binary-reader-interp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,10 @@ Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
CHECK_RESULT(validator_.OnDataSegmentInitExpr_Const(loc, ValueType::I32));
break;

case InitExprKind::I64:
CHECK_RESULT(validator_.OnDataSegmentInitExpr_Const(loc, ValueType::I64));
break;

case InitExprKind::GlobalGet:
CHECK_RESULT(validator_.OnDataSegmentInitExpr_GlobalGet(
loc, Var(init_expr_.index_)));
Expand Down
9 changes: 6 additions & 3 deletions src/interp/interp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,9 @@ Instance::Ptr Instance::Instantiate(Store& store,
if (desc.mode == SegmentMode::Active) {
Result result;
Memory::Ptr memory{store, inst->memories_[desc.memory_index]};
u32 offset = inst->ResolveInitExpr(store, desc.offset).Get<u32>();
Value offset_op = inst->ResolveInitExpr(store, desc.offset);
u64 offset = memory->type().limits.is_64 ? offset_op.Get<u64>()
: offset_op.Get<u32>();
if (pass == Check) {
result = memory->IsValidAccess(offset, 0, segment.size())
? Result::Ok
Expand All @@ -864,8 +866,9 @@ Instance::Ptr Instance::Instantiate(Store& store,
*out_trap = Trap::New(
store,
StringPrintf("out of bounds memory access: data segment is "
"out of bounds: [%u, %" PRIu64 ") >= max value %"
PRIu64, offset, u64{offset} + segment.size(),
"out of bounds: [%" PRIu64 ", %" PRIu64
") >= max value %"
PRIu64, offset, offset + segment.size(),
memory->ByteSize()));
return {};
}
Expand Down
10 changes: 7 additions & 3 deletions src/shared-validator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,9 @@ Result SharedValidator::OnDataSegment(const Location& loc,

Result SharedValidator::OnDataSegmentInitExpr_Const(const Location& loc,
Type type) {
return CheckType(loc, type, Type::I32, "data segment offset");
auto required =
memories_.empty() ? Type(Type::I32) : memories_[0].limits.IndexType();
return CheckType(loc, type, required, "data segment offset");
}

Result SharedValidator::OnDataSegmentInitExpr_GlobalGet(const Location& loc,
Expand All @@ -385,14 +387,16 @@ Result SharedValidator::OnDataSegmentInitExpr_GlobalGet(const Location& loc,
loc, "initializer expression cannot reference a mutable global");
}

result |= CheckType(loc, ref_global.type, Type::I32, "data segment offset");
auto required =
memories_.empty() ? Type(Type::I32) : memories_[0].limits.IndexType();
result |= CheckType(loc, ref_global.type, required, "data segment offset");
return result;
}

Result SharedValidator::OnDataSegmentInitExpr_Other(const Location& loc) {
return PrintError(loc,
"invalid data segment offset, must be a constant "
"expression; either i32.const or "
"expression; either iXX.const or "
"global.get.");
}

Expand Down
2 changes: 1 addition & 1 deletion src/type-checker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ Result TypeChecker::OnMemoryInit(uint32_t segment, const Limits& limits) {
}

Result TypeChecker::OnMemorySize(const Limits& limits) {
PushType(limits.is_64 ? Type::I64 : Type::I32);
PushType(limits.IndexType());
return Result::Ok;
}

Expand Down
3 changes: 2 additions & 1 deletion src/wast-parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,8 @@ Result WastParser::ParseMemoryModuleField(Module* module) {
auto data_segment_field = MakeUnique<DataSegmentModuleField>(loc);
DataSegment& data_segment = data_segment_field->data_segment;
data_segment.memory_var = Var(module->memories.size());
data_segment.offset.push_back(MakeUnique<ConstExpr>(Const::I32(0)));
data_segment.offset.push_back(MakeUnique<ConstExpr>(
field->memory.page_limits.is_64 ? Const::I64(0) : Const::I32(0)));
data_segment.offset.back().loc = loc;
ParseTextListOpt(&data_segment.data);
EXPECT(Rpar);
Expand Down
8 changes: 4 additions & 4 deletions test/interp/load64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
;;; ARGS: --enable-memory64
(module
(memory i64 1)
(data (i32.const 0) "\ff\ff\ff\ff")
(data (i32.const 4) "\00\00\ce\41")
(data (i32.const 8) "\00\00\00\00\00\ff\8f\40")
(data (i32.const 16) "\ff\ff\ff\ff\ff\ff\ff\ff")
(data (i64.const 0) "\ff\ff\ff\ff")
(data (i64.const 4) "\00\00\ce\41")
(data (i64.const 8) "\00\00\00\00\00\ff\8f\40")
(data (i64.const 16) "\ff\ff\ff\ff\ff\ff\ff\ff")

(func (export "i32_load8_s") (result i32)
i64.const 0
Expand Down
2 changes: 1 addition & 1 deletion test/regress/regress-27.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ section(DATA) {
data[str("test")]
}
(;; STDERR ;;;
error: invalid data segment offset, must be a constant expression; either i32.const or global.get.
error: invalid data segment offset, must be a constant expression; either iXX.const or global.get.
0000012: error: EndDataSegmentInitExpr callback failed
;;; STDERR ;;)
2 changes: 1 addition & 1 deletion test/spec/data.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ out/test/spec/data.wast:337: assert_invalid passed:
out/test/spec/data.wast:355: assert_invalid passed:
0000013: error: expected i32 init_expr
out/test/spec/data.wast:363: assert_invalid passed:
error: invalid data segment offset, must be a constant expression; either i32.const or global.get.
error: invalid data segment offset, must be a constant expression; either iXX.const or global.get.
0000012: error: EndDataSegmentInitExpr callback failed
out/test/spec/data.wast:371: assert_invalid passed:
0000014: error: expected END opcode after initializer expression
Expand Down

0 comments on commit 3c79f17

Please sign in to comment.