diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/cmd/gc/reflect.c | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/cmd/gc/reflect.c')
-rw-r--r-- | src/cmd/gc/reflect.c | 591 |
1 files changed, 334 insertions, 257 deletions
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index dbb447e4e..b2ff2fbc5 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -5,7 +5,9 @@ #include <u.h> #include <libc.h> #include "go.h" -#include "../../pkg/runtime/mgc0.h" +#include "../ld/textflag.h" +#include "../../runtime/mgc0.h" +#include "../../runtime/typekind.h" /* * runtime interface and reflection data structures @@ -15,7 +17,9 @@ static NodeList* signatlist; static Sym* dtypesym(Type*); static Sym* weaktypesym(Type*); static Sym* dalgsym(Type*); -static Sym* dgcsym(Type*); +static int usegcprog(Type*); +static void gengcprog(Type*, Sym**, Sym**); +static void gengcmask(Type*, uint8[16]); static int sigcmp(Sig *a, Sig *b) @@ -105,7 +109,7 @@ lsort(Sig *l, int(*f)(Sig*, Sig*)) // the given map type. This type is not visible to users - // we include only enough information to generate a correct GC // program for it. -// Make sure this stays in sync with ../../pkg/runtime/hashmap.c! +// Make sure this stays in sync with ../../runtime/hashmap.c! enum { BUCKETSIZE = 8, MAXKEYSIZE = 128, @@ -188,7 +192,7 @@ mapbucket(Type *t) // the given map type. This type is not visible to users - // we include only enough information to generate a correct GC // program for it. -// Make sure this stays in sync with ../../pkg/runtime/hashmap.c! +// Make sure this stays in sync with ../../runtime/hashmap.go! static Type* hmap(Type *t) { @@ -207,10 +211,6 @@ hmap(Type *t) offset += 4; // flags offset += 4; // hash0 offset += 1; // B - offset += 1; // keysize - offset += 1; // valuesize - offset = (offset + 1) / 2 * 2; - offset += 2; // bucketsize offset = (offset + widthptr - 1) / widthptr * widthptr; bucketsfield = typ(TFIELD); @@ -261,7 +261,7 @@ hiter(Type *t) // bptr *Bucket // other [4]uintptr // } - // must match ../../pkg/runtime/hashmap.c:hash_iter. + // must match ../../runtime/hashmap.c:hash_iter. field[0] = typ(TFIELD); field[0]->type = ptrto(t->down); field[0]->sym = mal(sizeof(Sym)); @@ -378,7 +378,7 @@ methods(Type *t) // type stored in interface word it = t; - if(it->width > widthptr) + if(!isdirectiface(it)) it = ptrto(t); // make list of methods for t, @@ -524,7 +524,7 @@ dimportpath(Pkg *p) p->pathsym = n->sym; gdatastring(n, p->path); - ggloblsym(n->sym, types[TSTRING]->width, 1, 1); + ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA); } static int @@ -550,7 +550,7 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg) /* * uncommonType - * ../../pkg/runtime/type.go:/uncommonType + * ../../runtime/type.go:/uncommonType */ static int dextratype(Sym *sym, int off, Type *t, int ptroff) @@ -564,6 +564,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) return off; // fill in *extraType pointer in header + off = rnd(off, widthptr); dsymptr(sym, ptroff, sym, off); n = 0; @@ -593,7 +594,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) // methods for(a=m; a; a=a->link) { // method - // ../../pkg/runtime/type.go:/method + // ../../runtime/type.go:/method ot = dgostringptr(s, ot, a->name); ot = dgopkgpath(s, ot, a->pkg); ot = dsymptr(s, ot, dtypesym(a->mtype), 0); @@ -611,37 +612,6 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) return ot; } -enum { - KindBool = 1, - KindInt, - KindInt8, - KindInt16, - KindInt32, - KindInt64, - KindUint, - KindUint8, - KindUint16, - KindUint32, - KindUint64, - KindUintptr, - KindFloat32, - KindFloat64, - KindComplex64, - KindComplex128, - KindArray, - KindChan, - KindFunc, - KindInterface, - KindMap, - KindPtr, - KindSlice, - KindString, - KindStruct, - KindUnsafePointer, - - KindNoPointers = 1<<7, -}; - static int kinds[] = { @@ -740,28 +710,30 @@ haspointers(Type *t) /* * commonType - * ../../pkg/runtime/type.go:/commonType + * ../../runtime/type.go:/commonType */ static int dcommontype(Sym *s, int ot, Type *t) { - int i, alg, sizeofAlg; - Sym *sptr, *algsym, *zero; + int i, alg, sizeofAlg, gcprog; + Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits; + uint8 gcmask[16]; static Sym *algarray; + uint64 x1, x2; char *p; if(ot != 0) fatal("dcommontype %d", ot); - sizeofAlg = 4*widthptr; + sizeofAlg = 2*widthptr; if(algarray == nil) algarray = pkglookup("algarray", runtimepkg); + dowidth(t); alg = algtype(t); algsym = S; if(alg < 0) algsym = dalgsym(t); - dowidth(t); if(t->sym != nil && !isptr[t->etype]) sptr = dtypesym(ptrto(t)); else @@ -808,17 +780,52 @@ dcommontype(Sym *s, int ot, Type *t) ot = duint8(s, ot, t->align); // align ot = duint8(s, ot, t->align); // fieldAlign + gcprog = usegcprog(t); i = kinds[t->etype]; if(t->etype == TARRAY && t->bound < 0) i = KindSlice; if(!haspointers(t)) i |= KindNoPointers; + if(isdirectiface(t)) + i |= KindDirectIface; + if(gcprog) + i |= KindGCProg; ot = duint8(s, ot, i); // kind if(alg >= 0) ot = dsymptr(s, ot, algarray, alg*sizeofAlg); else ot = dsymptr(s, ot, algsym, 0); - ot = dsymptr(s, ot, dgcsym(t), 0); // gc + // gc + if(gcprog) { + gengcprog(t, &gcprog0, &gcprog1); + if(gcprog0 != S) + ot = dsymptr(s, ot, gcprog0, 0); + else + ot = duintptr(s, ot, 0); + ot = dsymptr(s, ot, gcprog1, 0); + } else { + gengcmask(t, gcmask); + x1 = 0; + for(i=0; i<8; i++) + x1 = x1<<8 | gcmask[i]; + if(widthptr == 4) { + p = smprint("gcbits.%#016llux", x1); + } else { + x2 = 0; + for(i=0; i<8; i++) + x2 = x2<<8 | gcmask[i+8]; + p = smprint("gcbits.%#016llux%016llux", x1, x2); + } + sbits = pkglookup(p, runtimepkg); + if((sbits->flags & SymUniq) == 0) { + sbits->flags |= SymUniq; + for(i = 0; i < 2*widthptr; i++) + duint8(sbits, i, gcmask[i]); + ggloblsym(sbits, 2*widthptr, DUPOK|RODATA); + } + ot = dsymptr(s, ot, sbits, 0); + ot = duintptr(s, ot, 0); + } p = smprint("%-uT", t); //print("dcommontype: %s\n", p); ot = dgostringptr(s, ot, p); // string @@ -975,7 +982,9 @@ dtypesym(Type *t) tbase = t; if(isptr[t->etype] && t->sym == S && t->type->sym != S) tbase = t->type; - dupok = tbase->sym == S; + dupok = 0; + if(tbase->sym == S) + dupok = DUPOK; if(compiling_runtime && (tbase == types[tbase->etype] || @@ -1002,7 +1011,7 @@ ok: case TARRAY: if(t->bound >= 0) { - // ../../pkg/runtime/type.go:/ArrayType + // ../../runtime/type.go:/ArrayType s1 = dtypesym(t->type); t2 = typ(TARRAY); t2->type = t->type; @@ -1014,7 +1023,7 @@ ok: ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); } else { - // ../../pkg/runtime/type.go:/SliceType + // ../../runtime/type.go:/SliceType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1023,7 +1032,7 @@ ok: break; case TCHAN: - // ../../pkg/runtime/type.go:/ChanType + // ../../runtime/type.go:/ChanType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1073,14 +1082,14 @@ ok: n++; } - // ../../pkg/runtime/type.go:/InterfaceType + // ../../runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); for(a=m; a; a=a->link) { - // ../../pkg/runtime/type.go:/imethod + // ../../runtime/type.go:/imethod ot = dgostringptr(s, ot, a->name); ot = dgopkgpath(s, ot, a->pkg); ot = dsymptr(s, ot, dtypesym(a->type), 0); @@ -1088,7 +1097,7 @@ ok: break; case TMAP: - // ../../pkg/runtime/type.go:/MapType + // ../../runtime/type.go:/MapType s1 = dtypesym(t->down); s2 = dtypesym(t->type); s3 = dtypesym(mapbucket(t)); @@ -1099,16 +1108,31 @@ ok: ot = dsymptr(s, ot, s2, 0); ot = dsymptr(s, ot, s3, 0); ot = dsymptr(s, ot, s4, 0); + if(t->down->width > MAXKEYSIZE) { + ot = duint8(s, ot, widthptr); + ot = duint8(s, ot, 1); // indirect + } else { + ot = duint8(s, ot, t->down->width); + ot = duint8(s, ot, 0); // not indirect + } + if(t->type->width > MAXVALSIZE) { + ot = duint8(s, ot, widthptr); + ot = duint8(s, ot, 1); // indirect + } else { + ot = duint8(s, ot, t->type->width); + ot = duint8(s, ot, 0); // not indirect + } + ot = duint16(s, ot, mapbucket(t)->width); break; case TPTR32: case TPTR64: if(t->type->etype == TANY) { - // ../../pkg/runtime/type.go:/UnsafePointerType + // ../../runtime/type.go:/UnsafePointerType ot = dcommontype(s, ot, t); break; } - // ../../pkg/runtime/type.go:/PtrType + // ../../runtime/type.go:/PtrType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); xt = ot - 3*widthptr; @@ -1116,7 +1140,7 @@ ok: break; case TSTRUCT: - // ../../pkg/runtime/type.go:/StructType + // ../../runtime/type.go:/StructType // for security, only the exported fields. n = 0; for(t1=t->type; t1!=T; t1=t1->down) { @@ -1129,7 +1153,7 @@ ok: ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); for(t1=t->type; t1!=T; t1=t1->down) { - // ../../pkg/runtime/type.go:/structField + // ../../runtime/type.go:/structField if(t1->sym && !t1->embedded) { ot = dgostringptr(s, ot, t1->sym->name); if(exportname(t1->sym->name)) @@ -1150,7 +1174,7 @@ ok: break; } ot = dextratype(s, ot, t, xt); - ggloblsym(s, ot, dupok, 1); + ggloblsym(s, ot, dupok|RODATA); // generate typelink.foo pointing at s = type.foo. // The linker will leave a table of all the typelinks for @@ -1164,7 +1188,7 @@ ok: case TMAP: slink = typelinksym(t); dsymptr(slink, 0, s, 0); - ggloblsym(slink, widthptr, dupok, 1); + ggloblsym(slink, widthptr, dupok|RODATA); } } @@ -1236,8 +1260,7 @@ static Sym* dalgsym(Type *t) { int ot; - Sym *s, *hash, *eq; - char buf[100]; + Sym *s, *hash, *hashfunc, *eq, *eqfunc; // dalgsym is only called for a type that needs an algorithm table, // which implies that the type is comparable (or else it would use ANOEQ). @@ -1248,55 +1271,225 @@ dalgsym(Type *t) eq = typesymprefix(".eq", t); geneq(eq, t); - // ../../pkg/runtime/runtime.h:/Alg + // make Go funcs (closures) for calling hash and equal from Go + hashfunc = typesymprefix(".hashfunc", t); + dsymptr(hashfunc, 0, hash, 0); + ggloblsym(hashfunc, widthptr, DUPOK|RODATA); + eqfunc = typesymprefix(".eqfunc", t); + dsymptr(eqfunc, 0, eq, 0); + ggloblsym(eqfunc, widthptr, DUPOK|RODATA); + + // ../../runtime/alg.go:/typeAlg ot = 0; - ot = dsymptr(s, ot, hash, 0); - ot = dsymptr(s, ot, eq, 0); - ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0); - switch(t->width) { - default: - ot = dsymptr(s, ot, pkglookup("memcopy", runtimepkg), 0); - break; - case 1: - case 2: - case 4: - case 8: - case 16: - snprint(buf, sizeof buf, "memcopy%d", (int)t->width*8); - ot = dsymptr(s, ot, pkglookup(buf, runtimepkg), 0); - break; - } + ot = dsymptr(s, ot, hashfunc, 0); + ot = dsymptr(s, ot, eqfunc, 0); - ggloblsym(s, ot, 1, 1); + ggloblsym(s, ot, DUPOK|RODATA); return s; } static int -gcinline(Type *t) +usegcprog(Type *t) { - switch(t->etype) { - case TARRAY: - if(t->bound == 1) - return 1; - if(t->width <= 4*widthptr) - return 1; - break; + vlong size, nptr; + + if(!haspointers(t)) + return 0; + if(t->width == BADWIDTH) + dowidth(t); + // Calculate size of the unrolled GC mask. + nptr = (t->width+widthptr-1)/widthptr; + size = nptr; + if(size%2) + size *= 2; // repeated + size = size*gcBits/8; // 4 bits per word + // Decide whether to use unrolled GC mask or GC program. + // We could use a more elaborate condition, but this seems to work well in practice. + // For small objects GC program can't give significant reduction. + // While large objects usually contain arrays; and even if it don't + // the program uses 2-bits per word while mask uses 4-bits per word, + // so the program is still smaller. + return size > 2*widthptr; +} + +// Generates sparse GC bitmask (4 bits per word). +static void +gengcmask(Type *t, uint8 gcmask[16]) +{ + Bvec *vec; + vlong xoffset, nptr, i, j; + int half, mw; + uint8 bits, *pos; + + memset(gcmask, 0, 16); + if(!haspointers(t)) + return; + + // Generate compact mask as stacks use. + xoffset = 0; + vec = bvalloc(2*widthptr*8); + twobitwalktype1(t, &xoffset, vec); + + // Unfold the mask for the GC bitmap format: + // 4 bits per word, 2 high bits encode pointer info. + pos = (uint8*)gcmask; + nptr = (t->width+widthptr-1)/widthptr; + half = 0; + mw = 0; + // If number of words is odd, repeat the mask. + // This makes simpler handling of arrays in runtime. + for(j=0; j<=(nptr%2); j++) { + for(i=0; i<nptr; i++) { + bits = bvget(vec, i*BitsPerPointer) | bvget(vec, i*BitsPerPointer+1)<<1; + // Some fake types (e.g. Hmap) has missing fileds. + // twobitwalktype1 generates BitsDead for that holes, + // replace BitsDead with BitsScalar. + if(!mw && bits == BitsDead) + bits = BitsScalar; + mw = !mw && bits == BitsMultiWord; + bits <<= 2; + if(half) + bits <<= 4; + *pos |= bits; + half = !half; + if(!half) + pos++; + } } - return 0; } -static int -dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) +// Helper object for generation of GC programs. +typedef struct ProgGen ProgGen; +struct ProgGen { - Type *t1; - vlong o, off2, fieldoffset, i; + Sym* s; + int32 datasize; + uint8 data[256/PointersPerByte]; + vlong ot; +}; - if(t->align > 0 && (*off % t->align) != 0) - fatal("dgcsym1: invalid initial alignment, %T", t); +static void +proggeninit(ProgGen *g, Sym *s) +{ + g->s = s; + g->datasize = 0; + g->ot = 0; + memset(g->data, 0, sizeof(g->data)); +} + +static void +proggenemit(ProgGen *g, uint8 v) +{ + g->ot = duint8(g->s, g->ot, v); +} + +// Emits insData block from g->data. +static void +proggendataflush(ProgGen *g) +{ + int32 i, s; + + if(g->datasize == 0) + return; + proggenemit(g, insData); + proggenemit(g, g->datasize); + s = (g->datasize + PointersPerByte - 1)/PointersPerByte; + for(i = 0; i < s; i++) + proggenemit(g, g->data[i]); + g->datasize = 0; + memset(g->data, 0, sizeof(g->data)); +} + +static void +proggendata(ProgGen *g, uint8 d) +{ + g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); + g->datasize++; + if(g->datasize == 255) + proggendataflush(g); +} + +// Skip v bytes due to alignment, etc. +static void +proggenskip(ProgGen *g, vlong off, vlong v) +{ + vlong i; + + for(i = off; i < off+v; i++) { + if((i%widthptr) == 0) + proggendata(g, BitsScalar); + } +} + +// Emit insArray instruction. +static void +proggenarray(ProgGen *g, vlong len) +{ + int32 i; + + proggendataflush(g); + proggenemit(g, insArray); + for(i = 0; i < widthptr; i++, len >>= 8) + proggenemit(g, len); +} + +static void +proggenarrayend(ProgGen *g) +{ + proggendataflush(g); + proggenemit(g, insArrayEnd); +} + +static vlong +proggenfini(ProgGen *g) +{ + proggendataflush(g); + proggenemit(g, insEnd); + return g->ot; +} + +static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset); + +// Generates GC program for large types. +static void +gengcprog(Type *t, Sym **pgc0, Sym **pgc1) +{ + Sym *gc0, *gc1; + vlong nptr, size, ot, xoffset; + ProgGen g; + + nptr = (t->width+widthptr-1)/widthptr; + size = nptr; + if(size%2) + size *= 2; // repeated twice + size = size*PointersPerByte/8; // 4 bits per word + size++; // unroll flag in the beginning, used by runtime (see runtime.markallocated) + // emity space in BSS for unrolled program + *pgc0 = S; + // Don't generate it if it's too large, runtime will unroll directly into GC bitmap. + if(size <= MaxGCMask) { + gc0 = typesymprefix(".gc", t); + ggloblsym(gc0, size, DUPOK|NOPTR); + *pgc0 = gc0; + } + + // program in RODATA + gc1 = typesymprefix(".gcprog", t); + proggeninit(&g, gc1); + xoffset = 0; + gengcprog1(&g, t, &xoffset); + ot = proggenfini(&g); + ggloblsym(gc1, ot, DUPOK|RODATA); + *pgc1 = gc1; +} + +// Recursively walks type t and writes GC program into g. +static void +gengcprog1(ProgGen *g, Type *t, vlong *xoffset) +{ + vlong fieldoffset, i, o, n; + Type *t1; - if(t->width == BADWIDTH) - dowidth(t); - switch(t->etype) { case TINT8: case TUINT8: @@ -1314,187 +1507,71 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) case TFLOAT64: case TCOMPLEX64: case TCOMPLEX128: - *off += t->width; + proggenskip(g, *xoffset, t->width); + *xoffset += t->width; break; - case TPTR32: case TPTR64: - // NOTE: Any changes here need to be made to reflect.PtrTo as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - - // NOTE(rsc): Emitting GC_APTR here for *nonptrtype - // (pointer to non-pointer-containing type) means that - // we do not record 'nonptrtype' and instead tell the - // garbage collector to look up the type of the memory in - // type information stored in the heap. In effect we are telling - // the collector "we don't trust our information - use yours". - // It's not completely clear why we want to do this. - // It does have the effect that if you have a *SliceHeader and a *[]int - // pointing at the same actual slice header, *SliceHeader will not be - // used as an authoritative type for the memory, which is good: - // if the collector scanned the memory as type *SliceHeader, it would - // see no pointers inside but mark the block as scanned, preventing - // the seeing of pointers when we followed the *[]int pointer. - // Perhaps that kind of situation is the rationale. - if(!haspointers(t->type)) { - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - } else { - ot = duintptr(s, ot, GC_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(t->type), 0); - } - *off += t->width; - break; - case TUNSAFEPTR: case TFUNC: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - *off += t->width; - break; - - // struct Hchan* case TCHAN: - // NOTE: Any changes here need to be made to reflect.ChanOf as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_CHAN_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dtypesym(t), 0); - *off += t->width; - break; - - // struct Hmap* case TMAP: - // NOTE: Any changes here need to be made to reflect.MapOf as well. - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_PTR); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(hmap(t)), 0); - *off += t->width; + proggendata(g, BitsPointer); + *xoffset += t->width; break; - - // struct { byte *str; int32 len; } case TSTRING: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - ot = duintptr(s, ot, GC_STRING); - ot = duintptr(s, ot, *off); - *off += t->width; + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); + *xoffset += t->width; break; - - // struct { Itab* tab; void* data; } - // struct { Type* type; void* data; } // When isnilinter(t)==true case TINTER: - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - if(isnilinter(t)) { - ot = duintptr(s, ot, GC_EFACE); - ot = duintptr(s, ot, *off); - } else { - ot = duintptr(s, ot, GC_IFACE); - ot = duintptr(s, ot, *off); - } - *off += t->width; + proggendata(g, BitsMultiWord); + if(isnilinter(t)) + proggendata(g, BitsEface); + else + proggendata(g, BitsIface); + *xoffset += t->width; break; - case TARRAY: - if(t->bound < -1) - fatal("dgcsym1: invalid bound, %T", t); - if(t->type->width == BADWIDTH) - dowidth(t->type); if(isslice(t)) { - // NOTE: Any changes here need to be made to reflect.SliceOf as well. - // struct { byte* array; uint32 len; uint32 cap; } - if(*off % widthptr != 0) - fatal("dgcsym1: invalid alignment, %T", t); - if(t->type->width != 0) { - ot = duintptr(s, ot, GC_SLICE); - ot = duintptr(s, ot, *off); - ot = dsymptr(s, ot, dgcsym(t->type), 0); - } else { - ot = duintptr(s, ot, GC_APTR); - ot = duintptr(s, ot, *off); - } - *off += t->width; + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); + proggendata(g, BitsScalar); } else { - // NOTE: Any changes here need to be made to reflect.ArrayOf as well, - // at least once ArrayOf's gc info is implemented and ArrayOf is exported. - // struct { byte* array; uint32 len; uint32 cap; } - if(t->bound < 1 || !haspointers(t->type)) { - *off += t->width; - } else if(gcinline(t)) { - for(i=0; i<t->bound; i++) - ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1 + t1 = t->type; + if(t1->width == 0) { + // ignore + } if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) { + for(i = 0; i < t->bound; i++) + gengcprog1(g, t1, xoffset); + } else if(!haspointers(t1)) { + n = t->width; + n -= -*xoffset&(widthptr-1); // skip to next ptr boundary + proggenarray(g, (n+widthptr-1)/widthptr); + proggendata(g, BitsScalar); + proggenarrayend(g); + *xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width; } else { - if(stack_size < GC_STACK_CAPACITY) { - ot = duintptr(s, ot, GC_ARRAY_START); // a stack push during GC - ot = duintptr(s, ot, *off); - ot = duintptr(s, ot, t->bound); - ot = duintptr(s, ot, t->type->width); - off2 = 0; - ot = dgcsym1(s, ot, t->type, &off2, stack_size+1); // recursive call of dgcsym1 - ot = duintptr(s, ot, GC_ARRAY_NEXT); // a stack pop during GC - } else { - ot = duintptr(s, ot, GC_REGION); - ot = duintptr(s, ot, *off); - ot = duintptr(s, ot, t->width); - ot = dsymptr(s, ot, dgcsym(t), 0); - } - *off += t->width; + proggenarray(g, t->bound); + gengcprog1(g, t1, xoffset); + *xoffset += (t->bound-1)*t1->width; + proggenarrayend(g); } } break; - case TSTRUCT: o = 0; - for(t1=t->type; t1!=T; t1=t1->down) { + for(t1 = t->type; t1 != T; t1 = t1->down) { fieldoffset = t1->width; - *off += fieldoffset - o; - ot = dgcsym1(s, ot, t1->type, off, stack_size); // recursive call of dgcsym1 + proggenskip(g, *xoffset, fieldoffset - o); + *xoffset += fieldoffset - o; + gengcprog1(g, t1->type, xoffset); o = fieldoffset + t1->type->width; } - *off += t->width - o; + proggenskip(g, *xoffset, t->width - o); + *xoffset += t->width - o; break; - default: - fatal("dgcsym1: unexpected type %T", t); + fatal("gengcprog1: unexpected type, %T", t); } - - return ot; -} - -static Sym* -dgcsym(Type *t) -{ - int ot; - vlong off; - Sym *s; - - s = typesymprefix(".gc", t); - if(s->flags & SymGcgen) - return s; - s->flags |= SymGcgen; - - if(t->width == BADWIDTH) - dowidth(t); - - ot = 0; - off = 0; - ot = duintptr(s, ot, t->width); - ot = dgcsym1(s, ot, t, &off, 0); - ot = duintptr(s, ot, GC_END); - ggloblsym(s, ot, 1, 1); - - if(t->align > 0) - off = rnd(off, t->align); - if(off != t->width) - fatal("dgcsym: off=%lld, size=%lld, type %T", off, t->width, t); - - return s; } |