Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP fix(gnovm): correct map key persistence #3127

Draft
wants to merge 34 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions gno.land/cmd/gnoland/testdata/ptr_mapkey.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

gnoland start

# add contract
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/ptrmap -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout OK!

gnokey maketx call -pkgpath gno.land/r/demo/ptrmap -func AddToMap -args 5 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout OK!

gnokey maketx call -pkgpath gno.land/r/demo/ptrmap -func GetFromMap -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(5 int)'
stdout OK!

-- gno.mod --
module gno.land/r/demo/ptrmap

-- realm.gno --
package ptrmap

var (
m = map[*int]int{}
i = new(int)
)

func AddToMap(value int) {
m[i] = value
}

func GetFromMap() int {
return m[i]
}
13 changes: 13 additions & 0 deletions gnovm/1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

var arr1 [2]int
var arr2 [2]int

func init() {
arr1 = [2]int{1, 2}
arr2 = [2]int{1, 2}
}

func main() {
println(&arr1 == &arr1)
}
12 changes: 12 additions & 0 deletions gnovm/2.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

var i = new(int)

func init() {
println(i == i)
}

func main() {
*i = 1
println(i == i)
}
2 changes: 1 addition & 1 deletion gnovm/pkg/gnolang/gonative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestGoNativeDefine(t *testing.T) {
pkg.DefineGoNativeType(rt)
nt := pkg.GetValueRef(nil, Name("Foo"), true).GetType().(*NativeType)
assert.Equal(t, rt, nt.Type)
path := pkg.GetPathForName(nil, Name("Foo"))
path, _ := pkg.GetPathForName(nil, Name("Foo"))
assert.Equal(t, uint8(1), path.Depth)
assert.Equal(t, uint16(0), path.Index)
pv := pkg.NewPackage()
Expand Down
51 changes: 27 additions & 24 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,19 +505,22 @@ func (m *Machine) Stacktrace() (stacktrace Stacktrace) {
}

calls := make([]StacktraceCall, 0, len(m.Stmts))
nextStmtIndex := len(m.Stmts) - 1
for i := len(m.Frames) - 1; i >= 0; i-- {
if m.Frames[i].IsCall() {
stm := m.Stmts[nextStmtIndex]
bs := stm.(*bodyStmt)
stm = bs.Body[bs.NextBodyIndex-1]
calls = append(calls, StacktraceCall{
Stmt: stm,
Frame: m.Frames[i],
})
if len(m.Stmts) > 1 {

nextStmtIndex := len(m.Stmts) - 1
for i := len(m.Frames) - 1; i >= 0; i-- {
if m.Frames[i].IsCall() {
stm := m.Stmts[nextStmtIndex]
bs := stm.(*bodyStmt)
stm = bs.Body[bs.NextBodyIndex-1]
calls = append(calls, StacktraceCall{
Stmt: stm,
Frame: m.Frames[i],
})
}
// if the frame is a call, the next statement is the last statement of the frame.
nextStmtIndex = m.Frames[i].NumStmts - 1
}
// if the frame is a call, the next statement is the last statement of the frame.
nextStmtIndex = m.Frames[i].NumStmts - 1
}

// if the stacktrace is too long, we trim it down to maxStacktraceSize
Expand Down Expand Up @@ -1749,6 +1752,7 @@ func (m *Machine) PushValue(tv TypedValue) {
if debug {
m.Printf("+v %v\n", tv)
}
fmt.Printf("+v %v\n", tv)
if len(m.Values) == m.NumValues {
// TODO tune. also see PushOp().
newValues := make([]TypedValue, len(m.Values)*2)
Expand All @@ -1766,6 +1770,7 @@ func (m *Machine) PopValue() (tv *TypedValue) {
if debug {
m.Printf("-v %v\n", tv)
}
fmt.Printf("-v %v\n", tv)
m.NumValues--
return tv
}
Expand Down Expand Up @@ -2079,6 +2084,7 @@ func (m *Machine) PopUntilLastCallFrame() *Frame {
}

func (m *Machine) PushForPointer(lx Expr) {
fmt.Println("---PushForPointer, lx: ", lx)
switch lx := lx.(type) {
case *NameExpr:
// no Lhs eval needed.
Expand All @@ -2090,14 +2096,17 @@ func (m *Machine) PushForPointer(lx Expr) {
m.PushExpr(lx.X)
m.PushOp(OpEval)
case *SelectorExpr:
println("---selector expr")
// evaluate X
m.PushExpr(lx.X)
m.PushOp(OpEval)
case *StarExpr:
println("---star expr, eval .X")
// evaluate X (a reference)
m.PushExpr(lx.X)
m.PushOp(OpEval)
case *CompositeLitExpr: // for *RefExpr e.g. &mystruct{}
println("---CompositeLitExpr")
// evaluate lx.
m.PushExpr(lx)
m.PushOp(OpEval)
Expand All @@ -2109,28 +2118,22 @@ func (m *Machine) PushForPointer(lx Expr) {
}

func (m *Machine) PopAsPointer(lx Expr) PointerValue {
fmt.Println("---PopAsPointer, lx: ", lx)
switch lx := lx.(type) {
case *NameExpr:
switch lx.Type {
case NameExprTypeNormal:
lb := m.LastBlock()
return lb.GetPointerTo(m.Store, lx.Path)
case NameExprTypeHeapUse:
lb := m.LastBlock()
return lb.GetPointerToHeapUse(m.Store, lx.Path)
case NameExprTypeHeapClosure:
panic("should not happen")
default:
panic("unexpected NameExpr in PopAsPointer")
}
lb := m.LastBlock()
ptr := lb.GetPointerToMaybeHeapUse(m.Store, lx)
return ptr
case *IndexExpr:
iv := m.PopValue()
xv := m.PopValue()
fmt.Println("---index expr: ", lx)
return xv.GetPointerAtIndex(m.Alloc, m.Store, iv)
case *SelectorExpr:
xv := m.PopValue()
return xv.GetPointerToFromTV(m.Alloc, m.Store, lx.Path)
case *StarExpr:
println("---StarExpr")
ptr := m.PopValue().V.(PointerValue)
return ptr
case *CompositeLitExpr: // for *RefExpr
Expand Down
17 changes: 16 additions & 1 deletion gnovm/pkg/gnolang/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func isUpper(s string) bool {
return unicode.IsUpper(first)
}

//----------------------------------------
// ----------------------------------------
// converting uintptr to bytes.

const sizeOfUintPtr = unsafe.Sizeof(uintptr(0))
Expand Down Expand Up @@ -171,3 +171,18 @@ func DerivePkgAddr(pkgPath string) crypto.Address {
// NOTE: must not collide with pubkey addrs.
return crypto.AddressFromPreimage([]byte("pkgPath:" + pkgPath))
}

func buildAbsolutePath(n Expr) string {
switch n := n.(type) {
case *NameExpr:
return n.AbsPath
case *IndexExpr:
return buildAbsolutePath(n.X) + ":" + buildAbsolutePath(n.Index)
case *SelectorExpr:
return buildAbsolutePath(n.X) + ":" + string(n.Sel)
case *StarExpr:
return buildAbsolutePath(n.X)
default:
return n.String()
}
}
59 changes: 45 additions & 14 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,20 @@ const (
NameExprTypeHeapClosure // when closure captures name
)

type AbsPather interface {
GetAbsPath() string
}
type NameExpr struct {
Attributes
// TODO rename .Path's to .ValuePaths.
Path ValuePath // set by preprocessor.
Name
Type NameExprType
Type NameExprType
AbsPath string
}

func (nx *NameExpr) GetAbsPath() string {
return nx.AbsPath
}

type NameExprs []NameExpr
Expand Down Expand Up @@ -439,16 +447,26 @@ type CallExpr struct { // Func(Args<Varg?...>)

type IndexExpr struct { // X[Index]
Attributes
X Expr // expression
Index Expr // index expression
HasOK bool // if true, is form: `value, ok := <X>[<Key>]
X Expr // expression
Index Expr // index expression
HasOK bool // if true, is form: `value, ok := <X>[<Key>]
AbsPath string
}

func (ix *IndexExpr) GetAbsPath() string {
return ix.AbsPath
}

type SelectorExpr struct { // X.Sel
Attributes
X Expr // expression
Path ValuePath // set by preprocessor.
Sel Name // field selector
X Expr // expression
Path ValuePath // set by preprocessor.
Sel Name // field selector
AbsPath string
}

func (sx *SelectorExpr) GetAbsPath() string {
return sx.AbsPath
}

type SliceExpr struct { // X[Low:High:Max]
Expand All @@ -464,7 +482,12 @@ type SliceExpr struct { // X[Low:High:Max]
// expression, or a pointer type.
type StarExpr struct { // *X
Attributes
X Expr // operand
X Expr // operand
AbsPath string
}

func (sx *StarExpr) GetAbsPath() string {
return sx.AbsPath
}

type RefExpr struct { // &X
Expand Down Expand Up @@ -1364,6 +1387,7 @@ type PackageNode struct {
PkgPath string
PkgName Name
*FileSet
Time uint64
}

func PackageNodeLocation(path string) Location {
Expand Down Expand Up @@ -1529,7 +1553,7 @@ type BlockNode interface {
GetExternNames() []Name
GetNumNames() uint16
GetParentNode(Store) BlockNode
GetPathForName(Store, Name) ValuePath
GetPathForName(Store, Name) (ValuePath, string)
GetBlockNodeForPath(Store, ValuePath) BlockNode
GetIsConst(Store, Name) bool
GetLocalIndex(Name) (uint16, bool)
Expand All @@ -1555,6 +1579,7 @@ type StaticBlock struct {
Consts []Name // TODO consider merging with Names.
Externs []Name
Loc Location
BID BlockID

// temporary storage for rolling back redefinitions.
oldValues []oldValue
Expand Down Expand Up @@ -1662,14 +1687,16 @@ func (sb *StaticBlock) GetParentNode(store Store) BlockNode {

// Implements BlockNode.
// As a side effect, notes externally defined names.
func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath {
func (sb *StaticBlock) GetPathForName(store Store, n Name) (rel ValuePath, abs string) {
fmt.Println("---GetPathForName, n: ", n)
if n == blankIdentifier {
return NewValuePathBlock(0, 0, blankIdentifier)
return NewValuePathBlock(0, 0, blankIdentifier), ""
}
// Check local.
gen := 1
if idx, ok := sb.GetLocalIndex(n); ok {
return NewValuePathBlock(uint8(gen), idx, n)
fmt.Println("---bid1: ", sb.BID)
return NewValuePathBlock(uint8(gen), idx, n), fmt.Sprintf("%s:[%d]", sb.BID, idx)
}
// Register as extern.
// NOTE: uverse names are externs too.
Expand All @@ -1684,7 +1711,11 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath {
bp := sb.GetParentNode(store)
for bp != nil {
if idx, ok := bp.GetLocalIndex(n); ok {
return NewValuePathBlock(uint8(gen), idx, n)
fmt.Println("---bp: ", bp)
fmt.Println("---bid2: ", bp.GetStaticBlock().BID)
fmt.Println("---gen: ", gen)
fmt.Println("---idx: ", idx)
return NewValuePathBlock(uint8(gen), idx, n), fmt.Sprintf("%s:[%d]", bp.GetStaticBlock().BID, idx)
} else {
if !isFile(bp) {
bp.GetStaticBlock().addExternName(n)
Expand All @@ -1698,7 +1729,7 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath {
}
// Finally, check uverse.
if idx, ok := UverseNode().GetLocalIndex(n); ok {
return NewValuePathUverse(idx, n)
return NewValuePathUverse(idx, n), ""
}
// Name does not exist.
panic(fmt.Sprintf("name %s not declared", n))
Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/nodes_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func (vp ValuePath) String() string {
}
}

// TODO: modify this
func (x NameExpr) String() string {
switch x.Type {
case NameExprTypeNormal:
Expand Down
3 changes: 3 additions & 0 deletions gnovm/pkg/gnolang/op_assign.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package gnolang

import "fmt"

func (m *Machine) doOpDefine() {
s := m.PopStmt().(*AssignStmt)
// Define each value evaluated for Lhs.
Expand All @@ -26,6 +28,7 @@ func (m *Machine) doOpDefine() {

func (m *Machine) doOpAssign() {
s := m.PopStmt().(*AssignStmt)
fmt.Println("---doOpAssign, s: ", s)
// Assign each value evaluated for Lhs.
// NOTE: PopValues() returns a slice in
// forward order, not the usual reverse.
Expand Down
Loading
Loading