/* go-reflect.c -- implement unsafe.Reflect and unsafe.Typeof for Go. Copyright 2009 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include "interface.h" #include "go-alloc.h" #include "go-panic.h" #include "go-string.h" #include "go-type.h" /* For field alignment. */ struct field_align { char c; struct __go_type_descriptor *p; }; /* The type descriptors in the runtime package. */ extern const struct __go_type_descriptor ptr_bool_descriptor asm ("__go_td_pN30_libgo_runtime.runtime.BoolType"); extern const struct __go_type_descriptor ptr_float_descriptor asm ("__go_td_pN31_libgo_runtime.runtime.FloatType"); extern const struct __go_type_descriptor ptr_complex_descriptor asm ("__go_td_pN33_libgo_runtime.runtime.ComplexType"); extern const struct __go_type_descriptor ptr_int_descriptor asm ("__go_td_pN29_libgo_runtime.runtime.IntType"); extern const struct __go_type_descriptor ptr_uint_descriptor asm ("__go_td_pN30_libgo_runtime.runtime.UintType"); extern const struct __go_type_descriptor ptr_string_descriptor asm ("__go_td_pN32_libgo_runtime.runtime.StringType"); extern const struct __go_type_descriptor ptr_unsafe_pointer_decriptor asm ("__go_td_pN39_libgo_runtime.runtime.UnsafePointerType"); extern const struct __go_type_descriptor ptr_array_descriptor asm ("__go_td_pN31_libgo_runtime.runtime.ArrayType"); extern const struct __go_type_descriptor ptr_slice_descriptor asm ("__go_td_pN31_libgo_runtime.runtime.SliceType"); extern const struct __go_type_descriptor ptr_chan_descriptor asm ("__go_td_pN30_libgo_runtime.runtime.ChanType"); extern const struct __go_type_descriptor ptr_func_descriptor asm ("__go_td_pN30_libgo_runtime.runtime.FuncType"); extern const struct __go_type_descriptor ptr_interface_descriptor asm ("__go_td_pN35_libgo_runtime.runtime.InterfaceType"); extern const struct __go_type_descriptor ptr_map_descriptor asm ("__go_td_pN29_libgo_runtime.runtime.MapType"); extern const struct __go_type_descriptor ptr_ptr_descriptor asm ("__go_td_pN29_libgo_runtime.runtime.PtrType"); extern const struct __go_type_descriptor ptr_struct_descriptor asm ("__go_td_pN32_libgo_runtime.runtime.StructType"); const struct __go_type_descriptor * get_descriptor (int code) { switch (code) { case GO_BOOL: return &ptr_bool_descriptor; case GO_FLOAT32: case GO_FLOAT64: return &ptr_float_descriptor; case GO_COMPLEX64: case GO_COMPLEX128: return &ptr_complex_descriptor; case GO_INT16: case GO_INT32: case GO_INT64: case GO_INT8: case GO_INT: return &ptr_int_descriptor; case GO_UINT16: case GO_UINT32: case GO_UINT64: case GO_UINT8: case GO_UINTPTR: case GO_UINT: return &ptr_uint_descriptor; case GO_STRING: return &ptr_string_descriptor; case GO_UNSAFE_POINTER: return &ptr_unsafe_pointer_decriptor; case GO_ARRAY: return &ptr_array_descriptor; case GO_SLICE: return &ptr_slice_descriptor; case GO_CHAN: return &ptr_chan_descriptor; case GO_FUNC: return &ptr_func_descriptor; case GO_INTERFACE: return &ptr_interface_descriptor; case GO_MAP: return &ptr_map_descriptor; case GO_PTR: return &ptr_ptr_descriptor; case GO_STRUCT: return &ptr_struct_descriptor; default: abort (); } } /* Implement unsafe.Reflect. */ struct reflect_ret { struct __go_empty_interface rettype; void *addr; }; struct reflect_ret Reflect (struct __go_empty_interface) asm ("libgo_unsafe.unsafe.Reflect"); struct reflect_ret Reflect (struct __go_empty_interface e) { struct reflect_ret ret; if (((uintptr_t) e.__type_descriptor & reflectFlags) != 0) __go_panic_msg ("invalid interface value"); if (e.__type_descriptor == NULL) { ret.rettype.__type_descriptor = NULL; ret.rettype.__object = NULL; ret.addr = NULL; } else { size_t size; ret.rettype.__type_descriptor = get_descriptor (e.__type_descriptor->__code); /* This memcpy is really just an assignment of a const pointer to a non-const pointer. FIXME: We should canonicalize this pointer, so that for a given type we always return the same pointer. */ __builtin_memcpy (&ret.rettype.__object, &e.__type_descriptor, sizeof (void *)); /* Make a copy of the value. */ size = e.__type_descriptor->__size; if (size <= sizeof (uint64_t)) ret.addr = __go_alloc (sizeof (uint64_t)); else ret.addr = __go_alloc (size); if (__go_is_pointer_type (e.__type_descriptor)) *(void **) ret.addr = e.__object; else __builtin_memcpy (ret.addr, e.__object, size); } return ret; } /* Implement unsafe.Typeof. */ struct __go_empty_interface Typeof (struct __go_empty_interface) asm ("libgo_unsafe.unsafe.Typeof"); struct __go_empty_interface Typeof (const struct __go_empty_interface e) { struct __go_empty_interface ret; if (((uintptr_t) e.__type_descriptor & reflectFlags) != 0) __go_panic_msg ("invalid interface value"); if (e.__type_descriptor == NULL) { ret.__type_descriptor = NULL; ret.__object = NULL; } else { ret.__type_descriptor = get_descriptor (e.__type_descriptor->__code); /* This memcpy is really just an assignment of a const pointer to a non-const pointer. FIXME: We should canonicalize this pointer, so that for a given type we always return the same pointer. */ __builtin_memcpy (&ret.__object, &e.__type_descriptor, sizeof (void *)); } return ret; }