Commit 67c83db6 authored by Russ Cox's avatar Russ Cox

runtime: use goc2c as much as possible

Package runtime's C functions written to be called from Go
started out written in C using carefully constructed argument
lists and the FLUSH macro to write a result back to memory.

For some functions, the appropriate parameter list ended up
being architecture-dependent due to differences in alignment,
so we added 'goc2c', which takes a .goc file containing Go func
declarations but C bodies, rewrites the Go func declaration to
equivalent C declarations for the target architecture, adds the
needed FLUSH statements, and writes out an equivalent C file.
That C file is compiled as part of package runtime.

Native Client's x86-64 support introduces the most complex
alignment rules yet, breaking many functions that could until
now be portably written in C. Using goc2c for those avoids the
breakage.

Separately, Keith's work on emitting stack information from
the C compiler would require the hand-written functions
to add #pragmas specifying how many arguments are result
parameters. Using goc2c for those avoids maintaining #pragmas.

For both reasons, use goc2c for as many Go-called C functions
as possible.

This CL is a replay of the bulk of CL 15400047 and CL 15790043,
both of which were reviewed as part of the NaCl port and are
checked in to the NaCl branch. This CL is part of bringing the
NaCl code into the main tree.

No new code here, just reformatting and occasional movement
into .h files.

LGTM=r
R=dave, alex.brainman, r
CC=golang-codereviews
https://golang.org/cl/65220044
parent 258c278e
...@@ -370,10 +370,8 @@ mkzsys(char *dir, char *file) ...@@ -370,10 +370,8 @@ mkzsys(char *dir, char *file)
} }
static char *runtimedefs[] = { static char *runtimedefs[] = {
"defs.c",
"proc.c", "proc.c",
"iface.c",
"hashmap.c",
"chan.c",
"parfor.c", "parfor.c",
}; };
......
...@@ -85,11 +85,15 @@ enum { ...@@ -85,11 +85,15 @@ enum {
String, String,
Slice, Slice,
Eface, Eface,
Complex128,
Float32,
Float64,
}; };
static struct { static struct {
char *name; char *name;
int size; int size;
int rnd; // alignment
} type_table[] = { } type_table[] = {
/* /*
* variable sized first, for easy replacement. * variable sized first, for easy replacement.
...@@ -105,6 +109,7 @@ static struct { ...@@ -105,6 +109,7 @@ static struct {
{"String", 8}, {"String", 8},
{"Slice", 12}, {"Slice", 12},
{"Eface", 8}, {"Eface", 8},
{"Complex128", 16},
/* fixed size */ /* fixed size */
{"float32", 4}, {"float32", 4},
...@@ -130,7 +135,7 @@ int structround = 4; ...@@ -130,7 +135,7 @@ int structround = 4;
static void static void
bad_eof(void) bad_eof(void)
{ {
fatal("%s:%ud: unexpected EOF\n", file, lineno); fatal("%s:%d: unexpected EOF\n", file, lineno);
} }
/* Free a list of parameters. */ /* Free a list of parameters. */
...@@ -295,9 +300,9 @@ read_package(void) ...@@ -295,9 +300,9 @@ read_package(void)
token = read_token_no_eof(); token = read_token_no_eof();
if (token == nil) if (token == nil)
fatal("%s:%ud: no token\n", file, lineno); fatal("%s:%d: no token\n", file, lineno);
if (!streq(token, "package")) { if (!streq(token, "package")) {
fatal("%s:%ud: expected \"package\", got \"%s\"\n", fatal("%s:%d: expected \"package\", got \"%s\"\n",
file, lineno, token); file, lineno, token);
} }
return read_token_no_eof(); return read_token_no_eof();
...@@ -307,6 +312,9 @@ read_package(void) ...@@ -307,6 +312,9 @@ read_package(void)
static void static void
read_preprocessor_lines(void) read_preprocessor_lines(void)
{ {
int first;
first = 1;
while (1) { while (1) {
int c; int c;
...@@ -317,6 +325,10 @@ read_preprocessor_lines(void) ...@@ -317,6 +325,10 @@ read_preprocessor_lines(void)
xungetc(); xungetc();
break; break;
} }
if(first) {
first = 0;
xputchar('\n');
}
xputchar(c); xputchar(c);
do { do {
c = getchar_update_lineno(); c = getchar_update_lineno();
...@@ -365,17 +377,24 @@ read_type(void) ...@@ -365,17 +377,24 @@ read_type(void)
/* Return the size of the given type. */ /* Return the size of the given type. */
static int static int
type_size(char *p) type_size(char *p, int *rnd)
{ {
int i; int i;
if(p[xstrlen(p)-1] == '*') if(p[xstrlen(p)-1] == '*') {
*rnd = type_table[Uintptr].rnd;
return type_table[Uintptr].size; return type_table[Uintptr].size;
}
if(streq(p, "Iface"))
p = "Eface";
for(i=0; type_table[i].name; i++) for(i=0; type_table[i].name; i++)
if(streq(type_table[i].name, p)) if(streq(type_table[i].name, p)) {
*rnd = type_table[i].rnd;
return type_table[i].size; return type_table[i].size;
fatal("%s:%ud: unknown type %s\n", file, lineno, p); }
fatal("%s:%d: unknown type %s\n", file, lineno, p);
return 0; return 0;
} }
...@@ -398,18 +417,22 @@ read_params(int *poffset) ...@@ -398,18 +417,22 @@ read_params(int *poffset)
while (1) { while (1) {
p = xmalloc(sizeof(struct params)); p = xmalloc(sizeof(struct params));
p->name = token; p->name = token;
p->type = read_type();
p->next = nil; p->next = nil;
*pp = p; *pp = p;
pp = &p->next; pp = &p->next;
size = type_size(p->type); if(streq(token, "...")) {
rnd = size; p->type = xstrdup("");
if(rnd > structround) } else {
rnd = structround; p->type = read_type();
if(offset%rnd) rnd = 0;
offset += rnd - offset%rnd; size = type_size(p->type, &rnd);
offset += size; if(rnd > structround)
rnd = structround;
if(offset%rnd)
offset += rnd - offset%rnd;
offset += size;
}
token = read_token_no_eof(); token = read_token_no_eof();
if (!streq(token, ",")) if (!streq(token, ","))
...@@ -418,7 +441,7 @@ read_params(int *poffset) ...@@ -418,7 +441,7 @@ read_params(int *poffset)
} }
} }
if (!streq(token, ")")) { if (!streq(token, ")")) {
fatal("%s:%ud: expected '('\n", fatal("%s:%d: expected '('\n",
file, lineno); file, lineno);
} }
if (poffset != nil) if (poffset != nil)
...@@ -438,6 +461,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para ...@@ -438,6 +461,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
lastline = -1; lastline = -1;
while (1) { while (1) {
read_preprocessor_lines();
token = read_token(); token = read_token();
if (token == nil) if (token == nil)
return 0; return 0;
...@@ -460,7 +484,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para ...@@ -460,7 +484,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token(); token = read_token();
if (token == nil || !streq(token, "(")) { if (token == nil || !streq(token, "(")) {
fatal("%s:%ud: expected \"(\"\n", fatal("%s:%d: expected \"(\"\n",
file, lineno); file, lineno);
} }
*params = read_params(paramwid); *params = read_params(paramwid);
...@@ -473,7 +497,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para ...@@ -473,7 +497,7 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token(); token = read_token();
} }
if (token == nil || !streq(token, "{")) { if (token == nil || !streq(token, "{")) {
fatal("%s:%ud: expected \"{\"\n", fatal("%s:%d: expected \"{\"\n",
file, lineno); file, lineno);
} }
return 1; return 1;
...@@ -501,7 +525,11 @@ write_6g_func_header(char *package, char *name, struct params *params, ...@@ -501,7 +525,11 @@ write_6g_func_header(char *package, char *name, struct params *params,
{ {
int first, n; int first, n;
bwritef(output, "void\n%s·%s(", package, name); bwritef(output, "void\n");
if(!contains(name, "·"))
bwritef(output, "%s·", package);
bwritef(output, "%s(", name);
first = 1; first = 1;
write_params(params, &first); write_params(params, &first);
...@@ -527,7 +555,8 @@ write_6g_func_trailer(struct params *rets) ...@@ -527,7 +555,8 @@ write_6g_func_trailer(struct params *rets)
struct params *p; struct params *p;
for (p = rets; p != nil; p = p->next) for (p = rets; p != nil; p = p->next)
bwritef(output, "\tFLUSH(&%s);\n", p->name); if(!streq(p->name, "..."))
bwritef(output, "\tFLUSH(&%s);\n", p->name);
bwritef(output, "}\n"); bwritef(output, "}\n");
} }
...@@ -726,6 +755,7 @@ process_file(void) ...@@ -726,6 +755,7 @@ process_file(void)
void void
goc2c(char *goc, char *c) goc2c(char *goc, char *c)
{ {
int i;
Buf in, out; Buf in, out;
binit(&in); binit(&in);
...@@ -739,13 +769,15 @@ goc2c(char *goc, char *c) ...@@ -739,13 +769,15 @@ goc2c(char *goc, char *c)
if(!gcc) { if(!gcc) {
if(streq(goarch, "amd64")) { if(streq(goarch, "amd64")) {
type_table[Uintptr].size = 8; type_table[Uintptr].size = 8;
type_table[Eface].size = 8+8;
type_table[String].size = 16;
if(use64bitint) { if(use64bitint) {
type_table[Int].size = 8; type_table[Int].size = 8;
type_table[Uint].size = 8; } else {
type_table[Int].size = 4;
} }
type_table[Slice].size = 8+2*type_table[Int].size; structround = 8;
} else if(streq(goarch, "amd64p32")) {
type_table[Uintptr].size = 4;
type_table[Int].size = 4;
structround = 8; structround = 8;
} else { } else {
// NOTE: These are set in the initializer, // NOTE: These are set in the initializer,
...@@ -753,13 +785,22 @@ goc2c(char *goc, char *c) ...@@ -753,13 +785,22 @@ goc2c(char *goc, char *c)
// previous invocation of goc2c, so we have // previous invocation of goc2c, so we have
// to restore them. // to restore them.
type_table[Uintptr].size = 4; type_table[Uintptr].size = 4;
type_table[String].size = 8;
type_table[Slice].size = 16;
type_table[Eface].size = 4+4;
type_table[Int].size = 4; type_table[Int].size = 4;
type_table[Uint].size = 4;
structround = 4; structround = 4;
} }
type_table[Uint].size = type_table[Int].size;
type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size;
type_table[Eface].size = 2*type_table[Uintptr].size;
type_table[String].size = 2*type_table[Uintptr].size;
for(i=0; i<nelem(type_table); i++)
type_table[i].rnd = type_table[i].size;
type_table[String].rnd = type_table[Uintptr].rnd;
type_table[Slice].rnd = type_table[Uintptr].rnd;
type_table[Eface].rnd = type_table[Uintptr].rnd;
type_table[Complex128].rnd = type_table[Float64].rnd;
} }
bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch); bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package runtime
#include "runtime.h" #include "runtime.h"
#include "type.h" #include "type.h"
#include "../../cmd/ld/textflag.h" #include "../../cmd/ld/textflag.h"
...@@ -505,42 +506,40 @@ void ...@@ -505,42 +506,40 @@ void
runtime·equal(Type *t, ...) runtime·equal(Type *t, ...)
{ {
byte *x, *y; byte *x, *y;
uintptr ret; bool *ret;
x = (byte*)(&t+1); x = (byte*)ROUND((uintptr)(&t+1), t->align);
y = x + t->size; y = x + t->size;
ret = (uintptr)(y + t->size); ret = (bool*)ROUND((uintptr)(y+t->size), Structrnd);
ret = ROUND(ret, Structrnd);
t->alg->equal((bool*)ret, t->size, x, y); t->alg->equal((bool*)ret, t->size, x, y);
} }
// Testing adapter for memclr // Testing adapter for memclr
void runtime·memclrBytes(Slice s) { func memclrBytes(s Slice) {
runtime·memclr(s.array, s.len); runtime·memclr(s.array, s.len);
} }
// Testing adapters for hash quality tests (see hash_test.go) // Testing adapters for hash quality tests (see hash_test.go)
void runtime·haveGoodHash(bool res) { func haveGoodHash() (res bool) {
res = use_aeshash; res = use_aeshash;
FLUSH(&res);
} }
void runtime·stringHash(String s, uintptr seed, uintptr res) {
func stringHash(s String, seed uintptr) (res uintptr) {
runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s); runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
res = seed; res = seed;
FLUSH(&res);
} }
void runtime·bytesHash(Slice s, uintptr seed, uintptr res) {
func bytesHash(s Slice, seed uintptr) (res uintptr) {
runtime·algarray[AMEM].hash(&seed, s.len, s.array); runtime·algarray[AMEM].hash(&seed, s.len, s.array);
res = seed; res = seed;
FLUSH(&res);
} }
void runtime·int32Hash(uint32 i, uintptr seed, uintptr res) {
func int32Hash(i uint32, seed uintptr) (res uintptr) {
runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i); runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
res = seed; res = seed;
FLUSH(&res);
} }
void runtime·int64Hash(uint64 i, uintptr seed, uintptr res) {
func int64Hash(i uint64, seed uintptr) (res uintptr) {
runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i); runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
res = seed; res = seed;
FLUSH(&res);
} }
...@@ -170,17 +170,6 @@ endcgo(void) ...@@ -170,17 +170,6 @@ endcgo(void)
runtime·raceacquire(&cgosync); runtime·raceacquire(&cgosync);
} }
void
runtime·NumCgoCall(int64 ret)
{
M *mp;
ret = 0;
for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
ret += mp->ncgocall;
FLUSH(&ret);
}
// Helper functions for cgo code. // Helper functions for cgo code.
void (*_cgo_malloc)(void*); void (*_cgo_malloc)(void*);
......
// 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.
#define MAXALIGN 8
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
typedef struct Select Select;
typedef struct Scase Scase;
struct SudoG
{
G* g;
uint32* selectdone;
SudoG* link;
int64 releasetime;
byte* elem; // data element
};
struct WaitQ
{
SudoG* first;
SudoG* last;
};
// The garbage collector is assuming that Hchan can only contain pointers into the stack
// and cannot contain pointers into the heap.
struct Hchan
{
uintgo qcount; // total data in the q
uintgo dataqsiz; // size of the circular q
uint16 elemsize;
uint16 pad; // ensures proper alignment of the buffer that follows Hchan in memory
bool closed;
Type* elemtype; // element type
uintgo sendx; // send index
uintgo recvx; // receive index
WaitQ recvq; // list of recv waiters
WaitQ sendq; // list of send waiters
Lock;
};
// Buffer follows Hchan immediately in memory.
// chanbuf(c, i) is pointer to the i'th slot in the buffer.
#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
enum
{
debug = 0,
// Scase.kind
CaseRecv,
CaseSend,
CaseDefault,
};
struct Scase
{
SudoG sg; // must be first member (cast to Scase)
Hchan* chan; // chan
byte* pc; // return pc
uint16 kind;
uint16 so; // vararg of selected bool
bool* receivedp; // pointer to received bool (recv2)
};
struct Select
{
uint16 tcase; // total count of scase[]
uint16 ncase; // currently filled scase[]
uint16* pollorder; // case poll order
Hchan** lockorder; // channel lock order
Scase scase[1]; // one per case (in order of appearance)
};
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package runtime
#include "runtime.h" #include "runtime.h"
typedef struct Complex128 Complex128; func complex128div(n Complex128, d Complex128) (q Complex128) {
void
runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
{
int32 ninf, dinf, nnan, dnan; int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom; float64 a, b, ratio, denom;
...@@ -58,5 +55,4 @@ runtime·complex128div(Complex128 n, Complex128 d, Complex128 q) ...@@ -58,5 +55,4 @@ runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
q.imag = (n.imag - n.real*ratio) / denom; q.imag = (n.imag - n.real*ratio) / denom;
} }
} }
FLUSH(&q);
} }
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
// in order to let the log closer set the high bit to indicate "EOF" safely // in order to let the log closer set the high bit to indicate "EOF" safely
// in the situation when normally the goroutine "owns" handoff. // in the situation when normally the goroutine "owns" handoff.
package runtime
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h" #include "arch_GOARCH.h"
#include "malloc.h" #include "malloc.h"
...@@ -428,9 +429,6 @@ breakflush: ...@@ -428,9 +429,6 @@ breakflush:
// CPUProfile returns the next cpu profile block as a []byte. // CPUProfile returns the next cpu profile block as a []byte.
// The user documentation is in debug.go. // The user documentation is in debug.go.
void func CPUProfile() (ret Slice) {
runtime·CPUProfile(Slice ret)
{
ret = getprofile(prof); ret = getprofile(prof);
FLUSH(&ret);
} }
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file is compiled by cmd/dist to obtain debug information
// about the given header files.
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h" #include "arch_GOARCH.h"
#include "malloc.h"
void #include "type.h"
·GogoBytes(int32 x) #include "race.h"
{ #include "hashmap.h"
x = RuntimeGogoBytes; #include "chan.h"
FLUSH(&x);
}
...@@ -31,11 +31,11 @@ type LFNode struct { ...@@ -31,11 +31,11 @@ type LFNode struct {
Pushcnt uintptr Pushcnt uintptr
} }
func lfstackpush(head *uint64, node *LFNode) func lfstackpush_go(head *uint64, node *LFNode)
func lfstackpop2(head *uint64) *LFNode func lfstackpop_go(head *uint64) *LFNode
var LFStackPush = lfstackpush var LFStackPush = lfstackpush_go
var LFStackPop = lfstackpop2 var LFStackPop = lfstackpop_go
type ParFor struct { type ParFor struct {
body *byte body *byte
...@@ -48,17 +48,17 @@ type ParFor struct { ...@@ -48,17 +48,17 @@ type ParFor struct {
wait bool wait bool
} }
func parforalloc2(nthrmax uint32) *ParFor func newParFor(nthrmax uint32) *ParFor
func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) func parForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
func parfordo(desc *ParFor) func parForDo(desc *ParFor)
func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr) func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr)
var NewParFor = parforalloc2 var NewParFor = newParFor
var ParForSetup = parforsetup2 var ParForSetup = parForSetup
var ParForDo = parfordo var ParForDo = parForDo
func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) { func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
begin, end := parforiters(desc, uintptr(tid)) begin, end := parForIters(desc, uintptr(tid))
return uint32(begin), uint32(end) return uint32(begin), uint32(end)
} }
...@@ -80,11 +80,13 @@ var BytesHash = bytesHash ...@@ -80,11 +80,13 @@ var BytesHash = bytesHash
var Int32Hash = int32Hash var Int32Hash = int32Hash
var Int64Hash = int64Hash var Int64Hash = int64Hash
func GogoBytes() int32
var hashLoad float64 // declared in hashmap.c var hashLoad float64 // declared in hashmap.c
var HashLoad = &hashLoad var HashLoad = &hashLoad
func memclrBytes(b []byte) func memclrBytes(b []byte)
var MemclrBytes = memclrBytes var MemclrBytes = memclrBytes
func gogoBytes() int32
var GogoBytes = gogoBytes
// 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.
// 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
{
// Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
// ../reflect/type.go. Don't change this structure without also changing that code!
uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (or special mark below)
Bucket *overflow; // overflow bucket, if any
uint64 data[1]; // BUCKETSIZE keys followed by BUCKETSIZE values
};
// 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.
// tophash values. We reserve a few possibilities for special marks.
// Each bucket (including its overflow buckets, if any) will have either all or none of its
// entries in the Evacuated* states (except during the evacuate() method, which only happens
// during map writes and thus no one else can observe the map during that time).
enum
{
Empty = 0, // cell is empty
EvacuatedEmpty = 1, // cell is empty, bucket is evacuated.
EvacuatedX = 2, // key/value is valid. Entry has been evacuated to first half of larger table.
EvacuatedY = 3, // same as above, but evacuated to second half of larger table.
MinTopHash = 4, // minimum tophash for a normal filled cell.
};
#define evacuated(b) ((b)->tophash[0] > Empty && (b)->tophash[0] < MinTopHash)
struct Hmap
{
// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
// ../reflect/type.go. Don't change this structure without also changing that code!
uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
uint32 flags;
uint32 hash0; // hash seed
uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
uint8 keysize; // key size in bytes
uint8 valuesize; // value size in bytes
uint16 bucketsize; // bucket size in bytes
byte *buckets; // array of 2^B Buckets. may be nil if count==0.
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)
};
// possible flags
enum
{
IndirectKey = 1, // storing pointers to keys
IndirectValue = 2, // storing pointers to values
Iterator = 4, // there may be an iterator using buckets
OldIterator = 8, // there may be an iterator using oldbuckets
};
// 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))
// If you modify Hiter, also change cmd/gc/reflect.c to indicate
// the layout of this structure.
struct Hiter
{
uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
uint8* value; // Must be in second position (see cmd/gc/range.c).
MapType *t;
Hmap *h;
byte *buckets; // bucket ptr at hash_iter initialization time
struct Bucket *bptr; // current bucket
uint8 offset; // intra-bucket offset to start from during iteration (should be big enough to hold BUCKETSIZE-1)
bool done;
// state of table at time iterator is initialized
uint8 B;
// iter state
uintptr bucket;
uintptr i;
intptr check_bucket;
};
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
// +build ignore // +build ignore
// Because this file is #included, it cannot be processed by goc2c,
// so we have to handle the Go resuts ourselves.
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void void
HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value) HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package runtime
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h" #include "arch_GOARCH.h"
#include "type.h" #include "type.h"
...@@ -9,15 +10,11 @@ ...@@ -9,15 +10,11 @@
#include "malloc.h" #include "malloc.h"
#include "../../cmd/ld/textflag.h" #include "../../cmd/ld/textflag.h"
void func printiface(i Iface) {
runtime·printiface(Iface i)
{
runtime·printf("(%p,%p)", i.tab, i.data); runtime·printf("(%p,%p)", i.tab, i.data);
} }
void func printeface(e Eface) {
runtime·printeface(Eface e)
{
runtime·printf("(%p,%p)", e.type, e.data); runtime·printf("(%p,%p)", e.type, e.data);
} }
...@@ -172,22 +169,13 @@ copyout(Type *t, void **src, void *dst) ...@@ -172,22 +169,13 @@ copyout(Type *t, void **src, void *dst)
} }
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func typ2Itab(t *Type, inter *InterfaceType, cache **Itab) (tab *Itab) {
runtime·typ2Itab(Type *t, InterfaceType *inter, Itab **cache, Itab *ret)
{
Itab *tab;
tab = itab(inter, t, 0); tab = itab(inter, t, 0);
runtime·atomicstorep(cache, tab); runtime·atomicstorep(cache, tab);
ret = tab;
FLUSH(&ret);
} }
// func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func convT2I(t *Type, inter *InterfaceType, cache **Itab, elem *byte) (ret Iface) {
runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, byte *elem, Iface ret)
{
Itab *tab; Itab *tab;
tab = runtime·atomicloadp(cache); tab = runtime·atomicloadp(cache);
...@@ -197,30 +185,19 @@ runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, byte *elem, Iface ...@@ -197,30 +185,19 @@ runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, byte *elem, Iface
} }
ret.tab = tab; ret.tab = tab;
copyin(t, elem, &ret.data); copyin(t, elem, &ret.data);
FLUSH(&ret);
} }
// func convT2E(typ *byte, elem *any) (ret any)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func convT2E(t *Type, elem *byte) (ret Eface) {
runtime·convT2E(Type *t, byte *elem, Eface ret)
{
ret.type = t; ret.type = t;
copyin(t, elem, &ret.data); copyin(t, elem, &ret.data);
FLUSH(&ret);
} }
static void assertI2Tret(Type *t, Iface i, byte *ret); static void assertI2Tret(Type *t, Iface i, byte *ret);
// func ifaceI2T(typ *byte, iface any) (ret any)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func assertI2T(t *Type, i Iface) (ret byte, ...) {
runtime·assertI2T(Type *t, Iface i, ...) assertI2Tret(t, i, &ret);
{
byte *ret;
ret = (byte*)(&i+1);
assertI2Tret(t, i, ret);
} }
static void static void
...@@ -245,47 +222,33 @@ assertI2Tret(Type *t, Iface i, byte *ret) ...@@ -245,47 +222,33 @@ assertI2Tret(Type *t, Iface i, byte *ret)
copyout(t, &i.data, ret); copyout(t, &i.data, ret);
} }
// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func assertI2T2(t *Type, i Iface) (ret byte, ...) {
runtime·assertI2T2(Type *t, Iface i, ...)
{
byte *ret;
bool *ok; bool *ok;
int32 wid; int32 wid;
ret = (byte*)(&i+1);
wid = t->size; wid = t->size;
ok = (bool*)(ret + wid); ok = (bool*)(&ret + wid);
if(i.tab == nil || i.tab->type != t) { if(i.tab == nil || i.tab->type != t) {
*ok = false; *ok = false;
runtime·memclr(ret, wid); runtime·memclr(&ret, wid);
return; return;
} }
*ok = true; *ok = true;
copyout(t, &i.data, ret); copyout(t, &i.data, &ret);
} }
void func assertI2TOK(t *Type, i Iface) (ok bool) {
runtime·assertI2TOK(Type *t, Iface i, bool ok)
{
ok = i.tab!=nil && i.tab->type==t; ok = i.tab!=nil && i.tab->type==t;
FLUSH(&ok);
} }
static void assertE2Tret(Type *t, Eface e, byte *ret); static void assertE2Tret(Type *t, Eface e, byte *ret);
// func ifaceE2T(typ *byte, iface any) (ret any)
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func assertE2T(t *Type, e Eface) (ret byte, ...) {
runtime·assertE2T(Type *t, Eface e, ...) assertE2Tret(t, e, &ret);
{
byte *ret;
ret = (byte*)(&e+1);
assertE2Tret(t, e, ret);
} }
static void static void
...@@ -308,40 +271,29 @@ assertE2Tret(Type *t, Eface e, byte *ret) ...@@ -308,40 +271,29 @@ assertE2Tret(Type *t, Eface e, byte *ret)
copyout(t, &e.data, ret); copyout(t, &e.data, ret);
} }
// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func assertE2T2(t *Type, e Eface) (ret byte, ...) {
runtime·assertE2T2(Type *t, Eface e, ...)
{
byte *ret;
bool *ok; bool *ok;
int32 wid; int32 wid;
ret = (byte*)(&e+1);
wid = t->size; wid = t->size;
ok = (bool*)(ret + wid); ok = (bool*)(&ret + wid);
if(t != e.type) { if(t != e.type) {
*ok = false; *ok = false;
runtime·memclr(ret, wid); runtime·memclr(&ret, wid);
return; return;
} }
*ok = true; *ok = true;
copyout(t, &e.data, ret); copyout(t, &e.data, &ret);
} }
void func assertE2TOK(t *Type, e Eface) (ok bool) {
runtime·assertE2TOK(Type *t, Eface e, bool ok)
{
ok = t==e.type; ok = t==e.type;
FLUSH(&ok);
} }
// func convI2E(elem any) (ret any) func convI2E(i Iface) (ret Eface) {
void
runtime·convI2E(Iface i, Eface ret)
{
Itab *tab; Itab *tab;
ret.data = i.data; ret.data = i.data;
...@@ -349,13 +301,9 @@ runtime·convI2E(Iface i, Eface ret) ...@@ -349,13 +301,9 @@ runtime·convI2E(Iface i, Eface ret)
ret.type = nil; ret.type = nil;
else else
ret.type = tab->type; ret.type = tab->type;
FLUSH(&ret);
} }
// func ifaceI2E(typ *byte, iface any) (ret any) func assertI2E(inter *InterfaceType, i Iface) (ret Eface) {
void
runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
{
Itab *tab; Itab *tab;
Eface err; Eface err;
...@@ -369,13 +317,9 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret) ...@@ -369,13 +317,9 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
} }
ret.data = i.data; ret.data = i.data;
ret.type = tab->type; ret.type = tab->type;
FLUSH(&ret);
} }
// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool) func assertI2E2(inter *InterfaceType, i Iface) (ret Eface, ok bool) {
void
runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
{
Itab *tab; Itab *tab;
USED(inter); USED(inter);
...@@ -388,14 +332,9 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok) ...@@ -388,14 +332,9 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
ok = 1; ok = 1;
} }
ret.data = i.data; ret.data = i.data;
FLUSH(&ret);
FLUSH(&ok);
} }
// func convI2I(typ *byte, elem any) (ret any) func convI2I(inter *InterfaceType, i Iface) (ret Iface) {
void
runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
{
Itab *tab; Itab *tab;
ret.data = i.data; ret.data = i.data;
...@@ -405,7 +344,6 @@ runtime·convI2I(InterfaceType* inter, Iface i, Iface ret) ...@@ -405,7 +344,6 @@ runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
ret.tab = tab; ret.tab = tab;
else else
ret.tab = itab(inter, tab->type, 0); ret.tab = itab(inter, tab->type, 0);
FLUSH(&ret);
} }
void void
...@@ -426,17 +364,11 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret) ...@@ -426,17 +364,11 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
ret->tab = itab(inter, tab->type, 0); ret->tab = itab(inter, tab->type, 0);
} }
// func ifaceI2I(sigi *byte, iface any) (ret any) func assertI2I(inter *InterfaceType, i Iface) (ret Iface) {
void
runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
{
runtime·ifaceI2I(inter, i, &ret); runtime·ifaceI2I(inter, i, &ret);
} }
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool) func assertI2I2(inter *InterfaceType, i Iface) (ret Iface, ok bool) {
void
runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
Itab *tab; Itab *tab;
tab = i.tab; tab = i.tab;
...@@ -449,8 +381,6 @@ runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok) ...@@ -449,8 +381,6 @@ runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
ret.tab = 0; ret.tab = 0;
ok = 0; ok = 0;
} }
FLUSH(&ret);
FLUSH(&ok);
} }
void void
...@@ -481,25 +411,15 @@ runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret) ...@@ -481,25 +411,15 @@ runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
return true; return true;
} }
// For reflect func reflect·ifaceE2I(inter *InterfaceType, e Eface, dst *Iface) {
// func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
void
reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
{
runtime·ifaceE2I(inter, e, dst); runtime·ifaceE2I(inter, e, dst);
} }
// func ifaceE2I(sigi *byte, iface any) (ret any) func assertE2I(inter *InterfaceType, e Eface) (ret Iface) {
void
runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
{
runtime·ifaceE2I(inter, e, &ret); runtime·ifaceE2I(inter, e, &ret);
} }
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool) func assertE2I2(inter *InterfaceType, e Eface) (ret Iface, ok bool) {
void
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
if(e.type == nil) { if(e.type == nil) {
ok = 0; ok = 0;
ret.data = nil; ret.data = nil;
...@@ -511,14 +431,9 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) ...@@ -511,14 +431,9 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
ok = 1; ok = 1;
ret.data = e.data; ret.data = e.data;
} }
FLUSH(&ret);
FLUSH(&ok);
} }
// func ifaceE2E(typ *byte, iface any) (ret any) func assertE2E(inter *InterfaceType, e Eface) (ret Eface) {
void
runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
{
Type *t; Type *t;
Eface err; Eface err;
...@@ -531,18 +446,12 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret) ...@@ -531,18 +446,12 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
runtime·panic(err); runtime·panic(err);
} }
ret = e; ret = e;
FLUSH(&ret);
} }
// func ifaceE2E2(iface any) (ret any, ok bool) func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) {
void
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
USED(inter); USED(inter);
ret = e; ret = e;
ok = e.type != nil; ok = e.type != nil;
FLUSH(&ret);
FLUSH(&ok);
} }
static uintptr static uintptr
...@@ -630,81 +539,53 @@ runtime·efaceeq_c(Eface e1, Eface e2) ...@@ -630,81 +539,53 @@ runtime·efaceeq_c(Eface e1, Eface e2)
return ifaceeq1(e1.data, e2.data, e1.type); return ifaceeq1(e1.data, e2.data, e1.type);
} }
// ifaceeq(i1 any, i2 any) (ret bool); func ifaceeq(i1 Iface, i2 Iface) (ret bool) {
void
runtime·ifaceeq(Iface i1, Iface i2, bool ret)
{
ret = runtime·ifaceeq_c(i1, i2); ret = runtime·ifaceeq_c(i1, i2);
FLUSH(&ret);
} }
// efaceeq(i1 any, i2 any) (ret bool) func efaceeq(e1 Eface, e2 Eface) (ret bool) {
void
runtime·efaceeq(Eface e1, Eface e2, bool ret)
{
ret = runtime·efaceeq_c(e1, e2); ret = runtime·efaceeq_c(e1, e2);
FLUSH(&ret);
} }
// ifacethash(i1 any) (ret uint32); func ifacethash(i1 Iface) (ret uint32) {
void
runtime·ifacethash(Iface i1, uint32 ret)
{
Itab *tab; Itab *tab;
ret = 0; ret = 0;
tab = i1.tab; tab = i1.tab;
if(tab != nil) if(tab != nil)
ret = tab->type->hash; ret = tab->type->hash;
FLUSH(&ret);
} }
// efacethash(e1 any) (ret uint32) func efacethash(e1 Eface) (ret uint32) {
void
runtime·efacethash(Eface e1, uint32 ret)
{
Type *t; Type *t;
ret = 0; ret = 0;
t = e1.type; t = e1.type;
if(t != nil) if(t != nil)
ret = t->hash; ret = t->hash;
FLUSH(&ret);
} }
void func reflect·unsafe_Typeof(e Eface) (ret Eface) {
reflect·unsafe_Typeof(Eface e, Eface ret)
{
if(e.type == nil) { if(e.type == nil) {
ret.type = nil; ret.type = nil;
ret.data = nil; ret.data = nil;
} else { } else {
ret = *(Eface*)(e.type); ret = *(Eface*)(e.type);
} }
FLUSH(&ret);
} }
void func reflect·unsafe_New(t *Type) (ret *byte) {
reflect·unsafe_New(Type *t, void *ret)
{
ret = runtime·cnew(t); ret = runtime·cnew(t);
FLUSH(&ret);
} }
void func reflect·unsafe_NewArray(t *Type, n int) (ret *byte) {
reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
{
ret = runtime·cnewarray(t, n); ret = runtime·cnewarray(t, n);
FLUSH(&ret);
} }
void func reflect·typelinks() (ret Slice) {
reflect·typelinks(Slice ret)
{
extern Type *typelink[], *etypelink[]; extern Type *typelink[], *etypelink[];
static int32 first = 1; static int32 first = 1;
ret.array = (byte*)typelink; ret.array = (byte*)typelink;
ret.len = etypelink - typelink; ret.len = etypelink - typelink;
ret.cap = ret.len; ret.cap = ret.len;
FLUSH(&ret);
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// Lock-free stack. // Lock-free stack.
package runtime
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h" #include "arch_GOARCH.h"
...@@ -71,9 +72,10 @@ runtime·lfstackpop(uint64 *head) ...@@ -71,9 +72,10 @@ runtime·lfstackpop(uint64 *head)
} }
} }
void func lfstackpush_go(head *uint64, node *LFNode) {
runtime·lfstackpop2(uint64 *head, LFNode *node) runtime·lfstackpush(head, node);
{ }
func lfstackpop_go(head *uint64) (node *LFNode) {
node = runtime·lfstackpop(head); node = runtime·lfstackpop(head);
FLUSH(&node);
} }
...@@ -834,11 +834,8 @@ runtime·mal(uintptr n) ...@@ -834,11 +834,8 @@ runtime·mal(uintptr n)
} }
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func new(typ *Type) (ret *uint8) {
runtime·new(Type *typ, uint8 *ret)
{
ret = runtime·mallocgc(typ->size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0); ret = runtime·mallocgc(typ->size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
FLUSH(&ret);
} }
static void* static void*
......
...@@ -575,3 +575,4 @@ void runtime·gc_m_ptr(Eface*); ...@@ -575,3 +575,4 @@ void runtime·gc_m_ptr(Eface*);
void runtime·gc_itab_ptr(Eface*); void runtime·gc_itab_ptr(Eface*);
void runtime·memorydump(void); void runtime·memorydump(void);
int32 runtime·setgcpercent(int32);
...@@ -1152,6 +1152,7 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1152,6 +1152,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
continue; continue;
default: default:
runtime·printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
runtime·throw("scanblock: invalid GC instruction"); runtime·throw("scanblock: invalid GC instruction");
return; return;
} }
...@@ -2492,9 +2493,10 @@ runtime∕debug·readGCStats(Slice *pauses) ...@@ -2492,9 +2493,10 @@ runtime∕debug·readGCStats(Slice *pauses)
pauses->len = n+3; pauses->len = n+3;
} }
void int32
runtimedebug·setGCPercent(intgo in, intgo out) runtime·setgcpercent(int32 in) {
{ int32 out;
runtime·lock(&runtime·mheap); runtime·lock(&runtime·mheap);
if(gcpercent == GcpercentUnknown) if(gcpercent == GcpercentUnknown)
gcpercent = readgogc(); gcpercent = readgogc();
...@@ -2503,7 +2505,7 @@ runtime∕debug·setGCPercent(intgo in, intgo out) ...@@ -2503,7 +2505,7 @@ runtime∕debug·setGCPercent(intgo in, intgo out)
in = -1; in = -1;
gcpercent = in; gcpercent = in;
runtime·unlock(&runtime·mheap); runtime·unlock(&runtime·mheap);
FLUSH(&out); return out;
} }
static void static void
......
...@@ -33,15 +33,6 @@ runtime·parforalloc(uint32 nthrmax) ...@@ -33,15 +33,6 @@ runtime·parforalloc(uint32 nthrmax)
return desc; return desc;
} }
// For testing from Go
// func parforalloc2(nthrmax uint32) *ParFor
void
runtime·parforalloc2(uint32 nthrmax, ParFor *desc)
{
desc = runtime·parforalloc(nthrmax);
FLUSH(&desc);
}
void void
runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32)) runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
{ {
...@@ -75,14 +66,6 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, ...@@ -75,14 +66,6 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait,
} }
} }
// For testing from Go
// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
void
runtime·parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
{
runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
}
void void
runtime·parfordo(ParFor *desc) runtime·parfordo(ParFor *desc)
{ {
...@@ -207,13 +190,10 @@ exit: ...@@ -207,13 +190,10 @@ exit:
me->nsleep = 0; me->nsleep = 0;
} }
// For testing from Go // For testing from Go.
// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
void void
runtime·parforiters(ParFor *desc, uintptr tid, uintptr start, uintptr end) runtime·parforiters(ParFor *desc, uintptr tid, uintptr *start, uintptr *end)
{ {
start = (uint32)desc->thr[tid].pos; *start = (uint32)desc->thr[tid].pos;
end = (uint32)(desc->thr[tid].pos>>32); *end = (uint32)(desc->thr[tid].pos>>32);
FLUSH(&start);
FLUSH(&end);
} }
...@@ -279,31 +279,31 @@ func TestBlockProfile(t *testing.T) { ...@@ -279,31 +279,31 @@ func TestBlockProfile(t *testing.T) {
tests := [...]TestCase{ tests := [...]TestCase{
{"chan recv", blockChanRecv, ` {"chan recv", blockChanRecv, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+ # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`}, `},
{"chan send", blockChanSend, ` {"chan send", blockChanSend, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
# 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+ # 0x[0-9,a-f]+ runtime\.chansend1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`}, `},
{"chan close", blockChanClose, ` {"chan close", blockChanClose, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
# 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+ # 0x[0-9,a-f]+ runtime\.chanrecv1\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`}, `},
{"select recv async", blockSelectRecvAsync, ` {"select recv async", blockSelectRecvAsync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+ # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`}, `},
{"select send sync", blockSelectSendSync, ` {"select send sync", blockSelectSendSync, `
[0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
# 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.c:[0-9]+ # 0x[0-9,a-f]+ runtime\.selectgo\+0x[0-9,a-f]+ .*/src/pkg/runtime/chan.goc:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
# 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+ # 0x[0-9,a-f]+ runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+ .*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
`}, `},
......
...@@ -69,61 +69,61 @@ static void ...@@ -69,61 +69,61 @@ static void
vprintf(int8 *s, byte *base) vprintf(int8 *s, byte *base)
{ {
int8 *p, *lp; int8 *p, *lp;
uintptr arg, narg; uintptr arg, siz;
byte *v; byte *v;
//runtime·lock(&debuglock); //runtime·lock(&debuglock);
lp = p = s; lp = p = s;
arg = 0; arg = (uintptr)base;
for(; *p; p++) { for(; *p; p++) {
if(*p != '%') if(*p != '%')
continue; continue;
if(p > lp) if(p > lp)
gwrite(lp, p-lp); gwrite(lp, p-lp);
p++; p++;
narg = 0; siz = 0;
switch(*p) { switch(*p) {
case 't': case 't':
case 'c': case 'c':
narg = arg + 1; siz = 1;
break; break;
case 'd': // 32-bit case 'd': // 32-bit
case 'x': case 'x':
arg = ROUND(arg, 4); arg = ROUND(arg, 4);
narg = arg + 4; siz = 4;
break; break;
case 'D': // 64-bit case 'D': // 64-bit
case 'U': case 'U':
case 'X': case 'X':
case 'f': case 'f':
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + 8; siz = 8;
break; break;
case 'C': case 'C':
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + 16; siz = 16;
break; break;
case 'p': // pointer-sized case 'p': // pointer-sized
case 's': case 's':
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + sizeof(uintptr); siz = sizeof(uintptr);
break; break;
case 'S': // pointer-aligned but bigger case 'S': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + sizeof(String); siz = sizeof(String);
break; break;
case 'a': // pointer-aligned but bigger case 'a': // pointer-aligned but bigger
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + sizeof(Slice); siz = sizeof(Slice);
break; break;
case 'i': // pointer-aligned but bigger case 'i': // pointer-aligned but bigger
case 'e': case 'e':
arg = ROUND(arg, sizeof(uintptr)); arg = ROUND(arg, sizeof(uintptr));
narg = arg + sizeof(Eface); siz = sizeof(Eface);
break; break;
} }
v = base+arg; v = (byte*)arg;
switch(*p) { switch(*p) {
case 'a': case 'a':
runtime·printslice(*(Slice*)v); runtime·printslice(*(Slice*)v);
...@@ -171,7 +171,7 @@ vprintf(int8 *s, byte *base) ...@@ -171,7 +171,7 @@ vprintf(int8 *s, byte *base)
runtime·printhex(*(uint64*)v); runtime·printhex(*(uint64*)v);
break; break;
} }
arg = narg; arg += siz;
lp = p+1; lp = p+1;
} }
if(p > lp) if(p > lp)
...@@ -348,7 +348,7 @@ runtime·printhex(uint64 v) ...@@ -348,7 +348,7 @@ runtime·printhex(uint64 v)
void void
runtime·printpointer(void *p) runtime·printpointer(void *p)
{ {
runtime·printhex((uint64)p); runtime·printhex((uintptr)p);
} }
void void
...@@ -373,11 +373,3 @@ runtime·printnl(void) ...@@ -373,11 +373,3 @@ runtime·printnl(void)
{ {
gwrite("\n", 1); gwrite("\n", 1);
} }
void
runtime·typestring(Eface e, String s)
{
s = *e.type->string;
FLUSH(&s);
}
...@@ -2033,21 +2033,6 @@ runtime·lockedOSThread(void) ...@@ -2033,21 +2033,6 @@ runtime·lockedOSThread(void)
return g->lockedm != nil && m->lockedg != nil; return g->lockedm != nil && m->lockedg != nil;
} }
// for testing of callbacks
void
runtime·golockedOSThread(bool ret)
{
ret = runtime·lockedOSThread();
FLUSH(&ret);
}
void
runtime·NumGoroutine(intgo ret)
{
ret = runtime·gcount();
FLUSH(&ret);
}
int32 int32
runtime·gcount(void) runtime·gcount(void)
{ {
...@@ -3050,15 +3035,17 @@ runtime·topofstack(Func *f) ...@@ -3050,15 +3035,17 @@ runtime·topofstack(Func *f)
(runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp); (runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
} }
void int32
runtimedebug·setMaxThreads(intgo in, intgo out) runtime·setmaxthreads(int32 in)
{ {
int32 out;
runtime·lock(&runtime·sched); runtime·lock(&runtime·sched);
out = runtime·sched.maxmcount; out = runtime·sched.maxmcount;
runtime·sched.maxmcount = in; runtime·sched.maxmcount = in;
checkmcount(); checkmcount();
runtime·unlock(&runtime·sched); runtime·unlock(&runtime·sched);
FLUSH(&out); return out;
} }
static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
...@@ -3081,23 +3068,3 @@ haveexperiment(int8 *name) ...@@ -3081,23 +3068,3 @@ haveexperiment(int8 *name)
} }
return 0; return 0;
} }
// func runtime_procPin() int
void
sync·runtime_procPin(intgo p)
{
M *mp;
mp = m;
// Disable preemption.
mp->locks++;
p = mp->p->id;
FLUSH(&p);
}
// func runtime_procUnpin()
void
sync·runtime_procUnpin(void)
{
m->locks--;
}
// Copyright 2013 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.
package runtimedebug
#include "runtime.h"
#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
func setMaxStack(in int) (out int) {
out = runtime·maxstacksize;
runtime·maxstacksize = in;
}
func setGCPercent(in int) (out int) {
out = runtime·setgcpercent(in);
}
func setMaxThreads(in int) (out int) {
out = runtime·setmaxthreads(in);
}
...@@ -10,14 +10,6 @@ enum { ...@@ -10,14 +10,6 @@ enum {
maxround = sizeof(uintptr), maxround = sizeof(uintptr),
}; };
/*
* We assume that all architectures turn faults and the like
* into apparent calls to runtime.sigpanic. If we see a "call"
* to runtime.sigpanic, we do not back up the PC to find the
* line number of the CALL instruction, because there is no CALL.
*/
void runtime·sigpanic(void);
// The GOTRACEBACK environment variable controls the // The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting. // behavior of a Go program that is crashing and exiting.
// GOTRACEBACK=0 suppress all tracebacks // GOTRACEBACK=0 suppress all tracebacks
...@@ -130,16 +122,6 @@ runtime·goenvs_unix(void) ...@@ -130,16 +122,6 @@ runtime·goenvs_unix(void)
syscall·envs.cap = n; syscall·envs.cap = n;
} }
void
runtime·getgoroot(String out)
{
byte *p;
p = runtime·getenv("GOROOT");
out = runtime·gostringnocopy(p);
FLUSH(&out);
}
int32 int32
runtime·atoi(byte *p) runtime·atoi(byte *p)
{ {
...@@ -276,62 +258,6 @@ runtime·check(void) ...@@ -276,62 +258,6 @@ runtime·check(void)
TestAtomic64(); TestAtomic64();
} }
void
runtime·Caller(intgo skip, uintptr retpc, String retfile, intgo retline, bool retbool)
{
Func *f, *g;
uintptr pc;
uintptr rpc[2];
/*
* Ask for two PCs: the one we were asked for
* and what it called, so that we can see if it
* "called" sigpanic.
*/
retpc = 0;
if(runtime·callers(1+skip-1, rpc, 2) < 2) {
retfile = runtime·emptystring;
retline = 0;
retbool = false;
} else if((f = runtime·findfunc(rpc[1])) == nil) {
retfile = runtime·emptystring;
retline = 0;
retbool = true; // have retpc at least
} else {
retpc = rpc[1];
pc = retpc;
g = runtime·findfunc(rpc[0]);
if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
pc--;
retline = runtime·funcline(f, pc, &retfile);
retbool = true;
}
FLUSH(&retpc);
FLUSH(&retfile);
FLUSH(&retline);
FLUSH(&retbool);
}
void
runtime·Callers(intgo skip, Slice pc, intgo retn)
{
// runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here
// so that we don't let a nil pc slice get to it.
if(pc.len == 0)
retn = 0;
else
retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
FLUSH(&retn);
}
void
runtime·FuncForPC(uintptr pc, void *retf)
{
retf = runtime·findfunc(pc);
FLUSH(&retf);
}
uint32 uint32
runtime·fastrand1(void) runtime·fastrand1(void)
{ {
...@@ -375,13 +301,6 @@ runtime·tickspersecond(void) ...@@ -375,13 +301,6 @@ runtime·tickspersecond(void)
return res; return res;
} }
void
runtimepprof·runtime_cyclesPerSecond(int64 res)
{
res = runtime·tickspersecond();
FLUSH(&res);
}
DebugVars runtime·debug; DebugVars runtime·debug;
static struct { static struct {
......
...@@ -72,6 +72,7 @@ typedef struct MapType MapType; ...@@ -72,6 +72,7 @@ typedef struct MapType MapType;
typedef struct Defer Defer; typedef struct Defer Defer;
typedef struct Panic Panic; typedef struct Panic Panic;
typedef struct Hmap Hmap; typedef struct Hmap Hmap;
typedef struct Hiter Hiter;
typedef struct Hchan Hchan; typedef struct Hchan Hchan;
typedef struct Complex64 Complex64; typedef struct Complex64 Complex64;
typedef struct Complex128 Complex128; typedef struct Complex128 Complex128;
...@@ -580,7 +581,7 @@ extern bool runtime·precisestack; ...@@ -580,7 +581,7 @@ extern bool runtime·precisestack;
#define nelem(x) (sizeof(x)/sizeof((x)[0])) #define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0) #define nil ((void*)0)
#define offsetof(s,m) (uint32)(&(((s*)0)->m)) #define offsetof(s,m) (uint32)(&(((s*)0)->m))
#define ROUND(x, n) (((x)+(n)-1)&~((n)-1)) /* all-caps to mark as macro: it evaluates n twice */ #define ROUND(x, n) (((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
/* /*
* known to compiler * known to compiler
...@@ -761,10 +762,31 @@ int32 runtime·runetochar(byte*, int32); ...@@ -761,10 +762,31 @@ int32 runtime·runetochar(byte*, int32);
int32 runtime·charntorune(int32*, uint8*, int32); int32 runtime·charntorune(int32*, uint8*, int32);
/* /*
* very low level c-called * This macro is used when writing C functions
*/ * called as if they were Go functions.
* Passed the address of a result before a return statement,
* it makes sure the result has been flushed to memory
* before the return.
*
* It is difficult to write such functions portably, because
* of the varying requirements on the alignment of the
* first output value. Almost all code should write such
* functions in .goc files, where goc2c (part of cmd/dist)
* can arrange the correct alignment for the target system.
* Goc2c also takes care of conveying to the garbage collector
* which parts of the argument list are input vs outputs.
*
* Therefore, do NOT use this macro if at all possible.
*/
#define FLUSH(x) USED(x) #define FLUSH(x) USED(x)
/*
* GoOutput is a type with the same alignment requirements as the
* initial output argument from a Go function. Only for use in cases
* where using goc2c is not possible. See comment on FLUSH above.
*/
typedef uint64 GoOutput;
void runtime·gogo(Gobuf*); void runtime·gogo(Gobuf*);
void runtime·gostartcall(Gobuf*, void(*)(void), void*); void runtime·gostartcall(Gobuf*, void(*)(void), void*);
void runtime·gostartcallfn(Gobuf*, FuncVal*); void runtime·gostartcallfn(Gobuf*, FuncVal*);
...@@ -901,6 +923,7 @@ void runtime·crash(void); ...@@ -901,6 +923,7 @@ void runtime·crash(void);
void runtime·parsedebugvars(void); void runtime·parsedebugvars(void);
void _rt0_go(void); void _rt0_go(void);
void* runtime·funcdata(Func*, int32); void* runtime·funcdata(Func*, int32);
int32 runtime·setmaxthreads(int32);
#pragma varargck argpos runtime·printf 1 #pragma varargck argpos runtime·printf 1
#pragma varargck type "c" int32 #pragma varargck type "c" int32
...@@ -989,6 +1012,7 @@ LFNode* runtime·lfstackpop(uint64 *head); ...@@ -989,6 +1012,7 @@ LFNode* runtime·lfstackpop(uint64 *head);
ParFor* runtime·parforalloc(uint32 nthrmax); ParFor* runtime·parforalloc(uint32 nthrmax);
void runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32)); void runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
void runtime·parfordo(ParFor *desc); void runtime·parfordo(ParFor *desc);
void runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
/* /*
* This is consistent across Linux and BSD. * This is consistent across Linux and BSD.
...@@ -1071,6 +1095,7 @@ void runtime·procyield(uint32); ...@@ -1071,6 +1095,7 @@ void runtime·procyield(uint32);
void runtime·osyield(void); void runtime·osyield(void);
void runtime·lockOSThread(void); void runtime·lockOSThread(void);
void runtime·unlockOSThread(void); void runtime·unlockOSThread(void);
bool runtime·lockedOSThread(void);
bool runtime·showframe(Func*, G*); bool runtime·showframe(Func*, G*);
void runtime·printcreatedby(G*); void runtime·printcreatedby(G*);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package runtime package runtime
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h"
#include "type.h"
func GOMAXPROCS(n int) (ret int) { func GOMAXPROCS(n int) (ret int) {
ret = runtime·gomaxprocsfunc(n); ret = runtime·gomaxprocsfunc(n);
...@@ -12,3 +14,115 @@ func GOMAXPROCS(n int) (ret int) { ...@@ -12,3 +14,115 @@ func GOMAXPROCS(n int) (ret int) {
func NumCPU() (ret int) { func NumCPU() (ret int) {
ret = runtime·ncpu; ret = runtime·ncpu;
} }
func NumCgoCall() (ret int64) {
M *mp;
ret = 0;
for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
ret += mp->ncgocall;
}
func newParFor(nthrmax uint32) (desc *ParFor) {
desc = runtime·parforalloc(nthrmax);
}
func parForSetup(desc *ParFor, nthr uint32, n uint32, ctx *byte, wait bool, body *byte) {
runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
}
func parForDo(desc *ParFor) {
runtime·parfordo(desc);
}
func parForIters(desc *ParFor, tid uintptr) (start uintptr, end uintptr) {
runtime·parforiters(desc, tid, &start, &end);
}
func gogoBytes() (x int32) {
x = RuntimeGogoBytes;
}
func typestring(e Eface) (s String) {
s = *e.type->string;
}
func golockedOSThread() (ret bool) {
ret = runtime·lockedOSThread();
}
func NumGoroutine() (ret int) {
ret = runtime·gcount();
}
func getgoroot() (out String) {
byte *p;
p = runtime·getenv("GOROOT");
out = runtime·gostringnocopy(p);
}
/*
* We assume that all architectures turn faults and the like
* into apparent calls to runtime.sigpanic. If we see a "call"
* to runtime.sigpanic, we do not back up the PC to find the
* line number of the CALL instruction, because there is no CALL.
*/
void runtime·sigpanic(void);
func Caller(skip int) (retpc uintptr, retfile String, retline int, retbool bool) {
Func *f, *g;
uintptr pc;
uintptr rpc[2];
/*
* Ask for two PCs: the one we were asked for
* and what it called, so that we can see if it
* "called" sigpanic.
*/
retpc = 0;
if(runtime·callers(1+skip-1, rpc, 2) < 2) {
retfile = runtime·emptystring;
retline = 0;
retbool = false;
} else if((f = runtime·findfunc(rpc[1])) == nil) {
retfile = runtime·emptystring;
retline = 0;
retbool = true; // have retpc at least
} else {
retpc = rpc[1];
pc = retpc;
g = runtime·findfunc(rpc[0]);
if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
pc--;
retline = runtime·funcline(f, pc, &retfile);
retbool = true;
}
}
func Callers(skip int, pc Slice) (retn int) {
// runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here
// so that we don't let a nil pc slice get to it.
if(pc.len == 0)
retn = 0;
else
retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
}
func runtime∕pprof·runtime_cyclesPerSecond() (res int64) {
res = runtime·tickspersecond();
}
func sync·runtime_procPin() (p int) {
M *mp;
mp = m;
// Disable preemption.
mp->locks++;
p = mp->p->id;
}
func sync·runtime_procUnpin() {
m->locks--;
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package runtime
#include "runtime.h" #include "runtime.h"
#include "arch_GOARCH.h" #include "arch_GOARCH.h"
#include "type.h" #include "type.h"
...@@ -18,13 +19,9 @@ enum ...@@ -18,13 +19,9 @@ enum
static void makeslice1(SliceType*, intgo, intgo, Slice*); static void makeslice1(SliceType*, intgo, intgo, Slice*);
static void growslice1(SliceType*, Slice, intgo, Slice *); static void growslice1(SliceType*, Slice, intgo, Slice *);
void runtime·copy(Slice to, Slice fm, uintptr width, intgo ret);
// see also unsafe·NewArray // see also unsafe·NewArray
// makeslice(typ *Type, len, cap int64) (ary []any); func makeslice(t *SliceType, len int64, cap int64) (ret Slice) {
void
runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{
// NOTE: The len > MaxMem/elemsize check here is not strictly necessary, // NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
// but it produces a 'len out of range' error instead of a 'cap out of range' error // but it produces a 'len out of range' error instead of a 'cap out of range' error
// when someone does make([]T, bignumber). 'cap out of range' is true too, // when someone does make([]T, bignumber). 'cap out of range' is true too,
...@@ -59,9 +56,7 @@ makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret) ...@@ -59,9 +56,7 @@ makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret)
} }
// growslice(type *Type, x, []T, n int64) []T // growslice(type *Type, x, []T, n int64) []T
void func growslice(t *SliceType, old Slice, n int64) (ret Slice) {
runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
{
int64 cap; int64 cap;
void *pc; void *pc;
...@@ -80,8 +75,6 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) ...@@ -80,8 +75,6 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
growslice1(t, old, cap, &ret); growslice1(t, old, cap, &ret);
FLUSH(&ret);
if(debug) { if(debug) {
runtime·printf("growslice(%S,", *t->string); runtime·printf("growslice(%S,", *t->string);
runtime·printslice(old); runtime·printslice(old);
...@@ -142,11 +135,8 @@ growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret) ...@@ -142,11 +135,8 @@ growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
g->stackguard0 = StackPreempt; g->stackguard0 = StackPreempt;
} }
// copy(to any, fr any, wid uintptr) int
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func copy(to Slice, fm Slice, width uintptr) (ret int) {
runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
{
void *pc; void *pc;
if(fm.len == 0 || to.len == 0 || width == 0) { if(fm.len == 0 || to.len == 0 || width == 0) {
...@@ -171,7 +161,6 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret) ...@@ -171,7 +161,6 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
} }
out: out:
FLUSH(&ret);
if(debug) { if(debug) {
runtime·prints("main·copy: to="); runtime·prints("main·copy: to=");
...@@ -187,9 +176,7 @@ out: ...@@ -187,9 +176,7 @@ out:
} }
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void func slicestringcopy(to Slice, fm String) (ret int) {
runtime·slicestringcopy(Slice to, String fm, intgo ret)
{
void *pc; void *pc;
if(fm.len == 0 || to.len == 0) { if(fm.len == 0 || to.len == 0) {
...@@ -208,13 +195,10 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret) ...@@ -208,13 +195,10 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret)
runtime·memmove(to.array, fm.str, ret); runtime·memmove(to.array, fm.str, ret);
out: out:;
FLUSH(&ret);
} }
void func printslice(a Slice) {
runtime·printslice(Slice a)
{
runtime·prints("["); runtime·prints("[");
runtime·printint(a.len); runtime·printint(a.len);
runtime·prints("/"); runtime·prints("/");
......
...@@ -372,11 +372,3 @@ runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv) ...@@ -372,11 +372,3 @@ runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
{ {
runtime·gostartcall(gobuf, fv->fn, fv); runtime·gostartcall(gobuf, fv->fn, fv);
} }
void
runtimedebug·setMaxStack(intgo in, intgo out)
{
out = runtime·maxstacksize;
runtime·maxstacksize = in;
FLUSH(&out);
}
...@@ -101,11 +101,8 @@ runtime·gostringnocopy(byte *str) ...@@ -101,11 +101,8 @@ runtime·gostringnocopy(byte *str)
return s; return s;
} }
void func cstringToGo(str *byte) (s String) {
runtime·cstringToGo(byte *str, String s)
{
s = runtime·gostringnocopy(str); s = runtime·gostringnocopy(str);
FLUSH(&s);
} }
String String
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// Runtime symbol table parsing. // Runtime symbol table parsing.
// See http://golang.org/s/go12symtab for an overview. // See http://golang.org/s/go12symtab for an overview.
package runtime
#include "runtime.h" #include "runtime.h"
#include "defs_GOOS_GOARCH.h" #include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h" #include "os_GOOS.h"
...@@ -86,8 +87,11 @@ runtime·funcdata(Func *f, int32 i) ...@@ -86,8 +87,11 @@ runtime·funcdata(Func *f, int32 i)
if(i < 0 || i >= f->nfuncdata) if(i < 0 || i >= f->nfuncdata)
return nil; return nil;
p = (byte*)&f->nfuncdata + 4 + f->npcdata*4; p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
if(sizeof(void*) == 8 && ((uintptr)p & 4)) if(sizeof(void*) == 8 && ((uintptr)p & 4)) {
if(((uintptr)f & 4))
runtime·printf("misaligned func %p\n", f);
p += 4; p += 4;
}
return ((void**)p)[i]; return ((void**)p)[i];
} }
...@@ -224,27 +228,18 @@ runtime·funcarglen(Func *f, uintptr targetpc) ...@@ -224,27 +228,18 @@ runtime·funcarglen(Func *f, uintptr targetpc)
return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum); return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
} }
void func funcline_go(f *Func, targetpc uintptr) (retfile String, retline int) {
runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline)
{
// Pass strict=false here, because anyone can call this function, // Pass strict=false here, because anyone can call this function,
// and they might just be wrong about targetpc belonging to f. // and they might just be wrong about targetpc belonging to f.
retline = funcline(f, targetpc, &retfile, false); retline = funcline(f, targetpc, &retfile, false);
FLUSH(&retline);
} }
void func funcname_go(f *Func) (ret String) {
runtime·funcname_go(Func *f, String ret)
{
ret = runtime·gostringnocopy((uint8*)runtime·funcname(f)); ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
FLUSH(&ret);
} }
void func funcentry_go(f *Func) (ret uintptr) {
runtime·funcentry_go(Func *f, uintptr ret)
{
ret = f->entry; ret = f->entry;
FLUSH(&ret);
} }
Func* Func*
...@@ -281,6 +276,10 @@ runtime·findfunc(uintptr addr) ...@@ -281,6 +276,10 @@ runtime·findfunc(uintptr addr)
return nil; return nil;
} }
func FuncForPC(pc uintptr) (ret *Func) {
ret = runtime·findfunc(pc);
}
static bool static bool
hasprefix(String s, int8 *p) hasprefix(String s, int8 *p)
{ {
......
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