Skip to content

Commit da6d25f

Browse files
committed
precise gc wip
1 parent 8cf6740 commit da6d25f

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

compiler/gctype/gctype.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package gctype
2+
3+
import (
4+
"math/big"
5+
6+
"tinygo.org/x/go-llvm"
7+
)
8+
9+
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
10+
// bigint at the word offset that contains a pointer. This scan is recursive.
11+
func getPointerBitmap(targetData llvm.TargetData, typ llvm.Type, name string) *big.Int {
12+
alignment := targetData.PrefTypeAlignment(llvm.PointerType(typ.Context().Int8Type(), 0))
13+
switch typ.TypeKind() {
14+
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
15+
return big.NewInt(0)
16+
case llvm.PointerTypeKind:
17+
return big.NewInt(1)
18+
case llvm.StructTypeKind:
19+
ptrs := big.NewInt(0)
20+
for i, subtyp := range typ.StructElementTypes() {
21+
subptrs := getPointerBitmap(targetData, subtyp, name)
22+
if subptrs.BitLen() == 0 {
23+
continue
24+
}
25+
offset := targetData.ElementOffset(typ, i)
26+
if offset%uint64(alignment) != 0 {
27+
panic("precise GC: global contains unaligned pointer: " + name)
28+
}
29+
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
30+
ptrs.Or(ptrs, subptrs)
31+
}
32+
return ptrs
33+
case llvm.ArrayTypeKind:
34+
subtyp := typ.ElementType()
35+
subptrs := getPointerBitmap(targetData, subtyp, name)
36+
ptrs := big.NewInt(0)
37+
if subptrs.BitLen() == 0 {
38+
return ptrs
39+
}
40+
elementSize := targetData.TypeAllocSize(subtyp)
41+
for i := 0; i < typ.ArrayLength(); i++ {
42+
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
43+
ptrs.Or(ptrs, subptrs)
44+
}
45+
return ptrs
46+
default:
47+
panic("unknown type kind: " + name)
48+
}
49+
}
50+
51+
func bitmapToValue(b *big.Int, size uintptr, byte llvm.Type) llvm.Value {
52+
// Create a bitmap (a new global) that stores for each word in the globals
53+
// bundle whether it contains a pointer. This allows globals to be scanned
54+
// precisely: no non-pointers will be considered pointers if the bit pattern
55+
// looks like one.
56+
// This code assumes that pointers are self-aligned. For example, that a
57+
// 32-bit (4-byte) pointer is also aligned to 4 bytes.
58+
bitmapBytes := b.Bytes()
59+
bitmapValues := make([]llvm.Value, len(bitmapBytes))
60+
for i, b := range bitmapBytes {
61+
bitmapValues[len(bitmapBytes)-i-1] = llvm.ConstInt(byte, uint64(b), false)
62+
}
63+
return llvm.ConstArray(byte, bitmapValues)
64+
}
65+
66+
// Typer creates GC types.
67+
type Typer struct {
68+
// tcache is a cache of GC types by LLVM type.
69+
tcache map[llvm.Type]llvm.Value
70+
71+
// bcache is a cache of GC types by size and GC bitmap.
72+
bcache map[uint64]map[string]llvm.Value
73+
74+
// td is the target platform data.
75+
td llvm.TargetData
76+
77+
// idIntrinsic is used on AVR to map a type bitmap to a uintptr ID.
78+
idIntrinsic llvm.Value
79+
80+
uintptr, i8 llvm.Type
81+
}
82+
83+
func (t *Typer) createGlobal(size uint64, layout []byte) llvm.Value {
84+
// TODO: compression?
85+
86+
// Check the cache before attempting to create the global.
87+
if g, ok := t.bcache[size][string(layout)]; ok {
88+
return g
89+
}
90+
91+
// Convert the encoded layout to a byte array.
92+
bitmapValues := make([]llvm.Value, len(layout))
93+
for i, b := range layout {
94+
bitmapValues[len(layout)-i-1] = llvm.ConstInt(t.i8, uint64(b), false)
95+
}
96+
bitmapArray := llvm.ConstArray(t.i8, bitmapValues)
97+
98+
// Construct a tuple of the size + the array.
99+
tuple := llvm.ConstStruct([]llvm.Value{
100+
llvm.ConstInt(t.uintptr, size, false),
101+
bitmapArray,
102+
}, false)
103+
}

0 commit comments

Comments
 (0)