Commit 33649bd2 authored by Russ Cox's avatar Russ Cox

runtime: introduce unsafe.New and unsafe.NewArray

    to provide functionality previously hacked in to
    reflect and gob.

R=r
https://golang.org/cl/165076
parent a4a82241
...@@ -86,5 +86,7 @@ char *unsafeimport = ...@@ -86,5 +86,7 @@ char *unsafeimport =
"func unsafe.Typeof (i interface { }) (typ interface { })\n" "func unsafe.Typeof (i interface { }) (typ interface { })\n"
"func unsafe.Reflect (i interface { }) (typ interface { }, addr unsafe.Pointer)\n" "func unsafe.Reflect (i interface { }) (typ interface { }, addr unsafe.Pointer)\n"
"func unsafe.Unreflect (typ interface { }, addr unsafe.Pointer) (ret interface { })\n" "func unsafe.Unreflect (typ interface { }, addr unsafe.Pointer) (ret interface { })\n"
"func unsafe.New (typ interface { }) (? unsafe.Pointer)\n"
"func unsafe.NewArray (typ interface { }, n int) (? unsafe.Pointer)\n"
"\n" "\n"
"$$\n"; "$$\n";
...@@ -12,3 +12,5 @@ func Alignof(any) int ...@@ -12,3 +12,5 @@ func Alignof(any) int
func Typeof(i interface{}) (typ interface{}) func Typeof(i interface{}) (typ interface{})
func Reflect(i interface{}) (typ interface{}, addr Pointer) func Reflect(i interface{}) (typ interface{}, addr Pointer)
func Unreflect(typ interface{}, addr Pointer) (ret interface{}) func Unreflect(typ interface{}, addr Pointer) (ret interface{})
func New(typ interface{}) Pointer
func NewArray(typ interface{}, n int) Pointer
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"math"; "math";
"os"; "os";
"reflect"; "reflect";
"runtime";
"unsafe"; "unsafe";
) )
...@@ -361,10 +362,8 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer, ...@@ -361,10 +362,8 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
up = decIndirect(up, indir) up = decIndirect(up, indir)
} }
if *(*unsafe.Pointer)(up) == nil { if *(*unsafe.Pointer)(up) == nil {
// Allocate object by making a slice of bytes and recording the // Allocate object.
// address of the beginning of the array. TODO(rsc). *(*unsafe.Pointer)(up) = unsafe.New((*runtime.StructType)(unsafe.Pointer(rtyp)))
b := make([]byte, rtyp.Size());
*(*unsafe.Pointer)(up) = unsafe.Pointer(&b[0]);
} }
p = *(*uintptr)(up); p = *(*uintptr)(up);
} }
...@@ -437,10 +436,8 @@ func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp ...@@ -437,10 +436,8 @@ func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp
if indir > 0 { if indir > 0 {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
if *(*unsafe.Pointer)(up) == nil { if *(*unsafe.Pointer)(up) == nil {
// Allocate the array by making a slice of bytes of the correct size // Allocate object.
// and taking the address of the beginning of the array. TODO(rsc). *(*unsafe.Pointer)(up) = unsafe.New(atyp)
b := make([]byte, atyp.Size());
*(**byte)(up) = &b[0];
} }
p = *(*uintptr)(up); p = *(*uintptr)(up);
} }
...@@ -466,23 +463,22 @@ func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error { ...@@ -466,23 +463,22 @@ func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error {
} }
func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) os.Error { func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) os.Error {
length := uintptr(decodeUint(state)); n := int(uintptr(decodeUint(state)));
if indir > 0 { if indir > 0 {
up := unsafe.Pointer(p); up := unsafe.Pointer(p);
if *(*unsafe.Pointer)(up) == nil { if *(*unsafe.Pointer)(up) == nil {
// Allocate the slice header. // Allocate the slice header.
*(*unsafe.Pointer)(up) = unsafe.Pointer(new(reflect.SliceHeader)) *(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
} }
p = *(*uintptr)(up); p = *(*uintptr)(up);
} }
// Allocate storage for the slice elements, that is, the underlying array. // Allocate storage for the slice elements, that is, the underlying array.
data := make([]byte, length*atyp.Elem().Size());
// Always write a header at p. // Always write a header at p.
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p)); hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p));
hdrp.Data = uintptr(unsafe.Pointer(&data[0])); hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n));
hdrp.Len = int(length); hdrp.Len = n;
hdrp.Cap = int(length); hdrp.Cap = n;
return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, int(length), elemIndir, ovfl); return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl);
} }
func ignoreSlice(state *decodeState, elemOp decOp) os.Error { func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
......
...@@ -595,15 +595,11 @@ func (v *SliceValue) Elem(i int) Value { ...@@ -595,15 +595,11 @@ func (v *SliceValue) Elem(i int) Value {
// MakeSlice creates a new zero-initialized slice value // MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity. // for the specified slice type, length, and capacity.
func MakeSlice(typ *SliceType, len, cap int) *SliceValue { func MakeSlice(typ *SliceType, len, cap int) *SliceValue {
s := new(SliceHeader); s := &SliceHeader{
size := typ.Elem().Size() * uintptr(cap); Data: uintptr(unsafe.NewArray(typ.Elem(), cap)),
if size == 0 { Len: len,
size = 1 Cap: cap,
} };
data := make([]uint8, size);
s.Data = uintptr(addr(&data[0]));
s.Len = len;
s.Cap = cap;
return newValue(typ, addr(s), true).(*SliceValue); return newValue(typ, addr(s), true).(*SliceValue);
} }
...@@ -1270,13 +1266,8 @@ func newValue(typ Type, addr addr, canSet bool) Value { ...@@ -1270,13 +1266,8 @@ func newValue(typ Type, addr addr, canSet bool) Value {
// MakeZero returns a zero Value for the specified Type. // MakeZero returns a zero Value for the specified Type.
func MakeZero(typ Type) Value { func MakeZero(typ Type) Value {
// TODO: this will have to move into if typ == nil {
// the runtime proper in order to play nicely return nil
// with the garbage collector. }
size := typ.Size(); return newValue(typ, addr(unsafe.New(typ)), true);
if size == 0 {
size = 1
}
data := make([]uint8, size);
return newValue(typ, addr(&data[0]), true);
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "runtime.h" #include "runtime.h"
#include "type.h" #include "type.h"
#include "malloc.h"
static void static void
printiface(Iface i) printiface(Iface i)
...@@ -605,7 +606,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr) ...@@ -605,7 +606,7 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
} }
void void
unsafe·Unreflect(Iface typ, void *addr, Eface e) unsafe·Unreflect(Eface typ, void *addr, Eface e)
{ {
// Reflect library has reinterpreted typ // Reflect library has reinterpreted typ
// as its own kind of type structure. // as its own kind of type structure.
...@@ -625,3 +626,41 @@ unsafe·Unreflect(Iface typ, void *addr, Eface e) ...@@ -625,3 +626,41 @@ unsafe·Unreflect(Iface typ, void *addr, Eface e)
FLUSH(&e); FLUSH(&e);
} }
void
unsafe·New(Eface typ, void *ret)
{
Type *t;
// 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.
t = (Type*)((Eface*)typ.data-1);
if(t->kind&KindNoPointers)
ret = mallocgc(t->size, RefNoPointers, 1);
else
ret = mal(t->size);
FLUSH(&ret);
}
void
unsafe·NewArray(Eface typ, uint32 n, void *ret)
{
uint64 size;
Type *t;
// 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.
t = (Type*)((Eface*)typ.data-1);
size = n*t->size;
if(t->kind&KindNoPointers)
ret = mallocgc(size, RefNoPointers, 1);
else
ret = mal(size);
FLUSH(&ret);
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
static int32 debug = 0; static int32 debug = 0;
// see also unsafe·NewArray
// makeslice(typ *Type, nel int, cap int) (ary []any); // makeslice(typ *Type, nel int, cap int) (ary []any);
void void
runtime·makeslice(SliceType *t, uint32 nel, uint32 cap, Slice ret) runtime·makeslice(SliceType *t, uint32 nel, uint32 cap, Slice ret)
...@@ -21,9 +22,7 @@ runtime·makeslice(SliceType *t, uint32 nel, uint32 cap, Slice ret) ...@@ -21,9 +22,7 @@ runtime·makeslice(SliceType *t, uint32 nel, uint32 cap, Slice ret)
ret.len = nel; ret.len = nel;
ret.cap = cap; ret.cap = cap;
// TODO(rsc): Disabled because reflect and gob cast []byte if((t->elem->kind&KindNoPointers))
// to data structures with pointers.
if(0 && (t->elem->kind&KindNoPointers))
ret.array = mallocgc(size, RefNoPointers, 1); ret.array = mallocgc(size, RefNoPointers, 1);
else else
ret.array = mal(size); ret.array = mal(size);
......
...@@ -43,5 +43,17 @@ func Typeof(i interface{}) (typ interface{}) ...@@ -43,5 +43,17 @@ func Typeof(i interface{}) (typ interface{})
func Reflect(i interface{}) (typ interface{}, addr uintptr) func Reflect(i interface{}) (typ interface{}, addr uintptr)
// Unreflect inverts Reflect: Given a type and a pointer, it returns an empty interface value // Unreflect inverts Reflect: Given a type and a pointer, it returns an empty interface value
// with those contents. // with those contents. 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 uintptr) (ret interface{}) func Unreflect(typ interface{}, addr uintptr) (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.MakeZero 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