Hello,
I compiled to GVM the following test program:
(declare (standard-bindings) (fixnum) (not safe)) (define mkadder (lambda (n) (lambda (x) (+ x n)))) (define add1 (mkadder 1)) (add1 1)
In the produced GVM code (below, slightly edited for mail posting), I see that the code of the lambda uses a closure in the register 4, but nowhere in the code I see an assigment to this register. What do I miss?
**** #<primitive | test2.o7|> = #line 2 "............" #1 0 entry-point 0 () ~#mkadder = '#<procedure ~#mkadder> #line 6 -1 = +0 +1 = '1 +0 = #3 -2 = . -3 = . -4 = . jump* 4 #2 #2 4 jump 4 ~#mkadder 1 #3 4 return-point ~#add1 = +1 #line 7 +1 = '1 +0 = -1 jump* 4 #4 #4 4 jump 0 ~#add1 1
**** #<procedure ~#mkadder> = #line 2 "................" #1 0 entry-point 1 () close -1 = (#2 +1) +1 = -1 jump 0 +0 #2 0 closure-entry-point 1 () +4 = +4(1) +1 = (##fx+ +1 +4) jump 0 +0
Afficher les réponses par date
On 2010-11-18, at 8:11 AM, Oleg Parashchenko wrote:
Hello,
I compiled to GVM the following test program:
(declare (standard-bindings) (fixnum) (not safe)) (define mkadder (lambda (n) (lambda (x) (+ x n)))) (define add1 (mkadder 1)) (add1 1)
In the produced GVM code (below, slightly edited for mail posting), I see that the code of the lambda uses a closure in the register 4, but nowhere in the code I see an assigment to this register. What do I miss?
**** #<primitive | test2.o7|> = #line 2 "............" #1 0 entry-point 0 () ~#mkadder = '#<procedure ~#mkadder> #line 6 -1 = +0 +1 = '1 +0 = #3 -2 = . -3 = . -4 = . jump* 4 #2 #2 4 jump 4 ~#mkadder 1 #3 4 return-point ~#add1 = +1 #line 7 +1 = '1 +0 = -1 jump* 4 #4 #4 4 jump 0 ~#add1 1
**** #<procedure ~#mkadder> = #line 2 "................" #1 0 entry-point 1 () close -1 = (#2 +1) +1 = -1 jump 0 +0 #2 0 closure-entry-point 1 () +4 = +4(1) +1 = (##fx+ +1 +4) jump 0 +0
The setting of register 4 (i.e. "+4" in the GVM code) is a side effect of the jump instruction when a closure is being jumped to. Note that register 4 is unused at the moment of the jump because parameters are passed in 4 registers (+0=return address, +1=1st param, +2=2nd param, +3=3rd param). Register 4 will be set to the closure being called (i.e. register 4 is a "self" pointer). In your code this happens in the instruction "jump 0 +#add1 1" (the 0 is the new frame size and 1 is the argument count). The jumps with a star, i.e. "jump*", indicate that the jump includes a poll instruction (to check for stack overflow and interrupts).
What is your interest in the GVM code generated by Gambit?
Marc
Hello Marc,
On Thu, 18 Nov 2010 09:56:42 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
The setting of register 4 (i.e. "+4" in the GVM code) is a side effect of the jump instruction when a closure is being jumped to.
Thanks! Is it documented somewhere?
Note that register 4 is unused at the moment of the jump because parameters are passed in 4 registers (+0=return address, +1=1st param, +2=2nd param, +3=3rd param).
My test shows that 4rd etc param is located on the stack, and therefore there is no register 5 or more.
However, if I understand "A parallel virtual machine for efficient scheme compilation" correctly, a backend can specify a number N of registers. I suppose that in this case the closure register will be the last register, number N. Right?
...
What is your interest in the GVM code generated by Gambit?
Short-term goal: compile Scheme code to PHP.
Instead implementing a backend for Gambit, I'd like to start with an independent tool, which parses the GVM code.
By the way, is there an easy way to dump the internal representation for easy parsing? An optimistic try of "pretty-print" instead of "virtual.dump" is failed.
More global experiment: use of Scheme as a new portable Assembler or virtual machine:
http://uucode.com/blog/2010/09/28/r5rs-scheme-as-a-virtual-machine-i/ http://uucode.com/texts/genxml/genxml.html
Marc
On Nov 19, 2010, at 7:40 AM, Oleg Parashchenko wrote:
Short-term goal: compile Scheme code to PHP.
Might I suggest javascript instead. There's an awful lot of very well funded effort going into optimizing javascript VMs and jit compilation that you could leverage.
warmest regards,
Ralph
Raffael Cavallaro raffaelcavallaro@me.com
On 2010-11-19, at 8:10 AM, Raffael Cavallaro wrote:
On Nov 19, 2010, at 7:40 AM, Oleg Parashchenko wrote:
Short-term goal: compile Scheme code to PHP.
Might I suggest javascript instead. There's an awful lot of very well funded effort going into optimizing javascript VMs and jit compilation that you could leverage.
Are you suggesting
1) compiling Scheme to JavaScript
or
2) compiling JavaScript to PHP?
It would seem you mean #1, but that already exists (in fact you will find a Scheme to JavaScript compiler on Gambit's dumping grounds).
Marc
On Nov 19, 2010, at 9:11 AM, Marc Feeley wrote:
It would seem you mean #1, but that already exists (in fact you will find a Scheme to JavaScript compiler on Gambit's dumping grounds).
Yes, I mean #1. I know that such things already exist. I was just suggesting that javascript is a more useful target than php because of all the effort currently going into making javascript run fast and to give it additional, widely available capabilities (i.e., html5). A high quality scheme->javascript compiler could be the ultimate high performance, universal, cross-platform, write-once-run-anywhere scheme implementation.
warmest regards,
Ralph
Raffael Cavallaro raffaelcavallaro@me.com
On 2010-11-19, at 10:20 AM, Raffael Cavallaro wrote:
On Nov 19, 2010, at 9:11 AM, Marc Feeley wrote:
It would seem you mean #1, but that already exists (in fact you will find a Scheme to JavaScript compiler on Gambit's dumping grounds).
Yes, I mean #1. I know that such things already exist. I was just suggesting that javascript is a more useful target than php because of all the effort currently going into making javascript run fast and to give it additional, widely available capabilities (i.e., html5). A high quality scheme->javascript compiler could be the ultimate high performance, universal, cross-platform, write-once-run-anywhere scheme implementation.
warmest regards,
Ralph
I checked PHP, which I wasn't very familiar with, and it seems to have a similar syntax (in the sense of "program structure") as JavaScript. In particular they both have closures and GC, and don't have tail calls.
So if you start writing a back-end, I suggest that you supports both languages. In fact, you could support other target languages with similar properties (including Python, Ruby, elisp, ...). It should be easy to abstract the superficial differences between these languages in the "code generator" of the back-end.
Marc
On Nov 22, 2010, at 2:10 PM, Marc Feeley wrote:
In fact, you could support other target languages with similar properties (including Python, Ruby, elisp, ...). It should be easy to abstract the superficial differences between these languages in the "code generator" of the back-end.
Good idea.
warmest regards,
Ralph
Raffael Cavallaro raffaelcavallaro@me.com
Hello Marc,
On Mon, 22 Nov 2010 14:10:46 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
I checked PHP, which I wasn't very familiar with, and it seems to have a similar syntax (in the sense of "program structure") as JavaScript. In particular they both have closures and GC, and don't have tail calls.
PHP made me a nasty surprise, I did not expect that a popular language implemented closures only recently:
http://stackoverflow.com/questions/4155254/anonymous-functions-lambdas-closu... `` Some changes have been made starting with PHP 5.3, but even there you don't have your expected variable scopes that would allow you to do what you have in your examples. ''
By the way, this is the reason why I stopped with CPSCM: this interesting project relies on the host language for implementing closures.
So if you start writing a back-end, I suggest that you supports both languages. In fact, you could support other target languages with similar properties (including Python, Ruby, elisp, ...). It should be easy to abstract the superficial differences between these languages in the "code generator" of the back-end.
The idea is great, but right now I'm not the right person who is able to make such abstraction.
Marc
On 2010-11-23, at 7:22 AM, Oleg Parashchenko wrote:
Hello Marc,
On Mon, 22 Nov 2010 14:10:46 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
I checked PHP, which I wasn't very familiar with, and it seems to have a similar syntax (in the sense of "program structure") as JavaScript. In particular they both have closures and GC, and don't have tail calls.
PHP made me a nasty surprise, I did not expect that a popular language implemented closures only recently:
http://stackoverflow.com/questions/4155254/anonymous-functions-lambdas-closu... `` Some changes have been made starting with PHP 5.3, but even there you don't have your expected variable scopes that would allow you to do what you have in your examples. ''
By the way, this is the reason why I stopped with CPSCM: this interesting project relies on the host language for implementing closures.
Sorry, I wasn't clear. The important thing is to have first-class functions (they don't have to be closures). You can "fake" closures by creating your own "closure" structure which contains the function and its free variables. That works because only the code generated by the compiler will call these fake closures, so it can implement a closure calling protocol (which passes a "self" parameter). In addition, if you want to make Scheme functions easily callable from PHP and vice-versa, you can wrap these "closure" structures with PHP's create_function. Unfortunately, PHP doesn't GC functions, so this is not a perfect solution.
So if you start writing a back-end, I suggest that you supports both languages. In fact, you could support other target languages with similar properties (including Python, Ruby, elisp, ...). It should be easy to abstract the superficial differences between these languages in the "code generator" of the back-end.
The idea is great, but right now I'm not the right person who is able to make such abstraction.
The abstraction I'm talking about is at the level of the syntax. For example, when an "if" needs to be generated for PHP, JavaScript and many other languages, the syntax "if (<test>) <true_branch> else <false_branch>" can be used (possibly with extra braces in the branches to avoid ambiguities). On the other hand, to generate a reference to the variable "x" in PHP you need to generate "$x" whereas in JavaScript and many other languages "x" is sufficient. So the abstractions of these code generators would go something like this:
(define (gen-if targ test true-branch false-branch) (string-append "if (" test ") " true-branch " else " false-branch))
(define (gen-ref targ var) (case (target-name targ) ((php) (string-append "$" var)) (else var)))
There's not much more to it than that! Note that for simplicity I used strings here. That's not particularly efficient because strings are repeatedly recopied by the string-append. It is better to build the resulting code with lists or vectors and use the "print" function to output the text (the print function prints each element, without the parentheses, spaces, etc). For example:
(define (gen-if targ test true-branch false-branch) (vector "if (" test ") " true-branch " else " false-branch))
(define (gen-ref targ var) (case (target-name targ) ((php) (vector "$" var)) (else var)))
(print (gen-if 'dummy "A" "B;" (gen-if 'dummy "C" "D;" "E;")))
;; outputs: if (A) B; else if (C) D; else E;
Marc
On Fri, Nov 19, 2010 at 9:11 AM, Marc Feeley feeley@iro.umontreal.ca wrote:
It would seem you mean #1, but that already exists (in fact you will find a Scheme to JavaScript compiler on Gambit's dumping grounds).
There is also: http://www-sop.inria.fr/indes/scheme2js/
I've used it, good times. I'd love to be able to write client-side and server-side scheme code embedded together in the same source file.
I think that's what Hop is supposed to provide (http://hop.inria.fr/), like a Scheme-oriented environment similar to Google's Java-based GWT which compiles Java to JS, but I've unfortunately never heard of anyone actually using it. imho this should really be a killer application for Scheme, but somehow it is not being used that way.
Steve
On 2010-11-19, at 7:40 AM, Oleg Parashchenko wrote:
Hello Marc,
On Thu, 18 Nov 2010 09:56:42 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
The setting of register 4 (i.e. "+4" in the GVM code) is a side effect of the jump instruction when a closure is being jumped to.
Thanks! Is it documented somewhere?
In the source code of the compiler you will find comments:
- gsc/_back.scm: top of file comment is the API with the back-end - gsc/_t-c-1.scm: check comments for each API function
Note that register 4 is unused at the moment of the jump because parameters are passed in 4 registers (+0=return address, +1=1st param, +2=2nd param, +3=3rd param).
My test shows that 4rd etc param is located on the stack, and therefore there is no register 5 or more.
However, if I understand "A parallel virtual machine for efficient scheme compilation" correctly, a backend can specify a number N of registers. I suppose that in this case the closure register will be the last register, number N. Right?
Yes. But this is under the control of the back-end which can choose the calling convention. Here's how the C back-end does it (functions targ-jump-info and function targ-label-info in gsc/_t-c-1.scm):
;; After a GVM "jump" instruction with argument count, the following ;; is true: ;; ;; * the return address is in GVM register 0 ;; ;; * if nb-args <= nb-arg-regs ;; ;; then argument N is in GVM register N ;; ;; else argument N is in ;; GVM register N-F, if N > F ;; GVM stack slot N, if N <= F ;; where F = nb-args - nb-arg-regs ;; ;; * GVM register nb-arg-regs+1 contains a pointer to the closure object ;; if a closure is being jumped to ;; ;; * other GVM registers contain an unspecified value
;; After a GVM "entry-point" or "closure-entry-point" label, the following ;; is true: ;; ;; * return address is in GVM register 0 ;; ;; * if nb-parms <= nb-arg-regs ;; ;; then parameter N is in GVM register N ;; ;; else parameter N is in ;; GVM register N-F, if N > F ;; GVM stack slot N, if N <= F ;; where F = nb-parms - nb-arg-regs ;; ;; * for a "closure-entry-point" GVM register nb-arg-regs+1 contains ;; a pointer to the closure object ;; ;; * other GVM registers contain an unspecified value
...
What is your interest in the GVM code generated by Gambit?
Short-term goal: compile Scheme code to PHP.
Instead implementing a backend for Gambit, I'd like to start with an independent tool, which parses the GVM code.
Yikes! Please don't do this! It's plain wrong! Hook into the compiler by creating a new "target". A minimalist target is no more that 100 lines of simple code.
By the way, is there an easy way to dump the internal representation for easy parsing? An optimistic try of "pretty-print" instead of "virtual.dump" is failed.
If you want to go this route, the best is to clone virtual.dump and modify it to use your favourite syntax and only output the information you are interested in. But as I said, the best is to write a new target.
More global experiment: use of Scheme as a new portable Assembler or virtual machine:
http://uucode.com/blog/2010/09/28/r5rs-scheme-as-a-virtual-machine-i/ http://uucode.com/texts/genxml/genxml.html
Interesting! I've also been using Scheme (and in particular Gambit) as a VM for most of my compiler projects (compiling Java to Scheme, Erlang to Scheme, JavaScript to Scheme, ...).
If you need more information to get this going please let me know.
Marc
Hello Marc,
On Fri, 19 Nov 2010 09:09:13 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
In the source code of the compiler you will find comments:
- gsc/_back.scm: top of file comment is the API with the back-end
- gsc/_t-c-1.scm: check comments for each API function
Thanks for the pointer, the documentation there is useful.
...
Instead implementing a backend for Gambit, I'd like to start with an independent tool, which parses the GVM code.
Yikes! Please don't do this! It's plain wrong! Hook into the compiler by creating a new "target". A minimalist target is no more that 100 lines of simple code.
I'm a bit sceptical that the task can be so easy, but going to follow the advice.
At the first time, I'll need to experiment, but the cycle (change code, re-compile gsc, install it, run the new gsc) is a bit long. Is there a possibility to avoid re-compilation and immediately run the new code?
Marc
On 2010-11-23, at 7:11 AM, Oleg Parashchenko wrote:
Hello Marc,
On Fri, 19 Nov 2010 09:09:13 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
In the source code of the compiler you will find comments:
- gsc/_back.scm: top of file comment is the API with the back-end
- gsc/_t-c-1.scm: check comments for each API function
Thanks for the pointer, the documentation there is useful.
...
Instead implementing a backend for Gambit, I'd like to start with an independent tool, which parses the GVM code.
Yikes! Please don't do this! It's plain wrong! Hook into the compiler by creating a new "target". A minimalist target is no more that 100 lines of simple code.
I'm a bit sceptical that the task can be so easy, but going to follow the advice.
See the code attached below (_t-univ.scm) which you should put in the gsc/ subdirectory.
At the first time, I'll need to experiment, but the cycle (change code, re-compile gsc, install it, run the new gsc) is a bit long. Is there a possibility to avoid re-compilation and immediately run the new code?
Absolutely! You can interpret the code you are developing and hook it into the compiler (so that the compiler is calling your interpreted code). It is all transparent (the compiler, which is compiled Scheme code, can call interpreted Scheme code, and vice-versa). Here's a sample interaction from within the gsc/ subdirectory:
% gsc Gambit v4.6.0
(load "_t-univ.scm")
"/Users/feeley/gambit/gsc/_t-univ.scm"
(c#cf "fib.scm" 'php '() #f #f)
...
The (load "_t-univ.scm") installs a target for php. Note that I am calling c#cf (the compiler's internal "compile-file" function) directly so that the target (i.e. php) can be chosen explicitly. See the top of the file gsc/_front.scm for documentation on c#cf's parameters.
If you modify _t-univ.scm you can either reload the file, or send to the REPL the function definition that you modified (this can be done with a cut-and-paste, or even better, from within emacs with C-x C-e if your cursor is just after the code to send to the REPL, and you are running gsi as a subprocess, with C-u M-x run-scheme).
Marc
Hello Marc,
On Tue, 23 Nov 2010 09:35:29 -0500 Marc Feeley feeley@iro.umontreal.ca wrote:
...
I'm a bit sceptical that the task can be so easy, but going to follow the advice.
See the code attached below (_t-univ.scm) which you should put in the gsc/ subdirectory.
...
% gsc Gambit v4.6.0
(load "_t-univ.scm")
"/Users/feeley/gambit/gsc/_t-univ.scm"
(c#cf "fib.scm" 'php '() #f #f)
Thanks a lot!
Now I have enough information to learn and understand.
Marc