/* go-reflect-map.c -- map reflection support for Go. Copyright 2009, 2010 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 "runtime.h" #include "go-alloc.h" #include "go-assert.h" #include "go-type.h" #include "map.h" /* This file implements support for reflection on maps. These functions are called from reflect/value.go. */ struct mapaccess_ret { uintptr_t val; _Bool pres; }; extern struct mapaccess_ret mapaccess (struct __go_map_type *, uintptr_t, uintptr_t) __asm__ (GOSYM_PREFIX "reflect.mapaccess"); struct mapaccess_ret mapaccess (struct __go_map_type *mt, 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; __go_assert (mt->__common.__code == GO_MAP); key_descriptor = mt->__key_type; if (__go_is_pointer_type (key_descriptor)) key = &key_i; else key = (void *) key_i; if (map == NULL) p = NULL; else p = __go_map_index (map, key, 0); val_descriptor = mt->__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) ret.pres = 0; else { __builtin_memcpy (pv, p, val_descriptor->__size); ret.pres = 1; } ret.val = (uintptr_t) val; return ret; } extern void mapassign (struct __go_map_type *, uintptr_t, uintptr_t, uintptr_t, _Bool) __asm__ (GOSYM_PREFIX "reflect.mapassign"); void mapassign (struct __go_map_type *mt, 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; __go_assert (mt->__common.__code == GO_MAP); if (map == NULL) runtime_panicstring ("assignment to entry in nil map"); key_descriptor = mt->__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 = mt->__val_type; 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 (uintptr_t) __asm__ (GOSYM_PREFIX "reflect.maplen"); int32_t 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 (struct __go_map_type *, uintptr_t) __asm__ (GOSYM_PREFIX "reflect.mapiterinit"); unsigned char * mapiterinit (struct __go_map_type *mt, uintptr_t m) { struct __go_hash_iter *it; __go_assert (mt->__common.__code == GO_MAP); it = __go_alloc (sizeof (struct __go_hash_iter)); __go_mapiterinit ((struct __go_map *) m, it); return (unsigned char *) it; } extern void mapiternext (unsigned char *) __asm__ (GOSYM_PREFIX "reflect.mapiternext"); void mapiternext (unsigned char *it) { __go_mapiternext ((struct __go_hash_iter *) it); } struct mapiterkey_ret { uintptr_t key; _Bool ok; }; extern struct mapiterkey_ret mapiterkey (unsigned char *) __asm__ (GOSYM_PREFIX "reflect.mapiterkey"); 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) { ret.key = 0; ret.ok = 0; } else { 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 uintptr_t makemap (const struct __go_map_type *) __asm__ (GOSYM_PREFIX "reflect.makemap"); 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)); md->__map_descriptor = t; o = sizeof (void *); kt = t->__key_type; o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1); md->__key_offset = o; o += kt->__size; vt = t->__val_type; o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1); md->__val_offset = o; o += vt->__size; o = (o + sizeof (void *) - 1) & ~ (sizeof (void *) - 1); o = (o + kt->__field_align - 1) & ~ (kt->__field_align - 1); o = (o + vt->__field_align - 1) & ~ (vt->__field_align - 1); md->__entry_size = o; map = __go_new_map (md, 0); ret = __go_alloc (sizeof (void *)); __builtin_memcpy (ret, &map, sizeof (void *)); return (uintptr_t) ret; } extern _Bool ismapkey (const struct __go_type_descriptor *) __asm__ (GOSYM_PREFIX "reflect.ismapkey"); _Bool ismapkey (const struct __go_type_descriptor *typ) { return typ != NULL && typ->__hashfn != __go_type_hash_error; }