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
|
||||
|
||||
import "runtime"
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var xorshift32State uint32 = 1
|
||||
|
||||
@@ -19,6 +22,9 @@ func randuint32() uint32 {
|
||||
|
||||
func main() {
|
||||
testNonPointerHeap()
|
||||
testGlobalMapRoots()
|
||||
testGlobalChannelRoots()
|
||||
testReflectRoots()
|
||||
testKeepAlive()
|
||||
}
|
||||
|
||||
@@ -74,3 +80,146 @@ func testKeepAlive() {
|
||||
var x int
|
||||
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