mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-10 14:39:31 +00:00
runtime: test container GC layouts
This commit is contained in:
Vendored
+150
-1
@@ -1,6 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "runtime"
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
var xorshift32State uint32 = 1
|
var xorshift32State uint32 = 1
|
||||||
|
|
||||||
@@ -19,6 +22,9 @@ func randuint32() uint32 {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
testNonPointerHeap()
|
testNonPointerHeap()
|
||||||
|
testGlobalMapRoots()
|
||||||
|
testGlobalChannelRoots()
|
||||||
|
testReflectRoots()
|
||||||
testKeepAlive()
|
testKeepAlive()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,3 +80,146 @@ func testKeepAlive() {
|
|||||||
var x int
|
var x int
|
||||||
runtime.KeepAlive(&x)
|
runtime.KeepAlive(&x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type globalMapObject struct {
|
||||||
|
marker int
|
||||||
|
data [64]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalMap = make(map[int]*globalMapObject)
|
||||||
|
var globalChannel chan *globalMapObject
|
||||||
|
var globalPointerSlice []*globalMapObject
|
||||||
|
var globalGCClobber any
|
||||||
|
|
||||||
|
type globalMapLargeKey struct {
|
||||||
|
object *globalMapObject
|
||||||
|
data [129]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type globalMapLargeValue struct {
|
||||||
|
object *globalMapObject
|
||||||
|
data [129]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalLargeKeyMap = make(map[globalMapLargeKey]int)
|
||||||
|
var globalLargeValueMap = make(map[int]globalMapLargeValue)
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func populateGlobalMaps() {
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
globalMap[i] = &globalMapObject{marker: 100 + i}
|
||||||
|
globalPointerSlice = append(globalPointerSlice, &globalMapObject{marker: 800 + i})
|
||||||
|
}
|
||||||
|
globalLargeKeyMap[globalMapLargeKey{
|
||||||
|
object: &globalMapObject{marker: 200},
|
||||||
|
}] = 1
|
||||||
|
globalLargeValueMap[0] = globalMapLargeValue{
|
||||||
|
object: &globalMapObject{marker: 300},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGlobalMapRoots() {
|
||||||
|
populateGlobalMaps()
|
||||||
|
|
||||||
|
runtime.GC()
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
globalGCClobber = new(globalMapObject)
|
||||||
|
}
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
if globalMap[i].marker != 100+i {
|
||||||
|
panic("global map value was collected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for key := range globalLargeKeyMap {
|
||||||
|
if key.object.marker != 200 {
|
||||||
|
panic("indirect global map key was collected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if globalLargeValueMap[0].object.marker != 300 {
|
||||||
|
panic("indirect global map value was collected")
|
||||||
|
}
|
||||||
|
for i, object := range globalPointerSlice {
|
||||||
|
if object.marker != 800+i {
|
||||||
|
panic("global slice value was collected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func populateGlobalChannel() {
|
||||||
|
globalChannel = make(chan *globalMapObject, 4)
|
||||||
|
globalChannel <- &globalMapObject{marker: 400}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGlobalChannelRoots() {
|
||||||
|
populateGlobalChannel()
|
||||||
|
|
||||||
|
runtime.GC()
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
globalGCClobber = new(globalMapObject)
|
||||||
|
}
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
|
if (<-globalChannel).marker != 400 {
|
||||||
|
panic("global channel value was collected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type reflectRootObject struct {
|
||||||
|
marker int
|
||||||
|
child *reflectRootObject
|
||||||
|
data [128]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type reflectMapKey struct {
|
||||||
|
object *reflectRootObject
|
||||||
|
data [129]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type reflectMapValue struct {
|
||||||
|
object *reflectRootObject
|
||||||
|
data [129]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type reflectRootMap map[reflectMapKey]reflectMapValue
|
||||||
|
|
||||||
|
var globalReflectObject *reflectRootObject
|
||||||
|
var globalReflectMap reflectRootMap
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func populateReflectRoots() {
|
||||||
|
value := reflect.New(reflect.TypeOf(reflectRootObject{}))
|
||||||
|
globalReflectObject = value.Interface().(*reflectRootObject)
|
||||||
|
globalReflectObject.child = &reflectRootObject{marker: 500}
|
||||||
|
|
||||||
|
mapValue := reflect.MakeMapWithSize(reflect.TypeOf(globalReflectMap), 1)
|
||||||
|
mapValue.SetMapIndex(
|
||||||
|
reflect.ValueOf(reflectMapKey{object: &reflectRootObject{marker: 600}}),
|
||||||
|
reflect.ValueOf(reflectMapValue{object: &reflectRootObject{marker: 700}}),
|
||||||
|
)
|
||||||
|
globalReflectMap = mapValue.Interface().(reflectRootMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testReflectRoots() {
|
||||||
|
populateReflectRoots()
|
||||||
|
|
||||||
|
runtime.GC()
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
globalGCClobber = new(reflectRootObject)
|
||||||
|
}
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
|
if globalReflectObject.child.marker != 500 {
|
||||||
|
panic("reflected object field was collected")
|
||||||
|
}
|
||||||
|
for key, value := range globalReflectMap {
|
||||||
|
if key.object.marker != 600 {
|
||||||
|
panic("reflected map key was collected")
|
||||||
|
}
|
||||||
|
if value.object.marker != 700 {
|
||||||
|
panic("reflected map value was collected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user