Skip to content

Commit

Permalink
before unload module, unregister itab from itabList, otherwise, there…
Browse files Browse the repository at this point in the history
… will be panic when the itabList grow
  • Loading branch information
pkujhd committed May 2, 2020
1 parent 882355b commit 1c0d793
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 61 deletions.
3 changes: 3 additions & 0 deletions dymcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ func Load(code *CodeReloc, symPtr map[string]uintptr) (*CodeModule, error) {
}

func (cm *CodeModule) Unload() {
for i := 0; i < len(cm.itabs); i++ {
eraseiface(cm.itabs[i].inter, cm.itabs[i]._type)
}
runtime.GC()
modulesLock.Lock()
removeModule(cm.Module)
Expand Down
62 changes: 62 additions & 0 deletions iface.1.10.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// +build go1.10
// +build !go1.15

package goloader

import (
"unsafe"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

const itabInitSize = 512

// Note: change the formula in the mallocgc call in itabAdd if you change these fields.
type itabTableType struct {
size uintptr // length of entries array. Always a power of 2.
count uintptr // current number of filled entries.
entries [itabInitSize]*itab // really [size] large
}

//go:linkname itabTable runtime.itabTable
var itabTable *itabTableType // pointer to current table

//go:linkname itabLock runtime.itabLock
var itabLock mutex

//go:linkname itabHashFunc runtime.itabHashFunc
func itabHashFunc(inter *interfacetype, typ *_type) uintptr

func eraseiface(inter *interfacetype, typ *_type) bool {
lock(&itabLock)
defer unlock(&itabLock)
mask := itabTable.size - 1
h := itabHashFunc(inter, typ) & mask
for i := uintptr(1); ; i++ {
p := (**itab)(add(unsafe.Pointer(&itabTable.entries), h*PtrSize))
// Use atomic read here so if we see m != nil, we also see
// the initializations of the fields of m.
// m := *p
m := (*itab)(Loadp(unsafe.Pointer(p)))
if m == nil {
return false
}
if m.inter == inter && m._type == typ {
atomicstorep(unsafe.Pointer(p), unsafe.Pointer(nil))
itabTable.count = itabTable.count - 1
return true
}
h += i
h &= mask
}
}
52 changes: 52 additions & 0 deletions iface.1.8.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// +build go1.8
// +build !go1.10,!go1.11,!go1.12,!go1.13,!go1.14,!go1.15

package goloader

import (
"unsafe"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {
inter *interfacetype
_type *_type
link *itab
bad int32
inhash int32 // has this itab been added to hash?
fun [1]uintptr // variable sized
}

// See: src/runtime/iface.go
const hashSize = 1009

//go:linkname hash runtime.hash
var hash [hashSize]*itab

//go:linkname ifaceLock runtime.ifaceLock
var ifaceLock mutex

//go:linkname itabhash runtime.itabhash
func itabhash(inter *interfacetype, typ *_type) uint32

func eraseiface(inter *interfacetype, typ *_type) bool {
lock(&ifaceLock)
defer unlock(&ifaceLock)
h := itabhash(inter, typ)
var m, last *itab = nil, nil
for m = (*itab)(Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
if m.inter == inter && m._type == typ {
if last == nil {
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(nil))
} else {
last.link = m.link
}
return true
}
last = m
}
return false
}
23 changes: 23 additions & 0 deletions iface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package goloader

import "unsafe"

// Mutual exclusion locks. In the uncontended case,
// as fast as spin locks (just a few user-level instructions),
// but on the contention path they sleep in the kernel.
// A zeroed Mutex is unlocked (no need to initialize each lock).
type mutex struct {
// Futex-based impl treats it as uint32 key,
// while sema-based impl as M* waitm.
// Used to be a union, but unions break precise GC.
key uintptr
}

//go:linkname lock runtime.lock
func lock(l *mutex)

//go:linkname unlock runtime.unlock
func unlock(l *mutex)

//go:linkname atomicstorep runtime.atomicstorep
func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer)
12 changes: 0 additions & 12 deletions module.1.10.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ package goloader

import "cmd/objfile/goobj"

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/obj/funcdata.go.
Expand Down
12 changes: 0 additions & 12 deletions module.1.12.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ import (
"strings"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.
Expand Down
12 changes: 0 additions & 12 deletions module.1.13.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ import (
"strings"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.
Expand Down
12 changes: 0 additions & 12 deletions module.1.14.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ import (
"strings"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/objabi/funcdata.go.
Expand Down
13 changes: 0 additions & 13 deletions module.1.8.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,6 @@ import (
"cmd/objfile/goobj"
)

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
type itab struct {
inter *interfacetype
_type *_type
link *itab
bad int32
inhash int32 // has this itab been added to hash?
fun [1]uintptr // variable sized
}

// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and ../cmd/internal/obj/funcdata.go.
Expand Down
6 changes: 6 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ func copy2Slice(dst []byte, src unsafe.Pointer, size int) {
}
copy(dst, *(*[]byte)(unsafe.Pointer(&s)))
}

//go:nosplit
//go:noinline
func Loadp(ptr unsafe.Pointer) unsafe.Pointer {
return *(*unsafe.Pointer)(ptr)
}

0 comments on commit 1c0d793

Please sign in to comment.