#include <u.h>
#include <libc.h>
#include "go.h"
+#include "../../pkg/runtime/mgc0.h"
/*
* runtime interface and reflection data structures
static Sym* dtypesym(Type*);
static Sym* weaktypesym(Type*);
static Sym* dalgsym(Type*);
+static Sym* dgcsym(Type*);
static int
sigcmp(Sig *a, Sig *b)
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
else
ot = dsymptr(s, ot, algsym, 0);
- ot = duintptr(s, ot, 0); // gc
+ ot = dsymptr(s, ot, dgcsym(t), 0); // gc
p = smprint("%-uT", t);
//print("dcommontype: %s\n", p);
ot = dgostringptr(s, ot, p); // string
return s;
}
+static int
+dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
+{
+ Type *t1;
+ vlong o, off2, fieldoffset;
+
+ if(t->align > 0 && (*off % t->align) != 0)
+ fatal("dgcsym1: invalid initial alignment, %T", t);
+
+ switch(t->etype) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TFLOAT32:
+ case TFLOAT64:
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ *off += t->width;
+ break;
+
+ case TPTR32:
+ case TPTR64:
+ if(*off % widthptr != 0)
+ fatal("dgcsym1: invalid alignment, %T", t);
+ if(!haspointers(t->type) || t->type->etype == TUINT8) {
+ 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 TCHAN:
+ 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 Hmap*
+ case TMAP:
+ if(*off % widthptr != 0)
+ fatal("dgcsym1: invalid alignment, %T", t);
+ ot = duintptr(s, ot, GC_MAP_PTR);
+ ot = duintptr(s, ot, *off);
+ ot = dsymptr(s, ot, dtypesym(t), 0);
+ *off += 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;
+ 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;
+ break;
+
+ case TARRAY:
+ if(t->bound < -1)
+ fatal("dgcsym1: invalid bound, %T", t);
+ if(isslice(t)) {
+ // 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;
+ } else {
+ if(t->bound < 1 || !haspointers(t->type)) {
+ *off += t->width;
+ } else if(t->bound == 1) {
+ ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1
+ } 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;
+ }
+ }
+ break;
+
+ case TSTRUCT:
+ o = 0;
+ 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
+ o = fieldoffset + t1->type->width;
+ }
+ *off += t->width - o;
+ break;
+
+ default:
+ fatal("dgcsym1: 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;
+
+ 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;
+}
+
--- /dev/null
+// Copyright 2012 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.
+
+// Garbage collector (GC)
+
+// GC instruction opcodes.
+//
+// The opcode of an instruction is followed by zero or more
+// arguments to the instruction.
+//
+// Meaning of arguments:
+// off Offset (in bytes) from the start of the current object
+// objgc Pointer to GC info of an object
+// len Length of an array
+// elemsize Size (in bytes) of an element
+// size Size (in bytes)
+enum {
+ GC_END, // End of object, loop or subroutine. Args: none
+ GC_PTR, // A typed pointer. Args: (off, objgc)
+ GC_APTR, // Pointer to an arbitrary object. Args: (off)
+ GC_ARRAY_START, // Start an array with a fixed length. Args: (off, len, elemsize)
+ GC_ARRAY_NEXT, // The next element of an array. Args: none
+ GC_CALL, // Call a subroutine. Args: (off, objgc)
+ GC_MAP_PTR, // Go map. Args: (off, MapType*)
+ GC_STRING, // Go string. Args: (off)
+ GC_EFACE, // interface{}. Args: (off)
+ GC_IFACE, // interface{...}. Args: (off)
+ GC_SLICE, // Go slice. Args: (off, objgc)
+ GC_REGION, // A region/part of the current object. Args: (off, size, objgc)
+
+ GC_NUM_INSTR, // Number of instruction opcodes
+};
+
+enum {
+ // Size of GC's fixed stack.
+ //
+ // The current GC implementation permits:
+ // - at most 1 stack allocation because of GC_CALL
+ // - at most GC_STACK_CAPACITY allocations because of GC_ARRAY_START
+ GC_STACK_CAPACITY = 8,
+};