|
1 | 1 | package transform
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "math/big" |
5 |
| - |
6 | 4 | "tinygo.org/x/go-llvm"
|
7 | 5 | )
|
8 | 6 |
|
@@ -311,138 +309,6 @@ func MakeGCStackSlots(mod llvm.Module) bool {
|
311 | 309 | return true
|
312 | 310 | }
|
313 | 311 |
|
314 |
| -// AddGlobalsBitmap performs a few related functions. It is needed for scanning |
315 |
| -// globals on platforms where the .data/.bss section is not easily accessible by |
316 |
| -// the GC, and thus all globals that contain pointers must be made reachable by |
317 |
| -// the GC in some other way. |
318 |
| -// |
319 |
| -// First, it scans all globals, and bundles all globals that contain a pointer |
320 |
| -// into one large global (updating all uses in the process). Then it creates a |
321 |
| -// bitmap (bit vector) to locate all the pointers in this large global. This |
322 |
| -// bitmap allows the GC to know in advance where exactly all the pointers live |
323 |
| -// in the large globals bundle, to avoid false positives. |
324 |
| -func AddGlobalsBitmap(mod llvm.Module) bool { |
325 |
| - if mod.NamedGlobal("runtime.trackedGlobalsStart").IsNil() { |
326 |
| - return false // nothing to do: no GC in use |
327 |
| - } |
328 |
| - |
329 |
| - ctx := mod.Context() |
330 |
| - targetData := llvm.NewTargetData(mod.DataLayout()) |
331 |
| - defer targetData.Dispose() |
332 |
| - uintptrType := ctx.IntType(targetData.PointerSize() * 8) |
333 |
| - |
334 |
| - // Collect all globals that contain pointers (and thus must be scanned by |
335 |
| - // the GC). |
336 |
| - var trackedGlobals []llvm.Value |
337 |
| - var trackedGlobalTypes []llvm.Type |
338 |
| - for global := mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) { |
339 |
| - if global.IsDeclaration() || global.IsGlobalConstant() { |
340 |
| - continue |
341 |
| - } |
342 |
| - typ := global.Type().ElementType() |
343 |
| - ptrs := getPointerBitmap(targetData, typ, global.Name()) |
344 |
| - if ptrs.BitLen() == 0 { |
345 |
| - continue |
346 |
| - } |
347 |
| - trackedGlobals = append(trackedGlobals, global) |
348 |
| - trackedGlobalTypes = append(trackedGlobalTypes, typ) |
349 |
| - } |
350 |
| - |
351 |
| - // Make a new global that bundles all existing globals, and remove the |
352 |
| - // existing globals. All uses of the previous independent globals are |
353 |
| - // replaced with a GEP into the new globals bundle. |
354 |
| - globalsBundleType := ctx.StructType(trackedGlobalTypes, false) |
355 |
| - globalsBundle := llvm.AddGlobal(mod, globalsBundleType, "tinygo.trackedGlobals") |
356 |
| - globalsBundle.SetLinkage(llvm.InternalLinkage) |
357 |
| - globalsBundle.SetUnnamedAddr(true) |
358 |
| - initializer := llvm.Undef(globalsBundleType) |
359 |
| - for i, global := range trackedGlobals { |
360 |
| - initializer = llvm.ConstInsertValue(initializer, global.Initializer(), []uint32{uint32(i)}) |
361 |
| - gep := llvm.ConstGEP(globalsBundle, []llvm.Value{ |
362 |
| - llvm.ConstInt(ctx.Int32Type(), 0, false), |
363 |
| - llvm.ConstInt(ctx.Int32Type(), uint64(i), false), |
364 |
| - }) |
365 |
| - global.ReplaceAllUsesWith(gep) |
366 |
| - global.EraseFromParentAsGlobal() |
367 |
| - } |
368 |
| - globalsBundle.SetInitializer(initializer) |
369 |
| - |
370 |
| - // Update trackedGlobalsStart, which points to the globals bundle. |
371 |
| - trackedGlobalsStart := llvm.ConstPtrToInt(globalsBundle, uintptrType) |
372 |
| - mod.NamedGlobal("runtime.trackedGlobalsStart").SetInitializer(trackedGlobalsStart) |
373 |
| - mod.NamedGlobal("runtime.trackedGlobalsStart").SetLinkage(llvm.InternalLinkage) |
374 |
| - |
375 |
| - // Update trackedGlobalsLength, which contains the length (in words) of the |
376 |
| - // globals bundle. |
377 |
| - alignment := targetData.PrefTypeAlignment(llvm.PointerType(ctx.Int8Type(), 0)) |
378 |
| - trackedGlobalsLength := llvm.ConstInt(uintptrType, targetData.TypeAllocSize(globalsBundleType)/uint64(alignment), false) |
379 |
| - mod.NamedGlobal("runtime.trackedGlobalsLength").SetLinkage(llvm.InternalLinkage) |
380 |
| - mod.NamedGlobal("runtime.trackedGlobalsLength").SetInitializer(trackedGlobalsLength) |
381 |
| - |
382 |
| - // Create a bitmap (a new global) that stores for each word in the globals |
383 |
| - // bundle whether it contains a pointer. This allows globals to be scanned |
384 |
| - // precisely: no non-pointers will be considered pointers if the bit pattern |
385 |
| - // looks like one. |
386 |
| - // This code assumes that pointers are self-aligned. For example, that a |
387 |
| - // 32-bit (4-byte) pointer is also aligned to 4 bytes. |
388 |
| - bitmapBytes := getPointerBitmap(targetData, globalsBundleType, "globals bundle").Bytes() |
389 |
| - bitmapValues := make([]llvm.Value, len(bitmapBytes)) |
390 |
| - for i, b := range bitmapBytes { |
391 |
| - bitmapValues[len(bitmapBytes)-i-1] = llvm.ConstInt(ctx.Int8Type(), uint64(b), false) |
392 |
| - } |
393 |
| - bitmapArray := llvm.ConstArray(ctx.Int8Type(), bitmapValues) |
394 |
| - bitmapNew := llvm.AddGlobal(mod, bitmapArray.Type(), "runtime.trackedGlobalsBitmap.tmp") |
395 |
| - bitmapOld := mod.NamedGlobal("runtime.trackedGlobalsBitmap") |
396 |
| - bitmapOld.ReplaceAllUsesWith(llvm.ConstBitCast(bitmapNew, bitmapOld.Type())) |
397 |
| - bitmapNew.SetInitializer(bitmapArray) |
398 |
| - bitmapNew.SetName("runtime.trackedGlobalsBitmap") |
399 |
| - bitmapNew.SetLinkage(llvm.InternalLinkage) |
400 |
| - |
401 |
| - return true // the IR was changed |
402 |
| -} |
403 |
| - |
404 |
| -// getPointerBitmap scans the given LLVM type for pointers and sets bits in a |
405 |
| -// bigint at the word offset that contains a pointer. This scan is recursive. |
406 |
| -func getPointerBitmap(targetData llvm.TargetData, typ llvm.Type, name string) *big.Int { |
407 |
| - alignment := targetData.PrefTypeAlignment(llvm.PointerType(typ.Context().Int8Type(), 0)) |
408 |
| - switch typ.TypeKind() { |
409 |
| - case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind: |
410 |
| - return big.NewInt(0) |
411 |
| - case llvm.PointerTypeKind: |
412 |
| - return big.NewInt(1) |
413 |
| - case llvm.StructTypeKind: |
414 |
| - ptrs := big.NewInt(0) |
415 |
| - for i, subtyp := range typ.StructElementTypes() { |
416 |
| - subptrs := getPointerBitmap(targetData, subtyp, name) |
417 |
| - if subptrs.BitLen() == 0 { |
418 |
| - continue |
419 |
| - } |
420 |
| - offset := targetData.ElementOffset(typ, i) |
421 |
| - if offset%uint64(alignment) != 0 { |
422 |
| - panic("precise GC: global contains unaligned pointer: " + name) |
423 |
| - } |
424 |
| - subptrs.Lsh(subptrs, uint(offset)/uint(alignment)) |
425 |
| - ptrs.Or(ptrs, subptrs) |
426 |
| - } |
427 |
| - return ptrs |
428 |
| - case llvm.ArrayTypeKind: |
429 |
| - subtyp := typ.ElementType() |
430 |
| - subptrs := getPointerBitmap(targetData, subtyp, name) |
431 |
| - ptrs := big.NewInt(0) |
432 |
| - if subptrs.BitLen() == 0 { |
433 |
| - return ptrs |
434 |
| - } |
435 |
| - elementSize := targetData.TypeAllocSize(subtyp) |
436 |
| - for i := 0; i < typ.ArrayLength(); i++ { |
437 |
| - ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment)) |
438 |
| - ptrs.Or(ptrs, subptrs) |
439 |
| - } |
440 |
| - return ptrs |
441 |
| - default: |
442 |
| - panic("unknown type kind of global: " + name) |
443 |
| - } |
444 |
| -} |
445 |
| - |
446 | 312 | // markParentFunctions traverses all parent function calls (recursively) and
|
447 | 313 | // adds them to the set of marked functions. It only considers function calls:
|
448 | 314 | // any other uses of such a function is ignored.
|
|
0 commit comments