Skip to content

Commit 41b5a8f

Browse files
committed
[stack-switching] Compression tests for relocatable frames
1 parent 9215c09 commit 41b5a8f

1 file changed

Lines changed: 149 additions & 2 deletions

File tree

test/unittest/CompressionTest.v3

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,20 @@ def X_ = registerAll([
4141
("multi_frames", test_multi_frames),
4242
("single_val_per_frame", test_single_val_per_frame),
4343
("cont", test_cont),
44-
("frame_metadata", test_frame_metadata)
44+
("frame_metadata", test_frame_metadata),
45+
("repeated_vals", test_repeated_vals),
46+
("repeated_across_frames", test_repeated_across_frames),
47+
("many_diverse_vals", test_many_diverse_vals),
48+
("many_frames_diverse", test_many_frames_diverse),
49+
("refs_mixed", test_refs_mixed),
50+
("refs_shared_across_frames", test_refs_shared_across_frames),
51+
("large_uniform_frames", test_large_uniform_frames)
4552
]);
4653

4754
def registerAll(tests: Array<(string, CompressionTester -> void)>) {
4855
for (t in tests) {
4956
for (s in strategies) {
50-
var name = Strings.format2("compression:%s_%s", s.0, t.0);
57+
var name = Strings.format2("compression:%s:%s", s.0, t.0);
5158
var adapter = s.1;
5259
UnitTests.registerT(name, "", CompressionTester.new(_, adapter), t.1);
5360
}
@@ -246,3 +253,143 @@ def test_frame_metadata(t: CompressionTester) {
246253
if (got[0].pc != 42) t.t.fail1("expected pc=42, got pc=%d", got[0].pc);
247254
t.assert_vals_eq([Value.I32(99)], got[0].vals);
248255
}
256+
257+
// === Part 5: Repeated values ===
258+
259+
// Many identical values within a single frame.
260+
def test_repeated_vals(t: CompressionTester) {
261+
var vals = Array<Value>.new(100);
262+
for (i < vals.length) vals[i] = Value.I32(0xCAFEBABEu);
263+
t.assert_roundtrip_vals(vals);
264+
265+
// Repeat with i64.
266+
for (i < vals.length) vals[i] = Value.I64(0xDEADBEEF00000000uL);
267+
t.assert_roundtrip_vals(vals);
268+
269+
// Repeat with the same ref object.
270+
var obj = HeapObject.new(null, []);
271+
for (i < vals.length) vals[i] = Value.Ref(obj);
272+
t.assert_roundtrip_vals(vals);
273+
}
274+
275+
// Same repeating value pattern across multiple frames.
276+
def test_repeated_across_frames(t: CompressionTester) {
277+
var frames = Array<RelocatableFrame>.new(20);
278+
var shared_vals: Array<Value> = [Value.I32(42), Value.I64(42), Value.F32(42)];
279+
for (i < frames.length) frames[i] = t.make_frame(i, shared_vals);
280+
var got = t.roundtrip(frames);
281+
t.assert_frames_eq(frames, got);
282+
}
283+
284+
// === Part 6: Many diverse values ===
285+
286+
// Single frame with many values of varying types and magnitudes.
287+
def test_many_diverse_vals(t: CompressionTester) {
288+
var vals = Vector<Value>.new();
289+
for (i < 50) {
290+
vals.put(Value.I32(u32.view(i * 7)));
291+
vals.put(Value.I64(u64.view(i) * 0x100000001uL));
292+
vals.put(Value.F32(u32.view(i * 31)));
293+
vals.put(Value.F64(u64.view(i) * 0x123456789uL));
294+
}
295+
t.assert_roundtrip_vals(vals.extract());
296+
}
297+
298+
// Many frames, each with distinct values and varying sizes.
299+
def test_many_frames_diverse(t: CompressionTester) {
300+
var frames = Vector<RelocatableFrame>.new();
301+
for (i < 30) {
302+
var n_vals = (i % 5) + 1; // 1 to 5 values per frame
303+
var vals = Array<Value>.new(n_vals);
304+
for (j < n_vals) {
305+
var k = i * 5 + j;
306+
match (k % 4) {
307+
0 => vals[j] = Value.I32(u32.view(k * 13));
308+
1 => vals[j] = Value.I64(u64.view(k) * 0xABCDuL);
309+
2 => vals[j] = Value.F32(u32.view(k * 97));
310+
_ => vals[j] = Value.F64(u64.view(k) * 0x1111111111uL);
311+
}
312+
}
313+
frames.put(t.make_frame(i * 3, vals));
314+
}
315+
var input = frames.extract();
316+
var got = t.roundtrip(input);
317+
t.assert_frames_eq(input, got);
318+
}
319+
320+
// === Part 7: Complex reference objects ===
321+
322+
// Multiple distinct reference types in a single frame.
323+
def test_refs_mixed(t: CompressionTester) {
324+
var heap_obj = HeapObject.new(null, []);
325+
var host_obj = HostObject.new();
326+
var host_fn = HostFunction.new("test_fn", SigCache.v_v, nop_host);
327+
var vals: Array<Value> = [
328+
Value.Ref(heap_obj),
329+
Value.Ref(host_obj),
330+
Value.Ref(host_fn),
331+
Value.Ref(null),
332+
Value.Ref(heap_obj), // same object again
333+
Value.Ref(host_obj) // same object again
334+
];
335+
var frames = [t.make_frame(0, vals)];
336+
var got = t.roundtrip(frames);
337+
t.assert_length(1, got.length, "frames");
338+
t.assert_length(vals.length, got[0].vals.length, "values");
339+
// Verify identity for each ref.
340+
for (i < vals.length) {
341+
match (vals[i]) {
342+
Ref(expected) => match (got[0].vals[i]) {
343+
Ref(actual) => if (expected != actual) t.t.fail1("ref[%d]: identity not preserved", i);
344+
_ => t.t.fail1("ref[%d]: expected Ref", i);
345+
}
346+
_ => ;
347+
}
348+
}
349+
}
350+
351+
def nop_host(args: Range<Value>) -> HostResult { return HostResult.Value0; }
352+
353+
// Shared reference objects across multiple frames.
354+
def test_refs_shared_across_frames(t: CompressionTester) {
355+
var obj_a = HeapObject.new(null, [Value.I32(1)]);
356+
var obj_b = HostObject.new();
357+
var frames = [
358+
t.make_frame(0, [Value.Ref(obj_a), Value.I32(10)]),
359+
t.make_frame(1, [Value.Ref(obj_b), Value.Ref(obj_a)]),
360+
t.make_frame(2, [Value.Ref(obj_a), Value.Ref(obj_b), Value.Ref(null)])
361+
];
362+
var got = t.roundtrip(frames);
363+
t.assert_frames_eq(frames, got);
364+
// Verify cross-frame identity: obj_a in frame 0 == obj_a in frame 1 and 2.
365+
var get_ref = get_ref_val;
366+
var a0 = get_ref(got[0].vals[0]);
367+
var a1 = get_ref(got[1].vals[1]);
368+
var a2 = get_ref(got[2].vals[0]);
369+
if (a0 != a1) t.t.fail("obj_a identity not preserved across frames 0 and 1");
370+
if (a0 != a2) t.t.fail("obj_a identity not preserved across frames 0 and 2");
371+
var b1 = get_ref(got[1].vals[0]);
372+
var b2 = get_ref(got[2].vals[1]);
373+
if (b1 != b2) t.t.fail("obj_b identity not preserved across frames 1 and 2");
374+
}
375+
376+
def get_ref_val(v: Value) -> Object {
377+
match (v) {
378+
Ref(obj) => return obj;
379+
_ => return null;
380+
}
381+
}
382+
383+
// Many frames with uniform large value counts.
384+
def test_large_uniform_frames(t: CompressionTester) {
385+
var n_frames = 20;
386+
var n_vals = 50;
387+
var frames = Array<RelocatableFrame>.new(n_frames);
388+
for (i < n_frames) {
389+
var vals = Array<Value>.new(n_vals);
390+
for (j < n_vals) vals[j] = Value.I64(u64.view(i * n_vals + j));
391+
frames[i] = t.make_frame(i, vals);
392+
}
393+
var got = t.roundtrip(frames);
394+
t.assert_frames_eq(frames, got);
395+
}

0 commit comments

Comments
 (0)