github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/gc_leaking.go (about)

     1  //go:build gc.leaking
     2  
     3  package runtime
     4  
     5  // This GC implementation is the simplest useful memory allocator possible: it
     6  // only allocates memory and never frees it. For some constrained systems, it
     7  // may be the only memory allocator possible.
     8  
     9  import (
    10  	"unsafe"
    11  )
    12  
    13  // Ever-incrementing pointer: no memory is freed.
    14  var heapptr = heapStart
    15  
    16  // Total amount allocated for runtime.MemStats
    17  var gcTotalAlloc uint64
    18  
    19  // Total number of calls to alloc()
    20  var gcMallocs uint64
    21  
    22  // Total number of objected freed; for leaking collector this stays 0
    23  const gcFrees = 0
    24  
    25  // Inlining alloc() speeds things up slightly but bloats the executable by 50%,
    26  // see https://github.com/tinygo-org/tinygo/issues/2674.  So don't.
    27  //
    28  //go:noinline
    29  func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
    30  	// TODO: this can be optimized by not casting between pointers and ints so
    31  	// much. And by using platform-native data types (e.g. *uint8 for 8-bit
    32  	// systems).
    33  	size = align(size)
    34  	addr := heapptr
    35  	gcTotalAlloc += uint64(size)
    36  	gcMallocs++
    37  	heapptr += size
    38  	for heapptr >= heapEnd {
    39  		// Try to increase the heap and check again.
    40  		if growHeap() {
    41  			continue
    42  		}
    43  		// Failed to make the heap bigger, so we must really be out of memory.
    44  		runtimePanic("out of memory")
    45  	}
    46  	pointer := unsafe.Pointer(addr)
    47  	memzero(pointer, size)
    48  	return pointer
    49  }
    50  
    51  func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
    52  	newAlloc := alloc(size, nil)
    53  	if ptr == nil {
    54  		return newAlloc
    55  	}
    56  	// according to POSIX everything beyond the previous pointer's
    57  	// size will have indeterminate values so we can just copy garbage
    58  	memcpy(newAlloc, ptr, size)
    59  
    60  	return newAlloc
    61  }
    62  
    63  func free(ptr unsafe.Pointer) {
    64  	// Memory is never freed.
    65  }
    66  
    67  // ReadMemStats populates m with memory statistics.
    68  //
    69  // The returned memory statistics are up to date as of the
    70  // call to ReadMemStats. This would not do GC implicitly for you.
    71  func ReadMemStats(m *MemStats) {
    72  	m.HeapIdle = 0
    73  	m.HeapInuse = gcTotalAlloc
    74  	m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS.
    75  
    76  	m.HeapSys = m.HeapInuse + m.HeapIdle
    77  	m.GCSys = 0
    78  	m.TotalAlloc = gcTotalAlloc
    79  	m.Mallocs = gcMallocs
    80  	m.Frees = gcFrees
    81  	m.Sys = uint64(heapEnd - heapStart)
    82  }
    83  
    84  func GC() {
    85  	// No-op.
    86  }
    87  
    88  func SetFinalizer(obj interface{}, finalizer interface{}) {
    89  	// No-op.
    90  }
    91  
    92  func initHeap() {
    93  	// preinit() may have moved heapStart; reset heapptr
    94  	heapptr = heapStart
    95  }
    96  
    97  // setHeapEnd sets a new (larger) heapEnd pointer.
    98  func setHeapEnd(newHeapEnd uintptr) {
    99  	// This "heap" is so simple that simply assigning a new value is good
   100  	// enough.
   101  	heapEnd = newHeapEnd
   102  }