Skip to content

Commit e018404

Browse files
authored
wasm-interp: Handle refs_ correctly (#2484)
This fills in some TODOs, and cleans up some other issues, relevant for GC later on. We tried our best to make this efficient, hence the custom wabt opcodes.
1 parent ad72048 commit e018404

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

include/wabt/opcode.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe3, InterpData, "data", "")
235235
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe4, InterpDropKeep, "drop_keep", "")
236236
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe5, InterpCatchDrop, "catch_drop", "")
237237
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe6, InterpAdjustFrameForReturnCall, "adjust_frame_for_return_call", "")
238+
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe7, InterpGlobalGetRef, "global.get.ref", "")
239+
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xe9, InterpLocalGetRef, "local.get.ref", "")
240+
WABT_OPCODE(___, ___, ___, ___, 0, 0, 0xea, InterpMarkRef, "mark_ref", "")
238241

239242
/* Saturating float-to-int opcodes (--enable-saturating-float-to-int) */
240243
WABT_OPCODE(I32, F32, ___, ___, 0, 0xfc, 0x00, I32TruncSatF32S, "i32.trunc_sat_f32_s", "")

src/interp/binary-reader-interp.cc

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,11 @@ Result BinaryReaderInterp::OnLocalDecl(Index decl_index,
875875
Result BinaryReaderInterp::EndLocalDecls() {
876876
if (local_count_ != 0) {
877877
istream_.Emit(Opcode::InterpAlloca, local_count_);
878+
for (Index i = 0; i < local_count_; i++) {
879+
if (func_->GetLocalType(func_->type.params.size() + i).IsRef()) {
880+
istream_.Emit(Opcode::InterpMarkRef, local_count_ - i);
881+
}
882+
}
878883
}
879884
// Continuation of the implicit func label, used for exception handling. (See
880885
// BeginFunctionBody.)
@@ -1274,7 +1279,13 @@ Result BinaryReaderInterp::OnV128ConstExpr(v128 value_bits) {
12741279
Result BinaryReaderInterp::OnGlobalGetExpr(Index global_index) {
12751280
CHECK_RESULT(
12761281
validator_.OnGlobalGet(GetLocation(), Var(global_index, GetLocation())));
1277-
istream_.Emit(Opcode::GlobalGet, global_index);
1282+
1283+
Type type = global_types_.at(global_index).type;
1284+
if (type.IsRef()) {
1285+
istream_.Emit(Opcode::InterpGlobalGetRef, global_index);
1286+
} else {
1287+
istream_.Emit(Opcode::GlobalGet, global_index);
1288+
}
12781289
return Result::Ok;
12791290
}
12801291

@@ -1297,7 +1308,13 @@ Result BinaryReaderInterp::OnLocalGetExpr(Index local_index) {
12971308
Index translated_local_index = TranslateLocalIndex(local_index);
12981309
CHECK_RESULT(
12991310
validator_.OnLocalGet(GetLocation(), Var(local_index, GetLocation())));
1300-
istream_.Emit(Opcode::LocalGet, translated_local_index);
1311+
1312+
Type type = func_->GetLocalType(local_index);
1313+
if (type.IsRef()) {
1314+
istream_.Emit(Opcode::InterpLocalGetRef, translated_local_index);
1315+
} else {
1316+
istream_.Emit(Opcode::LocalGet, translated_local_index);
1317+
}
13011318
return Result::Ok;
13021319
}
13031320

@@ -1306,13 +1323,15 @@ Result BinaryReaderInterp::OnLocalSetExpr(Index local_index) {
13061323
Index translated_local_index = TranslateLocalIndex(local_index);
13071324
CHECK_RESULT(
13081325
validator_.OnLocalSet(GetLocation(), Var(local_index, GetLocation())));
1326+
13091327
istream_.Emit(Opcode::LocalSet, translated_local_index);
13101328
return Result::Ok;
13111329
}
13121330

13131331
Result BinaryReaderInterp::OnLocalTeeExpr(Index local_index) {
13141332
CHECK_RESULT(
13151333
validator_.OnLocalTee(GetLocation(), Var(local_index, GetLocation())));
1334+
13161335
istream_.Emit(Opcode::LocalTee, TranslateLocalIndex(local_index));
13171336
return Result::Ok;
13181337
}

src/interp/interp.cc

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ T WABT_VECTORCALL Thread::Pop() {
11311131
}
11321132

11331133
Value Thread::Pop() {
1134-
if (!refs_.empty() && refs_.back() >= values_.size()) {
1134+
if (!refs_.empty() && refs_.back() >= values_.size() - 1) {
11351135
refs_.pop_back();
11361136
}
11371137
auto value = values_.back();
@@ -1254,16 +1254,24 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
12541254
break;
12551255

12561256
case O::Select: {
1257-
// TODO: need to mark whether this is a ref.
12581257
auto cond = Pop<u32>();
1258+
auto ref = false;
1259+
// check if either is a ref
1260+
ref |= !refs_.empty() && refs_.back() == values_.size();
12591261
Value false_ = Pop();
1262+
ref |= !refs_.empty() && refs_.back() == values_.size();
12601263
Value true_ = Pop();
1264+
if (ref) {
1265+
refs_.push_back(values_.size());
1266+
}
12611267
Push(cond ? true_ : false_);
12621268
break;
12631269
}
12641270

1271+
case O::InterpLocalGetRef:
1272+
refs_.push_back(values_.size());
1273+
[[fallthrough]];
12651274
case O::LocalGet:
1266-
// TODO: need to mark whether this is a ref.
12671275
Push(Pick(instr.imm_u32));
12681276
break;
12691277

@@ -1277,8 +1285,14 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
12771285
Pick(instr.imm_u32) = Pick(1);
12781286
break;
12791287

1288+
case O::InterpMarkRef:
1289+
refs_.push_back(values_.size() - instr.imm_u32);
1290+
break;
1291+
1292+
case O::InterpGlobalGetRef:
1293+
refs_.push_back(values_.size());
1294+
[[fallthrough]];
12801295
case O::GlobalGet: {
1281-
// TODO: need to mark whether this is a ref.
12821296
Global::Ptr global{store_, inst_->globals()[instr.imm_u32]};
12831297
Push(global->Get());
12841298
break;
@@ -1478,9 +1492,7 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
14781492

14791493
case O::InterpAlloca:
14801494
values_.resize(values_.size() + instr.imm_u32);
1481-
// refs_ doesn't need to be updated; We may be allocating space for
1482-
// references, but they will be initialized to null, so it is OK if we
1483-
// don't mark them.
1495+
// refs_ will be marked in InterpMarkRef.
14841496
break;
14851497

14861498
case O::InterpBrUnless:
@@ -1499,13 +1511,23 @@ RunResult Thread::StepInternal(Trap::Ptr* out_trap) {
14991511
auto drop = instr.imm_u32x2.fst;
15001512
auto keep = instr.imm_u32x2.snd;
15011513
// Shift kept refs down.
1502-
for (auto iter = refs_.rbegin(); iter != refs_.rend(); ++iter) {
1514+
auto iter = refs_.rbegin();
1515+
for (; iter != refs_.rend(); ++iter) {
15031516
if (*iter >= values_.size() - keep) {
15041517
*iter -= drop;
15051518
} else {
15061519
break;
15071520
}
15081521
}
1522+
// Find dropped refs.
1523+
auto drop_iter = iter;
1524+
for (; drop_iter != refs_.rend(); ++drop_iter) {
1525+
if (*iter < values_.size() - keep - drop) {
1526+
break;
1527+
}
1528+
}
1529+
// Erase dropped refs.
1530+
refs_.erase(drop_iter.base(), iter.base());
15091531
std::move(values_.end() - keep, values_.end(),
15101532
values_.end() - drop - keep);
15111533
values_.resize(values_.size() - drop);

src/interp/istream.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ Instr Istream::Read(Offset* offset) const {
515515

516516
case Opcode::GlobalGet:
517517
case Opcode::LocalGet:
518+
case Opcode::InterpLocalGetRef:
519+
case Opcode::InterpGlobalGetRef:
520+
case Opcode::InterpMarkRef:
518521
case Opcode::MemorySize:
519522
case Opcode::TableSize:
520523
case Opcode::DataDrop:

0 commit comments

Comments
 (0)