Commit d8b5d039 authored by Russ Cox's avatar Russ Cox

gc: implement append

R=ken2
CC=golang-dev
https://golang.org/cl/2757042
parent b803a255
...@@ -21,6 +21,8 @@ char *runtimeimport = ...@@ -21,6 +21,8 @@ char *runtimeimport =
"func \"\".printsp ()\n" "func \"\".printsp ()\n"
"func \"\".printf ()\n" "func \"\".printf ()\n"
"func \"\".concatstring ()\n" "func \"\".concatstring ()\n"
"func \"\".append ()\n"
"func \"\".appendslice (typ *uint8, x any, y []any) any\n"
"func \"\".cmpstring (? string, ? string) int\n" "func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n" "func \"\".slicestring (? string, ? int, ? int) string\n"
"func \"\".slicestring1 (? string, ? int) string\n" "func \"\".slicestring1 (? string, ? int) string\n"
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#undef OAPPEND
// avoid <ctype.h> // avoid <ctype.h>
#undef isblank #undef isblank
#define isblank goisblank #define isblank goisblank
...@@ -349,6 +351,7 @@ enum ...@@ -349,6 +351,7 @@ enum
OADD, OSUB, OOR, OXOR, OADDSTR, OADD, OSUB, OOR, OXOR, OADDSTR,
OADDR, OADDR,
OANDAND, OANDAND,
OAPPEND,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE, OSTRARRAYBYTE, OSTRARRAYRUNE,
......
...@@ -1531,6 +1531,7 @@ static struct ...@@ -1531,6 +1531,7 @@ static struct
"type", LTYPE, Txxx, OXXX, "type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX, "var", LVAR, Txxx, OXXX,
"append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP, "cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE, "close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED, "closed", LNAME, Txxx, OCLOSED,
......
...@@ -37,6 +37,7 @@ exprfmt(Fmt *f, Node *n, int prec) ...@@ -37,6 +37,7 @@ exprfmt(Fmt *f, Node *n, int prec)
} }
switch(n->op) { switch(n->op) {
case OAPPEND:
case ONAME: case ONAME:
case ONONAME: case ONONAME:
case OPACK: case OPACK:
...@@ -400,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec) ...@@ -400,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, ")"); fmtprint(f, ")");
break; break;
case OAPPEND:
case OCAP: case OCAP:
case OCLOSE: case OCLOSE:
case OCLOSED: case OCLOSED:
......
...@@ -36,6 +36,10 @@ func printf() ...@@ -36,6 +36,10 @@ func printf()
// filled in by compiler: int n, string, string, ... // filled in by compiler: int n, string, string, ...
func concatstring() func concatstring()
// filled in by compiler: Type*, int n, Slice, ...
func append()
func appendslice(typ *byte, x any, y []any) any
func cmpstring(string, string) int func cmpstring(string, string) int
func slicestring(string, int, int) string func slicestring(string, int, int) string
func slicestring1(string, int) string func slicestring1(string, int) string
......
...@@ -810,6 +810,7 @@ goopnames[] = ...@@ -810,6 +810,7 @@ goopnames[] =
[OANDAND] = "&&", [OANDAND] = "&&",
[OANDNOT] = "&^", [OANDNOT] = "&^",
[OAND] = "&", [OAND] = "&",
[OAPPEND] = "append",
[OAS] = "=", [OAS] = "=",
[OAS2] = "=", [OAS2] = "=",
[OBREAK] = "break", [OBREAK] = "break",
......
...@@ -730,7 +730,7 @@ reswitch: ...@@ -730,7 +730,7 @@ reswitch:
typecheck(&n->left, Erv | Etype | Ecall); typecheck(&n->left, Erv | Etype | Ecall);
l = n->left; l = n->left;
if(l->op == ONAME && l->etype != 0) { if(l->op == ONAME && l->etype != 0) {
if(n->isddd) if(n->isddd && l->etype != OAPPEND)
yyerror("invalid use of ... with builtin %#N", l); yyerror("invalid use of ... with builtin %#N", l);
// builtin: OLEN, OCAP, etc. // builtin: OLEN, OCAP, etc.
n->op = l->etype; n->op = l->etype;
...@@ -905,6 +905,40 @@ reswitch: ...@@ -905,6 +905,40 @@ reswitch:
ok |= Etop; ok |= Etop;
goto ret; goto ret;
case OAPPEND:
ok |= Erv;
args = n->list;
if(args == nil) {
yyerror("missing arguments to append");
goto error;
}
typechecklist(args, Erv);
if((t = args->n->type) == T)
goto error;
n->type = t;
if(!isslice(t)) {
yyerror("first argument to append must be slice; have %lT", t);
goto error;
}
if(n->isddd) {
if(args->next == nil) {
yyerror("cannot use ... on first argument to append");
goto error;
}
if(args->next->next != nil) {
yyerror("too many arguments to append");
goto error;
}
args->next->n = assignconv(args->next->n, t->orig, "append");
goto ret;
}
for(args=args->next; args != nil; args=args->next) {
if(args->n->type == T)
continue;
args->n = assignconv(args->n, t->type, "append");
}
goto ret;
case OCOPY: case OCOPY:
ok |= Etop|Erv; ok |= Etop|Erv;
args = n->list; args = n->list;
......
...@@ -18,6 +18,7 @@ static NodeList* paramstoheap(Type **argin, int out); ...@@ -18,6 +18,7 @@ static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*); static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*); static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**); static Node* addstr(Node*, NodeList**);
static Node* append(Node*, NodeList**);
static NodeList* walkdefstack; static NodeList* walkdefstack;
...@@ -1265,6 +1266,10 @@ walkexpr(Node **np, NodeList **init) ...@@ -1265,6 +1266,10 @@ walkexpr(Node **np, NodeList **init)
} }
goto ret; goto ret;
case OAPPEND:
n = append(n, init);
goto ret;
case OCOPY: case OCOPY:
if(n->right->type->etype == TSTRING) if(n->right->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1); fn = syslook("slicestringcopy", 1);
...@@ -2304,3 +2309,44 @@ addstr(Node *n, NodeList **init) ...@@ -2304,3 +2309,44 @@ addstr(Node *n, NodeList **init)
return r; return r;
} }
static Node*
append(Node *n, NodeList **init)
{
int i, j;
Node *f, *r;
NodeList *in, *args;
if(n->isddd) {
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
argtype(f, n->type);
r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
return r;
}
j = count(n->list) - 1;
f = syslook("append", 1);
f->type = T;
f->ntype = nod(OTFUNC, N, N);
in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type
in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count
in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice
for(i=0; i<j; i++)
in = list(in, nod(ODCLFIELD, N, typenod(n->type->type)));
f->ntype->list = in;
f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type)));
args = list1(typename(n->type));
args = list(args, nodintconst(j));
args = concat(args, n->list);
r = nod(OCALL, f, N);
r->list = args;
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
return r;
}
...@@ -8,37 +8,101 @@ ...@@ -8,37 +8,101 @@
static int32 debug = 0; static int32 debug = 0;
static void makeslice(SliceType*, int32, int32, Slice*);
void ·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
// see also unsafe·NewArray // see also unsafe·NewArray
// makeslice(typ *Type, len, cap int64) (ary []any); // makeslice(typ *Type, len, cap int64) (ary []any);
void void
·makeslice(SliceType *t, int64 len, int64 cap, Slice ret) ·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{ {
uintptr size;
if(len < 0 || (int32)len != len) if(len < 0 || (int32)len != len)
panicstring("makeslice: len out of range"); panicstring("makeslice: len out of range");
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size) if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
panicstring("makeslice: cap out of range"); panicstring("makeslice: cap out of range");
makeslice(t, len, cap, &ret);
if(debug) {
printf("makeslice(%S, %D, %D); ret=",
*t->string, len, cap);
·printslice(ret);
}
}
static void
makeslice(SliceType *t, int32 len, int32 cap, Slice *ret)
{
uintptr size;
size = cap*t->elem->size; size = cap*t->elem->size;
ret.len = len; ret->len = len;
ret.cap = cap; ret->cap = cap;
if((t->elem->kind&KindNoPointers)) if((t->elem->kind&KindNoPointers))
ret.array = mallocgc(size, RefNoPointers, 1, 1); ret->array = mallocgc(size, RefNoPointers, 1, 1);
else else
ret.array = mal(size); ret->array = mal(size);
}
FLUSH(&ret); static void appendslice(SliceType*, Slice, Slice, Slice*);
if(debug) { // append(type *Type, n int, old []T, ...,) []T
printf("makeslice(%S, %D, %D); ret=", #pragma textflag 7
*t->string, len, cap); void
·printslice(ret); ·append(SliceType *t, int32 n, Slice old, ...)
{
Slice sl;
Slice *ret;
sl.len = n;
sl.array = (byte*)(&old+1);
ret = (Slice*)(sl.array + ((t->elem->size*n+sizeof(uintptr)-1) & ~(sizeof(uintptr)-1)));
appendslice(t, old, sl, ret);
}
// appendslice(type *Type, x, y, []T) []T
void
·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
{
appendslice(t, x, y, &ret);
}
static void
appendslice(SliceType *t, Slice x, Slice y, Slice *ret)
{
Slice newx;
int32 m;
uintptr w;
if(x.len+y.len < x.len)
throw("append: slice overflow");
w = t->elem->size;
if(x.len+y.len > x.cap) {
m = x.cap;
if(m == 0)
m = y.len;
else {
do {
if(x.len < 1024)
m += m;
else
m += m/4;
} while(m < x.len+y.len);
}
makeslice(t, x.len, m, &newx);
memmove(newx.array, x.array, x.len*w);
x = newx;
} }
memmove(x.array+x.len*w, y.array, y.len*w);
x.len += y.len;
*ret = x;
} }
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any); // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
void void
·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret) ·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
......
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