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:
Ayke van Laethem
2022-06-24 00:09:03 +02:00
committed by Ron Evans
parent ebb410afd9
commit 4e8453167f
27 changed files with 791 additions and 1346 deletions
+12 -10
View File
@@ -17,7 +17,7 @@ const (
)
type Value struct {
typecode rawType
typecode *rawType
value unsafe.Pointer
flags valueFlags
}
@@ -44,15 +44,15 @@ func Indirect(v Value) Value {
}
//go:linkname composeInterface runtime.composeInterface
func composeInterface(rawType, unsafe.Pointer) interface{}
func composeInterface(unsafe.Pointer, unsafe.Pointer) interface{}
//go:linkname decomposeInterface runtime.decomposeInterface
func decomposeInterface(i interface{}) (rawType, unsafe.Pointer)
func decomposeInterface(i interface{}) (unsafe.Pointer, unsafe.Pointer)
func ValueOf(i interface{}) Value {
typecode, value := decomposeInterface(i)
return Value{
typecode: typecode,
typecode: (*rawType)(typecode),
value: value,
flags: valueFlagExported,
}
@@ -85,7 +85,7 @@ func valueInterfaceUnsafe(v Value) interface{} {
}
v.value = unsafe.Pointer(value)
}
return composeInterface(v.typecode, v.value)
return composeInterface(unsafe.Pointer(v.typecode), v.value)
}
func (v Value) Type() Type {
@@ -136,7 +136,7 @@ func (v Value) IsZero() bool {
//
// RawType returns the raw, underlying type code. It is used in the runtime
// package and needs to be exported for the runtime package to access it.
func (v Value) RawType() rawType {
func (v Value) RawType() *rawType {
return v.typecode
}
@@ -205,7 +205,7 @@ func (v Value) pointer() unsafe.Pointer {
}
func (v Value) IsValid() bool {
return v.typecode != 0
return v.typecode != nil
}
func (v Value) CanInterface() bool {
@@ -453,7 +453,7 @@ func (v Value) Elem() Value {
case Interface:
typecode, value := decomposeInterface(*(*interface{})(v.value))
return Value{
typecode: typecode,
typecode: (*rawType)(typecode),
value: value,
flags: v.flags &^ valueFlagIndirect,
}
@@ -523,6 +523,8 @@ func (v Value) Field(i int) Value {
}
}
var uint8Type = TypeOf(uint8(0)).(*rawType)
func (v Value) Index(i int) Value {
switch v.Kind() {
case Slice:
@@ -550,7 +552,7 @@ func (v Value) Index(i int) Value {
panic("reflect: string index out of range")
}
return Value{
typecode: Uint8.basicType(),
typecode: uint8Type,
value: unsafe.Pointer(uintptr(*(*uint8)(unsafe.Pointer(uintptr(s.data) + uintptr(i))))),
flags: v.flags & valueFlagExported,
}
@@ -803,7 +805,7 @@ func Zero(typ Type) Value {
// new value of the given type.
func New(typ Type) Value {
return Value{
typecode: PtrTo(typ).(rawType),
typecode: PtrTo(typ).(*rawType),
value: alloc(typ.Size(), nil),
flags: valueFlagExported,
}