2008-11-13 11:35:44 -07:00
|
|
|
// 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 "runtime.h"
|
2012-10-21 15:41:32 -06:00
|
|
|
#include "arch_GOARCH.h"
|
|
|
|
#include "malloc.h"
|
2008-11-13 11:35:44 -07:00
|
|
|
#include "hashmap.h"
|
2009-09-08 14:46:54 -06:00
|
|
|
#include "type.h"
|
2012-10-07 12:05:32 -06:00
|
|
|
#include "race.h"
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// This file contains the implementation of Go's map type.
|
|
|
|
//
|
|
|
|
// The map is just a hash table. The data is arranged
|
|
|
|
// into an array of buckets. Each bucket contains up to
|
|
|
|
// 8 key/value pairs. The low-order bits of the hash are
|
|
|
|
// used to select a bucket. Each bucket contains a few
|
|
|
|
// high-order bits of each hash to distinguish the entries
|
|
|
|
// within a single bucket.
|
|
|
|
//
|
|
|
|
// If more than 8 keys hash to a bucket, we chain on
|
|
|
|
// extra buckets.
|
|
|
|
//
|
|
|
|
// When the hashtable grows, we allocate a new array
|
|
|
|
// of buckets twice as big. Buckets are incrementally
|
|
|
|
// copied from the old bucket array to the new bucket array.
|
|
|
|
//
|
|
|
|
// Map iterators walk through the array of buckets and
|
|
|
|
// return the keys in walk order (bucket #, then overflow
|
|
|
|
// chain order, then bucket index). To maintain iteration
|
|
|
|
// semantics, we never move keys within their bucket (if
|
|
|
|
// we did, keys might be returned 0 or 2 times). When
|
|
|
|
// growing the table, iterators remain iterating through the
|
|
|
|
// old table and must check the new table if the bucket
|
|
|
|
// they are iterating through has been moved ("evacuated")
|
|
|
|
// to the new table.
|
|
|
|
|
|
|
|
// Maximum number of key/value pairs a bucket can hold.
|
|
|
|
#define BUCKETSIZE 8
|
|
|
|
|
|
|
|
// Maximum average load of a bucket that triggers growth.
|
|
|
|
#define LOAD 6.5
|
|
|
|
|
|
|
|
// Picking LOAD: too large and we have lots of overflow
|
|
|
|
// buckets, too small and we waste a lot of space. I wrote
|
|
|
|
// a simple program to check some stats for different loads:
|
|
|
|
// (64-bit, 8 byte keys and values)
|
|
|
|
// LOAD %overflow bytes/entry hitprobe missprobe
|
|
|
|
// 4.00 2.13 20.77 3.00 4.00
|
|
|
|
// 4.50 4.05 17.30 3.25 4.50
|
|
|
|
// 5.00 6.85 14.77 3.50 5.00
|
|
|
|
// 5.50 10.55 12.94 3.75 5.50
|
|
|
|
// 6.00 15.27 11.67 4.00 6.00
|
|
|
|
// 6.50 20.90 10.79 4.25 6.50
|
|
|
|
// 7.00 27.14 10.15 4.50 7.00
|
|
|
|
// 7.50 34.03 9.73 4.75 7.50
|
|
|
|
// 8.00 41.10 9.40 5.00 8.00
|
|
|
|
//
|
|
|
|
// %overflow = percentage of buckets which have an overflow bucket
|
|
|
|
// bytes/entry = overhead bytes used per key/value pair
|
|
|
|
// hitprobe = # of entries to check when looking up a present key
|
|
|
|
// missprobe = # of entries to check when looking up an absent key
|
|
|
|
//
|
|
|
|
// Keep in mind this data is for maximally loaded tables, i.e. just
|
|
|
|
// before the table grows. Typical tables will be somewhat less loaded.
|
|
|
|
|
|
|
|
// Maximum key or value size to keep inline (instead of mallocing per element).
|
|
|
|
// Must fit in a uint8.
|
|
|
|
// Fast versions cannot handle big values - the cutoff size for
|
|
|
|
// fast versions in ../../cmd/gc/walk.c must be at most this value.
|
|
|
|
#define MAXKEYSIZE 128
|
|
|
|
#define MAXVALUESIZE 128
|
|
|
|
|
|
|
|
typedef struct Bucket Bucket;
|
|
|
|
struct Bucket
|
|
|
|
{
|
|
|
|
uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (0 = empty)
|
|
|
|
Bucket *overflow; // overflow bucket, if any
|
|
|
|
byte data[1]; // BUCKETSIZE keys followed by BUCKETSIZE values
|
2008-11-13 11:35:44 -07:00
|
|
|
};
|
2013-03-20 14:51:29 -06:00
|
|
|
// NOTE: packing all the keys together and then all the values together makes the
|
|
|
|
// code a bit more complicated than alternating key/value/key/value/... but it allows
|
|
|
|
// us to eliminate padding which would be needed for, e.g., map[int64]int8.
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// Low-order bit of overflow field is used to mark a bucket as already evacuated
|
|
|
|
// without destroying the overflow pointer.
|
|
|
|
// Only buckets in oldbuckets will be marked as evacuated.
|
|
|
|
// Evacuated bit will be set identically on the base bucket and any overflow buckets.
|
|
|
|
#define evacuated(b) (((uintptr)(b)->overflow & 1) != 0)
|
|
|
|
#define overflowptr(b) ((Bucket*)((uintptr)(b)->overflow & ~(uintptr)1))
|
2012-05-24 20:41:07 -06:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// Initialize bucket to the empty state. This only works if BUCKETSIZE==8!
|
|
|
|
#define clearbucket(b) { *(uint64*)((b)->tophash) = 0; (b)->overflow = nil; }
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
struct Hmap
|
|
|
|
{
|
|
|
|
uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
|
|
|
|
uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
|
|
|
|
uint8 flags;
|
|
|
|
uint8 keysize; // key size in bytes
|
|
|
|
uint8 valuesize; // value size in bytes
|
|
|
|
uint16 bucketsize; // bucket size in bytes
|
|
|
|
|
|
|
|
uintptr hash0; // hash seed
|
|
|
|
byte *buckets; // array of 2^B Buckets
|
|
|
|
byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
|
|
|
|
uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
|
2008-11-13 11:35:44 -07:00
|
|
|
};
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// possible flags
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
IndirectKey = 1, // storing pointers to keys
|
|
|
|
IndirectValue = 2, // storing pointers to values
|
2013-03-20 16:38:51 -06:00
|
|
|
Iterator = 4, // there may be an iterator using buckets
|
|
|
|
OldIterator = 8, // there may be an iterator using oldbuckets
|
|
|
|
CanFreeBucket = 16, // ok to free buckets
|
|
|
|
CanFreeKey = 32, // keys are indirect and ok to free keys
|
2013-03-20 14:51:29 -06:00
|
|
|
};
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// Macros for dereferencing indirect keys
|
|
|
|
#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
|
|
|
|
#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
docheck = 0, // check invariants before and after every op. Slow!!!
|
|
|
|
debug = 0, // print every operation
|
2013-03-25 14:35:46 -06:00
|
|
|
checkgc = 0 || docheck, // check interaction of mallocgc() with the garbage collector
|
2013-03-20 14:51:29 -06:00
|
|
|
};
|
|
|
|
static void
|
|
|
|
check(MapType *t, Hmap *h)
|
|
|
|
{
|
|
|
|
uintptr bucket, oldbucket;
|
|
|
|
Bucket *b;
|
|
|
|
uintptr i;
|
|
|
|
uintptr hash;
|
|
|
|
uintgo cnt;
|
|
|
|
uint8 top;
|
|
|
|
bool eq;
|
|
|
|
byte *k, *v;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
cnt = 0;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// check buckets
|
|
|
|
for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
|
|
|
|
if(h->oldbuckets != nil) {
|
|
|
|
oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if(!evacuated(b))
|
|
|
|
continue; // b is still uninitialized
|
|
|
|
}
|
|
|
|
for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] == 0)
|
|
|
|
continue;
|
|
|
|
cnt++;
|
|
|
|
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
|
|
|
|
if(!eq)
|
|
|
|
continue; // NaN!
|
|
|
|
hash = h->hash0;
|
|
|
|
t->key->alg->hash(&hash, t->key->size, IK(h, k));
|
|
|
|
top = hash >> (8*sizeof(uintptr) - 8);
|
|
|
|
if(top == 0)
|
|
|
|
top = 1;
|
|
|
|
if(top != b->tophash[i])
|
|
|
|
runtime·throw("bad hash");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// check oldbuckets
|
|
|
|
if(h->oldbuckets != nil) {
|
|
|
|
for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if(evacuated(b))
|
|
|
|
continue;
|
|
|
|
if(oldbucket < h->nevacuate)
|
|
|
|
runtime·throw("bucket became unevacuated");
|
|
|
|
for(; b != nil; b = overflowptr(b)) {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] == 0)
|
|
|
|
continue;
|
|
|
|
cnt++;
|
|
|
|
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
|
|
|
|
if(!eq)
|
|
|
|
continue; // NaN!
|
|
|
|
hash = h->hash0;
|
|
|
|
t->key->alg->hash(&hash, t->key->size, IK(h, k));
|
|
|
|
top = hash >> (8*sizeof(uintptr) - 8);
|
|
|
|
if(top == 0)
|
|
|
|
top = 1;
|
|
|
|
if(top != b->tophash[i])
|
|
|
|
runtime·throw("bad hash (old)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
if(cnt != h->count) {
|
|
|
|
runtime·printf("%D %D\n", (uint64)cnt, (uint64)h->count);
|
|
|
|
runtime·throw("entries missing");
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_init(MapType *t, Hmap *h, uint32 hint)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
uint8 B;
|
|
|
|
byte *buckets;
|
|
|
|
uintptr i;
|
|
|
|
uintptr keysize, valuesize, bucketsize;
|
|
|
|
uint8 flags;
|
|
|
|
Bucket *b;
|
|
|
|
|
2013-03-20 16:38:51 -06:00
|
|
|
flags = CanFreeBucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
// figure out how big we have to make everything
|
|
|
|
keysize = t->key->size;
|
|
|
|
if(keysize > MAXKEYSIZE) {
|
2013-03-20 16:38:51 -06:00
|
|
|
flags |= IndirectKey | CanFreeKey;
|
2013-03-20 14:51:29 -06:00
|
|
|
keysize = sizeof(byte*);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
valuesize = t->elem->size;
|
2013-03-29 12:04:07 -06:00
|
|
|
if(valuesize > MAXVALUESIZE) {
|
2013-03-20 14:51:29 -06:00
|
|
|
flags |= IndirectValue;
|
|
|
|
valuesize = sizeof(byte*);
|
|
|
|
}
|
|
|
|
bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
|
|
|
|
|
|
|
|
// invariants we depend on. We should probably check these at compile time
|
|
|
|
// somewhere, but for now we'll do it here.
|
|
|
|
if(t->key->align > BUCKETSIZE)
|
|
|
|
runtime·throw("key align too big");
|
|
|
|
if(t->elem->align > BUCKETSIZE)
|
|
|
|
runtime·throw("value align too big");
|
|
|
|
if(t->key->size % t->key->align != 0)
|
|
|
|
runtime·throw("key size not a multiple of key align");
|
|
|
|
if(t->elem->size % t->elem->align != 0)
|
|
|
|
runtime·throw("value size not a multiple of value align");
|
|
|
|
if(BUCKETSIZE < 8)
|
|
|
|
runtime·throw("bucketsize too small for proper alignment");
|
|
|
|
if(BUCKETSIZE != 8)
|
|
|
|
runtime·throw("must redo clearbucket");
|
|
|
|
if(sizeof(void*) == 4 && t->key->align > 4)
|
|
|
|
runtime·throw("need padding in bucket (key)");
|
|
|
|
if(sizeof(void*) == 4 && t->elem->align > 4)
|
|
|
|
runtime·throw("need padding in bucket (value)");
|
|
|
|
|
|
|
|
// find size parameter which will hold the requested # of elements
|
|
|
|
B = 0;
|
|
|
|
while(hint > BUCKETSIZE && hint > LOAD * ((uintptr)1 << B))
|
|
|
|
B++;
|
|
|
|
|
|
|
|
// allocate initial hash table
|
|
|
|
// If hint is large zeroing this memory could take a while.
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-27 17:28:51 -06:00
|
|
|
if(B == 0) {
|
|
|
|
// done lazily later.
|
|
|
|
buckets = nil;
|
|
|
|
} else {
|
|
|
|
buckets = runtime·mallocgc(bucketsize << B, 0, 1, 0);
|
|
|
|
for(i = 0; i < (uintptr)1 << B; i++) {
|
|
|
|
b = (Bucket*)(buckets + i * bucketsize);
|
|
|
|
clearbucket(b);
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// initialize Hmap
|
|
|
|
// Note: we save all these stores to the end so gciter doesn't see
|
|
|
|
// a partially initialized map.
|
2008-11-13 11:35:44 -07:00
|
|
|
h->count = 0;
|
2013-03-20 14:51:29 -06:00
|
|
|
h->B = B;
|
|
|
|
h->flags = flags;
|
|
|
|
h->keysize = keysize;
|
|
|
|
h->valuesize = valuesize;
|
|
|
|
h->bucketsize = bucketsize;
|
2012-01-30 22:37:03 -07:00
|
|
|
h->hash0 = runtime·fastrand1();
|
2013-03-20 14:51:29 -06:00
|
|
|
h->buckets = buckets;
|
|
|
|
h->oldbuckets = nil;
|
|
|
|
h->nevacuate = 0;
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
|
|
|
|
// We leave the original bucket intact, except for the evacuated marks, so that
|
|
|
|
// iterators can still iterate through the old buckets.
|
2008-11-13 11:35:44 -07:00
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
evacuate(MapType *t, Hmap *h, uintptr oldbucket)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
Bucket *b;
|
|
|
|
Bucket *nextb;
|
|
|
|
Bucket *x, *y;
|
|
|
|
Bucket *newx, *newy;
|
|
|
|
uintptr xi, yi;
|
|
|
|
uintptr newbit;
|
|
|
|
uintptr hash;
|
|
|
|
uintptr i;
|
|
|
|
byte *k, *v;
|
|
|
|
byte *xk, *yk, *xv, *yv;
|
2013-03-20 16:38:51 -06:00
|
|
|
byte *ob;
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
newbit = (uintptr)1 << (h->B - 1);
|
|
|
|
|
|
|
|
if(!evacuated(b)) {
|
|
|
|
// TODO: reuse overflow buckets instead of using new ones, if there
|
|
|
|
// is no iterator using the old buckets. (If CanFreeBuckets and !OldIterator.)
|
|
|
|
|
|
|
|
x = (Bucket*)(h->buckets + oldbucket * h->bucketsize);
|
|
|
|
y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
|
|
|
|
clearbucket(x);
|
|
|
|
clearbucket(y);
|
|
|
|
xi = 0;
|
|
|
|
yi = 0;
|
|
|
|
xk = x->data;
|
|
|
|
yk = y->data;
|
|
|
|
xv = xk + h->keysize * BUCKETSIZE;
|
|
|
|
yv = yk + h->keysize * BUCKETSIZE;
|
|
|
|
do {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] == 0)
|
|
|
|
continue;
|
|
|
|
hash = h->hash0;
|
|
|
|
t->key->alg->hash(&hash, t->key->size, IK(h, k));
|
|
|
|
// NOTE: if key != key, then this hash could be (and probably will be)
|
|
|
|
// entirely different from the old hash. We effectively only update
|
|
|
|
// the B'th bit of the hash in this case.
|
|
|
|
if((hash & newbit) == 0) {
|
|
|
|
if(xi == BUCKETSIZE) {
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
newx = runtime·mallocgc(h->bucketsize, 0, 1, 0);
|
|
|
|
clearbucket(newx);
|
|
|
|
x->overflow = newx;
|
|
|
|
x = newx;
|
|
|
|
xi = 0;
|
|
|
|
xk = x->data;
|
|
|
|
xv = xk + h->keysize * BUCKETSIZE;
|
|
|
|
}
|
|
|
|
x->tophash[xi] = b->tophash[i];
|
|
|
|
if((h->flags & IndirectKey) != 0) {
|
|
|
|
*(byte**)xk = *(byte**)k; // copy pointer
|
|
|
|
} else {
|
|
|
|
t->key->alg->copy(t->key->size, xk, k); // copy value
|
|
|
|
}
|
|
|
|
if((h->flags & IndirectValue) != 0) {
|
|
|
|
*(byte**)xv = *(byte**)v;
|
|
|
|
} else {
|
|
|
|
t->elem->alg->copy(t->elem->size, xv, v);
|
|
|
|
}
|
|
|
|
xi++;
|
|
|
|
xk += h->keysize;
|
|
|
|
xv += h->valuesize;
|
|
|
|
} else {
|
|
|
|
if(yi == BUCKETSIZE) {
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
newy = runtime·mallocgc(h->bucketsize, 0, 1, 0);
|
|
|
|
clearbucket(newy);
|
|
|
|
y->overflow = newy;
|
|
|
|
y = newy;
|
|
|
|
yi = 0;
|
|
|
|
yk = y->data;
|
|
|
|
yv = yk + h->keysize * BUCKETSIZE;
|
|
|
|
}
|
|
|
|
y->tophash[yi] = b->tophash[i];
|
|
|
|
if((h->flags & IndirectKey) != 0) {
|
|
|
|
*(byte**)yk = *(byte**)k;
|
|
|
|
} else {
|
|
|
|
t->key->alg->copy(t->key->size, yk, k);
|
|
|
|
}
|
|
|
|
if((h->flags & IndirectValue) != 0) {
|
|
|
|
*(byte**)yv = *(byte**)v;
|
|
|
|
} else {
|
|
|
|
t->elem->alg->copy(t->elem->size, yv, v);
|
|
|
|
}
|
|
|
|
yi++;
|
|
|
|
yk += h->keysize;
|
|
|
|
yv += h->valuesize;
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
// mark as evacuated so we don't do it again.
|
|
|
|
// this also tells any iterators that this data isn't golden anymore.
|
|
|
|
nextb = b->overflow;
|
|
|
|
b->overflow = (Bucket*)((uintptr)nextb + 1);
|
|
|
|
|
|
|
|
b = nextb;
|
|
|
|
} while(b != nil);
|
2013-03-20 16:38:51 -06:00
|
|
|
|
|
|
|
// Free old overflow buckets as much as we can.
|
|
|
|
if((h->flags & OldIterator) == 0) {
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if((h->flags & CanFreeBucket) != 0) {
|
|
|
|
while((nextb = overflowptr(b)) != nil) {
|
|
|
|
b->overflow = nextb->overflow;
|
|
|
|
runtime·free(nextb);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// can't explicitly free overflow buckets, but at least
|
|
|
|
// we can unlink them.
|
|
|
|
b->overflow = (Bucket*)1;
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// advance evacuation mark
|
|
|
|
if(oldbucket == h->nevacuate) {
|
|
|
|
h->nevacuate = oldbucket + 1;
|
|
|
|
if(oldbucket + 1 == newbit) { // newbit == # of oldbuckets
|
2013-03-20 16:38:51 -06:00
|
|
|
// free main bucket array
|
|
|
|
if((h->flags & (OldIterator | CanFreeBucket)) == CanFreeBucket) {
|
|
|
|
ob = h->oldbuckets;
|
|
|
|
h->oldbuckets = nil;
|
|
|
|
runtime·free(ob);
|
|
|
|
} else {
|
|
|
|
h->oldbuckets = nil;
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
grow_work(MapType *t, Hmap *h, uintptr bucket)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
uintptr noldbuckets;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
noldbuckets = (uintptr)1 << (h->B - 1);
|
|
|
|
|
|
|
|
// make sure we evacuate the oldbucket corresponding
|
|
|
|
// to the bucket we're about to use
|
|
|
|
evacuate(t, h, bucket & (noldbuckets - 1));
|
|
|
|
|
|
|
|
// evacuate one more oldbucket to make progress on growing
|
|
|
|
if(h->oldbuckets != nil)
|
|
|
|
evacuate(t, h, h->nevacuate);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_grow(MapType *t, Hmap *h)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
byte *old_buckets;
|
|
|
|
byte *new_buckets;
|
|
|
|
uint8 flags;
|
|
|
|
|
|
|
|
// allocate a bigger hash table
|
|
|
|
if(h->oldbuckets != nil)
|
|
|
|
runtime·throw("evacuation not done in time");
|
|
|
|
old_buckets = h->buckets;
|
|
|
|
// NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
new_buckets = runtime·mallocgc(h->bucketsize << (h->B + 1), 0, 1, 0);
|
|
|
|
flags = (h->flags & ~(Iterator | OldIterator));
|
2013-03-20 16:38:51 -06:00
|
|
|
if((h->flags & Iterator) != 0) {
|
2013-03-20 14:51:29 -06:00
|
|
|
flags |= OldIterator;
|
2013-03-20 16:38:51 -06:00
|
|
|
// We can't free indirect keys any more, as
|
|
|
|
// they are potentially aliased across buckets.
|
|
|
|
flags &= ~CanFreeKey;
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
// commit the grow (atomic wrt gc)
|
|
|
|
h->B++;
|
|
|
|
h->flags = flags;
|
|
|
|
h->oldbuckets = old_buckets;
|
|
|
|
h->buckets = new_buckets;
|
|
|
|
h->nevacuate = 0;
|
|
|
|
|
|
|
|
// the actual copying of the hash table data is done incrementally
|
|
|
|
// by grow_work() and evacuate().
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// returns ptr to value associated with key *keyp, or nil if none.
|
|
|
|
// if it returns non-nil, updates *keyp to point to the currently stored key.
|
|
|
|
static byte*
|
|
|
|
hash_lookup(MapType *t, Hmap *h, byte **keyp)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2012-05-24 20:41:07 -06:00
|
|
|
void *key;
|
2013-03-20 14:51:29 -06:00
|
|
|
uintptr hash;
|
2013-04-01 19:59:58 -06:00
|
|
|
uintptr bucket, oldbucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
Bucket *b;
|
|
|
|
uint8 top;
|
|
|
|
uintptr i;
|
2011-12-05 07:40:22 -07:00
|
|
|
bool eq;
|
2013-03-20 14:51:29 -06:00
|
|
|
byte *k, *k2, *v;
|
2012-05-29 12:02:29 -06:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
key = *keyp;
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2013-03-27 17:28:51 -06:00
|
|
|
if(h->count == 0)
|
|
|
|
return nil;
|
2012-01-30 22:37:03 -07:00
|
|
|
hash = h->hash0;
|
2013-03-20 14:51:29 -06:00
|
|
|
t->key->alg->hash(&hash, t->key->size, key);
|
|
|
|
bucket = hash & (((uintptr)1 << h->B) - 1);
|
2013-04-01 19:59:58 -06:00
|
|
|
if(h->oldbuckets != nil) {
|
|
|
|
oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if(evacuated(b)) {
|
|
|
|
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
top = hash >> (sizeof(uintptr)*8 - 8);
|
|
|
|
if(top == 0)
|
|
|
|
top = 1;
|
|
|
|
do {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] == top) {
|
|
|
|
k2 = IK(h, k);
|
|
|
|
t->key->alg->equal(&eq, t->key->size, key, k2);
|
|
|
|
if(eq) {
|
|
|
|
*keyp = k2;
|
|
|
|
return IV(h, v);
|
|
|
|
}
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
b = b->overflow;
|
|
|
|
} while(b != nil);
|
|
|
|
return nil;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// When an item is not found, fast versions return a pointer to this zeroed memory.
|
|
|
|
static uint8 empty_value[MAXVALUESIZE];
|
|
|
|
|
|
|
|
// Specialized versions of mapaccess1 for specific types.
|
|
|
|
// See ./hashmap_fast and ../../cmd/gc/walk.c.
|
|
|
|
#define HASH_LOOKUP1 runtime·mapaccess1_fast32
|
|
|
|
#define HASH_LOOKUP2 runtime·mapaccess2_fast32
|
|
|
|
#define KEYTYPE uint32
|
|
|
|
#define HASHFUNC runtime·algarray[AMEM32].hash
|
|
|
|
#define EQFUNC(x,y) ((x) == (y))
|
|
|
|
#define QUICKEQ(x) true
|
|
|
|
#include "hashmap_fast.c"
|
|
|
|
|
|
|
|
#undef HASH_LOOKUP1
|
|
|
|
#undef HASH_LOOKUP2
|
|
|
|
#undef KEYTYPE
|
|
|
|
#undef HASHFUNC
|
|
|
|
#undef EQFUNC
|
|
|
|
#undef QUICKEQ
|
|
|
|
|
|
|
|
#define HASH_LOOKUP1 runtime·mapaccess1_fast64
|
|
|
|
#define HASH_LOOKUP2 runtime·mapaccess2_fast64
|
|
|
|
#define KEYTYPE uint64
|
|
|
|
#define HASHFUNC runtime·algarray[AMEM64].hash
|
|
|
|
#define EQFUNC(x,y) ((x) == (y))
|
|
|
|
#define QUICKEQ(x) true
|
|
|
|
#include "hashmap_fast.c"
|
|
|
|
|
|
|
|
#undef HASH_LOOKUP1
|
|
|
|
#undef HASH_LOOKUP2
|
|
|
|
#undef KEYTYPE
|
|
|
|
#undef HASHFUNC
|
|
|
|
#undef EQFUNC
|
|
|
|
#undef QUICKEQ
|
|
|
|
|
|
|
|
#define HASH_LOOKUP1 runtime·mapaccess1_faststr
|
|
|
|
#define HASH_LOOKUP2 runtime·mapaccess2_faststr
|
|
|
|
#define KEYTYPE String
|
|
|
|
#define HASHFUNC runtime·algarray[ASTRING].hash
|
2013-04-02 17:26:15 -06:00
|
|
|
#define EQFUNC(x,y) ((x).len == (y).len && ((x).str == (y).str || runtime·memeq((x).str, (y).str, (x).len)))
|
2013-03-20 14:51:29 -06:00
|
|
|
#define QUICKEQ(x) ((x).len < 32)
|
|
|
|
#include "hashmap_fast.c"
|
|
|
|
|
|
|
|
static void
|
|
|
|
hash_insert(MapType *t, Hmap *h, void *key, void *value)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
uintptr hash;
|
|
|
|
uintptr bucket;
|
|
|
|
uintptr i;
|
2011-12-05 07:40:22 -07:00
|
|
|
bool eq;
|
2013-03-20 14:51:29 -06:00
|
|
|
Bucket *b;
|
|
|
|
Bucket *newb;
|
|
|
|
uint8 *inserti;
|
|
|
|
byte *insertk, *insertv;
|
|
|
|
uint8 top;
|
|
|
|
byte *k, *v;
|
|
|
|
byte *kmem, *vmem;
|
|
|
|
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2012-01-30 22:37:03 -07:00
|
|
|
hash = h->hash0;
|
2013-03-20 14:51:29 -06:00
|
|
|
t->key->alg->hash(&hash, t->key->size, key);
|
2013-03-27 17:28:51 -06:00
|
|
|
if(h->buckets == nil) {
|
|
|
|
h->buckets = runtime·mallocgc(h->bucketsize, 0, 1, 0);
|
|
|
|
b = (Bucket*)(h->buckets);
|
|
|
|
clearbucket(b);
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
again:
|
|
|
|
bucket = hash & (((uintptr)1 << h->B) - 1);
|
|
|
|
if(h->oldbuckets != nil)
|
|
|
|
grow_work(t, h, bucket);
|
|
|
|
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
|
|
|
|
top = hash >> (sizeof(uintptr)*8 - 8);
|
|
|
|
if(top == 0)
|
|
|
|
top = 1;
|
|
|
|
inserti = 0;
|
|
|
|
insertk = nil;
|
|
|
|
insertv = nil;
|
|
|
|
while(true) {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] != top) {
|
|
|
|
if(b->tophash[i] == 0 && inserti == nil) {
|
|
|
|
inserti = &b->tophash[i];
|
|
|
|
insertk = k;
|
|
|
|
insertv = v;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
|
|
|
|
if(!eq)
|
|
|
|
continue;
|
|
|
|
// already have a mapping for key. Update it.
|
|
|
|
t->key->alg->copy(t->key->size, IK(h, k), key); // Need to update key for keys which are distinct but equal (e.g. +0.0 and -0.0)
|
|
|
|
t->elem->alg->copy(t->elem->size, IV(h, v), value);
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
|
|
|
return;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if(b->overflow == nil)
|
|
|
|
break;
|
|
|
|
b = b->overflow;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
// did not find mapping for key. Allocate new cell & add entry.
|
|
|
|
if(h->count >= LOAD * ((uintptr)1 << h->B) && h->count >= BUCKETSIZE) {
|
|
|
|
hash_grow(t, h);
|
|
|
|
goto again; // Growing the table invalidates everything, so try again
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
if(inserti == nil) {
|
|
|
|
// all current buckets are full, allocate a new one.
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
newb = runtime·mallocgc(h->bucketsize, 0, 1, 0);
|
|
|
|
clearbucket(newb);
|
|
|
|
b->overflow = newb;
|
|
|
|
inserti = newb->tophash;
|
|
|
|
insertk = newb->data;
|
|
|
|
insertv = insertk + h->keysize * BUCKETSIZE;
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// store new key/value at insert position
|
|
|
|
if((h->flags & IndirectKey) != 0) {
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
kmem = runtime·mallocgc(t->key->size, 0, 1, 0);
|
|
|
|
*(byte**)insertk = kmem;
|
|
|
|
insertk = kmem;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if((h->flags & IndirectValue) != 0) {
|
2013-03-25 14:35:46 -06:00
|
|
|
if(checkgc) mstats.next_gc = mstats.heap_alloc;
|
2013-03-20 14:51:29 -06:00
|
|
|
vmem = runtime·mallocgc(t->elem->size, 0, 1, 0);
|
|
|
|
*(byte**)insertv = vmem;
|
|
|
|
insertv = vmem;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
t->key->alg->copy(t->key->size, insertk, key);
|
|
|
|
t->elem->alg->copy(t->elem->size, insertv, value);
|
|
|
|
*inserti = top;
|
|
|
|
h->count++;
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
static void
|
|
|
|
hash_remove(MapType *t, Hmap *h, void *key)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2011-12-05 07:40:22 -07:00
|
|
|
uintptr hash;
|
2013-03-20 14:51:29 -06:00
|
|
|
uintptr bucket;
|
|
|
|
Bucket *b;
|
|
|
|
uint8 top;
|
|
|
|
uintptr i;
|
|
|
|
byte *k, *v;
|
|
|
|
bool eq;
|
|
|
|
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
2013-03-27 17:28:51 -06:00
|
|
|
if(h->count == 0)
|
|
|
|
return;
|
2012-01-30 22:37:03 -07:00
|
|
|
hash = h->hash0;
|
2013-03-20 14:51:29 -06:00
|
|
|
t->key->alg->hash(&hash, t->key->size, key);
|
|
|
|
bucket = hash & (((uintptr)1 << h->B) - 1);
|
|
|
|
if(h->oldbuckets != nil)
|
|
|
|
grow_work(t, h, bucket);
|
|
|
|
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
|
|
|
|
top = hash >> (sizeof(uintptr)*8 - 8);
|
|
|
|
if(top == 0)
|
|
|
|
top = 1;
|
|
|
|
do {
|
|
|
|
for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] != top)
|
|
|
|
continue;
|
|
|
|
t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
|
|
|
|
if(!eq)
|
|
|
|
continue;
|
|
|
|
|
2013-03-20 16:38:51 -06:00
|
|
|
if((h->flags & CanFreeKey) != 0) {
|
|
|
|
k = *(byte**)k;
|
|
|
|
}
|
|
|
|
if((h->flags & IndirectValue) != 0) {
|
|
|
|
v = *(byte**)v;
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
b->tophash[i] = 0;
|
|
|
|
h->count--;
|
2013-03-20 16:38:51 -06:00
|
|
|
|
|
|
|
if((h->flags & CanFreeKey) != 0) {
|
|
|
|
runtime·free(k);
|
|
|
|
}
|
|
|
|
if((h->flags & IndirectValue) != 0) {
|
|
|
|
runtime·free(v);
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
// TODO: consolidate buckets if they are mostly empty
|
|
|
|
// can only consolidate if there are no live iterators at this size.
|
|
|
|
if(docheck)
|
|
|
|
check(t, h);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
b = b->overflow;
|
|
|
|
} while(b != nil);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// TODO: shrink the map, the same way we grow it.
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// If you modify hash_iter, also change cmd/gc/range.c to indicate
|
|
|
|
// the size of this structure.
|
|
|
|
struct hash_iter
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
|
|
|
|
uint8* value;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
MapType *t;
|
|
|
|
Hmap *h;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// end point for iteration
|
|
|
|
uintptr endbucket;
|
|
|
|
bool wrapped;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// state of table at time iterator is initialized
|
|
|
|
uint8 B;
|
|
|
|
byte *buckets;
|
|
|
|
|
|
|
|
// iter state
|
|
|
|
uintptr bucket;
|
|
|
|
struct Bucket *bptr;
|
|
|
|
uintptr i;
|
2013-04-01 19:59:58 -06:00
|
|
|
intptr check_bucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
// iterator state:
|
|
|
|
// bucket: the current bucket ID
|
|
|
|
// b: the current Bucket in the chain
|
|
|
|
// i: the next offset to check in the current bucket
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-04-01 19:59:58 -06:00
|
|
|
if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
|
|
|
|
runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
|
|
|
|
}
|
2011-12-05 07:40:22 -07:00
|
|
|
it->t = t;
|
2013-03-20 14:51:29 -06:00
|
|
|
it->h = h;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// grab snapshot of bucket state
|
|
|
|
it->B = h->B;
|
|
|
|
it->buckets = h->buckets;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// iterator state
|
|
|
|
it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
|
|
|
|
it->wrapped = false;
|
|
|
|
it->bptr = nil;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-04-01 19:59:58 -06:00
|
|
|
// Remember we have an iterator.
|
|
|
|
h->flags |= Iterator | OldIterator; // careful: see issue 5120.
|
2013-03-27 17:28:51 -06:00
|
|
|
|
|
|
|
if(h->buckets == nil) {
|
|
|
|
// Empty map. Force next hash_next to exit without
|
|
|
|
// evalulating h->bucket.
|
|
|
|
it->wrapped = true;
|
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// initializes it->key and it->value to the next key/value pair
|
|
|
|
// in the iteration, or nil if we've reached the end.
|
2008-11-13 11:35:44 -07:00
|
|
|
static void
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_next(struct hash_iter *it)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
Hmap *h;
|
|
|
|
MapType *t;
|
2013-04-01 19:59:58 -06:00
|
|
|
uintptr bucket, oldbucket;
|
|
|
|
uintptr hash;
|
2013-03-20 14:51:29 -06:00
|
|
|
Bucket *b;
|
|
|
|
uintptr i;
|
2013-04-01 19:59:58 -06:00
|
|
|
intptr check_bucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
bool eq;
|
|
|
|
byte *k, *v;
|
|
|
|
byte *rk, *rv;
|
|
|
|
|
|
|
|
h = it->h;
|
|
|
|
t = it->t;
|
|
|
|
bucket = it->bucket;
|
|
|
|
b = it->bptr;
|
|
|
|
i = it->i;
|
2013-04-01 19:59:58 -06:00
|
|
|
check_bucket = it->check_bucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
next:
|
|
|
|
if(b == nil) {
|
|
|
|
if(bucket == it->endbucket && it->wrapped) {
|
|
|
|
// end of iteration
|
|
|
|
it->key = nil;
|
|
|
|
it->value = nil;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(h->oldbuckets != nil && it->B == h->B) {
|
|
|
|
// Iterator was started in the middle of a grow, and the grow isn't done yet.
|
2013-04-01 19:59:58 -06:00
|
|
|
// If the bucket we're looking at hasn't been filled in yet (i.e. the old
|
|
|
|
// bucket hasn't been evacuated) then we need to iterate through the old
|
|
|
|
// bucket and only return the ones that will be migrated to this bucket.
|
|
|
|
oldbucket = bucket & (((uintptr)1 << (it->B - 1)) - 1);
|
|
|
|
b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if(!evacuated(b)) {
|
|
|
|
check_bucket = bucket;
|
|
|
|
} else {
|
|
|
|
b = (Bucket*)(it->buckets + bucket * h->bucketsize);
|
|
|
|
check_bucket = -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
b = (Bucket*)(it->buckets + bucket * h->bucketsize);
|
|
|
|
check_bucket = -1;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
bucket++;
|
|
|
|
if(bucket == ((uintptr)1 << it->B)) {
|
|
|
|
bucket = 0;
|
|
|
|
it->wrapped = true;
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
}
|
|
|
|
k = b->data + h->keysize * i;
|
|
|
|
v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
|
|
|
|
for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] != 0) {
|
2013-04-01 19:59:58 -06:00
|
|
|
if(check_bucket >= 0) {
|
|
|
|
// Special case: iterator was started during a grow and the
|
|
|
|
// grow is not done yet. We're working on a bucket whose
|
|
|
|
// oldbucket has not been evacuated yet. So we iterate
|
|
|
|
// through the oldbucket, skipping any keys that will go
|
|
|
|
// to the other new bucket (each oldbucket expands to two
|
|
|
|
// buckets during a grow).
|
|
|
|
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
|
|
|
|
if(!eq) {
|
|
|
|
// Hash is meaningless if k != k (NaNs). Return all
|
|
|
|
// NaNs during the first of the two new buckets.
|
|
|
|
if(bucket >= ((uintptr)1 << (it->B - 1))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If the item in the oldbucket is not destined for
|
|
|
|
// the current new bucket in the iteration, skip it.
|
|
|
|
hash = h->hash0;
|
|
|
|
t->key->alg->hash(&hash, t->key->size, IK(h, k));
|
|
|
|
if((hash & (((uintptr)1 << it->B) - 1)) != check_bucket) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if(!evacuated(b)) {
|
|
|
|
// this is the golden data, we can return it.
|
|
|
|
it->key = IK(h, k);
|
|
|
|
it->value = IV(h, v);
|
|
|
|
} else {
|
|
|
|
// The hash table has grown since the iterator was started.
|
|
|
|
// The golden data for this key is now somewhere else.
|
|
|
|
t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
|
|
|
|
if(eq) {
|
|
|
|
// Check the current hash table for the data.
|
|
|
|
// This code handles the case where the key
|
|
|
|
// has been deleted, updated, or deleted and reinserted.
|
|
|
|
// NOTE: we need to regrab the key as it has potentially been
|
|
|
|
// updated to an equal() but not identical key (e.g. +0.0 vs -0.0).
|
|
|
|
rk = IK(h, k);
|
|
|
|
rv = hash_lookup(t, it->h, &rk);
|
|
|
|
if(rv == nil)
|
|
|
|
continue; // key has been deleted
|
|
|
|
it->key = rk;
|
|
|
|
it->value = rv;
|
|
|
|
} else {
|
|
|
|
// if key!=key then the entry can't be deleted or
|
|
|
|
// updated, so we can just return it. That's lucky for
|
|
|
|
// us because when key!=key we can't look it up
|
|
|
|
// successfully in the current table.
|
|
|
|
it->key = IK(h, k);
|
|
|
|
it->value = IV(h, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
it->bucket = bucket;
|
|
|
|
it->bptr = b;
|
|
|
|
it->i = i + 1;
|
2013-04-01 19:59:58 -06:00
|
|
|
it->check_bucket = check_bucket;
|
2013-03-20 14:51:29 -06:00
|
|
|
return;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
b = overflowptr(b);
|
|
|
|
i = 0;
|
|
|
|
goto next;
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
|
|
|
|
#define PHASE_BUCKETS 0
|
|
|
|
#define PHASE_OLD_BUCKETS 1
|
|
|
|
#define PHASE_TABLE 2
|
|
|
|
#define PHASE_OLD_TABLE 3
|
|
|
|
#define PHASE_DONE 4
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-02-08 14:00:33 -07:00
|
|
|
// Initialize the iterator.
|
|
|
|
// Returns false if Hmap contains no pointers (in which case the iterator is not initialized).
|
|
|
|
bool
|
|
|
|
hash_gciter_init (Hmap *h, struct hash_gciter *it)
|
|
|
|
{
|
2013-03-27 17:28:51 -06:00
|
|
|
// GC during map initialization or on an empty map.
|
2013-03-20 14:51:29 -06:00
|
|
|
if(h->buckets == nil)
|
2013-02-08 14:00:33 -07:00
|
|
|
return false;
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
it->h = h;
|
|
|
|
it->phase = PHASE_BUCKETS;
|
|
|
|
it->bucket = 0;
|
|
|
|
it->b = nil;
|
|
|
|
|
|
|
|
// TODO: finish evacuating oldbuckets so that we can collect
|
|
|
|
// oldbuckets? We don't want to keep a partially evacuated
|
|
|
|
// table around forever, so each gc could make at least some
|
|
|
|
// evacuation progress. Need to be careful about concurrent
|
|
|
|
// access if we do concurrent gc. Even if not, we don't want
|
|
|
|
// to make the gc pause any longer than it has to be.
|
|
|
|
|
2013-02-08 14:00:33 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
// Returns true and fills *data with internal structure/key/value data,
|
2013-02-08 14:00:33 -07:00
|
|
|
// or returns false if the iterator has terminated.
|
2013-03-20 14:51:29 -06:00
|
|
|
// Ugh, this interface is really annoying. I want a callback fn!
|
2013-02-08 14:00:33 -07:00
|
|
|
bool
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_gciter_next(struct hash_gciter *it, struct hash_gciter_data *data)
|
2013-02-08 14:00:33 -07:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
Hmap *h;
|
|
|
|
uintptr bucket, oldbucket;
|
|
|
|
Bucket *b, *oldb;
|
|
|
|
uintptr i;
|
|
|
|
byte *k, *v;
|
|
|
|
|
|
|
|
h = it->h;
|
|
|
|
bucket = it->bucket;
|
|
|
|
b = it->b;
|
|
|
|
i = it->i;
|
2013-02-08 14:00:33 -07:00
|
|
|
|
|
|
|
data->st = nil;
|
|
|
|
data->key_data = nil;
|
|
|
|
data->val_data = nil;
|
2013-03-20 14:51:29 -06:00
|
|
|
data->indirectkey = (h->flags & IndirectKey) != 0;
|
|
|
|
data->indirectval = (h->flags & IndirectValue) != 0;
|
|
|
|
|
|
|
|
next:
|
|
|
|
switch (it->phase) {
|
|
|
|
case PHASE_BUCKETS:
|
|
|
|
if(b != nil) {
|
|
|
|
k = b->data + h->keysize * i;
|
|
|
|
v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
|
|
|
|
for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] != 0) {
|
|
|
|
data->key_data = k;
|
|
|
|
data->val_data = v;
|
|
|
|
it->bucket = bucket;
|
|
|
|
it->b = b;
|
|
|
|
it->i = i + 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b = b->overflow;
|
|
|
|
if(b != nil) {
|
|
|
|
data->st = (byte*)b;
|
|
|
|
it->bucket = bucket;
|
|
|
|
it->b = b;
|
|
|
|
it->i = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while(bucket < ((uintptr)1 << h->B)) {
|
|
|
|
if(h->oldbuckets != nil) {
|
|
|
|
oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
|
|
|
|
oldb = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
|
|
|
|
if(!evacuated(oldb)) {
|
|
|
|
// new bucket isn't valid yet
|
|
|
|
bucket++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b = (Bucket*)(h->buckets + bucket * h->bucketsize);
|
|
|
|
i = 0;
|
|
|
|
bucket++;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
it->phase = PHASE_OLD_BUCKETS;
|
|
|
|
bucket = 0;
|
|
|
|
b = nil;
|
|
|
|
goto next;
|
|
|
|
case PHASE_OLD_BUCKETS:
|
|
|
|
if(h->oldbuckets == nil) {
|
|
|
|
it->phase = PHASE_TABLE;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
if(b != nil) {
|
|
|
|
k = b->data + h->keysize * i;
|
|
|
|
v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
|
|
|
|
for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
|
|
|
|
if(b->tophash[i] != 0) {
|
|
|
|
data->key_data = k;
|
|
|
|
data->val_data = v;
|
|
|
|
it->bucket = bucket;
|
|
|
|
it->b = b;
|
|
|
|
it->i = i + 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
b = overflowptr(b);
|
|
|
|
if(b != nil) {
|
|
|
|
data->st = (byte*)b;
|
|
|
|
it->bucket = bucket;
|
|
|
|
it->b = b;
|
|
|
|
it->i = 0;
|
|
|
|
return true;
|
|
|
|
}
|
2013-02-08 14:00:33 -07:00
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if(bucket < ((uintptr)1 << (h->B - 1))) {
|
|
|
|
b = (Bucket*)(h->oldbuckets + bucket * h->bucketsize);
|
|
|
|
bucket++;
|
|
|
|
i = 0;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
it->phase = PHASE_TABLE;
|
|
|
|
goto next;
|
|
|
|
case PHASE_TABLE:
|
|
|
|
it->phase = PHASE_OLD_TABLE;
|
|
|
|
data->st = h->buckets;
|
|
|
|
return true;
|
|
|
|
case PHASE_OLD_TABLE:
|
|
|
|
it->phase = PHASE_DONE;
|
|
|
|
if(h->oldbuckets != nil) {
|
|
|
|
data->st = h->oldbuckets;
|
2013-02-08 14:00:33 -07:00
|
|
|
return true;
|
2013-03-20 14:51:29 -06:00
|
|
|
} else {
|
|
|
|
goto next;
|
2013-02-08 14:00:33 -07:00
|
|
|
}
|
|
|
|
}
|
2013-03-20 14:51:29 -06:00
|
|
|
if(it->phase != PHASE_DONE)
|
|
|
|
runtime·throw("bad phase at done");
|
2013-02-08 14:00:33 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-13 11:35:44 -07:00
|
|
|
//
|
|
|
|
/// interfaces to go runtime
|
|
|
|
//
|
|
|
|
|
2013-03-26 12:50:29 -06:00
|
|
|
void
|
|
|
|
reflect·ismapkey(Type *typ, bool ret)
|
|
|
|
{
|
|
|
|
ret = typ != nil && typ->alg->hash != runtime·nohash;
|
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2009-07-08 14:55:57 -06:00
|
|
|
Hmap*
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·makemap_c(MapType *typ, int64 hint)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
|
|
|
Hmap *h;
|
2013-03-20 14:51:29 -06:00
|
|
|
Type *key;
|
2012-05-29 12:02:29 -06:00
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
key = typ->key;
|
2009-09-08 14:46:54 -06:00
|
|
|
|
2010-05-01 14:15:42 -06:00
|
|
|
if(hint < 0 || (int32)hint != hint)
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·panicstring("makemap: size out of range");
|
2010-05-01 14:15:42 -06:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
if(key->alg->hash == runtime·nohash)
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·throw("runtime.makemap: unsupported map key type");
|
2008-11-13 11:35:44 -07:00
|
|
|
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
h = runtime·mal(sizeof(*h));
|
2012-05-24 20:41:07 -06:00
|
|
|
|
2012-10-21 15:41:32 -06:00
|
|
|
if(UseSpanType) {
|
|
|
|
if(false) {
|
|
|
|
runtime·printf("makemap %S: %p\n", *typ->string, h);
|
|
|
|
}
|
|
|
|
runtime·settype(h, (uintptr)typ | TypeInfo_Map);
|
|
|
|
}
|
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_init(typ, h, hint);
|
2009-06-30 21:02:07 -06:00
|
|
|
|
2009-01-26 16:36:39 -07:00
|
|
|
// these calculations are compiler dependent.
|
|
|
|
// figure out offsets of map call arguments.
|
2009-06-30 21:02:07 -06:00
|
|
|
|
2008-11-13 11:35:44 -07:00
|
|
|
if(debug) {
|
2011-12-05 07:40:22 -07:00
|
|
|
runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
|
2013-03-20 14:51:29 -06:00
|
|
|
h, key->size, typ->elem->size, key->alg, typ->elem->alg);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
2009-07-08 14:55:57 -06:00
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2010-05-01 14:15:42 -06:00
|
|
|
// makemap(key, val *Type, hint int64) (hmap *map[any]any);
|
2009-07-08 14:55:57 -06:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
|
2009-07-08 14:55:57 -06:00
|
|
|
{
|
2011-08-17 12:56:27 -06:00
|
|
|
ret = runtime·makemap_c(typ, hint);
|
2009-07-08 14:55:57 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
|
|
|
// func makemap(Type *mapType) (hmap *map)
|
|
|
|
void
|
|
|
|
reflect·makemap(MapType *t, Hmap *ret)
|
|
|
|
{
|
2011-08-17 12:56:27 -06:00
|
|
|
ret = runtime·makemap_c(t, 0);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2009-07-08 14:55:57 -06:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
|
2009-07-08 14:55:57 -06:00
|
|
|
{
|
|
|
|
byte *res;
|
2011-08-17 12:56:27 -06:00
|
|
|
Type *elem;
|
2009-07-08 14:55:57 -06:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
elem = t->elem;
|
2013-03-20 14:51:29 -06:00
|
|
|
if(h == nil || h->count == 0) {
|
2011-12-05 07:40:22 -07:00
|
|
|
elem->alg->copy(elem->size, av, nil);
|
2011-08-17 12:56:27 -06:00
|
|
|
*pres = false;
|
|
|
|
return;
|
|
|
|
}
|
2011-02-17 14:08:52 -07:00
|
|
|
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
if(runtime·gcwaiting)
|
|
|
|
runtime·gosched();
|
2010-01-09 10:47:45 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
res = hash_lookup(t, h, &ak);
|
|
|
|
|
|
|
|
if(res != nil) {
|
2009-07-08 14:55:57 -06:00
|
|
|
*pres = true;
|
2013-03-20 14:51:29 -06:00
|
|
|
elem->alg->copy(elem->size, av, res);
|
2009-07-08 14:55:57 -06:00
|
|
|
} else {
|
|
|
|
*pres = false;
|
2011-12-05 07:40:22 -07:00
|
|
|
elem->alg->copy(elem->size, av, nil);
|
2009-07-08 14:55:57 -06:00
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// mapaccess1(hmap *map[any]any, key any) (val any);
|
2010-03-04 16:34:25 -07:00
|
|
|
#pragma textflag 7
|
2008-11-13 11:35:44 -07:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapaccess1(MapType *t, Hmap *h, ...)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
|
|
|
byte *ak, *av;
|
2013-03-20 14:51:29 -06:00
|
|
|
byte *res;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled && h != nil)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
|
2012-10-07 12:05:32 -06:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
ak = (byte*)(&h + 1);
|
2012-05-29 12:02:29 -06:00
|
|
|
av = ak + ROUND(t->key->size, Structrnd);
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
if(h == nil || h->count == 0) {
|
|
|
|
t->elem->alg->copy(t->elem->size, av, nil);
|
|
|
|
} else {
|
|
|
|
res = hash_lookup(t, h, &ak);
|
|
|
|
t->elem->alg->copy(t->elem->size, av, res);
|
|
|
|
}
|
2010-03-23 14:00:02 -06:00
|
|
|
|
2008-11-13 11:35:44 -07:00
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("runtime.mapaccess1: map=");
|
|
|
|
runtime·printpointer(h);
|
|
|
|
runtime·prints("; key=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->key->alg->print(t->key->size, ak);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("; val=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->elem->alg->print(t->elem->size, av);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
|
2010-03-04 16:34:25 -07:00
|
|
|
#pragma textflag 7
|
2008-11-13 11:35:44 -07:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapaccess2(MapType *t, Hmap *h, ...)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
|
|
|
byte *ak, *av, *ap;
|
|
|
|
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled && h != nil)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
|
2012-10-07 12:05:32 -06:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
ak = (byte*)(&h + 1);
|
2012-05-29 12:02:29 -06:00
|
|
|
av = ak + ROUND(t->key->size, Structrnd);
|
2011-12-05 07:40:22 -07:00
|
|
|
ap = av + t->elem->size;
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapaccess(t, h, ak, av, ap);
|
2008-11-13 11:35:44 -07:00
|
|
|
|
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("runtime.mapaccess2: map=");
|
|
|
|
runtime·printpointer(h);
|
|
|
|
runtime·prints("; key=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->key->alg->print(t->key->size, ak);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("; val=");
|
2013-03-20 14:51:29 -06:00
|
|
|
t->elem->alg->print(t->elem->size, av);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("; pres=");
|
|
|
|
runtime·printbool(*ap);
|
|
|
|
runtime·prints("\n");
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
2011-08-17 12:56:27 -06:00
|
|
|
// func mapaccess(t type, h map, key iword) (val iword, pres bool)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// where an iword is the same word an interface value would use:
|
|
|
|
// the actual data if it fits, or else a pointer to the data.
|
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
{
|
|
|
|
byte *ak, *av;
|
|
|
|
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled && h != nil)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
|
2012-10-07 12:05:32 -06:00
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
if(t->key->size <= sizeof(key))
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
ak = (byte*)&key;
|
|
|
|
else
|
|
|
|
ak = (byte*)key;
|
|
|
|
val = 0;
|
|
|
|
pres = false;
|
2011-08-17 12:56:27 -06:00
|
|
|
if(t->elem->size <= sizeof(val))
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
av = (byte*)&val;
|
|
|
|
else {
|
2011-08-17 12:56:27 -06:00
|
|
|
av = runtime·mal(t->elem->size);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
val = (uintptr)av;
|
|
|
|
}
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapaccess(t, h, ak, av, &pres);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
FLUSH(&val);
|
|
|
|
FLUSH(&pres);
|
|
|
|
}
|
|
|
|
|
2009-07-08 14:55:57 -06:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
2011-02-17 14:08:52 -07:00
|
|
|
if(h == nil)
|
|
|
|
runtime·panicstring("assignment to entry in nil map");
|
|
|
|
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
if(runtime·gcwaiting)
|
|
|
|
runtime·gosched();
|
2010-01-09 10:47:45 -07:00
|
|
|
|
2009-07-08 14:55:57 -06:00
|
|
|
if(av == nil) {
|
2011-12-05 07:40:22 -07:00
|
|
|
hash_remove(t, h, ak);
|
2013-03-20 14:51:29 -06:00
|
|
|
} else {
|
|
|
|
hash_insert(t, h, ak, av);
|
2012-05-24 20:41:07 -06:00
|
|
|
}
|
2008-11-13 11:35:44 -07:00
|
|
|
|
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("mapassign: map=");
|
|
|
|
runtime·printpointer(h);
|
|
|
|
runtime·prints("; key=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->key->alg->print(t->key->size, ak);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("; val=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->elem->alg->print(t->elem->size, av);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
|
2010-03-04 16:34:25 -07:00
|
|
|
#pragma textflag 7
|
2008-11-13 11:35:44 -07:00
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapassign1(MapType *t, Hmap *h, ...)
|
2008-11-13 11:35:44 -07:00
|
|
|
{
|
|
|
|
byte *ak, *av;
|
|
|
|
|
2011-02-17 14:08:52 -07:00
|
|
|
if(h == nil)
|
|
|
|
runtime·panicstring("assignment to entry in nil map");
|
|
|
|
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
|
2011-12-05 07:40:22 -07:00
|
|
|
ak = (byte*)(&h + 1);
|
2012-05-29 12:02:29 -06:00
|
|
|
av = ak + ROUND(t->key->size, t->elem->align);
|
2008-11-13 11:35:44 -07:00
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapassign(t, h, ak, av);
|
2008-11-13 11:35:44 -07:00
|
|
|
}
|
|
|
|
|
2011-10-18 07:41:32 -06:00
|
|
|
// mapdelete(mapType *type, hmap *map[any]any, key any)
|
|
|
|
#pragma textflag 7
|
|
|
|
void
|
|
|
|
runtime·mapdelete(MapType *t, Hmap *h, ...)
|
|
|
|
{
|
|
|
|
byte *ak;
|
|
|
|
|
|
|
|
if(h == nil)
|
2012-12-13 08:48:48 -07:00
|
|
|
return;
|
2011-10-18 07:41:32 -06:00
|
|
|
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
|
2011-12-05 07:40:22 -07:00
|
|
|
ak = (byte*)(&h + 1);
|
2011-10-18 07:41:32 -06:00
|
|
|
runtime·mapassign(t, h, ak, nil);
|
|
|
|
|
|
|
|
if(debug) {
|
|
|
|
runtime·prints("mapdelete: map=");
|
|
|
|
runtime·printpointer(h);
|
|
|
|
runtime·prints("; key=");
|
2011-12-05 07:40:22 -07:00
|
|
|
t->key->alg->print(t->key->size, ak);
|
2011-10-18 07:41:32 -06:00
|
|
|
runtime·prints("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
2011-08-17 12:56:27 -06:00
|
|
|
// func mapassign(t type h map, key, val iword, pres bool)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// where an iword is the same word an interface value would use:
|
|
|
|
// the actual data if it fits, or else a pointer to the data.
|
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
{
|
|
|
|
byte *ak, *av;
|
|
|
|
|
|
|
|
if(h == nil)
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·panicstring("assignment to entry in nil map");
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
|
2011-12-05 07:40:22 -07:00
|
|
|
if(t->key->size <= sizeof(key))
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
ak = (byte*)&key;
|
|
|
|
else
|
|
|
|
ak = (byte*)key;
|
2011-12-05 07:40:22 -07:00
|
|
|
if(t->elem->size <= sizeof(val))
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
av = (byte*)&val;
|
|
|
|
else
|
|
|
|
av = (byte*)val;
|
|
|
|
if(!pres)
|
|
|
|
av = nil;
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapassign(t, h, ak, av);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
}
|
|
|
|
|
2011-08-17 12:56:27 -06:00
|
|
|
// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
|
2008-12-05 19:24:05 -07:00
|
|
|
void
|
2011-12-05 07:40:22 -07:00
|
|
|
runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
|
2008-12-05 19:24:05 -07:00
|
|
|
{
|
2009-03-23 19:32:37 -06:00
|
|
|
if(h == nil) {
|
2013-03-20 14:51:29 -06:00
|
|
|
it->key = nil;
|
2009-03-23 19:32:37 -06:00
|
|
|
return;
|
|
|
|
}
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapiterinit);
|
2011-12-05 07:40:22 -07:00
|
|
|
hash_iter_init(t, h, it);
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_next(it);
|
2008-12-05 19:24:05 -07:00
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("runtime.mapiterinit: map=");
|
|
|
|
runtime·printpointer(h);
|
|
|
|
runtime·prints("; iter=");
|
|
|
|
runtime·printpointer(it);
|
2013-03-20 14:51:29 -06:00
|
|
|
runtime·prints("; key=");
|
|
|
|
runtime·printpointer(it->key);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
|
|
|
// func mapiterinit(h map) (it iter)
|
|
|
|
void
|
2011-08-17 12:56:27 -06:00
|
|
|
reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
|
2009-07-08 14:55:57 -06:00
|
|
|
{
|
2013-03-20 14:51:29 -06:00
|
|
|
uint8 flags;
|
2012-05-24 20:41:07 -06:00
|
|
|
|
|
|
|
if(h != nil && t->key->size > sizeof(void*)) {
|
|
|
|
// reflect·mapiterkey returns pointers to key data,
|
|
|
|
// and reflect holds them, so we cannot free key data
|
2013-03-20 14:51:29 -06:00
|
|
|
// eagerly anymore.
|
|
|
|
flags = h->flags;
|
|
|
|
if(flags & IndirectKey)
|
|
|
|
flags &= ~CanFreeKey;
|
2012-05-24 20:41:07 -06:00
|
|
|
else
|
2013-03-20 14:51:29 -06:00
|
|
|
flags &= ~CanFreeBucket;
|
|
|
|
h->flags = flags;
|
2012-05-24 20:41:07 -06:00
|
|
|
}
|
|
|
|
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
it = runtime·mal(sizeof *it);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
FLUSH(&it);
|
2011-08-17 12:56:27 -06:00
|
|
|
runtime·mapiterinit(t, h, it);
|
2009-07-08 14:55:57 -06:00
|
|
|
}
|
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
// mapiternext(hiter *any);
|
|
|
|
void
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·mapiternext(struct hash_iter *it)
|
2008-12-05 19:24:05 -07:00
|
|
|
{
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
if(runtime·gcwaiting)
|
|
|
|
runtime·gosched();
|
2010-01-09 10:47:45 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
hash_next(it);
|
2008-12-05 19:24:05 -07:00
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("runtime.mapiternext: iter=");
|
|
|
|
runtime·printpointer(it);
|
2013-03-20 14:51:29 -06:00
|
|
|
runtime·prints("; key=");
|
|
|
|
runtime·printpointer(it->key);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
|
|
|
// func mapiternext(it iter)
|
|
|
|
void
|
|
|
|
reflect·mapiternext(struct hash_iter *it)
|
|
|
|
{
|
|
|
|
runtime·mapiternext(it);
|
|
|
|
}
|
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
// mapiter1(hiter *any) (key any);
|
2010-03-04 16:34:25 -07:00
|
|
|
#pragma textflag 7
|
2008-12-05 19:24:05 -07:00
|
|
|
void
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·mapiter1(struct hash_iter *it, ...)
|
2008-12-05 19:24:05 -07:00
|
|
|
{
|
|
|
|
byte *ak, *res;
|
2011-12-05 07:40:22 -07:00
|
|
|
Type *key;
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
ak = (byte*)(&it + 1);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
res = it->key;
|
2008-12-05 19:24:05 -07:00
|
|
|
if(res == nil)
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·throw("runtime.mapiter1: key:val nil pointer");
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
key = it->t->key;
|
2013-03-20 14:51:29 -06:00
|
|
|
key->alg->copy(key->size, ak, res);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
|
|
|
if(debug) {
|
2013-03-20 14:51:29 -06:00
|
|
|
runtime·prints("mapiter1: iter=");
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·printpointer(it);
|
|
|
|
runtime·prints("; map=");
|
2013-03-20 14:51:29 -06:00
|
|
|
runtime·printpointer(it->h);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-08 14:55:57 -06:00
|
|
|
bool
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·mapiterkey(struct hash_iter *it, void *ak)
|
2009-07-08 14:55:57 -06:00
|
|
|
{
|
|
|
|
byte *res;
|
2011-12-05 07:40:22 -07:00
|
|
|
Type *key;
|
2009-07-08 14:55:57 -06:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
res = it->key;
|
2009-07-08 14:55:57 -06:00
|
|
|
if(res == nil)
|
|
|
|
return false;
|
2011-12-05 07:40:22 -07:00
|
|
|
key = it->t->key;
|
2013-03-20 14:51:29 -06:00
|
|
|
key->alg->copy(key->size, ak, res);
|
2009-07-08 14:55:57 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// For reflect:
|
|
|
|
// func mapiterkey(h map) (key iword, ok bool)
|
|
|
|
// where an iword is the same word an interface value would use:
|
|
|
|
// the actual data if it fits, or else a pointer to the data.
|
|
|
|
void
|
|
|
|
reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
|
|
|
|
{
|
|
|
|
byte *res;
|
2011-12-05 07:40:22 -07:00
|
|
|
Type *tkey;
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
|
|
|
|
key = 0;
|
|
|
|
ok = false;
|
2013-03-20 14:51:29 -06:00
|
|
|
res = it->key;
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
if(res == nil) {
|
|
|
|
key = 0;
|
|
|
|
ok = false;
|
|
|
|
} else {
|
2011-12-05 07:40:22 -07:00
|
|
|
tkey = it->t->key;
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
key = 0;
|
2011-12-05 07:40:22 -07:00
|
|
|
if(tkey->size <= sizeof(key))
|
|
|
|
tkey->alg->copy(tkey->size, (byte*)&key, res);
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
else
|
|
|
|
key = (uintptr)res;
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
FLUSH(&key);
|
|
|
|
FLUSH(&ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For reflect:
|
2012-09-24 12:58:34 -06:00
|
|
|
// func maplen(h map) (len int)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
// Like len(m) in the actual language, we treat the nil map as length 0.
|
|
|
|
void
|
2012-09-24 12:58:34 -06:00
|
|
|
reflect·maplen(Hmap *h, intgo len)
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
{
|
|
|
|
if(h == nil)
|
|
|
|
len = 0;
|
2012-10-07 12:05:32 -06:00
|
|
|
else {
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
len = h->count;
|
2012-10-07 12:05:32 -06:00
|
|
|
if(raceenabled)
|
2012-11-29 23:29:41 -07:00
|
|
|
runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
|
2012-10-07 12:05:32 -06:00
|
|
|
}
|
reflect: more efficient; cannot Set result of NewValue anymore
* Reduces malloc counts during gob encoder/decoder test from 6/6 to 3/5.
The current reflect uses Set to mean two subtly different things.
(1) If you have a reflect.Value v, it might just represent
itself (as in v = reflect.NewValue(42)), in which case calling
v.Set only changed v, not any other data in the program.
(2) If you have a reflect Value v derived from a pointer
or a slice (as in x := []int{42}; v = reflect.NewValue(x).Index(0)),
v represents the value held there. Changing x[0] affects the
value returned by v.Int(), and calling v.Set affects x[0].
This was not really by design; it just happened that way.
The motivation for the new reflect implementation was
to remove mallocs. The use case (1) has an implicit malloc
inside it. If you can do:
v := reflect.NewValue(0)
v.Set(42)
i := v.Int() // i = 42
then that implies that v is referring to some underlying
chunk of memory in order to remember the 42; that is,
NewValue must have allocated some memory.
Almost all the time you are using reflect the goal is to
inspect or to change other data, not to manipulate data
stored solely inside a reflect.Value.
This CL removes use case (1), so that an assignable
reflect.Value must always refer to some other piece of data
in the program. Put another way, removing this case would
make
v := reflect.NewValue(0)
v.Set(42)
as illegal as
0 = 42.
It would also make this illegal:
x := 0
v := reflect.NewValue(x)
v.Set(42)
for the same reason. (Note that right now, v.Set(42) "succeeds"
but does not change the value of x.)
If you really wanted to make v refer to x, you'd start with &x
and dereference it:
x := 0
v := reflect.NewValue(&x).Elem() // v = *&x
v.Set(42)
It's pretty rare, except in tests, to want to use NewValue and then
call Set to change the Value itself instead of some other piece of
data in the program. I haven't seen it happen once yet while
making the tree build with this change.
For the same reasons, reflect.Zero (formerly reflect.MakeZero)
would also return an unassignable, unaddressable value.
This invalidates the (awkward) idiom:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.PointTo(v)
which, when the API changed, turned into:
pv := ... some Ptr Value we have ...
v := reflect.Zero(pv.Type().Elem())
pv.Set(v.Addr())
In both, it is far from clear what the code is trying to do. Now that
it is possible, this CL adds reflect.New(Type) Value that does the
obvious thing (same as Go's new), so this code would be replaced by:
pv := ... some Ptr Value we have ...
pv.Set(reflect.New(pv.Type().Elem()))
The changes just described can be confusing to think about,
but I believe it is because the old API was confusing - it was
conflating two different kinds of Values - and that the new API
by itself is pretty simple: you can only Set (or call Addr on)
a Value if it actually addresses some real piece of data; that is,
only if it is the result of dereferencing a Ptr or indexing a Slice.
If you really want the old behavior, you'd get it by translating:
v := reflect.NewValue(x)
into
v := reflect.New(reflect.Typeof(x)).Elem()
v.Set(reflect.NewValue(x))
Gofix will not be able to help with this, because whether
and how to change the code depends on whether the original
code meant use (1) or use (2), so the developer has to read
and think about the code.
You can see the effect on packages in the tree in
https://golang.org/cl/4423043/.
R=r
CC=golang-dev
https://golang.org/cl/4435042
2011-04-18 12:35:33 -06:00
|
|
|
FLUSH(&len);
|
|
|
|
}
|
|
|
|
|
2008-12-05 19:24:05 -07:00
|
|
|
// mapiter2(hiter *any) (key any, val any);
|
2010-03-04 16:34:25 -07:00
|
|
|
#pragma textflag 7
|
2008-12-05 19:24:05 -07:00
|
|
|
void
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·mapiter2(struct hash_iter *it, ...)
|
2008-12-05 19:24:05 -07:00
|
|
|
{
|
|
|
|
byte *ak, *av, *res;
|
2011-12-05 07:40:22 -07:00
|
|
|
MapType *t;
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2011-12-05 07:40:22 -07:00
|
|
|
t = it->t;
|
|
|
|
ak = (byte*)(&it + 1);
|
2012-05-29 12:02:29 -06:00
|
|
|
av = ak + ROUND(t->key->size, t->elem->align);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
res = it->key;
|
2008-12-05 19:24:05 -07:00
|
|
|
if(res == nil)
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·throw("runtime.mapiter2: key:val nil pointer");
|
2008-12-05 19:24:05 -07:00
|
|
|
|
2013-03-20 14:51:29 -06:00
|
|
|
t->key->alg->copy(t->key->size, ak, res);
|
|
|
|
t->elem->alg->copy(t->elem->size, av, it->value);
|
2008-12-05 19:24:05 -07:00
|
|
|
|
|
|
|
if(debug) {
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("mapiter2: iter=");
|
|
|
|
runtime·printpointer(it);
|
|
|
|
runtime·prints("; map=");
|
2013-03-20 14:51:29 -06:00
|
|
|
runtime·printpointer(it->h);
|
runtime: ,s/[a-zA-Z0-9_]+/runtime·&/g, almost
Prefix all external symbols in runtime by runtime·,
to avoid conflicts with possible symbols of the same
name in linked-in C libraries. The obvious conflicts
are printf, malloc, and free, but hide everything to
avoid future pain.
The symbols left alone are:
** known to cgo **
_cgo_free
_cgo_malloc
libcgo_thread_start
initcgo
ncgocall
** known to linker **
_rt0_$GOARCH
_rt0_$GOARCH_$GOOS
text
etext
data
end
pclntab
epclntab
symtab
esymtab
** known to C compiler **
_divv
_modv
_div64by32
etc (arch specific)
Tested on darwin/386, darwin/amd64, linux/386, linux/amd64.
Built (but not tested) for freebsd/386, freebsd/amd64, linux/arm, windows/386.
R=r, PeterGo
CC=golang-dev
https://golang.org/cl/2899041
2010-11-04 12:00:19 -06:00
|
|
|
runtime·prints("\n");
|
2008-12-05 19:24:05 -07:00
|
|
|
}
|
|
|
|
}
|