Skip to content

Commit

Permalink
fix: Properly initialize malloc free list (#700)
Browse files Browse the repository at this point in the history
  • Loading branch information
ospencer committed Jun 5, 2021
1 parent 79809bb commit 0576fd9
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 7 deletions.
30 changes: 30 additions & 0 deletions compiler/test/input/mallocTight.gr
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* grainc-flags --compilation-mode=runtime */

import Malloc from "runtime/malloc"
import WasmI32, { add as (+), sub as (-), mul as (*), eq as (==), ne as (!=) } from "runtime/unsafe/wasmi32"

primitive assert : Bool -> Void = "@assert"
primitive ignore : a -> Void = "@ignore"

// Because we're in runtime mode, malloc has yet to be called
// This provides us with a clean slate to test malloc

// allow malloc to initialize
ignore(Malloc.malloc(8n))

// The free list should be pointing at the base
let base = Malloc.getFreePtr()
assert base == Malloc._RESERVED_RUNTIME_SPACE

// grab the next (and only) block in the free list
let block = WasmI32.load(Malloc.getFreePtr(), 0n)
assert WasmI32.load(block, 0n) == base

// When we allocate, an extra 8 bytes is reserved for the block header
let remainingMemory = WasmI32.load(block, 4n) - 8n

let firstPtr = Malloc.malloc(remainingMemory)
let secondPtr = Malloc.malloc(remainingMemory)

// These two pointers should (obviously) be different
assert firstPtr != secondPtr
1 change: 1 addition & 0 deletions compiler/test/test_end_to_end.re
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ let gc = [
/* I've manually tested this test, but see TODO for automated testing */
/* tgcfile ~todo:"Need to figure out how to disable dead assignment elimination to make sure this test is actually checking what we want" "sinister_gc" 3072 "sinister-tail-call-gc" "true"; */
tgcfile("long_lists", 20000, "long_lists", "true"),
tfile("malloc_tight", "mallocTight", "void"),
tfile("memory_grow1", "memoryGrow", "1000000000000\nvoid"),
];

Expand Down
25 changes: 18 additions & 7 deletions stdlib/runtime/malloc.gr
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ let mut heapSize = 0n

export let _RESERVED_RUNTIME_SPACE = 16384n

/**
* The base the heap. The block at this address will be size 0 and
* serve as the root of the free list.
*/
let _BASE = _RESERVED_RUNTIME_SPACE

/**
* The start pointer of the heap.
*/
let _HEAP_START = _BASE + mallocHeaderSize

let _NEXT_OFFSET = 0n
let _SIZE_OFFSET = 4n

Expand Down Expand Up @@ -113,7 +124,7 @@ let growHeap = (nbytes: WasmI32) => {

// If the size has not been initialized, do so.
if (heapSize == 0n) {
heapSize = memorySize() * _PAGE_SIZE - _RESERVED_RUNTIME_SPACE
heapSize = memorySize() * _PAGE_SIZE - _HEAP_START
if (nbytes > heapSize) {
// More bytes requested than the initial heap size,
// so we need to request more anyway.
Expand All @@ -125,10 +136,10 @@ let growHeap = (nbytes: WasmI32) => {
-1n
} else {
heapSize += reqSize << 16n
_RESERVED_RUNTIME_SPACE
_HEAP_START
}
} else {
_RESERVED_RUNTIME_SPACE
_HEAP_START
}
} else {
// The size has already been initialized, so call the external function.
Expand Down Expand Up @@ -231,10 +242,10 @@ export let malloc = (nb: WasmI32) => {

// Handle initialization
if (heapSize == 0n) {
WasmI32.store(_RESERVED_RUNTIME_SPACE, _RESERVED_RUNTIME_SPACE, 0n)
freePtr = _RESERVED_RUNTIME_SPACE
prevp = _RESERVED_RUNTIME_SPACE
WasmI32.store(_RESERVED_RUNTIME_SPACE, 0n, 4n)
WasmI32.store(_BASE, _BASE, _NEXT_OFFSET)
freePtr = _BASE
prevp = _BASE
WasmI32.store(_BASE, 0n, _SIZE_OFFSET)
}

let mut ret = -1n
Expand Down

0 comments on commit 0576fd9

Please sign in to comment.