From a185be90f1c6c3f0d11e0f306d2e80ab5abc4a19 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 13 Aug 2024 23:04:29 +0200 Subject: [PATCH 01/25] save --- gnovm/pkg/gnolang/alloc.go | 6 ++++-- gnovm/pkg/gnolang/gonative.go | 1 + gnovm/pkg/gnolang/machine.go | 5 +++++ gnovm/pkg/gnolang/op_expressions.go | 20 +++++++++++++++++-- gnovm/pkg/gnolang/values.go | 30 ++++++++++++++++++++++------- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index 6fef5eda834..f6c7bede90d 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -196,14 +196,16 @@ func (alloc *Allocator) NewString(s string) StringValue { func (alloc *Allocator) NewListArray(n int) *ArrayValue { alloc.AllocateListArray(int64(n)) return &ArrayValue{ - List: make([]TypedValue, n), + List: make([]TypedValue, n), + NotAddressible: true, } } func (alloc *Allocator) NewDataArray(n int) *ArrayValue { alloc.AllocateDataArray(int64(n)) return &ArrayValue{ - Data: make([]byte, n), + Data: make([]byte, n), + NotAddressible: true, } } diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 6127fa42b07..2ccc2dd239f 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -715,6 +715,7 @@ func go2GnoValue2(alloc *Allocator, store Store, rv reflect.Value, recursive boo } } tv.V = av + tv.NotAddressable = av.NotAddressible } case reflect.Slice: rvl := rv.Len() diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 24f94abc10b..6448c5b1d3d 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2087,6 +2087,11 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { case *IndexExpr: iv := m.PopValue() xv := m.PopValue() + + if xv.NotAddressable { + panic("not addressable") + } + return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) case *SelectorExpr: xv := m.PopValue() diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 36130ccbf4d..c3454c21cb0 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -16,6 +16,11 @@ func (m *Machine) doOpIndex1() { } iv := m.PopValue() // index xv := m.PeekValue(1) // x + + if xv.NotAddressable { + panic("not addressable") + } + switch ct := baseOf(xv.T).(type) { case *MapType: mv := xv.V.(*MapValue) @@ -44,6 +49,11 @@ func (m *Machine) doOpIndex2() { } iv := m.PeekValue(1) // index xv := m.PeekValue(2) // x + + if xv.NotAddressable { + panic("not addressable") + } + switch ct := baseOf(xv.T).(type) { case *MapType: vt := ct.Value @@ -105,6 +115,11 @@ func (m *Machine) doOpSlice() { } // slice base x xv := m.PopValue() + + if xv.NotAddressable { + panic("not addressable") + } + // if a is a pointer to an array, a[low : high : max] is // shorthand for (*a)[low : high : max] if xv.T.Kind() == PointerKind && @@ -545,8 +560,9 @@ func (m *Machine) doOpArrayLit() { } // push value m.PushValue(TypedValue{ - T: at, - V: av, + T: at, + V: av, + NotAddressable: av.NotAddressible, }) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 5da7c15bb05..ef5824e094d 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -315,8 +315,9 @@ func (pv PointerValue) Deref() (tv TypedValue) { type ArrayValue struct { ObjectInfo - List []TypedValue - Data []byte + List []TypedValue + Data []byte + NotAddressible bool } // NOTE: Result should not be written to, @@ -392,6 +393,7 @@ func (av *ArrayValue) Copy(alloc *Allocator) *ArrayValue { if av.Data == nil { av2 := alloc.NewListArray(len(av.List)) copy(av2.List, av.List) + av2.NotAddressible = av.NotAddressible return av2 } av2 := alloc.NewDataArray(len(av.Data)) @@ -955,9 +957,10 @@ func (nv *NativeValue) Copy(alloc *Allocator) *NativeValue { // TypedValue (is not a value, but a tuple) type TypedValue struct { - T Type `json:",omitempty"` // never nil - V Value `json:",omitempty"` // an untyped value - N [8]byte `json:",omitempty"` // numeric bytes + T Type `json:",omitempty"` // never nil + V Value `json:",omitempty"` // an untyped value + N [8]byte `json:",omitempty"` // numeric bytes + NotAddressable bool `json:"-"` } func (tv *TypedValue) IsDefined() bool { @@ -2589,9 +2592,22 @@ func defaultTypedValue(alloc *Allocator, t Type) TypedValue { if t.Kind() == InterfaceKind { return TypedValue{} } + + dv := defaultValue(alloc, t) + + var naddr bool + + switch v := dv.(type) { + case *StructValue: + naddr = true + case *ArrayValue: + naddr = v.NotAddressible + } + return TypedValue{ - T: t, - V: defaultValue(alloc, t), + T: t, + V: dv, + NotAddressable: naddr, } } From d5742ae73d4b5b28447a5915727812e5bc921a85 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 13 Aug 2024 23:18:08 +0200 Subject: [PATCH 02/25] save --- gnovm/pkg/gnolang/machine.go | 2 +- gnovm/pkg/gnolang/op_expressions.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 6448c5b1d3d..7bbda026338 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2089,7 +2089,7 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { xv := m.PopValue() if xv.NotAddressable { - panic("not addressable") + panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) } return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index c3454c21cb0..86c5f147507 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -18,7 +18,7 @@ func (m *Machine) doOpIndex1() { xv := m.PeekValue(1) // x if xv.NotAddressable { - panic("not addressable") + panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) } switch ct := baseOf(xv.T).(type) { @@ -51,7 +51,7 @@ func (m *Machine) doOpIndex2() { xv := m.PeekValue(2) // x if xv.NotAddressable { - panic("not addressable") + panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) } switch ct := baseOf(xv.T).(type) { @@ -117,7 +117,7 @@ func (m *Machine) doOpSlice() { xv := m.PopValue() if xv.NotAddressable { - panic("not addressable") + panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) } // if a is a pointer to an array, a[low : high : max] is From 17e97e9818d77591cae68ee4a9bac377ab74e211 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 14 Aug 2024 09:52:13 +0200 Subject: [PATCH 03/25] save --- gnovm/pkg/gnolang/alloc.go | 3 ++- gnovm/pkg/gnolang/op_expressions.go | 11 +++++++++-- gnovm/pkg/gnolang/values.go | 8 ++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index f6c7bede90d..1afef960ffa 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -259,7 +259,8 @@ func (alloc *Allocator) NewSliceFromData(data []byte) *SliceValue { func (alloc *Allocator) NewStruct(fields []TypedValue) *StructValue { alloc.AllocateStruct() return &StructValue{ - Fields: fields, + Fields: fields, + NotAddressible: true, } } diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 86c5f147507..4bfd5eba5c3 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -93,6 +93,11 @@ func (m *Machine) doOpSelector() { m.Printf("-v[S] %v\n", xv) m.Printf("+v[S] %v\n", res) } + + if xv.NotAddressable { + panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) + } + *xv = res // reuse as result } @@ -758,9 +763,11 @@ func (m *Machine) doOpStructLit() { // construct and push value. m.PopValue() // baseOf() is st sv := m.Alloc.NewStruct(fs) + m.PushValue(TypedValue{ - T: xt, - V: sv, + T: xt, + V: sv, + NotAddressable: sv.NotAddressible, }) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index ef5824e094d..8c4806f606b 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -453,7 +453,8 @@ func (sv *SliceValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe type StructValue struct { ObjectInfo - Fields []TypedValue + Fields []TypedValue + NotAddressible bool } // TODO handle unexported fields in debug, and also ensure in the preprocessor. @@ -519,7 +520,10 @@ func (sv *StructValue) Copy(alloc *Allocator) *StructValue { fields[i] = field.Copy(alloc) } - return alloc.NewStruct(fields) + strct := alloc.NewStruct(fields) + + strct.NotAddressible = sv.NotAddressible + return strct } // ---------------------------------------- From d9233b33c4f71f2d6ec5ab12c7510da4bd9cc730 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 14 Aug 2024 11:03:59 +0200 Subject: [PATCH 04/25] Revert "save" This reverts commit 17e97e9818d77591cae68ee4a9bac377ab74e211. --- gnovm/pkg/gnolang/alloc.go | 3 +-- gnovm/pkg/gnolang/op_expressions.go | 11 ++--------- gnovm/pkg/gnolang/values.go | 8 ++------ 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index 1afef960ffa..f6c7bede90d 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -259,8 +259,7 @@ func (alloc *Allocator) NewSliceFromData(data []byte) *SliceValue { func (alloc *Allocator) NewStruct(fields []TypedValue) *StructValue { alloc.AllocateStruct() return &StructValue{ - Fields: fields, - NotAddressible: true, + Fields: fields, } } diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 4bfd5eba5c3..86c5f147507 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -93,11 +93,6 @@ func (m *Machine) doOpSelector() { m.Printf("-v[S] %v\n", xv) m.Printf("+v[S] %v\n", res) } - - if xv.NotAddressable { - panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) - } - *xv = res // reuse as result } @@ -763,11 +758,9 @@ func (m *Machine) doOpStructLit() { // construct and push value. m.PopValue() // baseOf() is st sv := m.Alloc.NewStruct(fs) - m.PushValue(TypedValue{ - T: xt, - V: sv, - NotAddressable: sv.NotAddressible, + T: xt, + V: sv, }) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 8c4806f606b..ef5824e094d 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -453,8 +453,7 @@ func (sv *SliceValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe type StructValue struct { ObjectInfo - Fields []TypedValue - NotAddressible bool + Fields []TypedValue } // TODO handle unexported fields in debug, and also ensure in the preprocessor. @@ -520,10 +519,7 @@ func (sv *StructValue) Copy(alloc *Allocator) *StructValue { fields[i] = field.Copy(alloc) } - strct := alloc.NewStruct(fields) - - strct.NotAddressible = sv.NotAddressible - return strct + return alloc.NewStruct(fields) } // ---------------------------------------- From dd3da1798a0da3e53cb1829567969c23c6a055b8 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Thu, 15 Aug 2024 10:17:27 +0200 Subject: [PATCH 05/25] save --- gnovm/pkg/gnolang/machine.go | 2 +- gnovm/pkg/gnolang/op_expressions.go | 6 ++-- gnovm/pkg/gnolang/values.go | 30 +++++++++++++++++-- .../more/realm_compositelit_filetest.gno | 1 + gnovm/tests/files/zrealm_tests0_stdlibs.gno | 1 + 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 7bbda026338..e62c809502e 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2089,7 +2089,7 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { xv := m.PopValue() if xv.NotAddressable { - panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) + panic(fmt.Sprintf("PopAsPointer: expr not addressable: %+v\n", xv)) } return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 86c5f147507..782017f8532 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -18,7 +18,7 @@ func (m *Machine) doOpIndex1() { xv := m.PeekValue(1) // x if xv.NotAddressable { - panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) + panic(fmt.Sprintf("doOpIndex1: expr not addressable: %+v\n", xv)) } switch ct := baseOf(xv.T).(type) { @@ -51,7 +51,7 @@ func (m *Machine) doOpIndex2() { xv := m.PeekValue(2) // x if xv.NotAddressable { - panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) + panic(fmt.Sprintf("doOpIndex2: expr not addressable: %+v\n", xv)) } switch ct := baseOf(xv.T).(type) { @@ -117,7 +117,7 @@ func (m *Machine) doOpSlice() { xv := m.PopValue() if xv.NotAddressable { - panic(fmt.Sprintf("expr not addressable: %+v\n", xv)) + panic(fmt.Sprintf("doOpSlice: expr not addressable: %+v\n", xv)) } // if a is a pointer to an array, a[low : high : max] is diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index ef5824e094d..d311704b38e 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -15,6 +15,10 @@ import ( "github.com/gnolang/gno/tm2/pkg/crypto" ) +type Addressable interface { + Addressable(b bool) +} + // ---------------------------------------- // (runtime) Value @@ -186,6 +190,13 @@ type PointerValue struct { Key *TypedValue `json:",omitempty"` // for maps. } +func (pv PointerValue) Addressable(b bool) { + pv.TV.NotAddressable = !b + if iface, ok := pv.TV.V.(Addressable); ok { + iface.Addressable(b) + } +} + const ( PointerIndexBlockBlank = -1 // for the "_" identifier in blocks PointerIndexMap = -2 // Base is Map, use Key. @@ -211,6 +222,8 @@ func (pv *PointerValue) GetBase(store Store) Object { // TODO: document as something that enables into-native assignment. // TODO: maybe consider this as entrypoint for DataByteValue too? func (pv PointerValue) Assign2(alloc *Allocator, store Store, rlm *Realm, tv2 TypedValue, cu bool) { + tv2.Addressable(true) + // Special cases. if pv.Index == PointerIndexNative { // Special case if extended object && native. @@ -320,6 +333,14 @@ type ArrayValue struct { NotAddressible bool } +func (av *ArrayValue) Addressable(b bool) { + av.NotAddressible = !b + + for i := range av.List { + av.List[i].Addressable(b) + } +} + // NOTE: Result should not be written to, // behavior is unexpected when .List bytes. func (av *ArrayValue) GetReadonlyBytes() []byte { @@ -963,6 +984,13 @@ type TypedValue struct { NotAddressable bool `json:"-"` } +func (tv *TypedValue) Addressable(b bool) { + tv.NotAddressable = !b + if iface, ok := tv.V.(Addressable); ok { + iface.Addressable(b) + } +} + func (tv *TypedValue) IsDefined() bool { return !tv.IsUndefined() } @@ -2598,8 +2626,6 @@ func defaultTypedValue(alloc *Allocator, t Type) TypedValue { var naddr bool switch v := dv.(type) { - case *StructValue: - naddr = true case *ArrayValue: naddr = v.NotAddressible } diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 5bdd878c146..1a22fbc7729 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -40,6 +40,7 @@ func main() { // } // } // ], +// "NotAddressible": false, // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno index d11701505e5..27476ae28c9 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0_stdlibs.gno @@ -123,6 +123,7 @@ func main() { // } // } // ], +// "NotAddressible": false, // "ObjectInfo": { // "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", // "ModTime": "0", From 3f4298deeec80010e7ea666f39a568a93d23d226 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Thu, 15 Aug 2024 13:13:47 +0200 Subject: [PATCH 06/25] save --- gnovm/tests/files/notaddressable1.gno | 12 ++++++++++++ gnovm/tests/files/notaddressable2.gno | 13 +++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 gnovm/tests/files/notaddressable1.gno create mode 100644 gnovm/tests/files/notaddressable2.gno diff --git a/gnovm/tests/files/notaddressable1.gno b/gnovm/tests/files/notaddressable1.gno new file mode 100644 index 00000000000..cf92b51224b --- /dev/null +++ b/gnovm/tests/files/notaddressable1.gno @@ -0,0 +1,12 @@ +package main + +func main() { + foo()[:] +} + +func foo() [2]byte { + return [2]byte{1, 2} +} + +// Error: +// doOpSlice: expr not addressable: (array[0x0102] [2]uint8) \ No newline at end of file diff --git a/gnovm/tests/files/notaddressable2.gno b/gnovm/tests/files/notaddressable2.gno new file mode 100644 index 00000000000..c9fccb3ffe6 --- /dev/null +++ b/gnovm/tests/files/notaddressable2.gno @@ -0,0 +1,13 @@ +package main + +func main() { + arr := &getArray()[0] + println(arr) +} + +func getArray() [3]int { + return [3]int{1, 2, 3} +} + +// Error: +// PopAsPointer: expr not addressable: (array[(1 int),(2 int),(3 int)] [3]int) \ No newline at end of file From 6ece565d77b4ccf8871586825c2da0114b3a4c71 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Fri, 16 Aug 2024 11:41:59 +0200 Subject: [PATCH 07/25] save --- gnovm/pkg/gnolang/values.go | 38 +++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index d311704b38e..034af094116 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -16,7 +16,7 @@ import ( ) type Addressable interface { - Addressable(b bool) + Addressable() } // ---------------------------------------- @@ -190,10 +190,10 @@ type PointerValue struct { Key *TypedValue `json:",omitempty"` // for maps. } -func (pv PointerValue) Addressable(b bool) { - pv.TV.NotAddressable = !b +func (pv *PointerValue) Addressable() { + pv.TV.NotAddressable = false if iface, ok := pv.TV.V.(Addressable); ok { - iface.Addressable(b) + iface.Addressable() } } @@ -222,7 +222,7 @@ func (pv *PointerValue) GetBase(store Store) Object { // TODO: document as something that enables into-native assignment. // TODO: maybe consider this as entrypoint for DataByteValue too? func (pv PointerValue) Assign2(alloc *Allocator, store Store, rlm *Realm, tv2 TypedValue, cu bool) { - tv2.Addressable(true) + tv2.Addressable() // Special cases. if pv.Index == PointerIndexNative { @@ -333,11 +333,11 @@ type ArrayValue struct { NotAddressible bool } -func (av *ArrayValue) Addressable(b bool) { - av.NotAddressible = !b +func (av *ArrayValue) Addressable() { + av.NotAddressible = false for i := range av.List { - av.List[i].Addressable(b) + av.List[i].Addressable() } } @@ -432,6 +432,12 @@ type SliceValue struct { Maxcap int } +func (sv *SliceValue) Addressable() { + if iface, ok := sv.Base.(Addressable); ok { + iface.Addressable() + } +} + func (sv *SliceValue) GetBase(store Store) *ArrayValue { switch cv := sv.Base.(type) { case nil: @@ -477,6 +483,12 @@ type StructValue struct { Fields []TypedValue } +func (sv *StructValue) Addressable() { + for i := range sv.Fields { + sv.Fields[i].Addressable() + } +} + // TODO handle unexported fields in debug, and also ensure in the preprocessor. func (sv *StructValue) GetPointerTo(store Store, path ValuePath) PointerValue { if debug { @@ -984,10 +996,12 @@ type TypedValue struct { NotAddressable bool `json:"-"` } -func (tv *TypedValue) Addressable(b bool) { - tv.NotAddressable = !b - if iface, ok := tv.V.(Addressable); ok { - iface.Addressable(b) +func (tv *TypedValue) Addressable() { + tv.NotAddressable = false + if p, ok := tv.V.(PointerValue); ok { + p.Addressable() + } else if iface, ok := tv.V.(Addressable); ok { + iface.Addressable() } } From 0e229f7671c6b61c340a824875cc37386a3b24c4 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Mon, 19 Aug 2024 00:49:17 +0200 Subject: [PATCH 08/25] save --- gnovm/pkg/gnolang/values.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 034af094116..b29655ba481 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -191,6 +191,10 @@ type PointerValue struct { } func (pv *PointerValue) Addressable() { + if pv.TV == nil { + return + } + pv.TV.NotAddressable = false if iface, ok := pv.TV.V.(Addressable); ok { iface.Addressable() From d1644d6b37d9e0e3fad821c52fd3ed19a7dd0b73 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 20 Aug 2024 00:40:03 +0200 Subject: [PATCH 09/25] save --- gnovm/pkg/gnolang/alloc.go | 4 ++-- gnovm/pkg/gnolang/gonative.go | 2 +- gnovm/pkg/gnolang/machine.go | 2 +- gnovm/pkg/gnolang/op_expressions.go | 8 ++++---- gnovm/pkg/gnolang/values.go | 31 +++++++++++++++++++++-------- 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index f6c7bede90d..e56c62c601d 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -197,7 +197,7 @@ func (alloc *Allocator) NewListArray(n int) *ArrayValue { alloc.AllocateListArray(int64(n)) return &ArrayValue{ List: make([]TypedValue, n), - NotAddressible: true, + NotAddressable: 1, } } @@ -205,7 +205,7 @@ func (alloc *Allocator) NewDataArray(n int) *ArrayValue { alloc.AllocateDataArray(int64(n)) return &ArrayValue{ Data: make([]byte, n), - NotAddressible: true, + NotAddressable: 1, } } diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 2ccc2dd239f..e10a9639ddd 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -715,7 +715,7 @@ func go2GnoValue2(alloc *Allocator, store Store, rv reflect.Value, recursive boo } } tv.V = av - tv.NotAddressable = av.NotAddressible + tv.NotAddressable = av.NotAddressable } case reflect.Slice: rvl := rv.Len() diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index e62c809502e..deb14ed8651 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2088,7 +2088,7 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { iv := m.PopValue() xv := m.PopValue() - if xv.NotAddressable { + if xv.NotAddressable != 0 { panic(fmt.Sprintf("PopAsPointer: expr not addressable: %+v\n", xv)) } diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 8e9969a63f7..ba5536acf53 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -17,7 +17,7 @@ func (m *Machine) doOpIndex1() { iv := m.PopValue() // index xv := m.PeekValue(1) // x - if xv.NotAddressable { + if xv.NotAddressable != 0 { panic(fmt.Sprintf("doOpIndex1: expr not addressable: %+v\n", xv)) } @@ -50,7 +50,7 @@ func (m *Machine) doOpIndex2() { iv := m.PeekValue(1) // index xv := m.PeekValue(2) // x - if xv.NotAddressable { + if xv.NotAddressable != 0 { panic(fmt.Sprintf("doOpIndex2: expr not addressable: %+v\n", xv)) } @@ -116,7 +116,7 @@ func (m *Machine) doOpSlice() { // slice base x xv := m.PopValue() - if xv.NotAddressable { + if xv.NotAddressable != 0 { panic(fmt.Sprintf("doOpSlice: expr not addressable: %+v\n", xv)) } @@ -567,7 +567,7 @@ func (m *Machine) doOpArrayLit() { m.PushValue(TypedValue{ T: at, V: av, - NotAddressable: av.NotAddressible, + NotAddressable: av.NotAddressable, }) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index b29655ba481..c1ec9ca18ad 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -195,10 +195,15 @@ func (pv *PointerValue) Addressable() { return } - pv.TV.NotAddressable = false + if pv.TV.NotAddressable == -1 { + return + } + + pv.TV.NotAddressable = -1 if iface, ok := pv.TV.V.(Addressable); ok { iface.Addressable() } + pv.TV.NotAddressable = 0 } const ( @@ -334,15 +339,21 @@ type ArrayValue struct { ObjectInfo List []TypedValue Data []byte - NotAddressible bool + NotAddressable int } func (av *ArrayValue) Addressable() { - av.NotAddressible = false + if av.NotAddressable == -1 { + return + } + + av.NotAddressable = -1 for i := range av.List { av.List[i].Addressable() } + + av.NotAddressable = 0 } // NOTE: Result should not be written to, @@ -418,7 +429,7 @@ func (av *ArrayValue) Copy(alloc *Allocator) *ArrayValue { if av.Data == nil { av2 := alloc.NewListArray(len(av.List)) copy(av2.List, av.List) - av2.NotAddressible = av.NotAddressible + av2.NotAddressable = av.NotAddressable return av2 } av2 := alloc.NewDataArray(len(av.Data)) @@ -997,16 +1008,20 @@ type TypedValue struct { T Type `json:",omitempty"` // never nil V Value `json:",omitempty"` // an untyped value N [8]byte `json:",omitempty"` // numeric bytes - NotAddressable bool `json:"-"` + NotAddressable int `json:"-"` } func (tv *TypedValue) Addressable() { - tv.NotAddressable = false + if tv.NotAddressable == -1 { + return + } + tv.NotAddressable = -1 if p, ok := tv.V.(PointerValue); ok { p.Addressable() } else if iface, ok := tv.V.(Addressable); ok { iface.Addressable() } + tv.NotAddressable = 0 } func (tv *TypedValue) IsDefined() bool { @@ -2641,11 +2656,11 @@ func defaultTypedValue(alloc *Allocator, t Type) TypedValue { dv := defaultValue(alloc, t) - var naddr bool + var naddr int switch v := dv.(type) { case *ArrayValue: - naddr = v.NotAddressible + naddr = v.NotAddressable } return TypedValue{ From c4399adda3b9a548c48f9a62071fccfc37beb497 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 20 Aug 2024 00:45:55 +0200 Subject: [PATCH 10/25] save --- .../assign_unnamed_type/more/realm_compositelit_filetest.gno | 2 +- gnovm/tests/files/zrealm_tests0_stdlibs.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 1a22fbc7729..3f123ca9e3d 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -40,7 +40,7 @@ func main() { // } // } // ], -// "NotAddressible": false, +// "NotAddressible": 0, // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno index 27476ae28c9..fc08c45f9c0 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0_stdlibs.gno @@ -123,7 +123,7 @@ func main() { // } // } // ], -// "NotAddressible": false, +// "NotAddressible": 0, // "ObjectInfo": { // "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", // "ModTime": "0", From 9a363d3a5810bdaa72ddc4c8cdf82f6df803755b Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 20 Aug 2024 00:53:15 +0200 Subject: [PATCH 11/25] save --- .../assign_unnamed_type/more/realm_compositelit_filetest.gno | 2 +- gnovm/tests/files/zrealm_tests0_stdlibs.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index 3f123ca9e3d..b9cb6c54be5 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -40,7 +40,7 @@ func main() { // } // } // ], -// "NotAddressible": 0, +// "NotAddressable": "0", // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno index fc08c45f9c0..c79ee398cae 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0_stdlibs.gno @@ -123,7 +123,7 @@ func main() { // } // } // ], -// "NotAddressible": 0, +// "NotAddressable": "0", // "ObjectInfo": { // "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", // "ModTime": "0", From 146817167d6759a656a30f7bc7bcc9555554a81a Mon Sep 17 00:00:00 2001 From: deelawn Date: Tue, 20 Aug 2024 13:40:43 -0700 Subject: [PATCH 12/25] switch back to boolean addressable flag --- gnovm/pkg/gnolang/alloc.go | 4 ++-- gnovm/pkg/gnolang/machine.go | 2 +- gnovm/pkg/gnolang/op_expressions.go | 6 +++--- gnovm/pkg/gnolang/values.go | 25 ++++++++++++------------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index e56c62c601d..9651aa313d1 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -197,7 +197,7 @@ func (alloc *Allocator) NewListArray(n int) *ArrayValue { alloc.AllocateListArray(int64(n)) return &ArrayValue{ List: make([]TypedValue, n), - NotAddressable: 1, + NotAddressable: true, } } @@ -205,7 +205,7 @@ func (alloc *Allocator) NewDataArray(n int) *ArrayValue { alloc.AllocateDataArray(int64(n)) return &ArrayValue{ Data: make([]byte, n), - NotAddressable: 1, + NotAddressable: true, } } diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index deb14ed8651..e62c809502e 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2088,7 +2088,7 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { iv := m.PopValue() xv := m.PopValue() - if xv.NotAddressable != 0 { + if xv.NotAddressable { panic(fmt.Sprintf("PopAsPointer: expr not addressable: %+v\n", xv)) } diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index ba5536acf53..71ffd141ef0 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -17,7 +17,7 @@ func (m *Machine) doOpIndex1() { iv := m.PopValue() // index xv := m.PeekValue(1) // x - if xv.NotAddressable != 0 { + if xv.NotAddressable { panic(fmt.Sprintf("doOpIndex1: expr not addressable: %+v\n", xv)) } @@ -50,7 +50,7 @@ func (m *Machine) doOpIndex2() { iv := m.PeekValue(1) // index xv := m.PeekValue(2) // x - if xv.NotAddressable != 0 { + if xv.NotAddressable { panic(fmt.Sprintf("doOpIndex2: expr not addressable: %+v\n", xv)) } @@ -116,7 +116,7 @@ func (m *Machine) doOpSlice() { // slice base x xv := m.PopValue() - if xv.NotAddressable != 0 { + if xv.NotAddressable { panic(fmt.Sprintf("doOpSlice: expr not addressable: %+v\n", xv)) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index c1ec9ca18ad..4240913c6ef 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -195,15 +195,15 @@ func (pv *PointerValue) Addressable() { return } - if pv.TV.NotAddressable == -1 { + // if addressable + if !pv.TV.NotAddressable { return } - pv.TV.NotAddressable = -1 + pv.TV.NotAddressable = false if iface, ok := pv.TV.V.(Addressable); ok { iface.Addressable() } - pv.TV.NotAddressable = 0 } const ( @@ -339,21 +339,20 @@ type ArrayValue struct { ObjectInfo List []TypedValue Data []byte - NotAddressable int + NotAddressable bool } func (av *ArrayValue) Addressable() { - if av.NotAddressable == -1 { + // if addressable + if !av.NotAddressable { return } - av.NotAddressable = -1 + av.NotAddressable = false for i := range av.List { av.List[i].Addressable() } - - av.NotAddressable = 0 } // NOTE: Result should not be written to, @@ -1008,20 +1007,20 @@ type TypedValue struct { T Type `json:",omitempty"` // never nil V Value `json:",omitempty"` // an untyped value N [8]byte `json:",omitempty"` // numeric bytes - NotAddressable int `json:"-"` + NotAddressable bool `json:"-"` } func (tv *TypedValue) Addressable() { - if tv.NotAddressable == -1 { + // if addressable + if !tv.NotAddressable { return } - tv.NotAddressable = -1 + tv.NotAddressable = false if p, ok := tv.V.(PointerValue); ok { p.Addressable() } else if iface, ok := tv.V.(Addressable); ok { iface.Addressable() } - tv.NotAddressable = 0 } func (tv *TypedValue) IsDefined() bool { @@ -2656,7 +2655,7 @@ func defaultTypedValue(alloc *Allocator, t Type) TypedValue { dv := defaultValue(alloc, t) - var naddr int + var naddr bool switch v := dv.(type) { case *ArrayValue: From 3908c22b643f830649220ded2eb796837760fa04 Mon Sep 17 00:00:00 2001 From: deelawn Date: Tue, 20 Aug 2024 13:44:11 -0700 Subject: [PATCH 13/25] updated tests --- .../assign_unnamed_type/more/realm_compositelit_filetest.gno | 2 +- gnovm/tests/files/zrealm_tests0_stdlibs.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index b9cb6c54be5..bf55b9a27f0 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -40,7 +40,7 @@ func main() { // } // } // ], -// "NotAddressable": "0", +// "NotAddressable": false, // "ObjectInfo": { // "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", diff --git a/gnovm/tests/files/zrealm_tests0_stdlibs.gno b/gnovm/tests/files/zrealm_tests0_stdlibs.gno index c79ee398cae..d2ad592f086 100644 --- a/gnovm/tests/files/zrealm_tests0_stdlibs.gno +++ b/gnovm/tests/files/zrealm_tests0_stdlibs.gno @@ -123,7 +123,7 @@ func main() { // } // } // ], -// "NotAddressable": "0", +// "NotAddressable": false, // "ObjectInfo": { // "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:16", // "ModTime": "0", From 2f033c02a171d97e9767995aa383d60ef8000311 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 20 Aug 2024 23:05:10 +0200 Subject: [PATCH 14/25] save --- gnovm/pkg/gnolang/op_expressions.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 71ffd141ef0..0ba573f4869 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -17,10 +17,6 @@ func (m *Machine) doOpIndex1() { iv := m.PopValue() // index xv := m.PeekValue(1) // x - if xv.NotAddressable { - panic(fmt.Sprintf("doOpIndex1: expr not addressable: %+v\n", xv)) - } - switch ct := baseOf(xv.T).(type) { case *MapType: mv := xv.V.(*MapValue) @@ -50,10 +46,6 @@ func (m *Machine) doOpIndex2() { iv := m.PeekValue(1) // index xv := m.PeekValue(2) // x - if xv.NotAddressable { - panic(fmt.Sprintf("doOpIndex2: expr not addressable: %+v\n", xv)) - } - switch ct := baseOf(xv.T).(type) { case *MapType: vt := ct.Value From b76bd8c5c114f3f0de5bbaa53ec2e050c8233842 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Tue, 20 Aug 2024 23:43:12 +0200 Subject: [PATCH 15/25] save --- gnovm/pkg/gnolang/op_expressions.go | 5 +++-- gnovm/pkg/gnolang/values.go | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 0ba573f4869..fe613170354 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -207,8 +207,9 @@ func (m *Machine) doOpRef() { elt = xv.TV.V.(DataByteValue).ElemType } m.PushValue(TypedValue{ - T: m.Alloc.NewType(&PointerType{Elt: elt}), - V: xv, + T: m.Alloc.NewType(&PointerType{Elt: elt}), + V: xv, + NotAddressable: xv.TV.NotAddressable, }) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 4240913c6ef..9b8b3a19fb9 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -231,7 +231,9 @@ func (pv *PointerValue) GetBase(store Store) Object { // TODO: document as something that enables into-native assignment. // TODO: maybe consider this as entrypoint for DataByteValue too? func (pv PointerValue) Assign2(alloc *Allocator, store Store, rlm *Realm, tv2 TypedValue, cu bool) { - tv2.Addressable() + if cu { + tv2.Addressable() + } // Special cases. if pv.Index == PointerIndexNative { From 9ece5fbb34ccd322d9dd01f51602478828744653 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 00:29:26 +0200 Subject: [PATCH 16/25] save --- gnovm/pkg/gnolang/machine.go | 4 ---- gnovm/pkg/gnolang/op_expressions.go | 7 +++++++ gnovm/tests/files/notaddressable2.gno | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index e62c809502e..6971c8ccb3f 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2088,10 +2088,6 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { iv := m.PopValue() xv := m.PopValue() - if xv.NotAddressable { - panic(fmt.Sprintf("PopAsPointer: expr not addressable: %+v\n", xv)) - } - return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) case *SelectorExpr: xv := m.PopValue() diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index fe613170354..19617ae6724 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -206,6 +206,13 @@ func (m *Machine) doOpRef() { if elt == DataByteType { elt = xv.TV.V.(DataByteValue).ElemType } + + if array, ok := xv.Base.(*ArrayValue); ok { + if array.NotAddressable { + panic(fmt.Sprintf("doOpRef: expr not addressable: %+v\n", array)) + } + } + m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{Elt: elt}), V: xv, diff --git a/gnovm/tests/files/notaddressable2.gno b/gnovm/tests/files/notaddressable2.gno index c9fccb3ffe6..16421b45832 100644 --- a/gnovm/tests/files/notaddressable2.gno +++ b/gnovm/tests/files/notaddressable2.gno @@ -10,4 +10,4 @@ func getArray() [3]int { } // Error: -// PopAsPointer: expr not addressable: (array[(1 int),(2 int),(3 int)] [3]int) \ No newline at end of file +// doOpRef: expr not addressable: array[(1 int),(2 int),(3 int)] \ No newline at end of file From d9ad3708b1f0428616a96c75bd1e780160c25145 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 11:27:36 +0200 Subject: [PATCH 17/25] save --- gnovm/pkg/gnolang/machine.go | 2 ++ gnovm/pkg/gnolang/values.go | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 6971c8ccb3f..98681e59012 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -1954,6 +1954,8 @@ func (m *Machine) PopFrameAndReturn() { if res.IsUndefined() && rtypes[i].Type.Kind() != InterfaceKind { res.T = rtypes[i].Type } + + res.Unaddressable() m.Values[fr.NumValues+i] = res } m.NumValues = fr.NumValues + numRes diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 9b8b3a19fb9..904fbef7060 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -17,6 +17,7 @@ import ( type Addressable interface { Addressable() + Unaddressable() } // ---------------------------------------- @@ -206,6 +207,21 @@ func (pv *PointerValue) Addressable() { } } +func (pv *PointerValue) Unaddressable() { + if pv.TV == nil { + return + } + + if pv.TV.NotAddressable { + return + } + + pv.TV.NotAddressable = true + if iface, ok := pv.TV.V.(Addressable); ok { + iface.Unaddressable() + } +} + const ( PointerIndexBlockBlank = -1 // for the "_" identifier in blocks PointerIndexMap = -2 // Base is Map, use Key. @@ -357,6 +373,18 @@ func (av *ArrayValue) Addressable() { } } +func (av *ArrayValue) Unaddressable() { + if av.NotAddressable { + return + } + + av.NotAddressable = true + + for i := range av.List { + av.List[i].Unaddressable() + } +} + // NOTE: Result should not be written to, // behavior is unexpected when .List bytes. func (av *ArrayValue) GetReadonlyBytes() []byte { @@ -454,6 +482,12 @@ func (sv *SliceValue) Addressable() { } } +func (sv *SliceValue) Unaddressable() { + if iface, ok := sv.Base.(Addressable); ok { + iface.Unaddressable() + } +} + func (sv *SliceValue) GetBase(store Store) *ArrayValue { switch cv := sv.Base.(type) { case nil: @@ -505,6 +539,12 @@ func (sv *StructValue) Addressable() { } } +func (sv *StructValue) Unaddressable() { + for i := range sv.Fields { + sv.Fields[i].Unaddressable() + } +} + // TODO handle unexported fields in debug, and also ensure in the preprocessor. func (sv *StructValue) GetPointerTo(store Store, path ValuePath) PointerValue { if debug { @@ -1025,6 +1065,19 @@ func (tv *TypedValue) Addressable() { } } +func (tv *TypedValue) Unaddressable() { + // if addressable + if tv.NotAddressable { + return + } + tv.NotAddressable = true + if p, ok := tv.V.(PointerValue); ok { + p.Unaddressable() + } else if iface, ok := tv.V.(Addressable); ok { + iface.Unaddressable() + } +} + func (tv *TypedValue) IsDefined() bool { return !tv.IsUndefined() } From ffa59bb9aaed497545eb0b483729e5cb922bc0cf Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 15:54:08 +0200 Subject: [PATCH 18/25] save --- gnovm/pkg/gnolang/op_assign.go | 3 +++ gnovm/pkg/gnolang/op_decl.go | 1 + gnovm/pkg/gnolang/values.go | 4 ---- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gnovm/pkg/gnolang/op_assign.go b/gnovm/pkg/gnolang/op_assign.go index eb67ffcc351..5932745b67e 100644 --- a/gnovm/pkg/gnolang/op_assign.go +++ b/gnovm/pkg/gnolang/op_assign.go @@ -20,6 +20,7 @@ func (m *Machine) doOpDefine() { } } } + rvs[i].Addressable() ptr.Assign2(m.Alloc, m.Store, m.Realm, rvs[i], true) } } @@ -41,6 +42,8 @@ func (m *Machine) doOpAssign() { } } } + + rvs[i].Addressable() lv.Assign2(m.Alloc, m.Store, m.Realm, rvs[i], true) } } diff --git a/gnovm/pkg/gnolang/op_decl.go b/gnovm/pkg/gnolang/op_decl.go index 2c20c43ae2f..4dc51871a2e 100644 --- a/gnovm/pkg/gnolang/op_decl.go +++ b/gnovm/pkg/gnolang/op_decl.go @@ -60,6 +60,7 @@ func (m *Machine) doOpValueDecl() { } nx := s.NameExprs[i] ptr := lb.GetPointerTo(m.Store, nx.Path) + tv.Addressable() ptr.Assign2(m.Alloc, m.Store, m.Realm, tv, false) } } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 904fbef7060..8c8273de70a 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -247,10 +247,6 @@ func (pv *PointerValue) GetBase(store Store) Object { // TODO: document as something that enables into-native assignment. // TODO: maybe consider this as entrypoint for DataByteValue too? func (pv PointerValue) Assign2(alloc *Allocator, store Store, rlm *Realm, tv2 TypedValue, cu bool) { - if cu { - tv2.Addressable() - } - // Special cases. if pv.Index == PointerIndexNative { // Special case if extended object && native. From ab205d7ca61162585af7dc0d0654e67a2c28c71b Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 17:17:47 +0200 Subject: [PATCH 19/25] save --- gnovm/pkg/gnolang/op_expressions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 19617ae6724..36742938cd0 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -108,7 +108,7 @@ func (m *Machine) doOpSlice() { // slice base x xv := m.PopValue() - if xv.NotAddressable { + if _, ok := xv.V.(Addressable); ok && xv.NotAddressable { panic(fmt.Sprintf("doOpSlice: expr not addressable: %+v\n", xv)) } From 4ed00ed56ffc1da6fc90a61335f029614194c06d Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 17:55:10 +0200 Subject: [PATCH 20/25] save --- gnovm/pkg/gnolang/op_call.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 15531ec610d..7ec9927ff71 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -165,6 +165,7 @@ func (m *Machine) doOpCall() { // Make a copy so that a reference to the argument isn't used // in cases where the non-primitive value type is represented // as a pointer, *StructValue, for example. + pv.Addressable() b.Values[i] = pv.Copy(m.Alloc) } } From b9fce6ca97db3a9baa42ec0ed9e776b38914fe15 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 18:16:46 +0200 Subject: [PATCH 21/25] save --- gnovm/pkg/gnolang/op_call.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 7ec9927ff71..d2c163d70f6 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -134,6 +134,9 @@ func (m *Machine) doOpCall() { list := m.PopCopyValues(nvar) vart := pts[numParams-1].Type.(*SliceType) varg := m.Alloc.NewSliceFromList(list) + + varg.Addressable() + m.PushValue(TypedValue{ T: vart, V: varg, From 7677ea02a568ac04e89825b681efa7073f4bd0cd Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 19:30:29 +0200 Subject: [PATCH 22/25] save --- gnovm/pkg/gnolang/machine.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 98681e59012..0d01adf4326 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -1955,7 +1955,9 @@ func (m *Machine) PopFrameAndReturn() { res.T = rtypes[i].Type } - res.Unaddressable() + if _, ok := res.V.(*ArrayValue); ok { + res.Unaddressable() + } m.Values[fr.NumValues+i] = res } m.NumValues = fr.NumValues + numRes From 74c5346bdfab8b97f8d9f395196e5851cc4a9f77 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 21 Aug 2024 23:21:17 +0200 Subject: [PATCH 23/25] save --- gnovm/stdlibs/crypto/sha256/sha256_test.gno | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gnovm/stdlibs/crypto/sha256/sha256_test.gno b/gnovm/stdlibs/crypto/sha256/sha256_test.gno index 26d96cd547e..69fda988a7a 100644 --- a/gnovm/stdlibs/crypto/sha256/sha256_test.gno +++ b/gnovm/stdlibs/crypto/sha256/sha256_test.gno @@ -7,10 +7,10 @@ import ( ) func TestSha256Sum(t *testing.T) { - got := sha256.Sum256([]byte("sha256 this string"))[:] + got := sha256.Sum256([]byte("sha256 this string")) expected := "1af1dfa857bf1d8814fe1af8983c18080019922e557f15a8a0d3db739d77aacb" - if hex.EncodeToString(got) != expected { - t.Errorf("got %v(%T), expected %v(%T)", hex.EncodeToString(got), got, expected, expected) + if hex.EncodeToString(got[:]) != expected { + t.Errorf("got %v(%T), expected %v(%T)", hex.EncodeToString(got[:]), got, expected, expected) } } From aac2f5338658776e53db4b2add9f8ffb4449f1ba Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Thu, 22 Aug 2024 00:27:08 +0200 Subject: [PATCH 24/25] save --- gnovm/pkg/gnolang/machine.go | 5 ++++- gnovm/pkg/gnolang/op_expressions.go | 14 ++++++++++++++ gnovm/pkg/gnolang/values.go | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 0d01adf4326..516558217c3 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -2095,7 +2095,10 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) case *SelectorExpr: xv := m.PopValue() - return xv.GetPointerTo(m.Alloc, m.Store, lx.Path) + nxv := xv.GetPointerTo(m.Alloc, m.Store, lx.Path) + nxv.TV.NotRef = xv.NotRef + + return nxv case *StarExpr: ptr := m.PopValue().V.(PointerValue) return ptr diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 36742938cd0..23fd2c74d00 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -213,6 +213,10 @@ func (m *Machine) doOpRef() { } } + if xv.TV.NotRef { + panic(fmt.Sprintf("doOpRef: expr not addressable: %+v\n", xv.TV)) + } + m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{Elt: elt}), V: xv, @@ -230,6 +234,11 @@ func (m *Machine) doOpTypeAssert1() { xv := m.PeekValue(1) // value result / value to assert xt := xv.T // underlying value's type + defer func() { + xv.Unaddressable() + xv.NotRef = true + }() + // xt may be nil, but we need to wait to return because the value of xt that is set // will depend on whether we are trying to assert to an interface or concrete type. // xt can be nil in the case where recover can't find a panic to recover from and @@ -337,6 +346,11 @@ func (m *Machine) doOpTypeAssert2() { xv := m.PeekValue(2) // value result / value to assert xt := xv.T // underlying value's type + defer func() { + xv.Unaddressable() + xv.NotRef = true + }() + // xt may be nil, but we need to wait to return because the value of xt that is set // will depend on whether we are trying to assert to an interface or concrete type. // xt can be nil in the case where recover can't find a panic to recover from and diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 8c8273de70a..929f4907366 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1046,6 +1046,7 @@ type TypedValue struct { V Value `json:",omitempty"` // an untyped value N [8]byte `json:",omitempty"` // numeric bytes NotAddressable bool `json:"-"` + NotRef bool `json:"-"` } func (tv *TypedValue) Addressable() { From c26c7c3904066a96c27e77b4141a85d16cdd00ab Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Thu, 22 Aug 2024 00:35:48 +0200 Subject: [PATCH 25/25] save --- gnovm/tests/files/notaddressable3.gno | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 gnovm/tests/files/notaddressable3.gno diff --git a/gnovm/tests/files/notaddressable3.gno b/gnovm/tests/files/notaddressable3.gno new file mode 100644 index 00000000000..34c5553aaba --- /dev/null +++ b/gnovm/tests/files/notaddressable3.gno @@ -0,0 +1,17 @@ +package main + +func main() { + var s S + assert4(s) +} + +type S struct { + s string +} + +func assert4(i interface{}) { + _ = &((i.(S)).s) +} + +// Error: +// doOpRef: expr not addressable: ( string) \ No newline at end of file