mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-15 00:13:43 +00:00
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.
This commit is contained in:
committed by
Ron Evans
parent
ebb410afd9
commit
4e8453167f
+5
-12
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user