Commit 6a75ece0 authored by Russ Cox's avatar Russ Cox

runtime: delete Type and implementations (use reflect instead)

unsafe: delete Typeof, Reflect, Unreflect, New, NewArray

Part of issue 2955 and issue 2968.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5650069
parent cbe7d8db
......@@ -764,6 +764,7 @@ EXTERN Pkg* gostringpkg; // fake pkg for Go strings
EXTERN Pkg* runtimepkg; // package runtime
EXTERN Pkg* stringpkg; // fake package for C strings
EXTERN Pkg* typepkg; // fake package for runtime type info
EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* phash[128];
EXTERN int tptr; // either TPTR32 or TPTR64
......
......@@ -209,6 +209,10 @@ main(int argc, char *argv[])
typepkg = mkpkg(strlit("type"));
typepkg->name = "type";
weaktypepkg = mkpkg(strlit("weak.type"));
weaktypepkg->name = "weak.type";
weaktypepkg->prefix = "weak.type"; // not weak%2etype
unsafepkg = mkpkg(strlit("unsafe"));
unsafepkg->name = "unsafe";
......
......@@ -454,54 +454,17 @@ kinds[] =
[TUNSAFEPTR] = KindUnsafePointer,
};
static char*
structnames[] =
{
[TINT] = "*runtime.IntType",
[TUINT] = "*runtime.UintType",
[TINT8] = "*runtime.IntType",
[TUINT8] = "*runtime.UintType",
[TINT16] = "*runtime.IntType",
[TUINT16] = "*runtime.UintType",
[TINT32] = "*runtime.IntType",
[TUINT32] = "*runtime.UintType",
[TINT64] = "*runtime.IntType",
[TUINT64] = "*runtime.UintType",
[TUINTPTR] = "*runtime.UintType",
[TCOMPLEX64] = "*runtime.ComplexType",
[TCOMPLEX128] = "*runtime.ComplexType",
[TFLOAT32] = "*runtime.FloatType",
[TFLOAT64] = "*runtime.FloatType",
[TBOOL] = "*runtime.BoolType",
[TSTRING] = "*runtime.StringType",
[TUNSAFEPTR] = "*runtime.UnsafePointerType",
[TPTR32] = "*runtime.PtrType",
[TPTR64] = "*runtime.PtrType",
[TSTRUCT] = "*runtime.StructType",
[TINTER] = "*runtime.InterfaceType",
[TCHAN] = "*runtime.ChanType",
[TMAP] = "*runtime.MapType",
[TARRAY] = "*runtime.ArrayType",
[TFUNC] = "*runtime.FuncType",
};
static Sym*
typestruct(Type *t)
{
char *name;
int et;
et = t->etype;
if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
fatal("typestruct %lT", t);
return nil; // silence gcc
}
if(isslice(t))
name = "*runtime.SliceType";
return pkglookup(name, typepkg);
// We use a weak reference to the reflect type
// to avoid requiring package reflect in every binary.
// If package reflect is available, the interface{} holding
// a runtime type will contain a *reflect.commonType.
// Otherwise it will use a nil type word but still be usable
// by package runtime (because we always use the memory
// after the interface value, not the interface value itself).
return pkglookup("*reflect.commonType", weaktypepkg);
}
int
......@@ -580,7 +543,7 @@ dcommontype(Sym *s, int ot, Type *t)
ot = dsymptr(s, ot, typestruct(t), 0);
ot = dsymptr(s, ot, s, 2*widthptr);
// ../../pkg/runtime/type.go:/commonType
// ../../pkg/reflect/type.go:/^type.commonType
// actual type structure
// type commonType struct {
// size uintptr;
......@@ -683,16 +646,9 @@ weaktypesym(Type *t)
{
char *p;
Sym *s;
static Pkg *weak;
if(weak == nil) {
weak = mkpkg(strlit("weak.type"));
weak->name = "weak.type";
weak->prefix = "weak.type"; // not weak%2etype
}
p = smprint("%-T", t);
s = pkglookup(p, weak);
s = pkglookup(p, weaktypepkg);
//print("weaktypesym: %s -> %+S\n", p, s);
free(p);
return s;
......
......@@ -2317,7 +2317,7 @@ dwarfemitdebugsections(void)
// Needed by the prettyprinter code for interface inspection.
defgotype(lookup_or_diag("type.runtime.commonType"));
defgotype(lookup_or_diag("type.runtime.InterfaceType"));
defgotype(lookup_or_diag("type.runtime.interfaceType"));
defgotype(lookup_or_diag("type.runtime.itab"));
genasmsym(defdwsymb);
......
......@@ -456,7 +456,7 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
}
if *(*unsafe.Pointer)(up) == nil {
// Allocate object.
*(*unsafe.Pointer)(up) = unsafe.New(rtyp)
*(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.New(rtyp).Pointer())
}
return *(*uintptr)(up)
}
......@@ -609,7 +609,7 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr,
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.ValueOf(unsafe.Unreflect(mtyp, unsafe.Pointer(p)))
v := reflect.NewAt(mtyp, unsafe.Pointer(p)).Elem()
n := int(state.decodeUint())
for i := 0; i < n; i++ {
key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
......@@ -662,7 +662,7 @@ func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintpt
// Always write a header at p.
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
if hdrp.Cap < n {
hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
hdrp.Cap = n
}
hdrp.Len = n
......@@ -969,16 +969,16 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
// Caller has gotten us to within one indirection of our value.
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.New(ut.base)
*(*unsafe.Pointer)(p) = unsafe.Pointer(reflect.New(ut.base).Pointer())
}
}
// Now p is a pointer to the base type. Do we need to climb out to
// get to the receiver type?
var v reflect.Value
if ut.decIndir == -1 {
v = reflect.ValueOf(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
v = reflect.NewAt(rcvrType, unsafe.Pointer(&p)).Elem()
} else {
v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p))
v = reflect.NewAt(rcvrType, p).Elem()
}
state.dec.decodeGobDecoder(state, v)
}
......
......@@ -590,7 +590,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
mv := reflect.Indirect(v)
// We send zero-length (but non-nil) maps because the
// receiver might want to use the map. (Maps don't use append.)
......@@ -613,7 +613,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
// Interfaces transmit the name and contents of the concrete
// value they contain.
v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
iv := reflect.Indirect(v)
if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
return
......@@ -645,9 +645,9 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
var v reflect.Value
if ut.encIndir == -1 {
// Need to climb up one level to turn value into pointer.
v = reflect.ValueOf(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
v = reflect.NewAt(rt, unsafe.Pointer(&p)).Elem()
} else {
v = reflect.ValueOf(unsafe.Unreflect(rt, p))
v = reflect.NewAt(rt, p).Elem()
}
if !state.sendZero && isZero(v) {
return
......
......@@ -16,7 +16,6 @@
package reflect
import (
"runtime"
"strconv"
"sync"
"unsafe"
......@@ -181,7 +180,7 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
runtimeType() *runtime.Type
runtimeType() *runtimeType
common() *commonType
uncommon() *uncommonType
}
......@@ -221,128 +220,131 @@ const (
)
/*
* Copy of data structures from ../runtime/type.go.
* For comments, see the ones in that file.
*
* These data structures are known to the compiler and the runtime.
*
* Putting these types in runtime instead of reflect means that
* reflect doesn't need to be autolinked into every binary, which
* simplifies bootstrapping and package dependencies.
* Unfortunately, it also means that reflect needs its own
* copy in order to access the private fields.
* These data structures are known to the compiler (../../cmd/gc/reflect.c).
* A few are known to ../runtime/type.go to convey to debuggers.
*/
// The compiler can only construct empty interface values at
// compile time; non-empty interface values get created
// during initialization. Type is an empty interface
// so that the compiler can lay out references as data.
// The underlying type is *reflect.ArrayType and so on.
type runtimeType interface{}
// commonType is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type commonType struct {
size uintptr
hash uint32
_ uint8
align uint8
fieldAlign uint8
kind uint8
alg *uintptr
string *string
*uncommonType
ptrToThis *runtime.Type
}
size uintptr // size in bytes
hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused/padding
align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *runtimeType // pointer to this type, if used in binary or has methods
}
// Method on non-interface type
type method struct {
name *string
pkgPath *string
mtyp *runtime.Type
typ *runtime.Type
ifn unsafe.Pointer
tfn unsafe.Pointer
}
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
mtyp *runtimeType // method type (without receiver)
typ *runtimeType // .(*FuncType) underneath (with receiver)
ifn unsafe.Pointer // fn used in interface call (one-word receiver)
tfn unsafe.Pointer // fn used for normal method call
}
// uncommonType is present only for types with names or methods
// (if T is a named type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
name *string
pkgPath *string
methods []method
name *string // name of type
pkgPath *string // import path; nil for built-in types like int, string
methods []method // methods associated with type
}
// ChanDir represents a channel type's direction.
type ChanDir int
const (
RecvDir ChanDir = 1 << iota
SendDir
BothDir = RecvDir | SendDir
RecvDir ChanDir = 1 << iota // <-chan
SendDir // chan<-
BothDir = RecvDir | SendDir // chan
)
// arrayType represents a fixed array type.
type arrayType struct {
commonType `reflect:"array"`
elem *runtime.Type
slice *runtime.Type
elem *runtimeType // array element type
slice *runtimeType // slice type
len uintptr
}
// chanType represents a channel type.
type chanType struct {
commonType `reflect:"chan"`
elem *runtime.Type
dir uintptr
elem *runtimeType // channel element type
dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
type funcType struct {
commonType `reflect:"func"`
dotdotdot bool
in []*runtime.Type
out []*runtime.Type
dotdotdot bool // last input parameter is ...
in []*runtimeType // input parameter types
out []*runtimeType // output parameter types
}
// imethod represents a method on an interface type
type imethod struct {
name *string
pkgPath *string
typ *runtime.Type
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
typ *runtimeType // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
commonType `reflect:"interface"`
methods []imethod
methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
commonType `reflect:"map"`
key *runtime.Type
elem *runtime.Type
key *runtimeType // map key type
elem *runtimeType // map element (value) type
}
// ptrType represents a pointer type.
type ptrType struct {
commonType `reflect:"ptr"`
elem *runtime.Type
elem *runtimeType // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
commonType `reflect:"slice"`
elem *runtime.Type
elem *runtimeType // slice element type
}
// Struct field
type structField struct {
name *string
pkgPath *string
typ *runtime.Type
tag *string
offset uintptr
name *string // nil for embedded fields
pkgPath *string // nil for exported Names; otherwise import path
typ *runtimeType // type of field
tag *string // nil if no tag
offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
type structType struct {
commonType `reflect:"struct"`
fields []structField
fields []structField // sorted by offset
}
/*
......@@ -909,23 +911,18 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (f StructField, pr
}
// Convert runtime type to reflect type.
func toCommonType(p *runtime.Type) *commonType {
func toCommonType(p *runtimeType) *commonType {
if p == nil {
return nil
}
type hdr struct {
x interface{}
t commonType
}
x := unsafe.Pointer(p)
return &(*hdr)(x).t
return (*p).(*commonType)
}
func toType(p *runtime.Type) Type {
func toType(p *runtimeType) Type {
if p == nil {
return nil
}
return toCommonType(p).toType()
return (*p).(*commonType)
}
// TypeOf returns the reflection Type of the value in the interface{}.
......@@ -940,14 +937,14 @@ var ptrMap struct {
m map[*commonType]*ptrType
}
func (t *commonType) runtimeType() *runtime.Type {
// The runtime.Type always precedes the commonType in memory.
func (t *commonType) runtimeType() *runtimeType {
// The runtimeType always precedes the commonType in memory.
// Adjust pointer to find it.
var rt struct {
i runtime.Type
i runtimeType
ct commonType
}
return (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
return (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
}
// PtrTo returns the pointer type with element t.
......@@ -986,16 +983,15 @@ func (ct *commonType) ptrTo() *commonType {
}
var rt struct {
i runtime.Type
i runtimeType
ptrType
}
rt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))
rt.i = &rt.commonType
// initialize p using *byte's ptrType as a prototype.
// have to do assignment as ptrType, not runtime.PtrType,
// in order to write to unexported fields.
p = &rt.ptrType
bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
var ibyte interface{} = (*byte)(nil)
bp := (*ptrType)(unsafe.Pointer((**(**runtimeType)(unsafe.Pointer(&ibyte))).(*commonType)))
*p = *bp
s := "*" + *ct.string
......@@ -1010,7 +1006,7 @@ func (ct *commonType) ptrTo() *commonType {
p.uncommonType = nil
p.ptrToThis = nil
p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
p.elem = (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
ptrMap.m[ct] = p
ptrMap.Unlock()
......
......@@ -207,7 +207,7 @@ func storeIword(p unsafe.Pointer, w iword, n uintptr) {
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *runtime.Type
typ *runtimeType
word iword
}
......@@ -215,8 +215,8 @@ type emptyInterface struct {
type nonEmptyInterface struct {
// see ../runtime/iface.c:/Itab
itab *struct {
ityp *runtime.Type // static interface type
typ *runtime.Type // dynamic concrete type
ityp *runtimeType // static interface type
typ *runtimeType // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
......@@ -1606,6 +1606,10 @@ func Copy(dst, src Value) int {
* constructors
*/
// implemented in package runtime
func unsafe_New(Type) unsafe.Pointer
func unsafe_NewArray(Type, int) unsafe.Pointer
// MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity.
func MakeSlice(typ Type, len, cap int) Value {
......@@ -1618,7 +1622,7 @@ func MakeSlice(typ Type, len, cap int) Value {
// Reinterpret as *SliceHeader to edit.
s := (*SliceHeader)(unsafe.Pointer(&x))
s.Data = uintptr(unsafe.NewArray(typ.Elem(), cap))
s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap))
s.Len = len
s.Cap = cap
......@@ -1697,7 +1701,7 @@ func Zero(typ Type) Value {
if t.size <= ptrSize {
return Value{t, nil, fl}
}
return Value{t, unsafe.New(typ), fl | flagIndir}
return Value{t, unsafe_New(typ), fl | flagIndir}
}
// New returns a Value representing a pointer to a new zero value
......@@ -1706,11 +1710,18 @@ func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
}
ptr := unsafe.New(typ)
ptr := unsafe_New(typ)
fl := flag(Ptr) << flagKindShift
return Value{typ.common().ptrTo(), ptr, fl}
}
// NewAt returns a Value representing a pointer to a value of the
// specified type, using p as that pointer.
func NewAt(typ Type, p unsafe.Pointer) Value {
fl := flag(Ptr) << flagKindShift
return Value{typ.common().ptrTo(), p, fl}
}
// assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use.
......@@ -1749,20 +1760,20 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va
func chancap(ch iword) int32
func chanclose(ch iword)
func chanlen(ch iword) int32
func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received bool)
func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool
func makechan(typ *runtime.Type, size uint32) (ch iword)
func makemap(t *runtime.Type) (m iword)
func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)
func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)
func mapiterinit(t *runtime.Type, m iword) *byte
func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool)
func chansend(t *runtimeType, ch iword, val iword, nb bool) bool
func makechan(typ *runtimeType, size uint32) (ch iword)
func makemap(t *runtimeType) (m iword)
func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool)
func mapassign(t *runtimeType, m iword, key, val iword, ok bool)
func mapiterinit(t *runtimeType, m iword) *byte
func mapiterkey(it *byte) (key iword, ok bool)
func mapiternext(it *byte)
func maplen(m iword) int32
func call(fn, arg unsafe.Pointer, n uint32)
func ifaceE2I(t *runtime.Type, src interface{}, dst unsafe.Pointer)
func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer)
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
......
......@@ -17,9 +17,6 @@ type Error interface {
// A TypeAssertionError explains a failed type assertion.
type TypeAssertionError struct {
interfaceType Type // interface had this type
concreteType Type // concrete value had this type
assertedType Type // asserted type
interfaceString string
concreteString string
assertedString string
......@@ -33,7 +30,7 @@ func (e *TypeAssertionError) Error() string {
if inter == "" {
inter = "interface"
}
if e.concreteType == nil {
if e.concreteString == "" {
return "interface conversion: " + inter + " is nil, not " + e.assertedString
}
if e.missingMethod == "" {
......@@ -44,40 +41,10 @@ func (e *TypeAssertionError) Error() string {
": missing method " + e.missingMethod
}
// Concrete returns the type of the concrete value in the failed type assertion.
// If the interface value was nil, Concrete returns nil.
func (e *TypeAssertionError) Concrete() Type {
return e.concreteType
}
// Asserted returns the type incorrectly asserted by the type assertion.
func (e *TypeAssertionError) Asserted() Type {
return e.assertedType
}
// If the type assertion is to an interface type, MissingMethod returns the
// name of a method needed to satisfy that interface type but not implemented
// by Concrete. If there are multiple such methods,
// MissingMethod returns one; which one is unspecified.
// If the type assertion is not to an interface type, MissingMethod returns an empty string.
func (e *TypeAssertionError) MissingMethod() string {
return e.missingMethod
}
// For calling from C.
func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
var t1, t2, t3 Type
func newTypeAssertionError(ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
var s1, s2, s3, meth string
if pt1 != nil {
t1 = *pt1
}
if pt2 != nil {
t2 = *pt2
}
if pt3 != nil {
t3 = *pt3
}
if ps1 != nil {
s1 = *ps1
}
......@@ -90,7 +57,7 @@ func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *st
if pmeth != nil {
meth = *pmeth
}
*ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
*ret = &TypeAssertionError{s1, s2, s3, meth}
}
// An errorString represents a runtime error described by a single string.
......
......@@ -7,14 +7,6 @@
#include "type.h"
#include "malloc.h"
enum
{
// If an empty interface has these bits set in its type
// pointer, it was copied from a reflect.Value and is
// not a valid empty interface.
reflectFlags = 3,
};
void
runtime·printiface(Iface i)
{
......@@ -127,7 +119,7 @@ search:
if(!canfail) {
throw:
// didn't find method
runtime·newTypeAssertionError(nil, type, inter,
runtime·newTypeAssertionError(
nil, type->string, inter->string,
iname, &err);
if(locked)
......@@ -243,13 +235,13 @@ assertI2Tret(Type *t, Iface i, byte *ret)
tab = i.tab;
if(tab == nil) {
runtime·newTypeAssertionError(nil, nil, t,
runtime·newTypeAssertionError(
nil, nil, t->string,
nil, &err);
runtime·panic(err);
}
if(tab->type != t) {
runtime·newTypeAssertionError(tab->inter, tab->type, t,
runtime·newTypeAssertionError(
tab->inter->string, tab->type->string, t->string,
nil, &err);
runtime·panic(err);
......@@ -289,8 +281,6 @@ runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
assertE2Tret(t, e, ret);
}
......@@ -300,16 +290,14 @@ assertE2Tret(Type *t, Eface e, byte *ret)
{
Eface err;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(e.type == nil) {
runtime·newTypeAssertionError(nil, nil, t,
runtime·newTypeAssertionError(
nil, nil, t->string,
nil, &err);
runtime·panic(err);
}
if(e.type != t) {
runtime·newTypeAssertionError(nil, e.type, t,
runtime·newTypeAssertionError(
nil, e.type->string, t->string,
nil, &err);
runtime·panic(err);
......@@ -326,8 +314,6 @@ runtime·assertE2T2(Type *t, Eface e, ...)
bool *ok;
int32 wid;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
wid = t->size;
ok = (bool*)(ret + wid);
......@@ -366,7 +352,7 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
runtime·newTypeAssertionError(nil, nil, inter,
runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
......@@ -421,7 +407,7 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
runtime·newTypeAssertionError(nil, nil, inter,
runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
......@@ -463,12 +449,10 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
Type *t;
Eface err;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
runtime·newTypeAssertionError(nil, nil, inter,
runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
......@@ -496,8 +480,6 @@ runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
void
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(e.type == nil) {
ok = 0;
ret.data = nil;
......@@ -520,12 +502,10 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
Type *t;
Eface err;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
runtime·newTypeAssertionError(nil, nil, inter,
runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
......@@ -538,8 +518,6 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
void
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
USED(inter);
ret = e;
ok = e.type != nil;
......@@ -626,10 +604,6 @@ runtime·ifaceeq_c(Iface i1, Iface i2)
bool
runtime·efaceeq_c(Eface e1, Eface e2)
{
if(((uintptr)e1.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(((uintptr)e2.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(e1.type != e2.type)
return false;
if(e1.type == nil)
......@@ -672,8 +646,6 @@ runtime·efacethash(Eface e1, uint32 ret)
{
Type *t;
if(((uintptr)e1.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
ret = 0;
t = e1.type;
if(t != nil)
......@@ -682,10 +654,8 @@ runtime·efacethash(Eface e1, uint32 ret)
}
void
unsafe·Typeof(Eface e, Eface ret)
reflect·unsafe_Typeof(Eface e, Eface ret)
{
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(e.type == nil) {
ret.type = nil;
ret.data = nil;
......@@ -696,73 +666,10 @@ unsafe·Typeof(Eface e, Eface ret)
}
void
unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
{
uintptr *p;
uintptr x;
if(((uintptr)e.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
if(e.type == nil) {
rettype.type = nil;
rettype.data = nil;
retaddr = 0;
} else {
rettype = *(Eface*)e.type;
if(e.type->size <= sizeof(uintptr)) {
// Copy data into x ...
x = 0;
e.type->alg->copy(e.type->size, &x, &e.data);
// but then build pointer to x so that Reflect
// always returns pointer to data.
p = runtime·mal(sizeof(uintptr));
*p = x;
} else {
// Already a pointer, but still make a copy,
// to preserve value semantics for interface data.
p = runtime·mal(e.type->size);
e.type->alg->copy(e.type->size, p, e.data);
}
retaddr = p;
}
FLUSH(&rettype);
FLUSH(&retaddr);
}
void
unsafe·Unreflect(Eface typ, void *addr, Eface e)
{
if(((uintptr)typ.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
// type structure sits before the data pointer.
e.type = (Type*)((Eface*)typ.data-1);
// Interface holds either pointer to data
// or copy of original data.
if(e.type->size <= sizeof(uintptr))
e.type->alg->copy(e.type->size, &e.data, addr);
else {
// Easier: already a pointer to data.
// TODO(rsc): Should this make a copy?
e.data = addr;
}
FLUSH(&e);
}
void
unsafe·New(Eface typ, void *ret)
reflect·unsafe_New(Eface typ, void *ret)
{
Type *t;
if(((uintptr)typ.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
......@@ -777,14 +684,11 @@ unsafe·New(Eface typ, void *ret)
}
void
unsafe·NewArray(Eface typ, uint32 n, void *ret)
reflect·unsafe_NewArray(Eface typ, uint32 n, void *ret)
{
uint64 size;
Type *t;
if(((uintptr)typ.type&reflectFlags) != 0)
runtime·throw("invalid interface value");
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
......
......@@ -674,7 +674,7 @@ void runtime·panicslice(void);
*/
void runtime·newError(String, Eface*);
void runtime·printany(Eface);
void runtime·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
void runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
void runtime·newErrorString(String, Eface*);
void runtime·fadd64c(uint64, uint64, uint64*);
void runtime·fsub64c(uint64, uint64, uint64*);
......
......@@ -4,206 +4,51 @@
/*
* Runtime type representation.
*
* The following files know the exact layout of these
* data structures and must be kept in sync with this file:
*
* ../../cmd/gc/reflect.c
* ../../cmd/ld/dwarf.c decodetype_*
* ../reflect/type.go
* type.h
* This file exists only to provide types that 6l can turn into
* DWARF information for use by gdb. Nothing else uses these.
* They should match the same types in ../reflect/type.go.
* For comments see ../reflect/type.go.
*/
package runtime
import "unsafe"
// The compiler can only construct empty interface values at
// compile time; non-empty interface values get created
// during initialization. Type is an empty interface
// so that the compiler can lay out references as data.
type Type interface{}
// All types begin with a few common fields needed for
// the interface runtime.
type commonType struct {
size uintptr // size in bytes
hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused
align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *Type // pointer to this type, if used in binary or has methods
}
// Values for commonType.kind.
const (
kindBool = 1 + iota
kindInt
kindInt8
kindInt16
kindInt32
kindInt64
kindUint
kindUint8
kindUint16
kindUint32
kindUint64
kindUintptr
kindFloat32
kindFloat64
kindComplex64
kindComplex128
kindArray
kindChan
kindFunc
kindInterface
kindMap
kindPtr
kindSlice
kindString
kindStruct
kindUnsafePointer
kindNoPointers = 1 << 7 // OR'ed into kind
)
// Method on non-interface type
type _method struct { // underscore is to avoid collision with C
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
mtyp *Type // method type (without receiver)
typ *Type // .(*FuncType) underneath (with receiver)
ifn unsafe.Pointer // fn used in interface call (one-word receiver)
tfn unsafe.Pointer // fn used for normal method call
size uintptr
hash uint32
_ uint8
align uint8
fieldAlign uint8
kind uint8
alg *uintptr
string *string
*uncommonType
ptrToThis *interface{}
}
type _method struct {
name *string
pkgPath *string
mtyp *interface{}
typ *interface{}
ifn unsafe.Pointer
tfn unsafe.Pointer
}
// uncommonType is present only for types with names or methods
// (if T is a named type, the uncommonTypes for T and *T have methods).
// Using a pointer to this struct reduces the overall size required
// to describe an unnamed type with no methods.
type uncommonType struct {
name *string // name of type
pkgPath *string // import path; nil for built-in types like int, string
methods []_method // methods associated with type
}
// BoolType represents a boolean type.
type BoolType commonType
// FloatType represents a float type.
type FloatType commonType
// ComplexType represents a complex type.
type ComplexType commonType
// IntType represents an int type.
type IntType commonType
// UintType represents a uint type.
type UintType commonType
// StringType represents a string type.
type StringType commonType
// UintptrType represents a uintptr type.
type UintptrType commonType
// UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType commonType
// ArrayType represents a fixed array type.
type ArrayType struct {
commonType
elem *Type // array element type
slice *Type // slice type
len uintptr
}
// SliceType represents a slice type.
type SliceType struct {
commonType
elem *Type // slice element type
}
// ChanDir represents a channel type's direction.
type ChanDir int
const (
RecvDir ChanDir = 1 << iota // <-chan
SendDir // chan<-
BothDir = RecvDir | SendDir // chan
)
// ChanType represents a channel type.
type ChanType struct {
commonType
elem *Type // channel element type
dir uintptr // channel direction (ChanDir)
}
// FuncType represents a function type.
type FuncType struct {
commonType
dotdotdot bool // last input parameter is ...
in []*Type // input parameter types
out []*Type // output parameter types
name *string
pkgPath *string
methods []_method
}
// Method on interface type
type _imethod struct { // underscore is to avoid collision with C
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
typ *Type // .(*FuncType) underneath
type _imethod struct {
name *string
pkgPath *string
typ *interface{}
}
// InterfaceType represents an interface type.
type InterfaceType struct {
type interfaceType struct {
commonType
methods []_imethod // sorted by hash
}
// MapType represents a map type.
type MapType struct {
commonType
key *Type // map key type
elem *Type // map element (value) type
}
// PtrType represents a pointer type.
type PtrType struct {
commonType
elem *Type // pointer element (pointed at) type
}
// Struct field
type structField struct {
name *string // nil for embedded fields
pkgPath *string // nil for exported Names; otherwise import path
typ *Type // type of field
tag *string // nil if no tag
offset uintptr // byte offset of field within struct
}
// StructType represents a struct type.
type StructType struct {
commonType
fields []structField // sorted by offset
}
/*
* Must match iface.c:/Itab and compilers.
* NOTE: this is the version used by the reflection code, there is another
* one in iface_defs.go that is closer to the original C version.
*/
type Itable struct {
Itype *Type // (*tab.inter).(*InterfaceType) is the interface type
Type *Type
link *Itable
bad int32
unused int32
Fn [100000]uintptr // bigger than we'll ever see
methods []_imethod
}
......@@ -35,27 +35,3 @@ func Offsetof(v ArbitraryType) uintptr
// that the address of a variable with the type of v will always always be zero mod m.
// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) uintptr
// Typeof returns the type of an interface value, a runtime.Type.
func Typeof(i interface{}) (typ interface{})
// Reflect unpacks an interface value into its type and the address of a copy of the
// internal value.
func Reflect(i interface{}) (typ interface{}, addr Pointer)
// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
// empty interface value with contents the type and the value (not the pointer to
// the value). The typ is assumed to contain a pointer to a runtime type; the type
// information in the interface{} is ignored, so that, for example, both
// *reflect.structType and *runtime.StructType can be passed for typ.
func Unreflect(typ interface{}, addr Pointer) (ret interface{})
// New allocates and returns a pointer to memory for a new value of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.New or reflect.Zero instead of invoking unsafe.New directly.
func New(typ interface{}) Pointer
// NewArray allocates and returns a pointer to an array of n elements of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
func NewArray(typ interface{}, n int) Pointer
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment