Skip to content

Commit

Permalink
Fix entry alignment issue with AssemblyScript maps (#461)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattjohnsonpint authored Oct 13, 2024
1 parent 5584603 commit ff178a9
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ In previous releases, the name "Hypermode" was used for all three._
- Improve `.env` file handling [#458](https://github.com/hypermodeinc/modus/pull/458)
- Update command-line args and env variables [#459](https://github.com/hypermodeinc/modus/pull/459)
- Update Sentry telemetry collection rules [#460](https://github.com/hypermodeinc/modus/pull/460)
- Fix entry alignment issue with AssemblyScript maps [#461](https://github.com/hypermodeinc/modus/pull/461)

## 2024-10-02 - Version 0.12.7

Expand Down
18 changes: 11 additions & 7 deletions runtime/languages/assemblyscript/handler_maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func (h *mapHandler) Read(ctx context.Context, wa langsupport.WasmAdapter, offse
entrySize := byteLength / entriesCapacity
keySize := h.keyHandler.TypeInfo().Size()
valueOffset := max(keySize, 4)
valueAlign := h.valueHandler.TypeInfo().Alignment()

if !h.usePseudoMap {
// return a map
Expand All @@ -144,7 +145,8 @@ func (h *mapHandler) Read(ctx context.Context, wa langsupport.WasmAdapter, offse
return nil, err
}

v, err := h.valueHandler.Read(ctx, wa, p+valueOffset)
p += langsupport.AlignOffset(valueOffset, valueAlign)
v, err := h.valueHandler.Read(ctx, wa, p)
if err != nil {
return nil, err
}
Expand All @@ -164,7 +166,8 @@ func (h *mapHandler) Read(ctx context.Context, wa langsupport.WasmAdapter, offse
return nil, err
}

v, err := h.valueHandler.Read(ctx, wa, p+keySize)
p += langsupport.AlignOffset(valueOffset, valueAlign)
v, err := h.valueHandler.Read(ctx, wa, p)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -211,13 +214,14 @@ func (h *mapHandler) Write(ctx context.Context, wa langsupport.WasmAdapter, offs
// note: unlike arrays, an empty map DOES have array buffers
keySize := h.keyHandler.TypeInfo().Size()
valueSize := h.valueHandler.TypeInfo().Size()
valueOffset := max(keySize, 4)
valueAlign := h.valueHandler.TypeInfo().Alignment()
valueOffset := langsupport.AlignOffset(max(keySize, 4), valueAlign)

const taggedNextSize = 4
taggedNextOffset := valueSize + valueOffset
taggedNextOffset := valueOffset + langsupport.AlignOffset(valueSize, valueAlign)

entryAlign := max(keySize, valueSize, 4) - 1
entrySize := (keySize + valueSize + taggedNextSize + entryAlign) & ^entryAlign
entryAlign := max(keySize, valueSize, taggedNextSize)
entrySize := langsupport.AlignOffset(taggedNextOffset+taggedNextSize, entryAlign)
entriesBufferSize := entrySize * entriesCapacity
entriesBufferOffset, c, err := wa.AllocateMemory(ctx, entriesBufferSize)
cln.AddCleaner(c)
Expand Down Expand Up @@ -259,7 +263,7 @@ func (h *mapHandler) Write(ctx context.Context, wa langsupport.WasmAdapter, offs

// write entry value
value := vals[i]
entryValueOffset := entryOffset + valueOffset
entryValueOffset := entryOffset + langsupport.AlignOffset(valueOffset, valueAlign)
c, err := h.valueHandler.Write(ctx, wa, entryValueOffset, value)
cln.AddCleaner(c)
if err != nil {
Expand Down
29 changes: 29 additions & 0 deletions runtime/languages/assemblyscript/testdata/assembly/maps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,32 @@ export function testClassContainingMapOutput_string_string(): TestClassWithMap {
c.m.set("c", "3");
return c;
}

export function testMapInput_string_f64(m: Map<string, f64>): void {
assert(m.size == 4, "expected size 4");

let n: f64 = 0.5;
assert(m.has("a"), "expected key 'a' to be present");
assert(m.get("a") == n, `expected value for key 'a' to be ${n}`);

n = f64.EPSILON;
assert(m.has("b"), "expected key 'b' to be present");
assert(m.get("b") == n, `expected value for key 'b' to be ${n}`);

n = f64.MIN_VALUE;
assert(m.has("c"), "expected key 'c' to be present");
assert(m.get("c") == n, `expected value for key 'c' to be ${n}`);

n = f64.MAX_VALUE;
assert(m.has("d"), "expected key 'd' to be present");
assert(m.get("d") == n, `expected value for key 'd' to be ${n}`);
}

export function testMapOutput_string_f64(): Map<string, f64> {
const m = new Map<string, f64>();
m.set("a", 0.5);
m.set("b", f64.EPSILON);
m.set("c", f64.MIN_VALUE);
m.set("d", f64.MAX_VALUE);
return m;
}
Binary file modified runtime/languages/assemblyscript/testdata/build/testdata.wasm
Binary file not shown.
45 changes: 45 additions & 0 deletions runtime/languages/assemblyscript/tests/maps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package assemblyscript_test
import (
"fmt"
"maps"
"math"
"reflect"
"testing"

Expand Down Expand Up @@ -232,3 +233,47 @@ func makeTestMap(size int) map[string]string {
}
return m
}

var epsilon = math.Nextafter(1, 2) - 1

func TestMapInput_string_f64(t *testing.T) {
fnName := "testMapInput_string_f64"
m := map[string]float64{
"a": 0.5,
"b": epsilon,
"c": math.SmallestNonzeroFloat64,
"d": math.MaxFloat64,
}

if _, err := fixture.CallFunction(t, fnName, m); err != nil {
t.Error(err)
}
if m, err := utils.ConvertToMap(m); err != nil {
t.Error(fmt.Errorf("failed conversion to interface map: %w", err))
} else if _, err := fixture.CallFunction(t, fnName, m); err != nil {
t.Error(err)
}
}

func TestMapOutput_string_f64(t *testing.T) {
fnName := "testMapOutput_string_f64"
result, err := fixture.CallFunction(t, fnName)
if err != nil {
t.Fatal(err)
}

expected := map[string]float64{
"a": 0.5,
"b": epsilon,
"c": math.SmallestNonzeroFloat64,
"d": math.MaxFloat64,
}

if result == nil {
t.Error("expected a result")
} else if r, ok := result.(map[string]float64); !ok {
t.Errorf("expected %T, got %T", expected, result)
} else if !maps.Equal(expected, r) {
t.Errorf("expected %v, got %v", expected, r)
}
}

0 comments on commit ff178a9

Please sign in to comment.