From b93590457e7d73f54d1a6c31eafa5e4df87f0f52 Mon Sep 17 00:00:00 2001 From: ltzMaxwell Date: Thu, 16 Jan 2025 23:21:04 +0800 Subject: [PATCH] fixup --- gnovm/pkg/gnolang/alloc.go | 23 ++++++++++++----- gnovm/pkg/gnolang/debug_false.go | 7 +++-- gnovm/pkg/gnolang/machine.go | 22 ++++++++++++---- gnovm/pkg/gnolang/nodes.go | 2 ++ gnovm/pkg/gnolang/op_call.go | 3 ++- gnovm/pkg/gnolang/op_expressions.go | 1 + gnovm/pkg/gnolang/preprocess.go | 1 + gnovm/pkg/gnolang/store.go | 3 +++ gnovm/pkg/gnolang/values.go | 7 +++++ gnovm/pkg/test/filetest.go | 3 ++- gnovm/pkg/test/test.go | 1 + gnovm/stdlibs/generated.go | 34 ++++++++++++++++++++++++ gnovm/stdlibs/runtime/runtime.gno | 4 +++ gnovm/stdlibs/runtime/runtime.go | 11 ++++++++ gnovm/tests/files/alloc1.gno | 40 +++++++++++++++++++---------- 15 files changed, 132 insertions(+), 30 deletions(-) create mode 100644 gnovm/stdlibs/runtime/runtime.gno create mode 100644 gnovm/stdlibs/runtime/runtime.go diff --git a/gnovm/pkg/gnolang/alloc.go b/gnovm/pkg/gnolang/alloc.go index 019d6f7db91..7a313180cde 100644 --- a/gnovm/pkg/gnolang/alloc.go +++ b/gnovm/pkg/gnolang/alloc.go @@ -105,11 +105,11 @@ func (alloc *Allocator) Fork() *Allocator { } func (alloc *Allocator) MemStats() string { - return fmt.Sprintf("Allocator{maxBytes:%d,bytes,bytes:%d}", alloc.maxBytes, alloc.bytes) + return fmt.Sprintf("Allocator{maxBytes:%d, bytes:%d}", alloc.maxBytes, alloc.bytes) } func (alloc *Allocator) GC() { - println("---gc") + debug2.Println2("---gc") // a throwaway allocator throwaway := NewAllocator(3000, nil) debug2.Println2("m: ", alloc.m) @@ -151,7 +151,7 @@ func (alloc *Allocator) GC() { debug2.Println2("---throwaway.bytes: ", throwaway.bytes) debug2.Println2("---before reset, alloc.bytes: ", alloc.bytes) alloc.bytes = throwaway.bytes - println("---after reset, alloc.bytes: ", alloc.bytes) + debug2.Println2("---after reset, alloc.bytes: ", alloc.bytes) } func (throwaway *Allocator) allocate2(v Value) { @@ -165,7 +165,16 @@ func (throwaway *Allocator) allocate2(v Value) { throwaway.allocate2(field.V) } case *FuncValue: - throwaway.AllocateFunc() + // TODO: is this right? + // if closure if fileNode, no allocate, + // cuz it's already done in compile stage. + debug2.Println2("funcValue, vv: ", vv) + debug2.Println2("clo: ", vv.Closure) + debug2.Println2("clo...Source: ", vv.Closure.(*Block).Source, reflect.TypeOf(vv.Closure.(*Block).Source)) + if _, ok := vv.Closure.(*Block).Source.(*FileNode); !ok { + debug2.Println2("not a FileNode, alloc func") + throwaway.AllocateFunc() + } case PointerValue: throwaway.AllocatePointer() throwaway.allocate2(vv.Base) @@ -213,14 +222,14 @@ func (alloc *Allocator) Allocate(size int64) { debug2.Println2("new allocated: ", size) alloc.bytes += size - debug2.Println2("bytes after allocated: ", alloc.bytes) + debug2.Println2("===========bytes after allocated============: ", alloc.bytes) if alloc.bytes > alloc.maxBytes { panic("allocation limit exceeded") } } func (alloc *Allocator) AllocateString(size int64) { - debug2.Println2("AllocateString") + debug2.Println2("AllocateString, size: ", size) alloc.Allocate(allocString + allocStringByte*size) } @@ -317,7 +326,7 @@ func (alloc *Allocator) AllocateHeapItem() { // constructor utilities. func (alloc *Allocator) NewString(s string) StringValue { - debug2.Println2("NewString: ", s) + debug2.Printf2("NewString, s: \"%s\" \n", s) alloc.AllocateString(int64(len(s))) return StringValue(s) } diff --git a/gnovm/pkg/gnolang/debug_false.go b/gnovm/pkg/gnolang/debug_false.go index 8252bde3abf..30e0af810f2 100644 --- a/gnovm/pkg/gnolang/debug_false.go +++ b/gnovm/pkg/gnolang/debug_false.go @@ -2,6 +2,9 @@ package gnolang -const debug debugging = false +//const debug debugging = true + +//const debug2 debugging = false -const debug2 debugging = false +const debug2 debugging = true +const debug debugging = false diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 9bf33d1b943..18488098245 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -134,6 +134,7 @@ var machinePool = sync.Pool{ // Machines initialized through this constructor must be finalized with // [Machine.Release]. func NewMachineWithOptions(opts MachineOptions) *Machine { + debug2.Println2("NewMachineWithOptions start") preprocessorMode := opts.PreprocessorMode readOnly := opts.ReadOnly maxCycles := opts.MaxCycles @@ -184,6 +185,7 @@ func NewMachineWithOptions(opts MachineOptions) *Machine { if pv != nil { mm.SetActivePackage(pv) } + debug2.Println2("NewMachineWithOptions end, Memstats: ", mm.Alloc.MemStats()) return mm } @@ -233,6 +235,8 @@ func (m *Machine) SetActivePackage(pv *PackageValue) { // NOTE: package paths not beginning with gno.land will be allowed to override, // to support cases of stdlibs processed through [RunMemPackagesWithOverrides]. func (m *Machine) PreprocessAllFilesAndSaveBlockNodes() { + debug2.Println2("=======PreprocessAllFilesAndSaveBlockNodes") + defer debug2.Println2("=========Done PreprocessAllFilesAndSaveBlockNodes") ch := m.Store.IterMemPackage() for memPkg := range ch { fset := ParseMemPackage(memPkg) @@ -462,8 +466,9 @@ func (m *Machine) RunFiles(fns ...*FileNode) { // This will also run each init function encountered. // Returns the updated typed values of package. func (m *Machine) runFileDecls(fns ...*FileNode) []TypedValue { - debug2.Println2("===runFileDecls", len(fns)) - defer debug2.Println2("===Done runFileDecls") + debug2.Println2("===runFileDecls, fns: ", fns) + debug2.Println2("Memstats: ", m.Alloc.MemStats()) + defer debug2.Println2("=======Done runFileDecls========") // Files' package names must match the machine's active one. // if there is one. for _, fn := range fns { @@ -515,7 +520,8 @@ func (m *Machine) runFileDecls(fns ...*FileNode) []TypedValue { // Each file for each *PackageValue gets its own file *Block, // with values copied over from each file's // *FileNode.StaticBlock. - debug2.Println2("---machine, runFileDecls") + debug2.Println2("============machine, runFileDecls, count from here===============") + debug2.Println2("Memstats: ", m.Alloc.MemStats()) fb := m.Alloc.NewBlock(fn, pb) fb.Values = make([]TypedValue, len(fn.StaticBlock.Values)) copy(fb.Values, fn.StaticBlock.Values) @@ -530,6 +536,7 @@ func (m *Machine) runFileDecls(fns ...*FileNode) []TypedValue { // recursive function for var declarations. var runDeclarationFor func(fn *FileNode, decl Decl) runDeclarationFor = func(fn *FileNode, decl Decl) { + debug2.Println2("runDeclarationFor, decl: ", decl) // get fileblock of fn. // fb := pv.GetFileBlock(nil, fn.Name) // get dependencies of decl. @@ -669,6 +676,7 @@ func (m *Machine) resavePackageValues(rlm *Realm) { } func (m *Machine) RunFunc(fn Name) { + debug2.Println2("Running func", fn) defer func() { if r := recover(); r != nil { switch r := r.(type) { @@ -686,6 +694,7 @@ func (m *Machine) RunFunc(fn Name) { } func (m *Machine) RunMain() { + debug2.Println2("Running main") defer func() { r := recover() @@ -814,8 +823,9 @@ func (m *Machine) EvalStaticTypeOf(last BlockNode, x Expr) Type { func (m *Machine) RunStatement(s Stmt) { sn := m.LastBlock().GetSource(m.Store) s = Preprocess(m.Store, sn, s).(Stmt) - debug2.Println2("Machine.RunStatement, s: ", s) - debug2.Println2("current machine: ", m) + debug2.Println2("==========Machine.RunStatement, s: ", s) + debug2.Println2("memstats: ", m.Alloc.MemStats()) + //debug2.Println2("current machine: ", m) m.PushOp(OpHalt) m.PushStmt(s) m.PushOp(OpExec) @@ -854,6 +864,7 @@ func (m *Machine) RunDeclaration(d Decl) { // package level, for which evaluations happen during // preprocessing). func (m *Machine) runDeclaration(d Decl) { + debug2.Println2("runDeclaration: ", d) switch d := d.(type) { case *FuncDecl: // nothing to do. @@ -1659,6 +1670,7 @@ func (m *Machine) PushValue(tv TypedValue) { if debug { m.Printf("+v %v\n", tv) } + debug2.Printf2("+v %v\n", tv) if len(m.Values) == m.NumValues { // TODO tune. also see PushOp(). newValues := make([]TypedValue, len(m.Values)*2) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 0496d37ed72..db931d21261 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -1412,6 +1412,7 @@ func (x *PackageNode) NewPackage() *PackageValue { // NOTE: declared methods do not get their closures set here. See // *DeclaredType.GetValueAt() which returns a filled copy. func (x *PackageNode) PrepareNewValues(pv *PackageValue) []TypedValue { + debug2.Println2("PrepareNewValues") if pv.PkgPath == "" { // nothing to prepare for throwaway packages. // TODO: double check to see if still relevant. @@ -1444,6 +1445,7 @@ func (x *PackageNode) PrepareNewValues(pv *PackageValue) []TypedValue { for i, tv := range nvs { if fv, ok := tv.V.(*FuncValue); ok { // copy function value and assign closure from package value. + debug2.Println2("Copy fv: ", fv) fv = fv.Copy(nilAllocator) fv.Closure = pv.fBlocksMap[fv.FileName] if fv.Closure == nil { diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 95c7f786dbc..cdebb2314ec 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -153,8 +153,9 @@ func (m *Machine) doOpCall() { } } else { list := m.PopCopyValues(nvar) + debug2.Println2("list: ", list) vart := pts[numParams-1].Type.(*SliceType) - debug2.Println2("varg") + debug2.Println2("has varg") varg := m.Alloc.NewSliceFromList(list) m.PushValue(TypedValue{ T: vart, diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 7dff5a1bc30..b4c22cc1796 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -204,6 +204,7 @@ func (m *Machine) doOpRef() { if elt == DataByteType { elt = xv.TV.V.(DataByteValue).ElemType } + debug2.Println2("doOpRef, new type") m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{Elt: elt}), V: xv, diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 79695d8888a..35a6f99a49f 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -21,6 +21,7 @@ const ( // Anything predefined or preprocessed here get skipped during the Preprocess // phase. func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { + debug2.Println2("PredefineFileSet") // First, initialize all file nodes and connect to package node. // This will also reserve names on BlockNode.StaticBlock by // calling StaticBlock.Predefine(). diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index bc56a7c6313..030e8a0af19 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -266,6 +266,8 @@ func (ds *defaultStore) SetPackageGetter(pg PackageGetter) { // Gets package from cache, or loads it from baseStore, or gets it from package getter. func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue { + debug2.Println2("GetPackage, pkgPath: ", pkgPath) + debug2.Println("ds.Alloc: ", ds.alloc) // helper to detect circular imports if isImport { if slices.Contains(ds.current, pkgPath) { @@ -430,6 +432,7 @@ func (ds *defaultStore) GetObjectSafe(oid ObjectID) Object { // loads and caches an object. // CONTRACT: object isn't already in the cache. func (ds *defaultStore) loadObjectSafe(oid ObjectID) Object { + debug2.Println2("loadObjectSafe", oid) if bm.OpsEnabled { bm.PauseOpCode() defer bm.ResumeOpCode() diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index f0bd67d401e..f37742ca175 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -570,6 +570,13 @@ func (fv *FuncValue) IsNative() bool { func (fv *FuncValue) Copy(alloc *Allocator) *FuncValue { debug2.Println2("Copy, fv: ", fv) debug2.Println2("allocator: ", alloc) + debug2.Println2("fv.clo: ", fv.Closure) + if b, ok := fv.Closure.(*Block); ok { + debug2.Println2("containing block of fv is: ", b) + if b != nil { + debug2.Println2("fv...source, type of source", b.Source, reflect.TypeOf(b.Source)) + } + } alloc.AllocateFunc() return &FuncValue{ Type: fv.Type, diff --git a/gnovm/pkg/test/filetest.go b/gnovm/pkg/test/filetest.go index f0b8b0b6274..e846127f199 100644 --- a/gnovm/pkg/test/filetest.go +++ b/gnovm/pkg/test/filetest.go @@ -184,6 +184,7 @@ type runResult struct { } func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, content []byte) (rr runResult) { + fmt.Println("runTest") pkgName := gno.Name(pkgPath[strings.LastIndexByte(pkgPath, '/')+1:]) // Eagerly load imports. @@ -236,7 +237,7 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte m.SetActivePackage(pv) n := gno.MustParseFile(filename, string(content)) m.RunFiles(n) - //fmt.Println("---after RunFiles, m: ", m) + fmt.Println("======after RunFiles, m.Alloc.Memstats: ", m.Alloc.MemStats()) m.RunStatement(gno.S(gno.Call(gno.X("main")))) } else { diff --git a/gnovm/pkg/test/test.go b/gnovm/pkg/test/test.go index 0c34e156260..954b35e1f5f 100644 --- a/gnovm/pkg/test/test.go +++ b/gnovm/pkg/test/test.go @@ -270,6 +270,7 @@ func (opts *TestOptions) runTestFiles( files *gno.FileSet, cw storetypes.Store, gs gno.TransactionStore, ) (errs error) { + fmt.Println("runTestFiles") var m *gno.Machine defer func() { if r := recover(); r != nil { diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 9f545f97b36..0182b1dd5cf 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -10,6 +10,7 @@ import ( libs_crypto_ed25519 "github.com/gnolang/gno/gnovm/stdlibs/crypto/ed25519" libs_crypto_sha256 "github.com/gnolang/gno/gnovm/stdlibs/crypto/sha256" libs_math "github.com/gnolang/gno/gnovm/stdlibs/math" + libs_runtime "github.com/gnolang/gno/gnovm/stdlibs/runtime" libs_std "github.com/gnolang/gno/gnovm/stdlibs/std" libs_testing "github.com/gnolang/gno/gnovm/stdlibs/testing" libs_time "github.com/gnolang/gno/gnovm/stdlibs/time" @@ -210,6 +211,38 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, + { + "runtime", + "GC", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{}, + true, + func(m *gno.Machine) { + libs_runtime.GC( + m, + ) + }, + }, + { + "runtime", + "MemStats", + []gno.FieldTypeExpr{}, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("string")}, + }, + true, + func(m *gno.Machine) { + r0 := libs_runtime.MemStats( + m, + ) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "std", "bankerGetCoins", @@ -1034,6 +1067,7 @@ var initOrder = [...]string{ "net/url", "regexp/syntax", "regexp", + "runtime", "std", "testing", "time", diff --git a/gnovm/stdlibs/runtime/runtime.gno b/gnovm/stdlibs/runtime/runtime.gno new file mode 100644 index 00000000000..e68c0840050 --- /dev/null +++ b/gnovm/stdlibs/runtime/runtime.gno @@ -0,0 +1,4 @@ +package runtime + +func GC() +func MemStats() string diff --git a/gnovm/stdlibs/runtime/runtime.go b/gnovm/stdlibs/runtime/runtime.go new file mode 100644 index 00000000000..4702340b6a5 --- /dev/null +++ b/gnovm/stdlibs/runtime/runtime.go @@ -0,0 +1,11 @@ +package runtime + +import gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + +func GC(m *gno.Machine) { + m.Alloc.GC() +} + +func MemStats(m *gno.Machine) string { + return m.Alloc.MemStats() +} diff --git a/gnovm/tests/files/alloc1.gno b/gnovm/tests/files/alloc1.gno index 2f970ad5b18..e6252eb7072 100644 --- a/gnovm/tests/files/alloc1.gno +++ b/gnovm/tests/files/alloc1.gno @@ -2,34 +2,46 @@ // max total allocation of 100 mb. package main -import "std" +import "runtime" +// fileBlock: 496 + n*40 = 536 var c = 1 var b = "hello" // rhs is const +// map: 176 + n*120 var m = map[string]int{"a": 1} type Foo struct{ name string } +// after new block: 3483 func bar() { - f := &Foo{"foo"} + f := &Foo{"foo"} // + field 40 + struct 184 + pointer 24 + heapItem 72 + NewType: *main.Foo 232 = 4305 f2 := f - println(f) - bb := &Foo{"bar"} - println("MemStats 2: ", std.MemStats()) + println(f) // +536 + 72 + 248 = 4891 + bb := &Foo{"foo2"} // + 40 + 184 + pointer 24 + heapItem72 + new type 232 = 5443 + println("MemStats 2: ", runtime.MemStats()) // 5979 + 536 + new string 67 = 6046 } +// before this, declaration is 536 + 176 + 120 = 832, +// + new block: 536 func main() { a := 1 - println("MemStats 1: ", std.MemStats()) - bar() - println("MemStats before GC: ", std.MemStats()) - std.GC() - println("MemStats after GC: ", std.MemStats()) + println("MemStats 1: ", runtime.MemStats()) // + 536 + 536 + NewString: 67 + (list)72 + 288 = 2867 + bar() // +616 + println("MemStats before GC: ", runtime.MemStats()) // 6046 + 536 + 72 + 288 + ... 7478(the moment memstas result generated) + runtime.GC() + println("MemStats after GC: ", runtime.MemStats()) + + f := func() { + println("func lit") + } + f() + runtime.GC() } // Output: -// MemStats 1: Allocator{maxBytes:10000000000,bytes,bytes:1904} +// MemStats 1: Allocator{maxBytes:10000000000, bytes:1944} // &(struct{("foo" string)} main.Foo) -// MemStats 2: Allocator{maxBytes:10000000000,bytes,bytes:5984} -// MemStats before GC: Allocator{maxBytes:10000000000,bytes,bytes:7488} -// MemStats after GC: Allocator{maxBytes:10000000000,bytes,bytes:3197} +// MemStats 2: Allocator{maxBytes:10000000000, bytes:6019} +// MemStats before GC: Allocator{maxBytes:10000000000, bytes:7518} +// MemStats after GC: Allocator{maxBytes:10000000000, bytes:2901} +// func lit