@@ -43,6 +43,7 @@ type typeDescInfo struct {
43
43
global llvm.Value
44
44
commonTypePtr llvm.Value
45
45
mapDescPtr llvm.Value
46
+ gc , gcPtr llvm.Value
46
47
47
48
interfaceMethodTables typeutil.Map
48
49
}
@@ -69,6 +70,9 @@ type TypeMap struct {
69
70
70
71
hashFnEmptyInterface , hashFnInterface , hashFnFloat , hashFnComplex , hashFnString , hashFnIdentity , hashFnError llvm.Value
71
72
equalFnEmptyInterface , equalFnInterface , equalFnFloat , equalFnComplex , equalFnString , equalFnIdentity , equalFnError llvm.Value
73
+
74
+ zeroType llvm.Type
75
+ zeroValue llvm.Value
72
76
}
73
77
74
78
func NewLLVMTypeMap (ctx llvm.Context , target llvm.TargetData ) * llvmTypeMap {
@@ -130,6 +134,14 @@ func NewTypeMap(pkg *ssa.Package, llvmtm *llvmTypeMap, module llvm.Module, r *ru
130
134
tm .equalFnIdentity = llvm .AddFunction (tm .module , "__go_type_equal_identity" , tm .equalFnType )
131
135
tm .equalFnError = llvm .AddFunction (tm .module , "__go_type_equal_error" , tm .equalFnType )
132
136
137
+ // The body of this type is set in emitTypeDescInitializers once we have scanned
138
+ // every type, as it needs to be as large and well aligned as the
139
+ // largest/most aligned type.
140
+ tm .zeroType = tm .ctx .StructCreateNamed ("zero" )
141
+ tm .zeroValue = llvm .AddGlobal (tm .module , tm .zeroType , "go$zerovalue" )
142
+ tm .zeroValue .SetLinkage (llvm .CommonLinkage )
143
+ tm .zeroValue .SetInitializer (llvm .ConstNull (tm .zeroType ))
144
+
133
145
tm .commonTypeType = tm .ctx .StructCreateNamed ("commonType" )
134
146
commonTypeTypePtr := llvm .PointerType (tm .commonTypeType , 0 )
135
147
@@ -159,9 +171,11 @@ func NewTypeMap(pkg *ssa.Package, llvmtm *llvmTypeMap, module llvm.Module, r *ru
159
171
tm .ctx .Int32Type (), // hash
160
172
llvm .PointerType (tm .hashFnType , 0 ), // hashfn
161
173
llvm .PointerType (tm .equalFnType , 0 ), // equalfn
174
+ voidPtrType , // gc
162
175
stringPtrType , // string
163
176
llvm .PointerType (tm .uncommonTypeType , 0 ), // uncommonType
164
177
commonTypeTypePtr , // ptrToThis
178
+ llvm .PointerType (tm .zeroType , 0 ), // zero
165
179
}, false )
166
180
167
181
tm .typeSliceType = tm .makeNamedSliceType ("typeSlice" , commonTypeTypePtr )
@@ -1037,6 +1051,9 @@ func (ts byTypeName) Less(i, j int) bool {
1037
1051
}
1038
1052
1039
1053
func (tm * TypeMap ) emitTypeDescInitializers () {
1054
+ var maxSize , maxAlign int64
1055
+ maxAlign = 1
1056
+
1040
1057
for changed := true ; changed ; {
1041
1058
changed = false
1042
1059
@@ -1047,6 +1064,7 @@ func (tm *TypeMap) emitTypeDescInitializers() {
1047
1064
if tdi .global .Initializer ().C == nil {
1048
1065
linkage , emit := tm .getTypeDescLinkage (key )
1049
1066
tdi .global .SetLinkage (linkage )
1067
+ tdi .gc .SetLinkage (linkage )
1050
1068
if emit {
1051
1069
changed = true
1052
1070
ts = append (ts , typeAndInfo {key , key .String (), tdi })
@@ -1057,10 +1075,127 @@ func (tm *TypeMap) emitTypeDescInitializers() {
1057
1075
if changed {
1058
1076
sort .Sort (byTypeName (ts ))
1059
1077
for _ , t := range ts {
1060
- t .tdi .global .SetInitializer (tm .makeTypeDescInitializer (t .typ ))
1078
+ tm .emitTypeDescInitializer (t .typ , t .tdi )
1079
+ if size := tm .Sizeof (t .typ ); size > maxSize {
1080
+ maxSize = size
1081
+ }
1082
+ if align := tm .Alignof (t .typ ); align > maxAlign {
1083
+ maxAlign = align
1084
+ }
1061
1085
}
1062
1086
}
1063
1087
}
1088
+
1089
+ tm .zeroType .StructSetBody ([]llvm.Type {llvm .ArrayType (tm .ctx .Int8Type (), int (maxSize ))}, false )
1090
+ tm .zeroValue .SetAlignment (int (maxAlign ))
1091
+ }
1092
+
1093
+ const (
1094
+ // From libgo/runtime/mgc0.h
1095
+ gcOpcodeEND = iota
1096
+ gcOpcodePTR
1097
+ gcOpcodeAPTR
1098
+ gcOpcodeARRAY_START
1099
+ gcOpcodeARRAY_NEXT
1100
+ gcOpcodeCALL
1101
+ gcOpcodeCHAN_PTR
1102
+ gcOpcodeSTRING
1103
+ gcOpcodeEFACE
1104
+ gcOpcodeIFACE
1105
+ gcOpcodeSLICE
1106
+ gcOpcodeREGION
1107
+
1108
+ gcStackCapacity = 8
1109
+ )
1110
+
1111
+ func (tm * TypeMap ) makeGcInst (val int64 ) llvm.Value {
1112
+ c := llvm .ConstInt (tm .inttype , uint64 (val ), false )
1113
+ return llvm .ConstIntToPtr (c , llvm .PointerType (tm .ctx .Int8Type (), 0 ))
1114
+ }
1115
+
1116
+ func (tm * TypeMap ) appendGcInsts (insts []llvm.Value , t types.Type , offset , stackSize int64 ) []llvm.Value {
1117
+ switch u := t .Underlying ().(type ) {
1118
+ case * types.Basic :
1119
+ switch u .Kind () {
1120
+ case types .String :
1121
+ insts = append (insts , tm .makeGcInst (gcOpcodeSTRING ), tm .makeGcInst (offset ))
1122
+ case types .UnsafePointer :
1123
+ insts = append (insts , tm .makeGcInst (gcOpcodeAPTR ), tm .makeGcInst (offset ))
1124
+ }
1125
+ case * types.Pointer :
1126
+ insts = append (insts , tm .makeGcInst (gcOpcodePTR ), tm .makeGcInst (offset ),
1127
+ tm .getGcPointer (u .Elem ()))
1128
+ case * types.Signature , * types.Map :
1129
+ insts = append (insts , tm .makeGcInst (gcOpcodeAPTR ), tm .makeGcInst (offset ))
1130
+ case * types.Array :
1131
+ if u .Len () == 0 {
1132
+ return insts
1133
+ } else if stackSize >= gcStackCapacity {
1134
+ insts = append (insts , tm .makeGcInst (gcOpcodeREGION ), tm .makeGcInst (offset ),
1135
+ tm .makeGcInst (tm .Sizeof (t )), tm .getGcPointer (t ))
1136
+ } else {
1137
+ insts = append (insts , tm .makeGcInst (gcOpcodeARRAY_START ), tm .makeGcInst (offset ),
1138
+ tm .makeGcInst (u .Len ()), tm .makeGcInst (tm .Sizeof (u .Elem ())))
1139
+ insts = tm .appendGcInsts (insts , u .Elem (), 0 , stackSize + 1 )
1140
+ insts = append (insts , tm .makeGcInst (gcOpcodeARRAY_NEXT ))
1141
+ }
1142
+ case * types.Slice :
1143
+ if tm .Sizeof (u .Elem ()) == 0 {
1144
+ insts = append (insts , tm .makeGcInst (gcOpcodeAPTR ), tm .makeGcInst (offset ))
1145
+ } else {
1146
+ insts = append (insts , tm .makeGcInst (gcOpcodeSLICE ), tm .makeGcInst (offset ),
1147
+ tm .getGcPointer (u .Elem ()))
1148
+ }
1149
+ case * types.Chan :
1150
+ insts = append (insts , tm .makeGcInst (gcOpcodeCHAN_PTR ), tm .makeGcInst (offset ),
1151
+ tm .ToRuntime (t ))
1152
+ case * types.Struct :
1153
+ fields := make ([]* types.Var , u .NumFields ())
1154
+ for i := range fields {
1155
+ fields [i ] = u .Field (i )
1156
+ }
1157
+ offsets := tm .Offsetsof (fields )
1158
+
1159
+ for i , field := range fields {
1160
+ insts = tm .appendGcInsts (insts , field .Type (), offset + offsets [i ], stackSize )
1161
+ }
1162
+ case * types.Interface :
1163
+ if u .NumMethods () == 0 {
1164
+ insts = append (insts , tm .makeGcInst (gcOpcodeEFACE ), tm .makeGcInst (offset ))
1165
+ } else {
1166
+ insts = append (insts , tm .makeGcInst (gcOpcodeIFACE ), tm .makeGcInst (offset ))
1167
+ }
1168
+ default :
1169
+ panic (fmt .Sprintf ("unhandled type: %#v" , t ))
1170
+ }
1171
+
1172
+ return insts
1173
+ }
1174
+
1175
+ func (tm * TypeMap ) emitTypeDescInitializer (t types.Type , tdi * typeDescInfo ) {
1176
+ // initialize type descriptor
1177
+ tdi .global .SetInitializer (tm .makeTypeDescInitializer (t ))
1178
+
1179
+ // initialize GC program
1180
+ insts := []llvm.Value {tm .makeGcInst (tm .Sizeof (t ))}
1181
+ insts = tm .appendGcInsts (insts , t , 0 , 0 )
1182
+ insts = append (insts , tm .makeGcInst (gcOpcodeEND ))
1183
+
1184
+ i8ptr := llvm .PointerType (llvm .Int8Type (), 0 )
1185
+ instArray := llvm .ConstArray (i8ptr , insts )
1186
+
1187
+ newGc := llvm .AddGlobal (tm .module , instArray .Type (), "" )
1188
+ newGc .SetGlobalConstant (true )
1189
+ newGc .SetInitializer (instArray )
1190
+ gcName := tdi .gc .Name ()
1191
+ tdi .gc .SetName ("" )
1192
+ newGc .SetName (gcName )
1193
+ newGc .SetLinkage (tdi .gc .Linkage ())
1194
+
1195
+ tdi .gc .ReplaceAllUsesWith (llvm .ConstBitCast (newGc , tdi .gc .Type ()))
1196
+ tdi .gc .EraseFromParentAsGlobal ()
1197
+ tdi .gc = llvm.Value {nil }
1198
+ tdi .gcPtr = llvm .ConstBitCast (newGc , i8ptr )
1064
1199
}
1065
1200
1066
1201
func (tm * TypeMap ) makeTypeDescInitializer (t types.Type ) llvm.Value {
@@ -1347,6 +1482,10 @@ func (tm *TypeMap) getTypeDescInfo(t types.Type) *typeDescInfo {
1347
1482
global .SetGlobalConstant (true )
1348
1483
ptr := llvm .ConstBitCast (global , llvm .PointerType (tm .commonTypeType , 0 ))
1349
1484
1485
+ gc := llvm .AddGlobal (tm .module , llvm .PointerType (llvm .Int8Type (), 0 ), b .String ()+ "$gc" )
1486
+ gc .SetGlobalConstant (true )
1487
+ gcPtr := llvm .ConstBitCast (gc , llvm .PointerType (tm .ctx .Int8Type (), 0 ))
1488
+
1350
1489
var mapDescPtr llvm.Value
1351
1490
if m , ok := t .Underlying ().(* types.Map ); ok {
1352
1491
var mapb bytes.Buffer
@@ -1358,7 +1497,13 @@ func (tm *TypeMap) getTypeDescInfo(t types.Type) *typeDescInfo {
1358
1497
mapDescPtr .SetInitializer (tm .makeMapDesc (ptr , m ))
1359
1498
}
1360
1499
1361
- tdi := & typeDescInfo {global : global , commonTypePtr : ptr , mapDescPtr : mapDescPtr }
1500
+ tdi := & typeDescInfo {
1501
+ global : global ,
1502
+ commonTypePtr : ptr ,
1503
+ mapDescPtr : mapDescPtr ,
1504
+ gc : gc ,
1505
+ gcPtr : gcPtr ,
1506
+ }
1362
1507
tm .types .Set (t , tdi )
1363
1508
return tdi
1364
1509
}
@@ -1371,6 +1516,10 @@ func (tm *TypeMap) getMapDescriptorPointer(t types.Type) llvm.Value {
1371
1516
return tm .getTypeDescInfo (t ).mapDescPtr
1372
1517
}
1373
1518
1519
+ func (tm * TypeMap ) getGcPointer (t types.Type ) llvm.Value {
1520
+ return tm .getTypeDescInfo (t ).gcPtr
1521
+ }
1522
+
1374
1523
func (tm * TypeMap ) getItabPointer (srctype types.Type , targettype * types.Interface ) llvm.Value {
1375
1524
if targettype .NumMethods () == 0 {
1376
1525
return tm .ToRuntime (srctype )
@@ -1543,7 +1692,7 @@ func runtimeTypeKind(t types.Type) (k uint8) {
1543
1692
}
1544
1693
1545
1694
func (tm * TypeMap ) makeCommonType (t types.Type ) llvm.Value {
1546
- var vals [10 ]llvm.Value
1695
+ var vals [12 ]llvm.Value
1547
1696
vals [0 ] = llvm .ConstInt (tm .ctx .Int8Type (), uint64 (runtimeTypeKind (t )), false )
1548
1697
vals [1 ] = llvm .ConstInt (tm .ctx .Int8Type (), uint64 (tm .Alignof (t )), false )
1549
1698
vals [2 ] = vals [1 ]
@@ -1552,15 +1701,17 @@ func (tm *TypeMap) makeCommonType(t types.Type) llvm.Value {
1552
1701
hash , equal := tm .getAlgorithmFunctions (t )
1553
1702
vals [5 ] = hash
1554
1703
vals [6 ] = equal
1704
+ vals [7 ] = tm .getGcPointer (t )
1555
1705
var b bytes.Buffer
1556
1706
tm .writeType (t , & b )
1557
- vals [7 ] = tm .globalStringPtr (b .String ())
1558
- vals [8 ] = tm .makeUncommonTypePtr (t )
1707
+ vals [8 ] = tm .globalStringPtr (b .String ())
1708
+ vals [9 ] = tm .makeUncommonTypePtr (t )
1559
1709
if _ , ok := t .(* types.Named ); ok {
1560
- vals [9 ] = tm .getTypeDescriptorPointer (types .NewPointer (t ))
1710
+ vals [10 ] = tm .getTypeDescriptorPointer (types .NewPointer (t ))
1561
1711
} else {
1562
- vals [9 ] = llvm .ConstPointerNull (llvm .PointerType (tm .commonTypeType , 0 ))
1712
+ vals [10 ] = llvm .ConstPointerNull (llvm .PointerType (tm .commonTypeType , 0 ))
1563
1713
}
1714
+ vals [11 ] = tm .zeroValue
1564
1715
1565
1716
return llvm .ConstNamedStruct (tm .commonTypeType , vals [:])
1566
1717
}
0 commit comments