diff --git a/examples/gno.land/p/demo/tests/p_crossrealm/p_crossrealm.gno b/examples/gno.land/p/demo/tests/p_crossrealm/p_crossrealm.gno new file mode 100644 index 00000000000..6d46203e98c --- /dev/null +++ b/examples/gno.land/p/demo/tests/p_crossrealm/p_crossrealm.gno @@ -0,0 +1,24 @@ +package p_crossrealm + +type Stringer interface { + String() string +} + +type Container struct { + A int + B Stringer +} + +func (c *Container) Touch() *Container { + c.A += 1 + return c +} + +func (c *Container) Print() { + println("A:", c.A) + if c.B == nil { + println("B: undefined") + } else { + println("B:", c.B.String()) + } +} diff --git a/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno b/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno new file mode 100644 index 00000000000..97273f642de --- /dev/null +++ b/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno @@ -0,0 +1,29 @@ +package crossrealm + +import ( + "gno.land/p/demo/tests/p_crossrealm" + "gno.land/p/demo/ufmt" +) + +type LocalStruct struct { + A int +} + +func (ls *LocalStruct) String() string { + return ufmt.Sprintf("LocalStruct{%d}", ls.A) +} + +// local is saved locally in this realm +var local *LocalStruct + +func init() { + local = &LocalStruct{A: 123} +} + +// Make1 returns a local object wrapped by a p struct +func Make1() *p_crossrealm.Container { + return &p_crossrealm.Container{ + A: 1, + B: local, + } +} diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index aa89b643ea6..413ff006ec5 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -279,7 +279,11 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* } else { pn = NewPackageNode(Name(memPkg.Name), memPkg.Path, &FileSet{}) pv = pn.NewPackage() - m.Store.SetBlockNode(pn) + if true { // TODO finish SetBlockNode() + m.Store.SetBlockNode(pn) + } else { + // TODO m.Store.SetCacheBlockNode(pn) + } m.Store.SetCachePackage(pv) } m.SetActivePackage(pv) @@ -1740,8 +1744,24 @@ func (m *Machine) PushFrameCall(cx *CallExpr, fv *FuncValue, recv TypedValue) { } m.Package = pv rlm := pv.GetRealm() + if rlm == nil && recv.IsDefined() { + // if bound method, get realm from receiver. + obj := recv.GetFirstObject(m.Store) + if obj == nil { + // panic("XXX not sure why this would be") + fmt.Println("XXX XXX", recv.String()) + } else { + recvOID := obj.GetObjectInfo().ID + if !recvOID.IsZero() { + recvPkgOID := ObjectIDFromPkgID(recvOID.PkgID) + pv := m.Store.GetObject(recvPkgOID).(*PackageValue) + rlm = pv.GetRealm() // done + } + } + } if rlm != nil && m.Realm != rlm { - m.Realm = rlm // enter new realm + // enter new realm + m.Realm = rlm } } diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 3a55b2e14b4..093cc934658 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -70,12 +70,21 @@ func (pid PkgID) Bytes() []byte { } func PkgIDFromPkgPath(path string) PkgID { + // fmt.Printf("PkgPath %s -> PkgID %v", path, + // PkgID{HashBytes([]byte(path))}) return PkgID{HashBytes([]byte(path))} } +// Returns the ObjectID of the PackageValue associated with path. func ObjectIDFromPkgPath(path string) ObjectID { + pkgID := PkgIDFromPkgPath(path) + return ObjectIDFromPkgID(pkgID) +} + +// Returns the ObjectID of the PackageValue associated with pkgID. +func ObjectIDFromPkgID(pkgID PkgID) ObjectID { return ObjectID{ - PkgID: PkgIDFromPkgPath(path), + PkgID: pkgID, NewTime: 1, // by realm logic. } } @@ -145,6 +154,10 @@ func (rlm *Realm) DidUpdate(po, xo, co Object) { return // do nothing. } if po.GetObjectID().PkgID != rlm.ID { + // fmt.Println("PO", po.String()) + // fmt.Println("PO.PKGID", po.GetObjectID().PkgID) + // fmt.Println("rlm", rlm) + // fmt.Println("rlm.ID", rlm.ID) panic("cannot modify external-realm or non-realm object") } diff --git a/gnovm/tests/files/zrealm_crossrealm13.gno b/gnovm/tests/files/zrealm_crossrealm13.gno new file mode 100644 index 00000000000..23451e6f5d1 --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm13.gno @@ -0,0 +1,17 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + crossrealm "gno.land/r/demo/tests/crossrealm" +) + +func main() { + // even though we are running within a realm, + // we aren't storing the result of crossrealm.Make1(), + // so this should print fine. + crossrealm.Make1().Touch().Print() +} + +// Output: +// A: 2 +// B: LocalStruct{123}