tinygo/src/runtime/interface.go
Ayke van Laethem a4afc3b4b0 compiler: simplify interface lowering
This commit simplifies the IR a little bit: instead of calling
pseudo-functions runtime.interfaceImplements and
runtime.interfaceMethod, real declared functions are being called that
are then defined in the interface lowering pass. This should simplify
the interaction between various transformation passes. It also reduces
the number of lines of code, which is generally a good thing.
2021-10-31 14:17:25 +01:00

139 строки
4,1 КиБ
Go

package runtime
// This file implements Go interfaces.
//
// Interfaces are represented as a pair of {typecode, value}, where value can be
// anything (including non-pointers).
import (
"reflect"
"unsafe"
)
type _interface struct {
typecode uintptr
value unsafe.Pointer
}
//go:inline
func composeInterface(typecode uintptr, value unsafe.Pointer) _interface {
return _interface{typecode, value}
}
//go:inline
func decomposeInterface(i _interface) (uintptr, unsafe.Pointer) {
return i.typecode, i.value
}
// Return true iff both interfaces are equal.
func interfaceEqual(x, y interface{}) bool {
return reflectValueEqual(reflect.ValueOf(x), reflect.ValueOf(y))
}
func reflectValueEqual(x, y reflect.Value) bool {
// Note: doing a x.Type() == y.Type() comparison would not work here as that
// would introduce an infinite recursion: comparing two reflect.Type values
// is done with this reflectValueEqual runtime call.
if x.RawType() == 0 || y.RawType() == 0 {
// One of them is nil.
return x.RawType() == y.RawType()
}
if x.RawType() != y.RawType() {
// The type is not the same, which means the interfaces are definitely
// not the same.
return false
}
switch x.RawType().Kind() {
case reflect.Bool:
return x.Bool() == y.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return x.Int() == y.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return x.Uint() == y.Uint()
case reflect.Float32, reflect.Float64:
return x.Float() == y.Float()
case reflect.Complex64, reflect.Complex128:
return x.Complex() == y.Complex()
case reflect.String:
return x.String() == y.String()
case reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
return x.Pointer() == y.Pointer()
case reflect.Array:
for i := 0; i < x.Len(); i++ {
if !reflectValueEqual(x.Index(i), y.Index(i)) {
return false
}
}
return true
case reflect.Struct:
for i := 0; i < x.NumField(); i++ {
if !reflectValueEqual(x.Field(i), y.Field(i)) {
return false
}
}
return true
default:
runtimePanic("comparing un-comparable type")
return false // unreachable
}
}
// interfaceTypeAssert is called when a type assert without comma-ok still
// returns false.
func interfaceTypeAssert(ok bool) {
if !ok {
runtimePanic("type assert failed")
}
}
// The following declarations are only used during IR construction. They are
// lowered to inline IR in the interface lowering pass.
// See compiler/interface-lowering.go for details.
type interfaceMethodInfo struct {
signature *uint8 // external *i8 with a name identifying the Go function signature
funcptr uintptr // bitcast from the actual function pointer
}
type typecodeID struct {
// Depending on the type kind of this typecodeID, this pointer is something
// different:
// * basic types: null
// * named type: the underlying type
// * interface: null
// * chan/pointer/slice/array: the element type
// * struct: bitcast of global with structField array
// * func/map: TODO
references *typecodeID
// The array length, for array types.
length uintptr
methodSet *interfaceMethodInfo // nil or a GEP of an array
// The type that's a pointer to this type, nil if it is already a pointer.
// Keeping the type struct alive here is important so that values from
// reflect.New (which uses reflect.PtrTo) can be used in type asserts etc.
ptrTo *typecodeID
// typeAssert is a ptrtoint of a declared interface assert function.
// It only exists to make the rtcalls pass easier.
typeAssert uintptr
}
// structField is used by the compiler to pass information to the interface
// lowering pass. It is not used in the final binary.
type structField struct {
typecode *typecodeID // type of this struct field
name *uint8 // pointer to char array
tag *uint8 // pointer to char array, or nil
embedded bool
}
// Pseudo function call used during a type assert. It is used during interface
// lowering, to assign the lowest type numbers to the types with the most type
// asserts. Also, it is replaced with const false if this type assert can never
// happen.
func typeAssert(actualType uintptr, assertedType *uint8) bool