From: Kai Backman Date: Tue, 20 Oct 2009 02:59:39 +0000 (-0700) Subject: first version of closures. test/closure doesn't yet pass. X-Git-Tag: weekly.2009-11-06~259 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=a15aa05ae2f7b39c28581be4563879381a6fcd2a;p=gostls13.git first version of closures. test/closure doesn't yet pass. go/test: passes 87% (300/343) R=rsc APPROVED=rsc DELTA=125 (125 added, 0 deleted, 0 changed) OCL=35893 CL=35900 --- diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c index bfa9df67f0..b0aa2ad8b0 100644 --- a/src/pkg/runtime/arm/closure.c +++ b/src/pkg/runtime/arm/closure.c @@ -1,3 +1,125 @@ // 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. + +#include "runtime.h" + +/* + There are two bits of magic: + - The signature of the compiler generated function uses two stack frames + as arguments (callerpc separates these frames) + - size determines how many arguments runtime.closure actually has + starting at arg0. + + Example closure with 3 captured variables: + func closure(siz int32, + fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy, + arg0, arg1, arg2 *ptr) (func(xxx) yyy) + + Code generated: + src R0 + dst R1 + end R3 + tmp R4 + frame = siz+4 + +//skip loop for 0 size closures + MOVW.W R14,-frame(R13) + + MOVW $vars(PC), R0 + MOVW $4(SP), R1 + MOVW $siz(R0), R3 +loop: MOVW.P 4(R0), R4 + MOVW.P R4, 4(R1) + CMP R0, R3 + BNE loop + + MOVW 8(PC), R0 + BL (R0) // 2 words + MOVW.P frame(R13),R15 +fptr: WORD *fn +vars: WORD arg0 + WORD arg1 + WORD arg2 +*/ + +#pragma textflag 7 +void +runtime·closure(int32 siz, byte *fn, byte *arg0) +{ + byte *p, *q, **ret; + uint32 *pc; + int32 n; + + if(siz < 0 || siz%4 != 0) + throw("bad closure size"); + + ret = (byte**)((byte*)&arg0 + siz); + + if(siz > 100) { + // TODO(kaib): implement stack growth preamble? + throw("closure too big"); + } + + // size of new fn. + // must match code laid out below. + if (siz > 0) + n = 6 * 4 + 7 * 4; + else + n = 6 * 4; + + // store args aligned after code, so gc can find them. + n += siz; + + p = mal(n); + *ret = p; + q = p + n - siz; + + pc = (uint32*)p; + + // MOVW.W R14,-frame(R13) + *pc++ = 0xe52de000 | (siz + 4); + + if(siz > 0) { + mcpy(q, (byte*)&arg0, siz); + + // MOVW $vars(PC), R0 + *pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8); + pc++; + + // MOVW $4(SP), R1 + *pc++ = 0xe28d1004; + + // MOVW $siz(R0), R3 + *pc++ = 0xe2803000 | siz; + + // MOVW.P 4(R0), R4 + *pc++ = 0xe4904004; + // MOVW.P R4, 4(R1) + *pc++ = 0xe4814004; + // CMP R0, R3 + *pc++ = 0xe1530000; + // BNE loop + *pc++ = 0x1afffffb; + } + + // MOVW fptr(PC), R0 + *pc = 0xe59f0008 | (int32)((q - 4) -(byte*) pc - 8); + pc++; + + // BL (R0) + *pc++ = 0xe28fe000; + *pc++ = 0xe280f000; + + // MOVW.P frame(R13),R15 + *pc++ = 0xe49df000 | (siz + 4); + + // WORD *fn + *pc++ = (uint32)fn; + + p = (byte*)pc; + + if(p > q) + throw("bad math in sys.closure"); +} + diff --git a/test/arm-pass.txt b/test/arm-pass.txt index 626051019a..6930db1a9c 100644 --- a/test/arm-pass.txt +++ b/test/arm-pass.txt @@ -27,6 +27,7 @@ convlit1.go decl.go declbad.go empty.go +env.go escape1.go fixedbugs/bug000.go fixedbugs/bug001.go @@ -83,6 +84,7 @@ fixedbugs/bug063.go fixedbugs/bug064.go fixedbugs/bug065.go fixedbugs/bug066.go +fixedbugs/bug067.go fixedbugs/bug068.go fixedbugs/bug069.go fixedbugs/bug070.go @@ -253,6 +255,7 @@ ken/interbasic.go ken/interfun.go ken/intervar.go ken/label.go +ken/litfun.go ken/mfunc.go ken/ptrfun.go ken/ptrvar.go