diff --git a/context.go b/context.go index a1fa3657..901a8456 100644 --- a/context.go +++ b/context.go @@ -176,6 +176,12 @@ func NewContext(mode Mode) *Context { return ctx } +func (ctx *Context) UnsafeRelease() { + ctx.pkgs = nil + ctx.Loader = nil + ctx.override = nil +} + func (ctx *Context) IsEvalMode() bool { return ctx.evalMode } @@ -424,6 +430,14 @@ func (ctx *Context) parseGoFiles(dir string, filenames []string) ([]*ast.File, e return files, nil } +func (ctx *Context) LoadInterp(filename string, src interface{}) (*Interp, error) { + pkg, err := ctx.LoadFile(filename, src) + if err != nil { + return nil, err + } + return ctx.NewInterp(pkg) +} + func (ctx *Context) LoadFile(filename string, src interface{}) (*ssa.Package, error) { file, err := ctx.ParseFile(filename, src) if err != nil { @@ -504,6 +518,7 @@ func (ctx *Context) RunPkg(mainPkg *ssa.Package, input string, args []string) (e if err != nil { return 2, err } + defer interp.UnsafeReleaseIcall() return ctx.RunInterp(interp, input, args) } diff --git a/go.mod b/go.mod index ddb33705..65b48d57 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/goplus/gop v1.1.4-0.20230225130145-e37691ce5fea github.com/goplus/gox v1.11.32 - github.com/goplus/reflectx v1.0.0 + github.com/goplus/reflectx v1.1.1 github.com/modern-go/reflect2 v1.0.2 github.com/peterh/liner v1.2.2 github.com/qiniu/x v1.11.9 diff --git a/go.sum b/go.sum index 81676fdc..cd28d4b1 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/goplus/gox v1.11.32/go.mod h1:hdKq5ghywtKWnBJNQNVBkPITmWCqCFRwwd2LTYT github.com/goplus/libc v0.3.13/go.mod h1:xqG4/g3ilKBE/UDn5vkaE7RRQPQPyspj7ecuMuvlQJ8= github.com/goplus/mod v0.9.12 h1:CjgBGQIYqUTPGl3MrAS5CICzJwxbIfSa4OlEb141Gs4= github.com/goplus/mod v0.9.12/go.mod h1:YoPIowz71rnLLROA4YG0AC8bzDtPRyMaQwgTRLr8ri4= -github.com/goplus/reflectx v1.0.0 h1:7KXnjojn5uM9ErYs/T9sf7+fdmO7obmpouMnOBhFBQE= -github.com/goplus/reflectx v1.0.0/go.mod h1:wHOS9ilbB4zrecI0W1dMmkW9JMcpXV7VjALVbNU9xfM= +github.com/goplus/reflectx v1.1.1 h1:4acdcG7+uIHdl7le1vAEt9M2HwGWNlVqv1fd4YsdCg0= +github.com/goplus/reflectx v1.1.1/go.mod h1:wHOS9ilbB4zrecI0W1dMmkW9JMcpXV7VjALVbNU9xfM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= diff --git a/interp.go b/interp.go index 1a86d43c..31946b4f 100644 --- a/interp.go +++ b/interp.go @@ -144,7 +144,7 @@ func (i *Interp) findType(rt reflect.Type, local bool) (types.Type, bool) { } func (i *Interp) tryDeferFrame() *frame { - if atomic.LoadInt32(&i.deferCount) != 0 { + if i != nil && atomic.LoadInt32(&i.deferCount) != 0 { if f, ok := i.deferMap.Load(goroutineID()); ok { return f.(*frame) } @@ -152,12 +152,16 @@ func (i *Interp) tryDeferFrame() *frame { return &frame{} } +func (pfn *function) callFunctionByReflect(mtyp reflect.Type, args []reflect.Value, env []interface{}) []reflect.Value { + return pfn.Interp.callFunctionByReflect(pfn.Interp.tryDeferFrame(), mtyp, pfn, args, env) +} + func (i *Interp) FindMethod(mtyp reflect.Type, fn *types.Func) func([]reflect.Value) []reflect.Value { typ := fn.Type().(*types.Signature).Recv().Type() if f := i.mainpkg.Prog.LookupMethod(typ, fn.Pkg(), fn.Name()); f != nil { pfn := i.loadFunction(f) return func(args []reflect.Value) []reflect.Value { - return i.callFunctionByReflect(i.tryDeferFrame(), mtyp, pfn, args, nil) + return pfn.callFunctionByReflect(mtyp, args, nil) } } name := fn.FullName() @@ -174,9 +178,9 @@ func (i *Interp) FindMethod(mtyp reflect.Type, fn *types.Func) func([]reflect.Va panic(fmt.Sprintf("Not found method %v", fn)) } -func (i *Interp) makeFunction(typ reflect.Type, pfn *function, env []value) reflect.Value { +func (pfn *function) makeFunction(typ reflect.Type, env []value) reflect.Value { return reflect.MakeFunc(typ, func(args []reflect.Value) []reflect.Value { - return i.callFunctionByReflect(i.tryDeferFrame(), typ, pfn, args, env) + return pfn.Interp.callFunctionByReflect(pfn.Interp.tryDeferFrame(), typ, pfn, args, env) }) } @@ -1129,7 +1133,6 @@ func doRecover(caller *frame) value { // func NewInterp(ctx *Context, mainpkg *ssa.Package) (*Interp, error) { - reflectx.Reset() return newInterp(ctx, mainpkg, nil) } @@ -1298,6 +1301,32 @@ func (i *Interp) RunInit() (err error) { return } +// icall allocate stat +func IcallStat() (capacity int, allocate int, aviable int) { + return reflectx.IcallStat() +} + +// icall allocate +func (i *Interp) IcallAlloc() int { + return i.record.rctx.IcallAlloc() +} + +func (i *Interp) UnsafeReleaseIcall() { + i.record.rctx.Reset() +} + +func (i *Interp) UnsafeRelease() { + i.record.Release() + for _, v := range i.funcs { + v.UnsafeRelease() + } + i.funcs = nil + i.msets = nil + i.globals = nil + i.preloadTypes = nil + i.record = nil +} + func (i *Interp) Abort() { atomic.StoreInt32(&i.exited, 1) } @@ -1325,7 +1354,7 @@ func (i *Interp) GetFunc(key string) (interface{}, bool) { if !ok { return nil, false } - return i.makeFunction(i.toType(fn.Type()), i.funcs[fn], nil).Interface(), true + return i.funcs[fn].makeFunction(i.toType(fn.Type()), nil).Interface(), true } func (i *Interp) GetVarAddr(key string) (interface{}, bool) { @@ -1402,7 +1431,7 @@ func (i *Interp) GetSymbol(key string) (m ssa.Member, v interface{}, ok bool) { v, ok = globalToValue(i, p) case *ssa.Function: typ := i.toType(p.Type()) - v = i.makeFunction(typ, i.funcs[p], nil) + v = i.funcs[p].makeFunction(typ, nil) case *ssa.Type: v = i.toType(p.Type()) } diff --git a/opblock.go b/opblock.go index e6271409..72d7df20 100644 --- a/opblock.go +++ b/opblock.go @@ -126,6 +126,20 @@ type function struct { cached int32 // enable cached by pool } +func (p *function) UnsafeRelease() { + p.Interp = nil + p.Fn = nil + p.pool = nil + p.index = nil + p.instrIndex = nil + p.Instrs = nil + p.Recover = nil + p.Blocks = nil + p.stack = nil + p.ssaInstrs = nil + p.Main = nil +} + func (p *function) initPool() { p.pool = &sync.Pool{} p.pool.New = func() interface{} { @@ -217,7 +231,7 @@ func (p *function) regInstr(v ssa.Value) uint32 { if v.Blocks != nil { typ := p.Interp.preToType(v.Type()) pfn := p.Interp.loadFunction(v) - vs = p.Interp.makeFunction(typ, pfn, nil).Interface() + vs = pfn.makeFunction(typ, nil).Interface() } else { ext, ok := findExternFunc(p.Interp, v) if !ok { @@ -494,7 +508,7 @@ func makeInstr(interp *Interp, pfn *function, instr ssa.Instruction) func(fr *fr for i := range instr.Bindings { bindings = append(bindings, fr.reg(ib[i])) } - v := interp.makeFunction(typ, pfn, bindings) + v := pfn.makeFunction(typ, bindings) fr.setReg(ir, v.Interface()) } case *ssa.MakeChan: @@ -1155,19 +1169,18 @@ func makeCallInstr(pfn *function, interp *Interp, instr ssa.Value, call *ssa.Cal } } -// makeFuncVal sync with Interp.makeFunc -// func (i *Interp) makeFunc(typ reflect.Type, pfn *Function, env []value) reflect.Value { +// makeFuncVal sync with function.makeFunction +// func (pfn *function) makeFunction(typ reflect.Type, env []value) reflect.Value { // return reflect.MakeFunc(typ, func(args []reflect.Value) []reflect.Value { -// return i.callFunctionByReflect(i.tryDeferFrame(), typ, pfn, args, env) +// return pfn.Interp.callFunctionByReflect(pfn.Interp.tryDeferFrame(), typ, pfn, args, env) // }) // } type makeFuncVal struct { funcval.FuncVal - interp *Interp - typ reflect.Type - pfn *function - env []interface{} + pfn *function + typ reflect.Type + env []interface{} } var ( diff --git a/runtime.go b/runtime.go index 1e568ff6..093b8196 100644 --- a/runtime.go +++ b/runtime.go @@ -62,15 +62,18 @@ func init() { RegisterExternal("runtime.Stack", runtimeStack) RegisterExternal("runtime/debug.Stack", debugStack) RegisterExternal("runtime/debug.PrintStack", debugPrintStack) - RegisterExternal("(reflect.Value).Pointer", func(v reflect.Value) uintptr { - if v.Kind() == reflect.Func { - if fv, n := funcval.Get(v.Interface()); n == 1 { - pc := (*makeFuncVal)(unsafe.Pointer(fv)).pfn.base - return uintptr(pc) + + if funcval.IsSupport { + RegisterExternal("(reflect.Value).Pointer", func(v reflect.Value) uintptr { + if v.Kind() == reflect.Func { + if fv, n := funcval.Get(v.Interface()); n == 1 { + pc := (*makeFuncVal)(unsafe.Pointer(fv)).pfn.base + return uintptr(pc) + } } - } - return v.Pointer() - }) + return v.Pointer() + }) + } } func runtimeFuncFileLine(fr *frame, f *runtime.Func, pc uintptr) (file string, line int) { diff --git a/visit.go b/visit.go index 8f0e9a11..7ef1d520 100644 --- a/visit.go +++ b/visit.go @@ -161,7 +161,7 @@ func (visit *visitor) findLinkFunc(sym *load.LinkSym) (ext reflect.Value, ok boo } typ := visit.intp.preToType(sig) pfn := visit.intp.loadFunction(link) - ext = visit.intp.makeFunction(typ, pfn, nil) + ext = pfn.makeFunction(typ, nil) ok = true } return diff --git a/xtypes.go b/xtypes.go index 84b3af46..a9edcdde 100644 --- a/xtypes.go +++ b/xtypes.go @@ -170,6 +170,7 @@ type FindMethod interface { } type TypesRecord struct { + rctx *reflectx.Context // reflectx context loader Loader finder FindMethod rcache map[reflect.Type]types.Type @@ -180,8 +181,19 @@ type TypesRecord struct { nstack nestedStack } +func (r *TypesRecord) Release() { + r.rctx.Reset() + r.loader = nil + r.rcache = nil + r.tcache = nil + r.ncache = nil + r.finder = nil + r.nested = nil +} + func NewTypesRecord(loader Loader, finder FindMethod, nested map[*types.Named]int) *TypesRecord { return &TypesRecord{ + rctx: reflectx.NewContext(), loader: loader, finder: finder, rcache: make(map[reflect.Type]types.Type), @@ -297,7 +309,7 @@ func (r *TypesRecord) toInterfaceType(t *types.Interface) (reflect.Type, bool) { ms[i].PkgPath = pkg.Path() } } - return reflectx.InterfaceOf(nil, ms), nested + return r.rctx.InterfaceOf(nil, ms), nested } func (r *TypesRecord) toNamedType(t *types.Named) (reflect.Type, bool) { @@ -322,7 +334,7 @@ func (r *TypesRecord) toNamedType(t *types.Named) (reflect.Type, bool) { } pcount++ } - typ = reflectx.NewMethodSet(typ, mcount, pcount) + typ = r.rctx.NewMethodSet(typ, mcount, pcount) } r.saveType(t, typ, nested) utype, _ := r.ToType(ut) @@ -352,7 +364,7 @@ func (r *TypesRecord) toStructType(t *types.Struct) (reflect.Type, bool) { } flds[i] = r.toStructField(f, typ, t.Tag(i)) } - typ := reflectx.StructOf(flds) + typ := r.rctx.StructOf(flds) methods := typeutil.IntuitiveMethodSet(t, nil) if numMethods := len(methods); numMethods != 0 { // anonymous structs with methods. struct { T } @@ -364,7 +376,7 @@ func (r *TypesRecord) toStructType(t *types.Struct) (reflect.Type, bool) { } pcount++ } - typ = reflectx.NewMethodSet(typ, mcount, pcount) + typ = r.rctx.NewMethodSet(typ, mcount, pcount) r.setMethods(typ, methods) } return typ, nested @@ -450,7 +462,7 @@ func (r *TypesRecord) setMethods(typ reflect.Type, methods []*types.Selection) { } ms = append(ms, reflectx.MakeMethod(fn.Name(), pkgpath, pointer, mtyp, mfn)) } - err := reflectx.SetMethodSet(typ, ms, false) + err := r.rctx.SetMethodSet(typ, ms, false) if err != nil { log.Fatalf("SetMethodSet %v err, %v\n", typ, err) }