Commit d09afc2e authored by Jan Ziak's avatar Jan Ziak Committed by Russ Cox

gc: generate garbage collection info for types

R=rsc, nigeltao, minux.ma
CC=golang-dev
https://golang.org/cl/6290043
parent 792518c6
......@@ -347,6 +347,7 @@ enum
SymExported = 1<<2, // already written out by export
SymUniq = 1<<3,
SymSiggen = 1<<4,
SymGcgen = 1<<5,
};
struct Sym
......
......@@ -5,6 +5,7 @@
#include <u.h>
#include <libc.h>
#include "go.h"
#include "../../pkg/runtime/mgc0.h"
/*
* runtime interface and reflection data structures
......@@ -14,6 +15,7 @@ static NodeList* signatlist;
static Sym* dtypesym(Type*);
static Sym* weaktypesym(Type*);
static Sym* dalgsym(Type*);
static Sym* dgcsym(Type*);
static int
sigcmp(Sig *a, Sig *b)
......@@ -586,7 +588,7 @@ dcommontype(Sym *s, int ot, Type *t)
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
......@@ -970,3 +972,177 @@ dalgsym(Type *t)
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;
}
......@@ -42,3 +42,19 @@ func TestGcSys(t *testing.T) {
func workthegc() []byte {
return make([]byte, 1029)
}
func TestGcDeepNesting(t *testing.T) {
type T [2][2][2][2][2][2][2][2][2][2]*int
a := new(T)
// Prevent the compiler from applying escape analysis.
// This makes sure new(T) is allocated on heap, not on the stack.
t.Logf("%p", a)
a[0][0][0][0][0][0][0][0][0][0] = new(int)
*a[0][0][0][0][0][0][0][0][0][0] = 13
runtime.GC()
if *a[0][0][0][0][0][0][0][0][0][0] != 13 {
t.Fail()
}
}
// 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,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment