 4e8453167f
			
		
	
	
		4e8453167f
		
	
	
	
	
		
			
			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.
		
	
			
		
			
				
	
	
		
			41 строка
		
	
	
	
		
			3 КиБ
		
	
	
	
		
			LLVM
		
	
	
	
	
	
			
		
		
	
	
			41 строка
		
	
	
	
		
			3 КиБ
		
	
	
	
		
			LLVM
		
	
	
	
	
	
| target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
 | |
| target triple = "i686--linux"
 | |
| 
 | |
| %runtime._interface = type { i8*, i8* }
 | |
| 
 | |
| @"reflect/types.type:named:error" = internal constant { i8, i8*, i8* } { i8 52, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:named:error", i32 0, i32 0), i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, i32 0) }, align 4
 | |
| @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = internal constant { i8, i8* } { i8 20, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", i32 0, i32 0) }, align 4
 | |
| @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = internal constant { i8, i8* } { i8 21, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, i32 0) }, align 4
 | |
| @"reflect/types.type:pointer:named:error" = internal constant { i8, i8* } { i8 21, i8* getelementptr inbounds ({ i8, i8*, i8* }, { i8, i8*, i8* }* @"reflect/types.type:named:error", i32 0, i32 0) }, align 4
 | |
| @"reflect/types.type:pointer:named:reflect.rawType" = internal constant { i8*, i8, i8* } { i8* null, i8 21, i8* null }, align 4
 | |
| @"reflect/methods.Implements(reflect.Type) bool" = internal constant i8 0, align 1
 | |
| 
 | |
| ; var errorType = reflect.TypeOf((*error)(nil)).Elem()
 | |
| ; func isError(typ reflect.Type) bool {
 | |
| ;   return typ.Implements(errorType)
 | |
| ; }
 | |
| ; The type itself is stored in %typ.value, %typ.typecode just refers to the
 | |
| ; type of reflect.Type. This function can be optimized because errorType is
 | |
| ; known at compile time (after the interp pass has run).
 | |
| define i1 @main.isError(i8* %typ.typecode, i8* %typ.value, i8* %context) {
 | |
| entry:
 | |
|   %result = call i1 @"reflect.Type.Implements$invoke"(i8* %typ.value, i8* getelementptr inbounds ({ i8*, i8, i8* }, { i8*, i8, i8* }* @"reflect/types.type:pointer:named:reflect.rawType", i32 0, i32 1), i8* getelementptr inbounds ({ i8, i8*, i8* }, { i8, i8*, i8* }* @"reflect/types.type:named:error", i32 0, i32 0), i8* %typ.typecode, i8* undef)
 | |
|   ret i1 %result
 | |
| }
 | |
| 
 | |
| ; This Implements method call can not be optimized because itf is not known at
 | |
| ; compile time.
 | |
| ; func isUnknown(typ, itf reflect.Type) bool {
 | |
| ;   return typ.Implements(itf)
 | |
| ; }
 | |
| define i1 @main.isUnknown(i8* %typ.typecode, i8* %typ.value, i8* %itf.typecode, i8* %itf.value, i8* %context) {
 | |
| entry:
 | |
|   %result = call i1 @"reflect.Type.Implements$invoke"(i8* %typ.value, i8* %itf.typecode, i8* %itf.value, i8* %typ.typecode, i8* undef)
 | |
|   ret i1 %result
 | |
| }
 | |
| 
 | |
| declare i1 @"reflect.Type.Implements$invoke"(i8*, i8*, i8*, i8*, i8*) #0
 | |
| declare i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i8* %0) #1
 | |
| 
 | |
| attributes #0 = { "tinygo-invoke"="reflect/methods.Implements(reflect.Type) bool" "tinygo-methods"="reflect/methods.Align() int; reflect/methods.Implements(reflect.Type) bool" }
 | |
| attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
 |