diff options
author | Ayke van Laethem <[email protected]> | 2022-06-24 00:09:03 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-02-17 22:54:34 +0100 |
commit | 4e8453167f42976aad87099ffdb3746fc540d6a6 (patch) | |
tree | b3acee7dc97a19219fd1a84cabaf9b9d8eba1f3a /transform/rtcalls.go | |
parent | ebb410afd916047ee17f0e51dfba36ad3a6c002b (diff) | |
download | tinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.tar.gz tinygo-4e8453167f42976aad87099ffdb3746fc540d6a6.zip |
all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in
the binary. Instead of compressing it and storing it in a number of sidetables,
it is stored similar to how the Go compiler toolchain stores it (but still more
compactly).
This has a number of advantages:
* It is much easier to add new features to reflect support. They can simply
be added to these structs without requiring massive changes (especially in
the reflect lowering pass).
* It removes the reflect lowering pass, which was a large amount of hard to
understand and debug code.
* The reflect lowering pass also required merging all LLVM IR into one
module, which is terrible for performance especially when compiling large
amounts of code. See issue 2870 for details.
* It is (probably!) easier to reason about for the compiler.
The downside is that it increases code size a bit, especially when reflect is
involved. I hope to fix some of that in later patches.
Diffstat (limited to 'transform/rtcalls.go')
-rw-r--r-- | transform/rtcalls.go | 17 |
1 files changed, 5 insertions, 12 deletions
diff --git a/transform/rtcalls.go b/transform/rtcalls.go index 209e15ae1..b7192ad4f 100644 --- a/transform/rtcalls.go +++ b/transform/rtcalls.go @@ -113,11 +113,6 @@ func OptimizeReflectImplements(mod llvm.Module) { builder := mod.Context().NewBuilder() defer builder.Dispose() - // Get a few useful object for use later. - targetData := llvm.NewTargetData(mod.DataLayout()) - defer targetData.Dispose() - uintptrType := mod.Context().IntType(targetData.PointerSize() * 8) - // Look up the (reflect.Value).Implements() method. var implementsFunc llvm.Value for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) { @@ -141,14 +136,13 @@ func OptimizeReflectImplements(mod llvm.Module) { } interfaceType := stripPointerCasts(call.Operand(2)) if interfaceType.IsAGlobalVariable().IsNil() { - // The asserted interface is not constant, so can't optimize this - // code. + // Interface is unknown at compile time. This can't be optimized. continue } if strings.HasPrefix(interfaceType.Name(), "reflect/types.type:named:") { // Get the underlying type. - interfaceType = builder.CreateExtractValue(interfaceType.Initializer(), 0, "") + interfaceType = stripPointerCasts(builder.CreateExtractValue(interfaceType.Initializer(), 2, "")) } if !strings.HasPrefix(interfaceType.Name(), "reflect/types.type:interface:") { // This is an error. The Type passed to Implements should be of @@ -156,16 +150,15 @@ func OptimizeReflectImplements(mod llvm.Module) { // reported at runtime. continue } - if interfaceType.IsAGlobalVariable().IsNil() { - // Interface is unknown at compile time. This can't be optimized. + typeAssertFunction := mod.NamedFunction(strings.TrimPrefix(interfaceType.Name(), "reflect/types.type:") + ".$typeassert") + if typeAssertFunction.IsNil() { continue } - typeAssertFunction := builder.CreateExtractValue(interfaceType.Initializer(), 4, "").Operand(0) // Replace Implements call with the type assert call. builder.SetInsertPointBefore(call) implements := builder.CreateCall(typeAssertFunction.GlobalValueType(), typeAssertFunction, []llvm.Value{ - builder.CreatePtrToInt(call.Operand(0), uintptrType, ""), // typecode to check + call.Operand(0), // typecode to check }, "") call.ReplaceAllUsesWith(implements) call.EraseFromParentAsInstruction() |