Complete working GC mode.

This commit is contained in:
Greg 2019-06-19 14:07:33 -04:00
parent c8209dd260
commit 4aa1211d73
5 changed files with 50 additions and 45 deletions

View File

@ -38,9 +38,9 @@ func discoverPeripheral(c *ns.CBCentralManager, p *ns.CBPeripheral, d *ns.NSDict
// and if so release the old one. Be careful to check the Objective-C pointers // and if so release the old one. Be careful to check the Objective-C pointers
// here as the Go pointers will differ. // here as the Go pointers will differ.
// if peripheral != nil && p.Ptr() != peripheral.Ptr() { if peripheral != nil && p.Ptr() != peripheral.Ptr() {
// peripheral.Release() peripheral.Release()
// } }
peripheral = p peripheral = p

View File

@ -151,7 +151,7 @@ func memtest5() {
time.Sleep(time.Second/50) time.Sleep(time.Second/50)
runtime.GC() runtime.GC()
i++ i++
fmt.Printf("loop completed\n") //fmt.Printf("loop completed\n")
} }
} }

View File

@ -314,9 +314,7 @@ type %s interface {
type %s struct { %s } type %s struct { %s }
func (o *%s) Ptr() unsafe.Pointer { if o == nil { return nil }; return o.ptr } func (o *%s) Ptr() unsafe.Pointer { if o == nil { return nil }; return o.ptr }
func (o *Id) %s() *%s { func (o *Id) %s() *%s {
ret := &%s{} return (*%s)(unsafe.Pointer(o))
ret.ptr = o.ptr
return ret
} }
`, gt, super, gt, gt, gt, gt) `, gt, super, gt, gt, gt, gt)
} }

View File

@ -9,7 +9,7 @@ var (
) )
func dbg(f string, xs ...interface{}) { func dbg(f string, xs ...interface{}) {
if Debug { if Debug && false {
fmt.Printf(f, xs...) fmt.Printf(f, xs...)
} }
} }

View File

@ -153,25 +153,25 @@ type Method struct {
} }
func (m *Method) ShouldFinalize() bool { func (m *Method) ShouldFinalize() bool {
return shouldFinalize(m.Type.GoType(), m.Name) grtype := m.Type.GoType()
} return Gogc && grtype != "NSAutoreleasePool" &&
func shouldFinalize (grtype, name string) bool {
return Gogc && grtype != "*NSAutoreleasePool" &&
(types.PtrShouldWrap(grtype) || grtype == "*Id") && (types.PtrShouldWrap(grtype) || grtype == "*Id") &&
(len(name) < 6 || name != "retain") (!m.ClassMethod || IsRetained(m.Name))
} }
// IsRetained returns true if the name matches a retained property for the // IsRetained returns true if a given instance method returns a retained object.
// given interface. func IsRetained(name string) bool {
func (i *Interface) IsRetained(name string) bool { return (
// init, copy and MutableCopy always return a retained object (len(name) >= 3 && name[:3] == "new") ||
if len(name) >= 4 && (name[:4] == "init" || (len(name) >= 4 && name[:4] == "init") ||
name[:4] == "copy") || (len(name) >= 4 && name[:4] == "copy") ||
len(name) >= 11 && name[:11] == "mutableCopy" { (len(name) >= 5 && name[:5] == "alloc") ||
return true (len(name) >= 11 && name[:11] == "mutableCopy"))
} }
// IsRetainedProperty returns true if the name matches a retained property for
// the given interface.
func (i *Interface) IsRetainedProperty(name string) bool {
if p, ok := i.Properties[name]; ok { if p, ok := i.Properties[name]; ok {
if p.retained { if p.retained {
return true return true
@ -976,6 +976,7 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
gname = strings.Title(gname) gname = strings.Title(gname)
gname = strings.ReplaceAll(gname, " ", "") gname = strings.ReplaceAll(gname, " ", "")
receiver := "" receiver := ""
constructor := false // this is an autoreleased object constructor
var cname string var cname string
if fun { if fun {
cname = m.Name cname = m.Name
@ -985,6 +986,16 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
if Debug { if Debug {
fmt.Printf("Method %s (GoClass %s)\n", cname, m.GoClass) fmt.Printf("Method %s (GoClass %s)\n", cname, m.GoClass)
} }
grtype := m.Type.GoType()
if grtype == "Void" {
grtype = ""
}
if types.PtrIsGoInterface(grtype) {
grtype = "*Id"
}
if grtype == "BOOL" { // convert objective-c bools to Go bools
grtype = "bool"
}
switch { switch {
case !m.ClassMethod: case !m.ClassMethod:
if types.IsGoInterface(m.GoClass) { if types.IsGoInterface(m.GoClass) {
@ -994,15 +1005,19 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
} }
//Disambiguate instance methods with same name as a class method //Disambiguate instance methods with same name as a class method
cname = "inst_" + cname cname = "inst_" + cname
default: case m.ClassMethod:
//Shorten class method names //Shorten class method names
lens1 := len(m.Class) lens1 := len(m.Class)
i := 0 i := 0
if len(gname) < len(m.Class) { if len(gname) < lens1 {
i = lens1 - len(gname) i = lens1 - len(gname)
} }
for ; i < lens1; i++ { for ; i < lens1; i++ {
if m.Class[i:] == gname[:lens1-i] { if m.Class[i:] == gname[:lens1-i] {
if Gogc &&
(types.PtrShouldWrap(grtype) || grtype == "*Id") {
constructor = true
}
break break
} }
} }
@ -1029,16 +1044,6 @@ func (w *Wrapper) _processMethod(m *Method, fun bool) {
cmtype = m.Type.CTypeAttrib() cmtype = m.Type.CTypeAttrib()
} }
ns, snames, tps, gplist := w.gpntp(m) ns, snames, tps, gplist := w.gpntp(m)
grtype := m.Type.GoType()
if grtype == "Void" {
grtype = ""
}
if types.PtrIsGoInterface(grtype) {
grtype = "*Id"
}
if grtype == "BOOL" { // convert objective-c bools to Go bools
grtype = "bool"
}
if gname == grtype { // avoid name conflicts between methods and types if gname == grtype { // avoid name conflicts between methods and types
gname = "Get" + gname gname = "Get" + gname
} }
@ -1088,7 +1093,7 @@ func %s%s(%s) %s {
`, snames[i], n, n, snames[i], n)) `, snames[i], n, n, snames[i], n))
} }
w.goCode.WriteString(` ` + w.goCode.WriteString(` ` +
types.GoToC(m.Name, cname, ns, snames, m.Type, tps, fun, m.ShouldFinalize(), m.ClassMethod) + "\n}\n") types.GoToC(m.Name, cname, ns, snames, m.Type, tps, fun, constructor || m.ShouldFinalize(), m.ClassMethod) + "\n}\n")
cret := "" cret := ""
if !m.isVoid() { if !m.isVoid() {
@ -1131,15 +1136,14 @@ func %s%s(%s) %s {
if types.PtrShouldWrap(m.Type.GoType()) { if types.PtrShouldWrap(m.Type.GoType()) {
switch { switch {
case m.ClassMethod: case m.ClassMethod:
if grtype != "*NSAutoreleasePool" { if grtype != "*NSAutoreleasePool" && constructor {
// retain objects returned by class methods // retain objects returned by class constructor methods
rtn = ` rtn = `
[ret retain];` [ret retain];`
} }
// some methods always return retained objects, // do not retain new, alloc, init and copy methods
// including "getters" for retained properties. case IsRetained(m.Name):
case inter.IsRetained(m.Name):
default: default:
// by default, for instance methods, retain // by default, for instance methods, retain
@ -1148,13 +1152,16 @@ func %s%s(%s) %s {
if (o != ret) { [ret retain]; }` if (o != ret) { [ret retain]; }`
} }
} }
var ar1, ar2 string
if constructor || true {
ar1 = "@autoreleasepool {\n\t\t"
ar2 = "\n }"
}
w.cCode.WriteString(fmt.Sprintf( w.cCode.WriteString(fmt.Sprintf(
` %s ret; ` %s ret;
@autoreleasepool { %sret = [%s %s];%s%s
ret = [%s %s];%s
}
return ret; return ret;
}`, m.Type.CTypeAttrib(), cobj, w.objcparamlist(m),rtn)) }`, m.Type.CTypeAttrib(), ar1, cobj, w.objcparamlist(m), rtn, ar2))
} else { } else {
w.cCode.WriteString(fmt.Sprintf(` %s[%s %s]; w.cCode.WriteString(fmt.Sprintf(` %s[%s %s];
}`, cret, cobj, w.objcparamlist(m))) }`, cret, cobj, w.objcparamlist(m)))