diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-05-20 00:18:15 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-05-20 00:18:15 +0000 |
commit | 9ff56c9570642711d5b7ab29920ecf5dbff14a27 (patch) | |
tree | c891bdec1e6f073f73fedeef23718bc3ac30d499 /libgo/runtime | |
parent | 37cb25ed7acdb844b218231130e54b8b7a0ff6e6 (diff) | |
download | gcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.zip gcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.tar.gz gcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.tar.bz2 |
Update to current version of Go library.
From-SVN: r173931
Diffstat (limited to 'libgo/runtime')
32 files changed, 458 insertions, 143 deletions
diff --git a/libgo/runtime/chan.goc b/libgo/runtime/chan.goc index 9326f26..acfff85 100644 --- a/libgo/runtime/chan.goc +++ b/libgo/runtime/chan.goc @@ -13,7 +13,8 @@ typedef struct __go_channel chan; /* Do a channel receive with closed status. */ func chanrecv2(c *chan, val *byte) (received bool) { - if (c->element_size > 8) { + uintptr_t element_size = c->element_type->__size; + if (element_size > 8) { return __go_receive_big(c, val, 0); } else { union { @@ -23,10 +24,9 @@ func chanrecv2(c *chan, val *byte) (received bool) { u.v = __go_receive_small_closed(c, 0, &received); #ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, c->element_size); + __builtin_memcpy(val, u.b, element_size); #else - __builtin_memcpy(val, u.b + 8 - c->element_size, - c->element_size); + __builtin_memcpy(val, u.b + 8 - element_size, element_size); #endif return received; } @@ -35,7 +35,8 @@ func chanrecv2(c *chan, val *byte) (received bool) { /* Do a channel receive with closed status for a select statement. */ func chanrecv3(c *chan, val *byte) (received bool) { - if (c->element_size > 8) { + uintptr_t element_size = c->element_type->__size; + if (element_size > 8) { return __go_receive_big(c, val, 1); } else { union { @@ -45,10 +46,9 @@ func chanrecv3(c *chan, val *byte) (received bool) { u.v = __go_receive_small_closed(c, 1, &received); #ifndef WORDS_BIGENDIAN - __builtin_memcpy(val, u.b, c->element_size); + __builtin_memcpy(val, u.b, element_size); #else - __builtin_memcpy(val, u.b + 8 - c->element_size, - c->element_size); + __builtin_memcpy(val, u.b + 8 - element_size, element_size); #endif return received; } diff --git a/libgo/runtime/channel.h b/libgo/runtime/channel.h index 9dcaf7f..d4f1632 100644 --- a/libgo/runtime/channel.h +++ b/libgo/runtime/channel.h @@ -7,6 +7,8 @@ #include <stdint.h> #include <pthread.h> +#include "go-type.h" + /* This structure is used when a select is waiting for a synchronous channel. */ @@ -34,8 +36,8 @@ struct __go_channel /* A condition variable. This is signalled when data is added to the channel and when data is removed from the channel. */ pthread_cond_t cond; - /* The size of elements on this channel. */ - size_t element_size; + /* The type of elements on this channel. */ + const struct __go_type_descriptor *element_type; /* True if a goroutine is waiting to send on a synchronous channel. */ _Bool waiting_to_send; @@ -82,7 +84,8 @@ typedef struct __go_channel __go_channel; acquired while this mutex is held. */ extern pthread_mutex_t __go_select_data_mutex; -extern struct __go_channel *__go_new_channel (uintptr_t, uintptr_t); +extern struct __go_channel * +__go_new_channel (const struct __go_type_descriptor *, uintptr_t); extern _Bool __go_synch_with_select (struct __go_channel *, _Bool); diff --git a/libgo/runtime/go-eface-compare.c b/libgo/runtime/go-eface-compare.c index c90177e..6734405 100644 --- a/libgo/runtime/go-eface-compare.c +++ b/libgo/runtime/go-eface-compare.c @@ -4,6 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ +#include "go-panic.h" #include "interface.h" /* Compare two interface values. Return 0 for equal, not zero for not @@ -16,6 +17,11 @@ __go_empty_interface_compare (struct __go_empty_interface left, const struct __go_type_descriptor *left_descriptor; left_descriptor = left.__type_descriptor; + + if (((uintptr_t) left_descriptor & reflectFlags) != 0 + || ((uintptr_t) right.__type_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); + if (left_descriptor == NULL && right.__type_descriptor == NULL) return 0; if (left_descriptor == NULL || right.__type_descriptor == NULL) diff --git a/libgo/runtime/go-eface-val-compare.c b/libgo/runtime/go-eface-val-compare.c index 319ede2..d754cc5 100644 --- a/libgo/runtime/go-eface-val-compare.c +++ b/libgo/runtime/go-eface-val-compare.c @@ -4,6 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ +#include "go-panic.h" #include "go-type.h" #include "interface.h" @@ -19,6 +20,8 @@ __go_empty_interface_value_compare ( const struct __go_type_descriptor *left_descriptor; left_descriptor = left.__type_descriptor; + if (((uintptr_t) left_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); if (left_descriptor == NULL) return 1; if (!__go_type_descriptors_equal (left_descriptor, right_descriptor)) diff --git a/libgo/runtime/go-interface-eface-compare.c b/libgo/runtime/go-interface-eface-compare.c index 9de8424..ff69a27 100644 --- a/libgo/runtime/go-interface-eface-compare.c +++ b/libgo/runtime/go-interface-eface-compare.c @@ -4,6 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ +#include "go-panic.h" #include "interface.h" /* Compare a non-empty interface value with an empty interface value. @@ -16,6 +17,8 @@ __go_interface_empty_compare (struct __go_interface left, { const struct __go_type_descriptor *left_descriptor; + if (((uintptr_t) right.__type_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); if (left.__methods == NULL && right.__type_descriptor == NULL) return 0; if (left.__methods == NULL || right.__type_descriptor == NULL) diff --git a/libgo/runtime/go-new-channel.c b/libgo/runtime/go-new-channel.c index 028715e..e440e87 100644 --- a/libgo/runtime/go-new-channel.c +++ b/libgo/runtime/go-new-channel.c @@ -13,12 +13,16 @@ #include "channel.h" struct __go_channel* -__go_new_channel (uintptr_t element_size, uintptr_t entries) +__go_new_channel (const struct __go_type_descriptor *element_type, + uintptr_t entries) { + uintptr_t element_size; struct __go_channel* ret; size_t alloc_size; int i; + element_size = element_type->__size; + if ((uintptr_t) (int) entries != entries || entries > (uintptr_t) -1 / element_size) __go_panic_msg ("chan size out of range"); @@ -40,7 +44,7 @@ __go_new_channel (uintptr_t element_size, uintptr_t entries) __go_assert (i == 0); i = pthread_cond_init (&ret->cond, NULL); __go_assert (i == 0); - ret->element_size = element_size; + ret->element_type = element_type; ret->waiting_to_send = 0; ret->waiting_to_receive = 0; ret->selected_for_send = 0; diff --git a/libgo/runtime/go-rec-big.c b/libgo/runtime/go-rec-big.c index fd3923c..580ccb0 100644 --- a/libgo/runtime/go-rec-big.c +++ b/libgo/runtime/go-rec-big.c @@ -15,23 +15,24 @@ _Bool __go_receive_big (struct __go_channel *channel, void *val, _Bool for_select) { + uintptr_t element_size; size_t alloc_size; size_t offset; if (channel == NULL) __go_panic_msg ("receive from nil channel"); - alloc_size = ((channel->element_size + sizeof (uint64_t) - 1) - / sizeof (uint64_t)); + element_size = channel->element_type->__size; + alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); if (!__go_receive_acquire (channel, for_select)) { - __builtin_memset (val, 0, channel->element_size); + __builtin_memset (val, 0, element_size); return 0; } offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], channel->element_size); + __builtin_memcpy (val, &channel->data[offset], element_size); __go_receive_release (channel); diff --git a/libgo/runtime/go-rec-nb-big.c b/libgo/runtime/go-rec-nb-big.c index 78db587..8c315b1 100644 --- a/libgo/runtime/go-rec-nb-big.c +++ b/libgo/runtime/go-rec-nb-big.c @@ -14,23 +14,24 @@ _Bool __go_receive_nonblocking_big (struct __go_channel* channel, void *val, _Bool *closed) { + uintptr_t element_size; size_t alloc_size; size_t offset; - alloc_size = ((channel->element_size + sizeof (uint64_t) - 1) - / sizeof (uint64_t)); + element_size = channel->element_type->__size; + alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); int data = __go_receive_nonblocking_acquire (channel); if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) { - __builtin_memset (val, 0, channel->element_size); + __builtin_memset (val, 0, element_size); if (closed != NULL) *closed = data == RECEIVE_NONBLOCKING_ACQUIRE_CLOSED; return 0; } offset = channel->next_fetch * alloc_size; - __builtin_memcpy (val, &channel->data[offset], channel->element_size); + __builtin_memcpy (val, &channel->data[offset], element_size); __go_receive_release (channel); diff --git a/libgo/runtime/go-rec-nb-small.c b/libgo/runtime/go-rec-nb-small.c index 29cad9a..eb0a25e 100644 --- a/libgo/runtime/go-rec-nb-small.c +++ b/libgo/runtime/go-rec-nb-small.c @@ -94,9 +94,11 @@ __go_receive_nonblocking_acquire (struct __go_channel *channel) struct __go_receive_nonblocking_small __go_receive_nonblocking_small (struct __go_channel *channel) { + uintptr_t element_size; struct __go_receive_nonblocking_small ret; - __go_assert (channel->element_size <= sizeof (uint64_t)); + element_size = channel->element_type->__size; + __go_assert (element_size <= sizeof (uint64_t)); int data = __go_receive_nonblocking_acquire (channel); if (data != RECEIVE_NONBLOCKING_ACQUIRE_DATA) diff --git a/libgo/runtime/go-rec-small.c b/libgo/runtime/go-rec-small.c index 019b20a..946a18c 100644 --- a/libgo/runtime/go-rec-small.c +++ b/libgo/runtime/go-rec-small.c @@ -266,12 +266,14 @@ uint64_t __go_receive_small_closed (struct __go_channel *channel, _Bool for_select, _Bool *received) { + uintptr_t element_size; uint64_t ret; if (channel == NULL) __go_panic_msg ("receive from nil channel"); - __go_assert (channel->element_size <= sizeof (uint64_t)); + element_size = channel->element_type->__size; + __go_assert (element_size <= sizeof (uint64_t)); if (!__go_receive_acquire (channel, for_select)) { diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index 6ae749f..a769142 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -14,9 +14,32 @@ #include "go-type.h" #include "runtime.h" -/* Forward declaration. */ - -static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *); +/* The functions in this file are only called from reflect_call. As + reflect_call calls a libffi function, which will be compiled + without -fsplit-stack, it will always run with a large stack. */ + +static ffi_type *go_array_to_ffi (const struct __go_array_type *) + __attribute__ ((no_split_stack)); +static ffi_type *go_slice_to_ffi (const struct __go_slice_type *) + __attribute__ ((no_split_stack)); +static ffi_type *go_struct_to_ffi (const struct __go_struct_type *) + __attribute__ ((no_split_stack)); +static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack)); +static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack)); +static ffi_type *go_complex_to_ffi (ffi_type *) + __attribute__ ((no_split_stack)); +static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *) + __attribute__ ((no_split_stack)); +static ffi_type *go_func_return_ffi (const struct __go_func_type *) + __attribute__ ((no_split_stack)); +static void go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, + ffi_cif *) + __attribute__ ((no_split_stack)); +static size_t go_results_size (const struct __go_func_type *) + __attribute__ ((no_split_stack)); +static void go_set_results (const struct __go_func_type *, unsigned char *, + void **) + __attribute__ ((no_split_stack)); /* Return an ffi_type for a Go array type. The libffi library does not have any builtin support for passing arrays as values. We work @@ -31,7 +54,6 @@ go_array_to_ffi (const struct __go_array_type *descriptor) uintptr_t i; ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - __builtin_memset (ret, 0, sizeof (ffi_type)); ret->type = FFI_TYPE_STRUCT; len = descriptor->__len; ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *)); @@ -52,7 +74,6 @@ go_slice_to_ffi ( ffi_type *ret; ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - __builtin_memset (ret, 0, sizeof (ffi_type)); ret->type = FFI_TYPE_STRUCT; ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *)); ret->elements[0] = &ffi_type_pointer; @@ -73,7 +94,6 @@ go_struct_to_ffi (const struct __go_struct_type *descriptor) int i; ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - __builtin_memset (ret, 0, sizeof (ffi_type)); ret->type = FFI_TYPE_STRUCT; field_count = descriptor->__fields.__count; fields = (const struct __go_struct_field *) descriptor->__fields.__values; @@ -237,7 +257,6 @@ go_func_return_ffi (const struct __go_func_type *func) return go_type_to_ffi (types[0]); ret = (ffi_type *) __go_alloc (sizeof (ffi_type)); - __builtin_memset (ret, 0, sizeof (ffi_type)); ret->type = FFI_TYPE_STRUCT; ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *)); for (i = 0; i < count; ++i) @@ -251,7 +270,7 @@ go_func_return_ffi (const struct __go_func_type *func) static void go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, - ffi_cif *cif) + _Bool is_method, ffi_cif *cif) { int num_params; const struct __go_type_descriptor **in_types; @@ -268,10 +287,19 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, num_args = num_params + (is_interface ? 1 : 0); args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *)); + i = 0; + off = 0; if (is_interface) - args[0] = &ffi_type_pointer; - off = is_interface ? 1 : 0; - for (i = 0; i < num_params; ++i) + { + args[0] = &ffi_type_pointer; + off = 1; + } + else if (is_method) + { + args[0] = &ffi_type_pointer; + i = 1; + } + for (; i < num_params; ++i) args[i + off] = go_type_to_ffi (in_types[i]); rettype = go_func_return_ffi (func); @@ -354,13 +382,14 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result, void reflect_call (const struct __go_func_type *func_type, const void *func_addr, - _Bool is_interface, void **params, void **results) + _Bool is_interface, _Bool is_method, void **params, + void **results) { ffi_cif cif; unsigned char *call_result; __go_assert (func_type->__common.__code == GO_FUNC); - go_func_to_cif (func_type, is_interface, &cif); + go_func_to_cif (func_type, is_interface, is_method, &cif); call_result = (unsigned char *) malloc (go_results_size (func_type)); diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c index c9ccda7..d568024 100644 --- a/libgo/runtime/go-reflect-chan.c +++ b/libgo/runtime/go-reflect-chan.c @@ -8,30 +8,54 @@ #include <stdint.h> #include "config.h" +#include "go-alloc.h" +#include "go-assert.h" +#include "go-panic.h" #include "go-type.h" #include "channel.h" /* This file implements support for reflection on channels. These functions are called from reflect/value.go. */ -extern unsigned char *makechan (const struct __go_type_descriptor *, uint32_t) +extern uintptr_t makechan (const struct __go_type_descriptor *, uint32_t) asm ("libgo_reflect.reflect.makechan"); -unsigned char * +uintptr_t makechan (const struct __go_type_descriptor *typ, uint32_t size) { - return (unsigned char *) __go_new_channel (typ->__size, size); + struct __go_channel *channel; + void *ret; + + __go_assert (typ->__code == GO_CHAN); + typ = ((const struct __go_channel_type *) typ)->__element_type; + + channel = __go_new_channel (typ, size); + + ret = __go_alloc (sizeof (void *)); + __builtin_memcpy (ret, &channel, sizeof (void *)); + return (uintptr_t) ret; } -extern void chansend (unsigned char *, unsigned char *, _Bool *) +extern _Bool chansend (uintptr_t, uintptr_t, _Bool) asm ("libgo_reflect.reflect.chansend"); -void -chansend (unsigned char *ch, unsigned char *val, _Bool *selected) +_Bool +chansend (uintptr_t ch, uintptr_t val_i, _Bool nb) { struct __go_channel *channel = (struct __go_channel *) ch; + uintptr_t element_size; + void *pv; + + if (channel == NULL) + __go_panic_msg ("send to nil channel"); + + if (__go_is_pointer_type (channel->element_type)) + pv = &val_i; + else + pv = (void *) val_i; - if (channel->element_size <= sizeof (uint64_t)) + element_size = channel->element_type->__size; + if (element_size <= sizeof (uint64_t)) { union { @@ -41,35 +65,60 @@ chansend (unsigned char *ch, unsigned char *val, _Bool *selected) __builtin_memset (u.b, 0, sizeof (uint64_t)); #ifndef WORDS_BIGENDIAN - __builtin_memcpy (u.b, val, channel->element_size); + __builtin_memcpy (u.b, pv, element_size); #else - __builtin_memcpy (u.b + sizeof (uint64_t) - channel->element_size, val, - channel->element_size); + __builtin_memcpy (u.b + sizeof (uint64_t) - element_size, pv, + element_size); #endif - if (selected == NULL) - __go_send_small (channel, u.v, 0); + if (nb) + return __go_send_nonblocking_small (channel, u.v); else - *selected = __go_send_nonblocking_small (channel, u.v); + { + __go_send_small (channel, u.v, 0); + return 1; + } } else { - if (selected == NULL) - __go_send_big (channel, val, 0); + if (nb) + return __go_send_nonblocking_big (channel, pv); else - *selected = __go_send_nonblocking_big (channel, val); + { + __go_send_big (channel, pv, 0); + return 1; + } } } -extern void chanrecv (unsigned char *, unsigned char *, _Bool *, _Bool *) +struct chanrecv_ret +{ + uintptr_t val; + _Bool selected; + _Bool received; +}; + +extern struct chanrecv_ret chanrecv (uintptr_t, _Bool) asm ("libgo_reflect.reflect.chanrecv"); -void -chanrecv (unsigned char *ch, unsigned char *val, _Bool *selected, - _Bool *received) +struct chanrecv_ret +chanrecv (uintptr_t ch, _Bool nb) { struct __go_channel *channel = (struct __go_channel *) ch; + void *pv; + uintptr_t element_size; + struct chanrecv_ret ret; + + element_size = channel->element_type->__size; - if (channel->element_size <= sizeof (uint64_t)) + if (__go_is_pointer_type (channel->element_type)) + pv = &ret.val; + else + { + pv = __go_alloc (element_size); + ret.val = (uintptr_t) pv; + } + + if (element_size <= sizeof (uint64_t)) { union { @@ -77,74 +126,73 @@ chanrecv (unsigned char *ch, unsigned char *val, _Bool *selected, uint64_t v; } u; - if (selected == NULL) - u.v = __go_receive_small_closed (channel, 0, received); + if (!nb) + { + u.v = __go_receive_small_closed (channel, 0, &ret.received); + ret.selected = 1; + } else { struct __go_receive_nonblocking_small s; s = __go_receive_nonblocking_small (channel); - *selected = s.__success || s.__closed; - if (received != NULL) - *received = s.__success; + ret.selected = s.__success || s.__closed; + ret.received = s.__success; u.v = s.__val; } #ifndef WORDS_BIGENDIAN - __builtin_memcpy (val, u.b, channel->element_size); + __builtin_memcpy (pv, u.b, element_size); #else - __builtin_memcpy (val, u.b + sizeof (uint64_t) - channel->element_size, - channel->element_size); + __builtin_memcpy (pv, u.b + sizeof (uint64_t) - element_size, + element_size); #endif } else { - if (selected == NULL) + if (!nb) { - _Bool success; - - success = __go_receive_big (channel, val, 0); - if (received != NULL) - *received = success; + ret.received = __go_receive_big (channel, pv, 0); + ret.selected = 1; } else { _Bool got; _Bool closed; - got = __go_receive_nonblocking_big (channel, val, &closed); - *selected = got || closed; - if (received != NULL) - *received = got; + got = __go_receive_nonblocking_big (channel, pv, &closed); + ret.selected = got || closed; + ret.received = got; } } + + return ret; } -extern void chanclose (unsigned char *) - asm ("libgo_reflect.reflect.chanclose"); +extern void chanclose (uintptr_t) asm ("libgo_reflect.reflect.chanclose"); void -chanclose (unsigned char *ch) +chanclose (uintptr_t ch) { struct __go_channel *channel = (struct __go_channel *) ch; __go_builtin_close (channel); } -extern int32_t chanlen (unsigned char *) asm ("libgo_reflect.reflect.chanlen"); +extern int32_t chanlen (uintptr_t) asm ("libgo_reflect.reflect.chanlen"); int32_t -chanlen (unsigned char *ch) +chanlen (uintptr_t ch) { struct __go_channel *channel = (struct __go_channel *) ch; return (int32_t) __go_chan_len (channel); } -extern int32_t chancap (unsigned char *) asm ("libgo_reflect.reflect.chancap"); +extern int32_t chancap (uintptr_t) asm ("libgo_reflect.reflect.chancap"); int32_t -chancap (unsigned char *ch) +chancap (uintptr_t ch) { struct __go_channel *channel = (struct __go_channel *) ch; diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c index 67960de..5559f6e 100644 --- a/libgo/runtime/go-reflect-map.c +++ b/libgo/runtime/go-reflect-map.c @@ -8,69 +8,125 @@ #include <stdint.h> #include "go-alloc.h" +#include "go-panic.h" #include "go-type.h" #include "map.h" /* This file implements support for reflection on maps. These functions are called from reflect/value.go. */ -extern _Bool mapaccess (unsigned char *, unsigned char *, unsigned char *) +struct mapaccess_ret +{ + uintptr_t val; + _Bool pres; +}; + +extern struct mapaccess_ret mapaccess (uintptr_t, uintptr_t) asm ("libgo_reflect.reflect.mapaccess"); -_Bool -mapaccess (unsigned char *m, unsigned char *key, unsigned char *val) +struct mapaccess_ret +mapaccess (uintptr_t m, uintptr_t key_i) { struct __go_map *map = (struct __go_map *) m; + void *key; + const struct __go_type_descriptor *key_descriptor; void *p; const struct __go_type_descriptor *val_descriptor; + struct mapaccess_ret ret; + void *val; + void *pv; + + if (map == NULL) + __go_panic_msg ("lookup in nil map"); + + key_descriptor = map->__descriptor->__map_descriptor->__key_type; + if (__go_is_pointer_type (key_descriptor)) + key = &key_i; + else + key = (void *) key_i; p = __go_map_index (map, key, 0); + + val_descriptor = map->__descriptor->__map_descriptor->__val_type; + if (__go_is_pointer_type (val_descriptor)) + { + val = NULL; + pv = &val; + } + else + { + val = __go_alloc (val_descriptor->__size); + pv = val; + } + if (p == NULL) - return 0; + ret.pres = 0; else { - val_descriptor = map->__descriptor->__map_descriptor->__val_type; - __builtin_memcpy (val, p, val_descriptor->__size); - return 1; + __builtin_memcpy (pv, p, val_descriptor->__size); + ret.pres = 1; } + + ret.val = (uintptr_t) val; + return ret; } -extern void mapassign (unsigned char *, unsigned char *, unsigned char *) +extern void mapassign (uintptr_t, uintptr_t, uintptr_t, _Bool) asm ("libgo_reflect.reflect.mapassign"); void -mapassign (unsigned char *m, unsigned char *key, unsigned char *val) +mapassign (uintptr_t m, uintptr_t key_i, uintptr_t val_i, _Bool pres) { struct __go_map *map = (struct __go_map *) m; + const struct __go_type_descriptor *key_descriptor; + void *key; - if (val == NULL) + if (map == NULL) + __go_panic_msg ("lookup in nil map"); + + key_descriptor = map->__descriptor->__map_descriptor->__key_type; + if (__go_is_pointer_type (key_descriptor)) + key = &key_i; + else + key = (void *) key_i; + + if (!pres) __go_map_delete (map, key); else { void *p; const struct __go_type_descriptor *val_descriptor; + void *pv; p = __go_map_index (map, key, 1); + val_descriptor = map->__descriptor->__map_descriptor->__val_type; - __builtin_memcpy (p, val, val_descriptor->__size); + if (__go_is_pointer_type (val_descriptor)) + pv = &val_i; + else + pv = (void *) val_i; + __builtin_memcpy (p, pv, val_descriptor->__size); } } -extern int32_t maplen (unsigned char *) +extern int32_t maplen (uintptr_t) asm ("libgo_reflect.reflect.maplen"); int32_t -maplen (unsigned char *m __attribute__ ((unused))) +maplen (uintptr_t m) { struct __go_map *map = (struct __go_map *) m; + + if (map == NULL) + return 0; return (int32_t) map->__element_count; } -extern unsigned char *mapiterinit (unsigned char *) +extern unsigned char *mapiterinit (uintptr_t) asm ("libgo_reflect.reflect.mapiterinit"); unsigned char * -mapiterinit (unsigned char *m) +mapiterinit (uintptr_t m) { struct __go_hash_iter *it; @@ -88,35 +144,67 @@ mapiternext (unsigned char *it) __go_mapiternext ((struct __go_hash_iter *) it); } -extern _Bool mapiterkey (unsigned char *, unsigned char *) +struct mapiterkey_ret +{ + uintptr_t key; + _Bool ok; +}; + +extern struct mapiterkey_ret mapiterkey (unsigned char *) asm ("libgo_reflect.reflect.mapiterkey"); -_Bool -mapiterkey (unsigned char *ita, unsigned char *key) +struct mapiterkey_ret +mapiterkey (unsigned char *ita) { struct __go_hash_iter *it = (struct __go_hash_iter *) ita; + struct mapiterkey_ret ret; if (it->entry == NULL) - return 0; + { + ret.key = 0; + ret.ok = 0; + } else { - __go_mapiter1 (it, key); - return 1; + const struct __go_type_descriptor *key_descriptor; + void *key; + void *pk; + + key_descriptor = it->map->__descriptor->__map_descriptor->__key_type; + if (__go_is_pointer_type (key_descriptor)) + { + key = NULL; + pk = &key; + } + else + { + key = __go_alloc (key_descriptor->__size); + pk = key; + } + + __go_mapiter1 (it, pk); + + ret.key = (uintptr_t) key; + ret.ok = 1; } + + return ret; } /* Make a new map. We have to build our own map descriptor. */ -extern unsigned char *makemap (const struct __go_map_type *) +extern uintptr_t makemap (const struct __go_map_type *) asm ("libgo_reflect.reflect.makemap"); -unsigned char * +uintptr_t makemap (const struct __go_map_type *t) { struct __go_map_descriptor *md; unsigned int o; const struct __go_type_descriptor *kt; const struct __go_type_descriptor *vt; + struct __go_map* map; + void *ret; /* FIXME: Reference count. */ md = (struct __go_map_descriptor *) __go_alloc (sizeof (*md)); @@ -135,5 +223,9 @@ makemap (const struct __go_map_type *t) o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1); md->__entry_size = o; - return (unsigned char *) __go_new_map (md, 0); + map = __go_new_map (md, 0); + + ret = __go_alloc (sizeof (void *)); + __builtin_memcpy (ret, &map, sizeof (void *)); + return (uintptr_t) ret; } diff --git a/libgo/runtime/go-reflect.c b/libgo/runtime/go-reflect.c index 9485c09..bf13a11 100644 --- a/libgo/runtime/go-reflect.c +++ b/libgo/runtime/go-reflect.c @@ -121,6 +121,9 @@ 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; @@ -166,6 +169,9 @@ 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; diff --git a/libgo/runtime/go-send-big.c b/libgo/runtime/go-send-big.c index c273263..0b4aa04 100644 --- a/libgo/runtime/go-send-big.c +++ b/libgo/runtime/go-send-big.c @@ -12,19 +12,20 @@ void __go_send_big (struct __go_channel* channel, const void *val, _Bool for_select) { + uintptr_t element_size; size_t alloc_size; size_t offset; if (channel == NULL) __go_panic_msg ("send to nil channel"); - alloc_size = ((channel->element_size + sizeof (uint64_t) - 1) - / sizeof (uint64_t)); + element_size = channel->element_type->__size; + alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); __go_send_acquire (channel, for_select); offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, channel->element_size); + __builtin_memcpy (&channel->data[offset], val, element_size); __go_send_release (channel); } diff --git a/libgo/runtime/go-send-nb-big.c b/libgo/runtime/go-send-nb-big.c index 1d33dd6..1274859 100644 --- a/libgo/runtime/go-send-nb-big.c +++ b/libgo/runtime/go-send-nb-big.c @@ -11,17 +11,18 @@ _Bool __go_send_nonblocking_big (struct __go_channel* channel, const void *val) { + uintptr_t element_size; size_t alloc_size; size_t offset; - alloc_size = ((channel->element_size + sizeof (uint64_t) - 1) - / sizeof (uint64_t)); + element_size = channel->element_type->__size; + alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t); if (!__go_send_nonblocking_acquire (channel)) return 0; offset = channel->next_store * alloc_size; - __builtin_memcpy (&channel->data[offset], val, channel->element_size); + __builtin_memcpy (&channel->data[offset], val, element_size); __go_send_release (channel); diff --git a/libgo/runtime/go-send-nb-small.c b/libgo/runtime/go-send-nb-small.c index 5c49a67..0a25ba3 100644 --- a/libgo/runtime/go-send-nb-small.c +++ b/libgo/runtime/go-send-nb-small.c @@ -93,7 +93,7 @@ __go_send_nonblocking_acquire (struct __go_channel *channel) _Bool __go_send_nonblocking_small (struct __go_channel *channel, uint64_t val) { - __go_assert (channel->element_size <= sizeof (uint64_t)); + __go_assert (channel->element_type->__size <= sizeof (uint64_t)); if (!__go_send_nonblocking_acquire (channel)) return 0; diff --git a/libgo/runtime/go-send-small.c b/libgo/runtime/go-send-small.c index 56f9470..8e21d36 100644 --- a/libgo/runtime/go-send-small.c +++ b/libgo/runtime/go-send-small.c @@ -147,7 +147,7 @@ __go_send_small (struct __go_channel *channel, uint64_t val, _Bool for_select) if (channel == NULL) __go_panic_msg ("send to nil channel"); - __go_assert (channel->element_size <= sizeof (uint64_t)); + __go_assert (channel->element_type->__size <= sizeof (uint64_t)); __go_send_acquire (channel, for_select); diff --git a/libgo/runtime/go-setenv.c b/libgo/runtime/go-setenv.c new file mode 100644 index 0000000..20f9939 --- /dev/null +++ b/libgo/runtime/go-setenv.c @@ -0,0 +1,50 @@ +/* go-setenv.c -- set the C environment from Go. + + Copyright 2011 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 <stddef.h> +#include <stdlib.h> + +#include "go-alloc.h" +#include "go-string.h" + +/* Set the C environment from Go. This is called by os.Setenv. */ + +void setenv_c (struct __go_string, struct __go_string) + __asm__ ("libgo_os.os.setenv_c"); + +void +setenv_c (struct __go_string k, struct __go_string v) +{ + const unsigned char *ks; + unsigned char *kn; + const unsigned char *vs; + unsigned char *vn; + + ks = k.__data; + kn = NULL; + if (ks[k.__length] != 0) + { + kn = __go_alloc (k.__length + 1); + __builtin_memcpy (kn, k.__data, k.__length); + ks = kn; + } + + vs = v.__data; + vn = NULL; + if (vs[v.__length] != 0) + { + vn = __go_alloc (v.__length + 1); + __builtin_memcpy (vn, v.__data, v.__length); + vs = vn; + } + + setenv ((const char *) ks, (const char *) vs, 1); + + if (kn != NULL) + __go_free (kn); + if (vn != NULL) + __go_free (vn); +} diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index edeeccc..c16b058 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -245,3 +245,26 @@ runtime_resetcpuprofiler(int32 hz) m->profilehz = hz; } + +/* Used by the os package to raise SIGPIPE. */ + +void os_sigpipe (void) __asm__ ("libgo_os.os.sigpipe"); + +void +os_sigpipe (void) +{ + struct sigaction sa; + int i; + + memset (&sa, 0, sizeof sa); + + sa.sa_handler = SIG_DFL; + + i = sigemptyset (&sa.sa_mask); + __go_assert (i == 0); + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + abort (); + + raise (SIGPIPE); +} diff --git a/libgo/runtime/go-type-eface.c b/libgo/runtime/go-type-eface.c index 84ca05e..cea9c24 100644 --- a/libgo/runtime/go-type-eface.c +++ b/libgo/runtime/go-type-eface.c @@ -5,6 +5,7 @@ license that can be found in the LICENSE file. */ #include "interface.h" +#include "go-panic.h" #include "go-type.h" /* A hash function for an empty interface. */ @@ -43,6 +44,9 @@ __go_type_equal_empty_interface (const void *vv1, const void *vv2, v2 = (const struct __go_empty_interface *) vv2; v1_descriptor = v1->__type_descriptor; v2_descriptor = v2->__type_descriptor; + if (((uintptr_t) v1_descriptor & reflectFlags) != 0 + || ((uintptr_t) v2_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); if (v1_descriptor == NULL || v2_descriptor == NULL) return v1_descriptor == v2_descriptor; if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor)) diff --git a/libgo/runtime/go-type.h b/libgo/runtime/go-type.h index 7668121..e048141 100644 --- a/libgo/runtime/go-type.h +++ b/libgo/runtime/go-type.h @@ -149,6 +149,9 @@ struct __go_array_type /* The element type. */ struct __go_type_descriptor *__element_type; + /* The type of a slice of the same element type. */ + struct __go_type_descriptor *__slice_type; + /* The length of the array. */ uintptr_t __len; }; @@ -289,6 +292,15 @@ struct __go_struct_type struct __go_open_array __fields; }; +/* 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. */ + +enum +{ + reflectFlags = 3, +}; + /* Whether a type descriptor is a pointer. */ static inline _Bool diff --git a/libgo/runtime/go-unreflect.c b/libgo/runtime/go-unreflect.c index 8860485..c4da5fd 100644 --- a/libgo/runtime/go-unreflect.c +++ b/libgo/runtime/go-unreflect.c @@ -5,6 +5,7 @@ license that can be found in the LICENSE file. */ #include "go-alloc.h" +#include "go-panic.h" #include "go-type.h" #include "interface.h" @@ -19,6 +20,9 @@ Unreflect (struct __go_empty_interface type, void *object) { struct __go_empty_interface ret; + if (((uintptr_t) type.__type_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); + /* FIXME: We should check __type_descriptor to verify that this is really a type descriptor. */ ret.__type_descriptor = type.__object; diff --git a/libgo/runtime/go-unsafe-new.c b/libgo/runtime/go-unsafe-new.c index e55d415..b0a65c4 100644 --- a/libgo/runtime/go-unsafe-new.c +++ b/libgo/runtime/go-unsafe-new.c @@ -5,6 +5,7 @@ license that can be found in the LICENSE file. */ #include "go-alloc.h" +#include "go-panic.h" #include "go-type.h" #include "interface.h" @@ -20,6 +21,9 @@ New (struct __go_empty_interface type) { const struct __go_type_descriptor *descriptor; + if (((uintptr_t) type.__type_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); + /* FIXME: We should check __type_descriptor to verify that this is really a type descriptor. */ descriptor = (const struct __go_type_descriptor *) type.__object; diff --git a/libgo/runtime/go-unsafe-newarray.c b/libgo/runtime/go-unsafe-newarray.c index 3bea282..5fd81ce 100644 --- a/libgo/runtime/go-unsafe-newarray.c +++ b/libgo/runtime/go-unsafe-newarray.c @@ -5,6 +5,7 @@ license that can be found in the LICENSE file. */ #include "go-alloc.h" +#include "go-panic.h" #include "go-type.h" #include "interface.h" @@ -21,6 +22,9 @@ NewArray (struct __go_empty_interface type, int n) { const struct __go_type_descriptor *descriptor; + if (((uintptr_t) type.__type_descriptor & reflectFlags) != 0) + __go_panic_msg ("invalid interface value"); + /* FIXME: We should check __type_descriptor to verify that this is really a type descriptor. */ descriptor = (const struct __go_type_descriptor *) type.__object; diff --git a/libgo/runtime/iface.goc b/libgo/runtime/iface.goc index 356b318..05e3773 100644 --- a/libgo/runtime/iface.goc +++ b/libgo/runtime/iface.goc @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. package runtime +#include "go-panic.h" #include "go-type.h" #include "interface.h" #define nil NULL @@ -33,6 +34,8 @@ func ifacetype(i interface) (d *const_descriptor) { // Convert an empty interface to an empty interface. func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) { + if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0) + __go_panic_msg("invalid interface value"); ret = e; ok = ret.__type_descriptor != nil; } @@ -52,6 +55,8 @@ func ifaceI2E2(i interface) (ret empty_interface, ok bool) { // Convert an empty interface to a non-empty interface. func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) { + if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0) + __go_panic_msg("invalid interface value"); if (e.__type_descriptor == nil) { ret.__methods = nil; ret.__object = nil; @@ -81,6 +86,8 @@ func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) { // Convert an empty interface to a pointer type. func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) { + if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0) + __go_panic_msg("invalid interface value"); if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) { ret = nil; ok = 0; @@ -104,6 +111,8 @@ func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) { // Convert an empty interface to a non-pointer type. func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) { + if(((uintptr_t)e.__type_descriptor&reflectFlags) != 0) + __go_panic_msg("invalid interface value"); if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) { __builtin_memset(ret, 0, inter->__size); ok = 0; diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc index 196271a..b46995a 100644 --- a/libgo/runtime/malloc.goc +++ b/libgo/runtime/malloc.goc @@ -386,7 +386,7 @@ runtime_MHeap_SysAlloc(MHeap *h, uintptr n) return nil; if(p < h->arena_start || (uintptr)(p+n - h->arena_start) >= MaxArena32) { - runtime_printf("runtime: memory allocated by OS not in usable range"); + runtime_printf("runtime: memory allocated by OS not in usable range\n"); runtime_SysFree(p, n); return nil; } diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c index ce65757..65d849c 100644 --- a/libgo/runtime/mcache.c +++ b/libgo/runtime/mcache.c @@ -22,6 +22,8 @@ runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed) // Replenish using central lists. n = runtime_MCentral_AllocList(&runtime_mheap.central[sizeclass], runtime_class_to_transfercount[sizeclass], &first); + if(n == 0) + runtime_throw("out of memory"); l->list = first; l->nlist = n; c->size += n*size; diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 27fc3cd..0f28f5f 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -90,6 +90,11 @@ scanblock(byte *b, int64 n) void **bw, **w, **ew; Workbuf *wbuf; + if((int64)(uintptr)n != n || n < 0) { + // runtime_printf("scanblock %p %lld\n", b, (long long)n); + runtime_throw("scanblock"); + } + // Memory arena parameters. arena_start = runtime_mheap.arena_start; @@ -602,7 +607,7 @@ runfinq(void* dummy) next = f->next; params[0] = &f->arg; - reflect_call(f->ft, (void*)f->fn, 0, params, nil); + reflect_call(f->ft, (void*)f->fn, 0, 0, params, nil); f->fn = nil; f->arg = nil; f->next = nil; diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c index b36df25..cc6b3af 100644 --- a/libgo/runtime/mheap.c +++ b/libgo/runtime/mheap.c @@ -181,9 +181,7 @@ MHeap_Grow(MHeap *h, uintptr npage) // Allocate a multiple of 64kB (16 pages). npage = (npage+15)&~15; ask = npage<<PageShift; - if(ask > (uintptr)(h->arena_end - h->arena_used)) - return false; - if(ask < HeapAllocChunk && HeapAllocChunk <= h->arena_end - h->arena_used) + if(ask < HeapAllocChunk) ask = HeapAllocChunk; v = runtime_MHeap_SysAlloc(h, ask); @@ -192,8 +190,10 @@ MHeap_Grow(MHeap *h, uintptr npage) ask = npage<<PageShift; v = runtime_MHeap_SysAlloc(h, ask); } - if(v == nil) + if(v == nil) { + runtime_printf("runtime: out of memory: cannot allocate %llu-byte block (%llu in use)\n", (unsigned long long)ask, (unsigned long long)mstats.heap_sys); return false; + } } mstats.heap_sys += ask; diff --git a/libgo/runtime/reflect.goc b/libgo/runtime/reflect.goc index 01d218a..4666dd5 100644 --- a/libgo/runtime/reflect.goc +++ b/libgo/runtime/reflect.goc @@ -5,31 +5,27 @@ package reflect #include "go-type.h" #include "interface.h" -#define nil NULL -typedef unsigned char byte; +#include "runtime.h" +#include "go-panic.h" +typedef struct __go_type_descriptor Type; typedef struct __go_interface Iface; typedef struct __go_empty_interface Eface; -func setiface(typ *byte, x *byte, ret *byte) { - struct __go_interface_type *t; - const struct __go_type_descriptor* xt; +func ifaceE2I(inter *Type, e Eface, ret *Iface) { + const Type *t; + Eface err; - /* FIXME: We should check __type_descriptor to verify that - this is really a type descriptor. */ - t = (struct __go_interface_type *)typ; - if(t->__methods.__count == 0) { - // already an empty interface - *(Eface*)ret = *(Eface*)x; - return; + if(((uintptr)e.__type_descriptor&reflectFlags) != 0) + runtime_throw("invalid interface value"); + t = e.__type_descriptor; + if(t == nil) { + // explicit conversions require non-nil interface value. + newTypeAssertionError(nil, nil, inter, + nil, nil, inter->__reflection, + nil, &err); + __go_panic(err); } - xt = ((Eface*)x)->__type_descriptor; - if(xt == nil) { - // can assign nil to any interface - ((Iface*)ret)->__methods = nil; - ((Iface*)ret)->__object = nil; - return; - } - ((Iface*)ret)->__methods = __go_convert_interface(&t->__common, xt); - ((Iface*)ret)->__object = ((Eface*)x)->__object; + ret->__object = e.__object; + ret->__methods = __go_convert_interface(inter, t); } diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 00ba40f..bf07c12 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -194,8 +194,8 @@ void runtime_resetcpuprofiler(int32); void runtime_setcpuprofilerate(void(*)(uintptr*, int32), int32); struct __go_func_type; -void reflect_call(const struct __go_func_type *, const void *, _Bool, void **, - void **) +void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool, + void **, void **) asm ("libgo_reflect.reflect.call"); #ifdef __rtems__ |