mirror of
https://github.com/golang/go
synced 2024-11-12 07:40:23 -07:00
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
This commit is contained in:
parent
1be74762c1
commit
a15aa05ae2
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user