what runtime code generation do we have again?

17 views
Skip to first unread message

Kai Backman

unread,
Nov 12, 2009, 2:07:06 AM11/12/09
to golang-dev
My closure bug turned out to be stale icaches. I have a vague
recollection we did some other runtime code generation related to
interfaces, can someone refresh my memory to where this was?

Kai

Russ Cox

unread,
Nov 12, 2009, 2:10:21 AM11/12/09
to Kai Backman, golang-nuts
Closures are the only place runtime code generation
happens in Go. There is some implicit compile time
code generation related to interfaces.

Russ

Kai Backman

unread,
Nov 12, 2009, 2:19:06 AM11/12/09
to r...@golang.org, golang-nuts
Cool. AFAIK all the remaining failures in test/* are now due to floats.

Oleg Finkelshteyn

unread,
Nov 12, 2009, 3:44:05 AM11/12/09
to golang-nuts
> Closures are the only place runtime code generation
> happens in Go.

Is there any documentation about closure implementation in Go? What
exactly does it use runtime code generation for?
I'm a bit lost in cmd/gc/closure.c and a document I might have
overlooked would probably answer most of my questions.

Thanks,
Oleg

Russ Cox

unread,
Nov 12, 2009, 3:49:14 AM11/12/09
to Oleg Finkelshteyn, golang-nuts
There needs to be an implementation document, but it
doesn't exist yet. Regarding your phi functions on the other
thread, I don't have a good suggestion. The easiest thing
to do is to write

var f func() int
f = func() int {... use f instead of phi ...}

and not worry about editing the compiler.

Russ

Oleg Finkelshteyn

unread,
Nov 12, 2009, 4:08:39 AM11/12/09
to r...@golang.org, golang-nuts
> The easiest thing
> to do is to write
>
>    var f func() int
>    f = func() int {... use f instead of phi ...}
>
> and not worry about editing the compiler.

Indeed, and I'm not even sure I'd use phi enough to justify the
compiler change even in my source checkout, but I have always wanted
to have this somewhere, and Go seems to be a good match:
; sed -n 1259p lex.c
"despiteallobjections", LIGNORE, Txxx, OXXX,

As to the closure questions, from a superficial look it might seem
that I'd be happy with closure nname generation moved from
walkclosure() to closurehdr(). Is there a reason it should be done at
a later stage?

Russ Cox

unread,
Nov 12, 2009, 6:09:45 PM11/12/09
to Oleg Finkelshteyn, golang-nuts
On Thu, Nov 12, 2009 at 01:08, Oleg Finkelshteyn <oleg...@gmail.com> wrote:
> As to the closure questions, from a superficial look it might seem
> that I'd be happy with closure nname generation moved from
> walkclosure() to closurehdr(). Is there a reason it should be done at
> a later stage?

I thought more about this. I don't think you want to put it in
that section of the code. Instead, I think that much closer to
the front end, when a function literal is starting, the thing to do
is declare a fake phi variable and rewrite func(){...} into logically
phi = func(){...} returning value phi (not possible in Go but
possible in the internal representation). Then if the ... mentions
phi it will be grabbed properly. Even inside the closure generation
code, there is no name for the result of the func(){} expression,
because the stub code is generated at run time.

Russ

Oleg Finkelshteyn

unread,
Nov 12, 2009, 6:50:26 PM11/12/09
to r...@golang.org, golang-nuts
> I thought more about this.  I don't think you want to put it in
> that section of the code.  Instead, I think that much closer to
> the front end, when a function literal is starting, the thing to do
> is declare a fake phi variable and rewrite func(){...} into logically
> phi = func(){...} returning value phi (not possible in Go but
> possible in the internal representation).  Then if the ... mentions
> phi it will be grabbed properly.  Even inside the closure generation
> code, there is no name for the result of the func(){} expression,
> because the stub code is generated at run time.

I tried an approach similar to what is done to print/panic/etc. (diff
below), but now I see that the function I see during the walk (named
_f%d in walkclosure()) is not the one I want (for the code below the
typechecker and 8g -w say its signature for [func(n int) int] in the
code is [func(uintptr, n int) int]).
The variable approach is more sensible. I'm still somewhat confused as
to what the relations between given Node, its ->nname and ->ntype are
-- they seem to be used interchangeably to some extent. Do I
understand you correctly that what you suggest should be done about
the parsing time before the walk (so probably in closurehdr), or
should still all the rewrite happen in walkclosure? And how do I
implement the proposed code? By wrapping in another closure?

Thanks,
Oleg

In case the diff output comes garbled again:
http://rain.ifmo.ru/~olegfink/go-phi.diff
diff -r cb140bac9ab0 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/go.h Fri Nov 13 02:20:51 2009 +0300
@@ -360,6 +360,7 @@
ONOT, OCOM, OPLUS, OMINUS,
OOROR,
OPANIC, OPANICN, OPRINT, OPRINTN,
+ OPHI,
OSEND, OSENDNB,
OSLICE, OSLICEARR, OSLICESTR,
ORECV,
diff -r cb140bac9ab0 src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/lex.c Fri Nov 13 02:20:51 2009 +0300
@@ -1252,6 +1252,7 @@
"panicln", LNAME, Txxx, OPANICN,
"print", LNAME, Txxx, OPRINT,
"println", LNAME, Txxx, OPRINTN,
+ "phi", LNAME, Txxx, OPHI,

"notwithstanding", LIGNORE, Txxx, OXXX,
"thetruthofthematter", LIGNORE, Txxx, OXXX,
diff -r cb140bac9ab0 src/cmd/gc/print.c
--- a/src/cmd/gc/print.c Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/print.c Fri Nov 13 02:20:51 2009 +0300
@@ -311,6 +311,7 @@
case OPANICN:
case OPRINT:
case OPRINTN:
+ case OPHI:
fmtprint(f, "%#O(", n->op);
if(n->left)
exprfmt(f, n->left, 0);
diff -r cb140bac9ab0 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/subr.c Fri Nov 13 02:20:51 2009 +0300
@@ -774,6 +774,7 @@
[OOR] = "|",
[OPANICN] = "panicln",
[OPANIC] = "panic",
+ [OPHI] = "phi",
[OPLUS] = "+",
[OPRINTN] = "println",
[OPRINT] = "print",
diff -r cb140bac9ab0 src/cmd/gc/typecheck.c
--- a/src/cmd/gc/typecheck.c Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/typecheck.c Fri Nov 13 02:20:51 2009 +0300
@@ -899,6 +899,11 @@
typechecklist(n->list, Erv);
goto ret;

+ case OPHI:
+ ok |= Erv;
+ typechecklist(n->list, Erv);
+ goto ret;
+
case OCLOSURE:
ok |= Erv;
typecheckclosure(n);
diff -r cb140bac9ab0 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Thu Nov 12 14:55:26 2009 -0800
+++ b/src/cmd/gc/walk.c Fri Nov 13 02:20:51 2009 +0300
@@ -5,6 +5,7 @@
#include "go.h"

static Node* walkprint(Node*, NodeList**);
+static Node* walkphi(Node*, NodeList**);
static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**);
@@ -536,6 +537,11 @@
n = walkprint(n, init);
goto ret;

+ case OPHI:
+ walkexprlist(n->list, init);
+ n = walkphi(n, init);
+ goto ret;
+
case OLITERAL:
n->addable = 1;
goto ret;
@@ -1558,6 +1564,16 @@
return r;
}

+static Node*
+walkphi(Node *nn, NodeList **init)
+{
+ Node *n;
+ n = nod(OCALL, curfn, N);
+ n->list = nn->list;
+ typecheck(&n, Erv);
+ return n;
+}
+
Node*
callnew(Type *t)
{
Reply all
Reply to author
Forward
0 new messages