mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-18 18:40:22 +02:00
Fixed the compiler, got the disassembler working.
* doc/guile-vm.texi: Texified and cleaned up. * src/vm.c: Use `scm_from_locale_string ()' instead of `scm_makfrom0str ()'. * src/vm_engine.c: Likewise. * src/programs.c (scm_program_bytecode): Return a u8vector instead of a string. * module/system/vm/conv.scm (make-byte-decoder): Fixed a few things wrt. to the string to u8vector transition. * src/objcodes.c (bytecode->objcode): Fixed a bug where the last 10 bytes of the bytecode where ignored. * module/system/vm/assemble.scm (dump-object!): Don't convert everything to a u8vector, keep strings where it makes sense. * module/system/vm/conv.scm (code->bytes): Accordingly, convert strings to u8vectors when needed. (make-byte-decoder): Accordingly too, when decoding instructions, return variable-length instructions' argument as strings except for `load-program'. * module/system/vm/disasm.scm: Export `disassemble-bytecode'. git-archimport-id: lcourtes@laas.fr--2004-libre/guile-vm--revival--0.6--patch-4
This commit is contained in:
parent
054599f117
commit
fa19602c28
9 changed files with 223 additions and 135 deletions
|
@ -6,9 +6,9 @@
|
||||||
@setchapternewpage odd
|
@setchapternewpage odd
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@set EDITION 0.3
|
@set EDITION 0.6
|
||||||
@set VERSION 0.3
|
@set VERSION 0.6
|
||||||
@set UPDATED 2000-08-22
|
@set UPDATED 2005-04-26
|
||||||
|
|
||||||
@ifinfo
|
@ifinfo
|
||||||
@dircategory Scheme Programming
|
@dircategory Scheme Programming
|
||||||
|
@ -79,10 +79,14 @@ approved by the Free Software Foundation.
|
||||||
This document corresponds to Guile VM @value{VERSION}.
|
This document corresponds to Guile VM @value{VERSION}.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
* Introduction::
|
||||||
|
* Variable Management::
|
||||||
|
* Program Execution::
|
||||||
|
* Instruction Set::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@c *********************************************************************
|
@c *********************************************************************
|
||||||
@node Introduction, Getting Started, Top, Top
|
@node Introduction, Variable Management, Top, Top
|
||||||
@chapter What is Guile VM?
|
@chapter What is Guile VM?
|
||||||
|
|
||||||
A Guile VM has a set of registers and its own stack memory. Guile may
|
A Guile VM has a set of registers and its own stack memory. Guile may
|
||||||
|
@ -90,33 +94,35 @@ have more than one VM's. Each VM may execute at most one program at a
|
||||||
time. Guile VM is a CISC system so designed as to execute Scheme and
|
time. Guile VM is a CISC system so designed as to execute Scheme and
|
||||||
other languages efficiently.
|
other languages efficiently.
|
||||||
|
|
||||||
@unnumberdsubsec Registers
|
@unnumberedsubsec Registers
|
||||||
|
|
||||||
pc - Program counter ;; ip (instruction poiner) is better?
|
@itemize
|
||||||
sp - Stack pointer
|
@item pc - Program counter ;; ip (instruction poiner) is better?
|
||||||
bp - Base pointer
|
@item sp - Stack pointer
|
||||||
ac - Accumulator
|
@item bp - Base pointer
|
||||||
|
@item ac - Accumulator
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@unnumberdsubsec Engine
|
@unnumberedsubsec Engine
|
||||||
|
|
||||||
A VM may have one of three engines: reckless, regular, or debugging.
|
A VM may have one of three engines: reckless, regular, or debugging.
|
||||||
Reckless engine is fastest but dangerous. Regular engine is normally
|
Reckless engine is fastest but dangerous. Regular engine is normally
|
||||||
fail-safe and reasonably fast. Debugging engine is safest and
|
fail-safe and reasonably fast. Debugging engine is safest and
|
||||||
functional but very slow.
|
functional but very slow.
|
||||||
|
|
||||||
@unnumberdsubsec Memory
|
@unnumberedsubsec Memory
|
||||||
|
|
||||||
Stack is the only memory that each VM owns. The other memory is shared
|
Stack is the only memory that each VM owns. The other memory is shared
|
||||||
memory that is shared among every VM and other part of Guile.
|
memory that is shared among every VM and other part of Guile.
|
||||||
|
|
||||||
@unnumberdsubsec Program
|
@unnumberedsubsec Program
|
||||||
|
|
||||||
A VM program consists of a bytecode that is executed and an environment
|
A VM program consists of a bytecode that is executed and an environment
|
||||||
in which execution is done. Each program is allocated in the shared
|
in which execution is done. Each program is allocated in the shared
|
||||||
memory and may be executed by any VM. A program may call other programs
|
memory and may be executed by any VM. A program may call other programs
|
||||||
within a VM.
|
within a VM.
|
||||||
|
|
||||||
@unnumberdsubsec Instruction
|
@unnumberedsubsec Instruction
|
||||||
|
|
||||||
Guile VM has dozens of system instructions and (possibly) hundreds of
|
Guile VM has dozens of system instructions and (possibly) hundreds of
|
||||||
functional instructions. Some Scheme procedures such as cons and car
|
functional instructions. Some Scheme procedures such as cons and car
|
||||||
|
@ -129,18 +135,19 @@ Most instructions deal with the accumulator (ac). The VM stores all
|
||||||
results from functions in ac, instead of pushing them into the stack.
|
results from functions in ac, instead of pushing them into the stack.
|
||||||
I'm not sure whether this is a good thing or not.
|
I'm not sure whether this is a good thing or not.
|
||||||
|
|
||||||
@node Variable Management
|
@node Variable Management, Program Execution, Introduction, Top
|
||||||
@chapter Variable Management
|
@chapter Variable Management
|
||||||
|
|
||||||
A program may have access to local variables, external variables, and
|
A program may have access to local variables, external variables, and
|
||||||
top-level variables.
|
top-level variables.
|
||||||
|
|
||||||
** Local/external variables
|
@section Local/external variables
|
||||||
|
|
||||||
A stack is logically divided into several blocks during execution. A
|
A stack is logically divided into several blocks during execution. A
|
||||||
"block" is such a unit that maintains local variables and dynamic chain.
|
"block" is such a unit that maintains local variables and dynamic chain.
|
||||||
A "frame" is an upper level unit that maintains subprogram calls.
|
A "frame" is an upper level unit that maintains subprogram calls.
|
||||||
|
|
||||||
|
@example
|
||||||
Stack
|
Stack
|
||||||
dynamic | | | |
|
dynamic | | | |
|
||||||
chain +==========+ - =
|
chain +==========+ - =
|
||||||
|
@ -159,9 +166,11 @@ A "frame" is an upper level unit that maintains subprogram calls.
|
||||||
/|frame data| | |
|
/|frame data| | |
|
||||||
| +----------+ - |
|
| +----------+ - |
|
||||||
| | | | |
|
| | | | |
|
||||||
|
@end example
|
||||||
|
|
||||||
The first block of each frame may look like this:
|
The first block of each frame may look like this:
|
||||||
|
|
||||||
|
@example
|
||||||
Address Data
|
Address Data
|
||||||
------- ----
|
------- ----
|
||||||
xxx0028 Local variable 2
|
xxx0028 Local variable 2
|
||||||
|
@ -172,6 +181,7 @@ The first block of each frame may look like this:
|
||||||
xxx0014 Stack pointer (block data)
|
xxx0014 Stack pointer (block data)
|
||||||
xxx0010 Return address (frame data)
|
xxx0010 Return address (frame data)
|
||||||
xxx000c Parent program (frame data)
|
xxx000c Parent program (frame data)
|
||||||
|
@end example
|
||||||
|
|
||||||
The base pointer (bp) always points to the lowest address of local
|
The base pointer (bp) always points to the lowest address of local
|
||||||
variables of the recent block. Local variables are referred as "bp[n]".
|
variables of the recent block. Local variables are referred as "bp[n]".
|
||||||
|
@ -185,6 +195,7 @@ The external link field of a block has a pointer to such a variable set,
|
||||||
which I call "fragment" (what should I call?). A fragment has a set of
|
which I call "fragment" (what should I call?). A fragment has a set of
|
||||||
variables and its own chain.
|
variables and its own chain.
|
||||||
|
|
||||||
|
@example
|
||||||
local external
|
local external
|
||||||
chain| | chain
|
chain| | chain
|
||||||
| +-----+ .--------, |
|
| +-----+ .--------, |
|
||||||
|
@ -195,6 +206,7 @@ variables and its own chain.
|
||||||
`-|block|---->|external|-'
|
`-|block|---->|external|-'
|
||||||
+-----+ `--------'
|
+-----+ `--------'
|
||||||
| |
|
| |
|
||||||
|
@end example
|
||||||
|
|
||||||
An external variable is referred as "bp[-2]->variables[n]" or
|
An external variable is referred as "bp[-2]->variables[n]" or
|
||||||
"bp[-2]->link->...->variables[n]". This is also represented by a pair
|
"bp[-2]->link->...->variables[n]". This is also represented by a pair
|
||||||
|
@ -204,19 +216,21 @@ current environment of a program.
|
||||||
|
|
||||||
Other data fields are described later.
|
Other data fields are described later.
|
||||||
|
|
||||||
** Top-level variables
|
@section Top-level variables
|
||||||
|
|
||||||
Guile VM uses the same top-level variables as the regular Guile. A
|
Guile VM uses the same top-level variables as the regular Guile. A
|
||||||
program may have direct access to vcells. Currently this is done by
|
program may have direct access to vcells. Currently this is done by
|
||||||
calling scm_intern0, but a program is possible to have any top-level
|
calling scm_intern0, but a program is possible to have any top-level
|
||||||
environment defined by the current module.
|
environment defined by the current module.
|
||||||
|
|
||||||
*** Scheme and VM variable
|
@section Scheme and VM variable
|
||||||
|
|
||||||
Let's think about the following Scheme code as an example:
|
Let's think about the following Scheme code as an example:
|
||||||
|
|
||||||
|
@example
|
||||||
(define (foo a)
|
(define (foo a)
|
||||||
(lambda (b) (list foo a b)))
|
(lambda (b) (list foo a b)))
|
||||||
|
@end example
|
||||||
|
|
||||||
In the lambda expression, "foo" is a top-level variable, "a" is an
|
In the lambda expression, "foo" is a top-level variable, "a" is an
|
||||||
external variable, and "b" is a local variable.
|
external variable, and "b" is a local variable.
|
||||||
|
@ -228,24 +242,28 @@ creates a subprogram (closure), associating the fragment with the
|
||||||
subprogram as its external environment. When the closure is executed,
|
subprogram as its external environment. When the closure is executed,
|
||||||
its environment will look like this:
|
its environment will look like this:
|
||||||
|
|
||||||
|
@example
|
||||||
block Top-level: foo
|
block Top-level: foo
|
||||||
+-------------+
|
+-------------+
|
||||||
|local var: b | fragment
|
|local var: b | fragment
|
||||||
+-------------+ .-----------,
|
+-------------+ .-----------,
|
||||||
|external link|---->|variable: a|
|
|external link|---->|variable: a|
|
||||||
+-------------+ `-----------'
|
+-------------+ `-----------'
|
||||||
|
@end example
|
||||||
|
|
||||||
The fragment remains as long as the closure exists.
|
The fragment remains as long as the closure exists.
|
||||||
|
|
||||||
** Addressing mode
|
@section Addressing mode
|
||||||
|
|
||||||
Guile VM has five addressing modes:
|
Guile VM has five addressing modes:
|
||||||
|
|
||||||
o Real address
|
@itemize
|
||||||
o Local position
|
@item Real address
|
||||||
o External position
|
@item Local position
|
||||||
o Top-level location
|
@item External position
|
||||||
o Constant object
|
@item Top-level location
|
||||||
|
@item Constant object
|
||||||
|
@end itemize
|
||||||
|
|
||||||
Real address points to the address in the real program and is only used
|
Real address points to the address in the real program and is only used
|
||||||
with the program counter (pc).
|
with the program counter (pc).
|
||||||
|
@ -262,50 +280,56 @@ object directly.
|
||||||
|
|
||||||
[ We'll also need dynamic scope addressing to support Emacs Lisp? ]
|
[ We'll also need dynamic scope addressing to support Emacs Lisp? ]
|
||||||
|
|
||||||
*** At a Glance
|
@unnumberedsubsec At a Glance
|
||||||
|
|
||||||
Guile VM has a set of instructions for each instruction family. `%load'
|
Guile VM has a set of instructions for each instruction family. `%load'
|
||||||
is, for example, a family to load an object from memory and set the
|
is, for example, a family to load an object from memory and set the
|
||||||
accumulator (ac). There are four basic `%load' instructions:
|
accumulator (ac). There are four basic `%load' instructions:
|
||||||
|
|
||||||
|
@example
|
||||||
%loadl - Local addressing
|
%loadl - Local addressing
|
||||||
%loade - External addressing
|
%loade - External addressing
|
||||||
%loadt - Top-level addressing
|
%loadt - Top-level addressing
|
||||||
%loadi - Immediate addressing
|
%loadi - Immediate addressing
|
||||||
|
@end example
|
||||||
|
|
||||||
A possible program code may look like this:
|
A possible program code may look like this:
|
||||||
|
|
||||||
|
@example
|
||||||
%loadl (0 . 1) ; ac = local[0][1]
|
%loadl (0 . 1) ; ac = local[0][1]
|
||||||
%loade (2 . 3) ; ac = external[2][3]
|
%loade (2 . 3) ; ac = external[2][3]
|
||||||
%loadt (foo . #<undefined>) ; ac = #<undefined>
|
%loadt (foo . #<undefined>) ; ac = #<undefined>
|
||||||
%loadi "hello" ; ac = "hello"
|
%loadi "hello" ; ac = "hello"
|
||||||
|
@end example
|
||||||
|
|
||||||
One instruction that uses real addressing is `%jump', which changes the
|
One instruction that uses real addressing is `%jump', which changes the
|
||||||
value of the program counter:
|
value of the program counter:
|
||||||
|
|
||||||
|
@example
|
||||||
%jump 0x80234ab8 ; pc = 0x80234ab8
|
%jump 0x80234ab8 ; pc = 0x80234ab8
|
||||||
|
@end example
|
||||||
|
|
||||||
* Program Execution
|
|
||||||
|
@node Program Execution, Instruction Set, Variable Management, Top
|
||||||
|
@chapter Program Execution
|
||||||
|
|
||||||
Overall procedure:
|
Overall procedure:
|
||||||
|
|
||||||
1. A source program is compiled into a bytecode.
|
@enumerate
|
||||||
|
@item A source program is compiled into a bytecode.
|
||||||
|
@item A bytecode is given an environment and becomes a program.
|
||||||
|
@item A VM starts execution, creating a frame for it.
|
||||||
|
@item Whenever a program calls a subprogram, a new frame is created for it.
|
||||||
|
@item When a program finishes execution, it returns a value, and the VM
|
||||||
|
continues execution of the parent program.
|
||||||
|
@item When all programs terminated, the VM returns the final value and stops.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
2. A bytecode is given an environment and becomes a program.
|
@section Environment
|
||||||
|
|
||||||
3. A VM starts execution, creating a frame for it.
|
|
||||||
|
|
||||||
4. Whenever a program calls a subprogram, a new frame is created for it.
|
|
||||||
|
|
||||||
5. When a program finishes execution, it returns a value, and the VM
|
|
||||||
continues execution of the parent program.
|
|
||||||
|
|
||||||
6. When all programs terminated, the VM returns the final value and stops.
|
|
||||||
|
|
||||||
** Environment
|
|
||||||
|
|
||||||
Local variable:
|
Local variable:
|
||||||
|
|
||||||
|
@example
|
||||||
(let ((a 1) (b 2) (c 3)) (+ a b c)) ->
|
(let ((a 1) (b 2) (c 3)) (+ a b c)) ->
|
||||||
|
|
||||||
%pushi 1 ; a
|
%pushi 1 ; a
|
||||||
|
@ -317,9 +341,11 @@ Local variable:
|
||||||
%pushl (0 . 2) ; local variable c
|
%pushl (0 . 2) ; local variable c
|
||||||
add 3 ; ac = a + b + c
|
add 3 ; ac = a + b + c
|
||||||
%unbind ; remove local bindings
|
%unbind ; remove local bindings
|
||||||
|
@end example
|
||||||
|
|
||||||
External variable:
|
External variable:
|
||||||
|
|
||||||
|
@example
|
||||||
(define foo (let ((n 0)) (lambda () n)))
|
(define foo (let ((n 0)) (lambda () n)))
|
||||||
|
|
||||||
%pushi 0 ; n
|
%pushi 0 ; n
|
||||||
|
@ -335,15 +361,19 @@ External variable:
|
||||||
%call 0 ; change the current external link
|
%call 0 ; change the current external link
|
||||||
%loade (0 . 0) ; external variable n
|
%loade (0 . 0) ; external variable n
|
||||||
%return ; recover the external link
|
%return ; recover the external link
|
||||||
|
@end example
|
||||||
|
|
||||||
Top-level variable:
|
Top-level variable:
|
||||||
|
|
||||||
|
@example
|
||||||
foo ->
|
foo ->
|
||||||
|
|
||||||
%loadt (foo . #<program xxx>) ; top-level variable foo
|
%loadt (foo . #<program xxx>) ; top-level variable foo
|
||||||
|
@end example
|
||||||
|
|
||||||
** Flow control
|
@section Flow control
|
||||||
|
|
||||||
|
@example
|
||||||
(if #t 1 0) ->
|
(if #t 1 0) ->
|
||||||
|
|
||||||
%loadi #t
|
%loadi #t
|
||||||
|
@ -352,11 +382,13 @@ Top-level variable:
|
||||||
%jump L2
|
%jump L2
|
||||||
L1: %loadi 0
|
L1: %loadi 0
|
||||||
L2:
|
L2:
|
||||||
|
@end example
|
||||||
|
|
||||||
** Function call
|
@section Function call
|
||||||
|
|
||||||
Builtin function:
|
Builtin function:
|
||||||
|
|
||||||
|
@example
|
||||||
(1+ 2) ->
|
(1+ 2) ->
|
||||||
|
|
||||||
%loadi 2 ; ac = 2
|
%loadi 2 ; ac = 2
|
||||||
|
@ -374,9 +406,11 @@ Builtin function:
|
||||||
%pushi 2 ; 2 -> stack
|
%pushi 2 ; 2 -> stack
|
||||||
%pushi 3 ; 3 -> stack
|
%pushi 3 ; 3 -> stack
|
||||||
add 3 ; many argument
|
add 3 ; many argument
|
||||||
|
@end example
|
||||||
|
|
||||||
External function:
|
External function:
|
||||||
|
|
||||||
|
@example
|
||||||
(version) ->
|
(version) ->
|
||||||
|
|
||||||
%func0 (version . #<primitive-procedure version>) ; no argument
|
%func0 (version . #<primitive-procedure version>) ; no argument
|
||||||
|
@ -399,9 +433,11 @@ External function:
|
||||||
%pushi 3
|
%pushi 3
|
||||||
%loadi 3 ; the number of arguments
|
%loadi 3 ; the number of arguments
|
||||||
%func (equal . #<primitive-procedure equal>) ; many arguments
|
%func (equal . #<primitive-procedure equal>) ; many arguments
|
||||||
|
@end example
|
||||||
|
|
||||||
** Subprogram call
|
@section Subprogram call
|
||||||
|
|
||||||
|
@example
|
||||||
(define (plus a b) (+ a b))
|
(define (plus a b) (+ a b))
|
||||||
(plus 1 2) ->
|
(plus 1 2) ->
|
||||||
|
|
||||||
|
@ -413,8 +449,10 @@ External function:
|
||||||
%loadl (0 . 1) ; argument 2
|
%loadl (0 . 1) ; argument 2
|
||||||
add2 ; ac = 1 + 2
|
add2 ; ac = 1 + 2
|
||||||
%return ; result is 3
|
%return ; result is 3
|
||||||
|
@end example
|
||||||
|
|
||||||
* Instruction Set
|
@node Instruction Set, , Program Execution, Top
|
||||||
|
@chapter Instruction Set
|
||||||
|
|
||||||
The Guile VM instruction set is roughly divided two groups: system
|
The Guile VM instruction set is roughly divided two groups: system
|
||||||
instructions and functional instructions. System instructions control
|
instructions and functional instructions. System instructions control
|
||||||
|
@ -422,79 +460,97 @@ the execution of programs, while functional instructions provide many
|
||||||
useful calculations. By convention, system instructions begin with a
|
useful calculations. By convention, system instructions begin with a
|
||||||
letter `%'.
|
letter `%'.
|
||||||
|
|
||||||
** Environment control instructions
|
@section Environment control instructions
|
||||||
|
|
||||||
- %alloc
|
@itemize
|
||||||
- %bind
|
@item %alloc
|
||||||
- %export
|
@item %bind
|
||||||
- %unbind
|
@item %export
|
||||||
|
@item %unbind
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Subprogram control instructions
|
@section Subprogram control instructions
|
||||||
|
|
||||||
- %make-program
|
@itemize
|
||||||
- %call
|
@item %make-program
|
||||||
- %return
|
@item %call
|
||||||
|
@item %return
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Data control instructinos
|
@section Data control instructinos
|
||||||
|
|
||||||
- %push
|
@itemize
|
||||||
- %pushi
|
@item %push
|
||||||
- %pushl, %pushl:0:0, %pushl:0:1, %pushl:0:2, %pushl:0:3
|
@item %pushi
|
||||||
- %pushe, %pushe:0:0, %pushe:0:1, %pushe:0:2, %pushe:0:3
|
@item %pushl, %pushl:0:0, %pushl:0:1, %pushl:0:2, %pushl:0:3
|
||||||
- %pusht
|
@item %pushe, %pushe:0:0, %pushe:0:1, %pushe:0:2, %pushe:0:3
|
||||||
|
@item %pusht
|
||||||
|
@end itemize
|
||||||
|
|
||||||
- %loadi
|
@itemize
|
||||||
- %loadl, %loadl:0:0, %loadl:0:1, %loadl:0:2, %loadl:0:3
|
@item %loadi
|
||||||
- %loade, %loade:0:0, %loade:0:1, %loade:0:2, %loade:0:3
|
@item %loadl, %loadl:0:0, %loadl:0:1, %loadl:0:2, %loadl:0:3
|
||||||
- %loadt
|
@item %loade, %loade:0:0, %loade:0:1, %loade:0:2, %loade:0:3
|
||||||
|
@item %loadt
|
||||||
|
@end itemize
|
||||||
|
|
||||||
- %savei
|
@itemize
|
||||||
- %savel, %savel:0:0, %savel:0:1, %savel:0:2, %savel:0:3
|
@item %savei
|
||||||
- %savee, %savee:0:0, %savee:0:1, %savee:0:2, %savee:0:3
|
@item %savel, %savel:0:0, %savel:0:1, %savel:0:2, %savel:0:3
|
||||||
- %savet
|
@item %savee, %savee:0:0, %savee:0:1, %savee:0:2, %savee:0:3
|
||||||
|
@item %savet
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Flow control instructions
|
@section Flow control instructions
|
||||||
|
|
||||||
- %br-if
|
@itemize
|
||||||
- %br-if-not
|
@item %br-if
|
||||||
- %jump
|
@item %br-if-not
|
||||||
|
@item %jump
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Function call instructions
|
@section Function call instructions
|
||||||
|
|
||||||
- %func, %func0, %func1, %func2
|
@itemize
|
||||||
|
@item %func, %func0, %func1, %func2
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Scheme buitin functions
|
@section Scheme built-in functions
|
||||||
|
|
||||||
- cons
|
@itemize
|
||||||
- car
|
@item cons
|
||||||
- cdr
|
@item car
|
||||||
|
@item cdr
|
||||||
|
@end itemize
|
||||||
|
|
||||||
** Mathematical buitin functions
|
@section Mathematical buitin functions
|
||||||
|
|
||||||
- 1+
|
@itemize
|
||||||
- 1-
|
@item 1+
|
||||||
- add, add2
|
@item 1-
|
||||||
- sub, sub2, minus
|
@item add, add2
|
||||||
- mul2
|
@item sub, sub2, minus
|
||||||
- div2
|
@item mul2
|
||||||
- lt2
|
@item div2
|
||||||
- gt2
|
@item lt2
|
||||||
- le2
|
@item gt2
|
||||||
- ge2
|
@item le2
|
||||||
- num-eq2
|
@item ge2
|
||||||
|
@item num-eq2
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@c *********************************************************************
|
@c *********************************************************************
|
||||||
@node Concept Index, Command Index, Related Information, Top
|
@c @node Concept Index, Command Index, Related Information, Top
|
||||||
@unnumbered Concept Index
|
@c @unnumbered Concept Index
|
||||||
@printindex cp
|
@c @printindex cp
|
||||||
|
|
||||||
@node Command Index, Variable Index, Concept Index, Top
|
@c @node Command Index, Variable Index, Concept Index, Top
|
||||||
@unnumbered Command Index
|
@c @unnumbered Command Index
|
||||||
@printindex fn
|
@c @printindex fn
|
||||||
|
|
||||||
@node Variable Index, , Command Index, Top
|
@c @node Variable Index, , Command Index, Top
|
||||||
@unnumbered Variable Index
|
@c @unnumbered Variable Index
|
||||||
@printindex vr
|
@c @printindex vr
|
||||||
|
|
||||||
@bye
|
@bye
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
(label-alist '())
|
(label-alist '())
|
||||||
(object-alist '()))
|
(object-alist '()))
|
||||||
(define (push-code! code)
|
(define (push-code! code)
|
||||||
|
(format #t "push-code! ~a~%" code)
|
||||||
(set! stack (cons (code->bytes code) stack)))
|
(set! stack (cons (code->bytes code) stack)))
|
||||||
(define (push-object! x)
|
(define (push-object! x)
|
||||||
(cond ((object->code x) => push-code!)
|
(cond ((object->code x) => push-code!)
|
||||||
|
@ -90,7 +91,7 @@
|
||||||
(push-code! `(object-ref ,i))))))
|
(push-code! `(object-ref ,i))))))
|
||||||
(define (current-address)
|
(define (current-address)
|
||||||
(define (byte-length x)
|
(define (byte-length x)
|
||||||
(cond ((string? x) (u8vector-length x))
|
(cond ((u8vector? x) (u8vector-length x))
|
||||||
(else 3)))
|
(else 3)))
|
||||||
(apply + (map byte-length stack)))
|
(apply + (map byte-length stack)))
|
||||||
(define (generate-code x)
|
(define (generate-code x)
|
||||||
|
@ -167,6 +168,7 @@
|
||||||
;;
|
;;
|
||||||
;; main
|
;; main
|
||||||
(for-each generate-code body)
|
(for-each generate-code body)
|
||||||
|
(format #t "codegen: stack = ~a~%" (reverse stack))
|
||||||
(let ((bytes (stack->bytes (reverse! stack) label-alist)))
|
(let ((bytes (stack->bytes (reverse! stack) label-alist)))
|
||||||
(if toplevel
|
(if toplevel
|
||||||
(bytecode->objcode bytes vars.nlocs vars.nexts)
|
(bytecode->objcode bytes vars.nlocs vars.nexts)
|
||||||
|
@ -211,18 +213,6 @@
|
||||||
;; NOTE: undumpped in vm_load.c.
|
;; NOTE: undumpped in vm_load.c.
|
||||||
|
|
||||||
(define (dump-object! push-code! x)
|
(define (dump-object! push-code! x)
|
||||||
(define (symbol->u8vector sym)
|
|
||||||
(apply u8vector
|
|
||||||
(map char->integer
|
|
||||||
(string->list (symbol->string sym)))))
|
|
||||||
(define (number->u8vector num)
|
|
||||||
(apply u8vector
|
|
||||||
(map char->integer
|
|
||||||
(string->list (number->string num)))))
|
|
||||||
(define (string->u8vector str)
|
|
||||||
(apply u8vector
|
|
||||||
(map char->integer (string->list str))))
|
|
||||||
|
|
||||||
(let dump! ((x x))
|
(let dump! ((x x))
|
||||||
(cond
|
(cond
|
||||||
((object->code x) => push-code!)
|
((object->code x) => push-code!)
|
||||||
|
@ -256,7 +246,7 @@
|
||||||
(push-code! `(load-program ,bytes)))
|
(push-code! `(load-program ,bytes)))
|
||||||
(($ <vlink> module name)
|
(($ <vlink> module name)
|
||||||
;; FIXME: dump module
|
;; FIXME: dump module
|
||||||
(push-code! `(link ,(symbol->u8vector name))))
|
(push-code! `(link ,(symbol->string name))))
|
||||||
(($ <vmod> id)
|
(($ <vmod> id)
|
||||||
(push-code! `(load-module ,id)))
|
(push-code! `(load-module ,id)))
|
||||||
((and ($ integer) ($ exact))
|
((and ($ integer) ($ exact))
|
||||||
|
@ -266,14 +256,14 @@
|
||||||
(apply u8vector l)))))
|
(apply u8vector l)))))
|
||||||
(push-code! `(load-integer ,str))))
|
(push-code! `(load-integer ,str))))
|
||||||
(($ number)
|
(($ number)
|
||||||
(push-code! `(load-number ,(number->u8vector x))))
|
(push-code! `(load-number ,(number->string x))))
|
||||||
(($ string)
|
(($ string)
|
||||||
(push-code! `(load-string ,(string->u8vector x))))
|
(push-code! `(load-string ,(string->string x))))
|
||||||
(($ symbol)
|
(($ symbol)
|
||||||
(push-code! `(load-symbol ,(symbol->u8vector x))))
|
(push-code! `(load-symbol ,(symbol->string x))))
|
||||||
(($ keyword)
|
(($ keyword)
|
||||||
(push-code! `(load-keyword
|
(push-code! `(load-keyword
|
||||||
,(symbol->u8vector (keyword-dash-symbol x)))))
|
,(symbol->string (keyword-dash-symbol x)))))
|
||||||
(($ list)
|
(($ list)
|
||||||
(for-each dump! x)
|
(for-each dump! x)
|
||||||
(push-code! `(list ,(length x))))
|
(push-code! `(list ,(length x))))
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
:use-module (ice-9 match)
|
:use-module (ice-9 match)
|
||||||
:use-module (ice-9 regex)
|
:use-module (ice-9 regex)
|
||||||
:use-module (srfi srfi-4)
|
:use-module (srfi srfi-4)
|
||||||
|
:use-module (srfi srfi-1)
|
||||||
:export (code-pack code-unpack object->code code->object code->bytes
|
:export (code-pack code-unpack object->code code->object code->bytes
|
||||||
make-byte-decoder))
|
make-byte-decoder))
|
||||||
|
|
||||||
|
@ -86,7 +87,18 @@
|
||||||
(('load-keyword s) (make-keyword-from-dash-symbol (string->symbol s)))
|
(('load-keyword s) (make-keyword-from-dash-symbol (string->symbol s)))
|
||||||
(else #f)))
|
(else #f)))
|
||||||
|
|
||||||
|
; (let ((c->o code->object))
|
||||||
|
; (set! code->object
|
||||||
|
; (lambda (code)
|
||||||
|
; (format #t "code->object: ~a~%" code)
|
||||||
|
; (let ((ret (c->o code)))
|
||||||
|
; (format #t "code->object returned ~a~%" ret)
|
||||||
|
; ret))))
|
||||||
|
|
||||||
(define (code->bytes code)
|
(define (code->bytes code)
|
||||||
|
(define (string->u8vector str)
|
||||||
|
(apply u8vector (map char->integer (string->list str))))
|
||||||
|
|
||||||
(let* ((code (code-pack code))
|
(let* ((code (code-pack code))
|
||||||
(inst (car code))
|
(inst (car code))
|
||||||
(rest (cdr code))
|
(rest (cdr code))
|
||||||
|
@ -95,6 +107,8 @@
|
||||||
(cond ((< len 0)
|
(cond ((< len 0)
|
||||||
;; Variable-length code
|
;; Variable-length code
|
||||||
;; Typical instructions are `link' and `load-program'.
|
;; Typical instructions are `link' and `load-program'.
|
||||||
|
(if (string? (car rest))
|
||||||
|
(set-car! rest (string->u8vector (car rest))))
|
||||||
(let* ((str (car rest))
|
(let* ((str (car rest))
|
||||||
(str-len (u8vector-length str))
|
(str-len (u8vector-length str))
|
||||||
(encoded-len (encode-length str-len))
|
(encoded-len (encode-length str-len))
|
||||||
|
@ -121,9 +135,11 @@
|
||||||
(define (make-byte-decoder bytes)
|
(define (make-byte-decoder bytes)
|
||||||
(let ((addr 0) (size (u8vector-length bytes)))
|
(let ((addr 0) (size (u8vector-length bytes)))
|
||||||
(define (pop)
|
(define (pop)
|
||||||
(let ((byte (char->integer (u8vector-ref bytes addr))))
|
(let ((byte (u8vector-ref bytes addr)))
|
||||||
(set! addr (1+ addr))
|
(set! addr (1+ addr))
|
||||||
byte))
|
byte))
|
||||||
|
(define (sublist lst start end)
|
||||||
|
(take (drop lst start) (- end start)))
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(if (< addr size)
|
(if (< addr size)
|
||||||
(let* ((start addr)
|
(let* ((start addr)
|
||||||
|
@ -132,12 +148,16 @@
|
||||||
(code (if (< n 0)
|
(code (if (< n 0)
|
||||||
;; variable length
|
;; variable length
|
||||||
(let* ((end (+ (decode-length pop) addr))
|
(let* ((end (+ (decode-length pop) addr))
|
||||||
(str (apply u8vector
|
(subbytes (sublist
|
||||||
(list-tail (u8vector->list
|
(u8vector->list bytes)
|
||||||
bytes)
|
addr end))
|
||||||
addr))))
|
(->string? (not (eq? inst 'load-program))))
|
||||||
(set! addr end)
|
(set! addr end)
|
||||||
(list inst str))
|
(list inst
|
||||||
|
(if ->string?
|
||||||
|
(list->string
|
||||||
|
(map integer->char subbytes))
|
||||||
|
(apply u8vector subbytes))))
|
||||||
;; fixed length
|
;; fixed length
|
||||||
(do ((n n (1- n))
|
(do ((n n (1- n))
|
||||||
(l '() (cons (pop) l)))
|
(l '() (cons (pop) l)))
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
:use-module (ice-9 format)
|
:use-module (ice-9 format)
|
||||||
:use-module (ice-9 receive)
|
:use-module (ice-9 receive)
|
||||||
:use-module (ice-9 and-let-star)
|
:use-module (ice-9 and-let-star)
|
||||||
:export (disassemble-objcode disassemble-program))
|
:export (disassemble-objcode disassemble-program disassemble-bytecode))
|
||||||
|
|
||||||
(define (disassemble-objcode objcode . opts)
|
(define (disassemble-objcode objcode . opts)
|
||||||
(let* ((prog (objcode->program objcode))
|
(let* ((prog (objcode->program objcode))
|
||||||
|
@ -129,6 +129,15 @@
|
||||||
(define (list->info list)
|
(define (list->info list)
|
||||||
(object->string list))
|
(object->string list))
|
||||||
|
|
||||||
|
; (define (u8vector->string vec)
|
||||||
|
; (list->string (map integer->char (u8vector->list vec))))
|
||||||
|
|
||||||
|
; (case (car list)
|
||||||
|
; ((link)
|
||||||
|
; (object->string `(link ,(u8vector->string (cadr list)))))
|
||||||
|
; (else
|
||||||
|
; (object->string list))))
|
||||||
|
|
||||||
(define (print-info addr info extra)
|
(define (print-info addr info extra)
|
||||||
(if extra
|
(if extra
|
||||||
(format #t "~4@A ~32A;; ~A\n" addr info extra)
|
(format #t "~4@A ~32A;; ~A\n" addr info extra)
|
||||||
|
|
|
@ -87,7 +87,7 @@ SCM_DEFINE (scm_instruction_list, "instruction-list", 0, 0, 0,
|
||||||
SCM list = SCM_EOL;
|
SCM list = SCM_EOL;
|
||||||
struct scm_instruction *ip;
|
struct scm_instruction *ip;
|
||||||
for (ip = scm_instruction_table; ip->opcode != scm_op_last; ip++)
|
for (ip = scm_instruction_table; ip->opcode != scm_op_last; ip++)
|
||||||
list = scm_cons (scm_str2symbol (ip->name), list);
|
list = scm_cons (scm_from_locale_symbol (ip->name), list);
|
||||||
return scm_reverse_x (list, SCM_EOL);
|
return scm_reverse_x (list, SCM_EOL);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
@ -150,7 +150,7 @@ SCM_DEFINE (scm_opcode_to_instruction, "opcode->instruction", 1, 0, 0,
|
||||||
SCM_VALIDATE_INUM (1, op);
|
SCM_VALIDATE_INUM (1, op);
|
||||||
i = scm_to_int (op);
|
i = scm_to_int (op);
|
||||||
SCM_ASSERT_RANGE (1, op, 0 <= i && i < scm_op_last);
|
SCM_ASSERT_RANGE (1, op, 0 <= i && i < scm_op_last);
|
||||||
return scm_str2symbol (scm_instruction_table[i].name);
|
return scm_from_locale_symbol (scm_instruction_table[i].name);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,8 @@ SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 3, 0, 0,
|
||||||
c_bytecode = scm_u8vector_elements (bytecode, &handle, &size, &increment);
|
c_bytecode = scm_u8vector_elements (bytecode, &handle, &size, &increment);
|
||||||
assert (increment == 1);
|
assert (increment == 1);
|
||||||
|
|
||||||
|
/* Account for the 10 byte-long header. */
|
||||||
|
size += 10;
|
||||||
objcode = make_objcode (size);
|
objcode = make_objcode (size);
|
||||||
base = SCM_OBJCODE_BASE (objcode);
|
base = SCM_OBJCODE_BASE (objcode);
|
||||||
|
|
||||||
|
|
|
@ -188,15 +188,26 @@ SCM_DEFINE (scm_program_external, "program-external", 1, 0, 0,
|
||||||
|
|
||||||
SCM_DEFINE (scm_program_bytecode, "program-bytecode", 1, 0, 0,
|
SCM_DEFINE (scm_program_bytecode, "program-bytecode", 1, 0, 0,
|
||||||
(SCM program),
|
(SCM program),
|
||||||
"")
|
"Return a u8vector containing @var{program}'s bytecode.")
|
||||||
#define FUNC_NAME s_scm_program_bytecode
|
#define FUNC_NAME s_scm_program_bytecode
|
||||||
{
|
{
|
||||||
|
size_t size;
|
||||||
|
char *c_bytecode;
|
||||||
|
|
||||||
SCM_VALIDATE_PROGRAM (1, program);
|
SCM_VALIDATE_PROGRAM (1, program);
|
||||||
return scm_makfromstr (SCM_PROGRAM_DATA (program)->base,
|
|
||||||
SCM_PROGRAM_DATA (program)->size, 0);
|
size = SCM_PROGRAM_DATA (program)->size;
|
||||||
|
c_bytecode = malloc (size);
|
||||||
|
if (!c_bytecode)
|
||||||
|
return SCM_BOOL_F;
|
||||||
|
|
||||||
|
memcpy (c_bytecode, SCM_PROGRAM_DATA (program)->base, size);
|
||||||
|
|
||||||
|
return scm_take_u8vector (c_bytecode, size);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
scm_init_programs (void)
|
scm_init_programs (void)
|
||||||
|
|
2
src/vm.c
2
src/vm.c
|
@ -301,7 +301,7 @@ SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
|
||||||
"")
|
"")
|
||||||
#define FUNC_NAME s_scm_vm_version
|
#define FUNC_NAME s_scm_vm_version
|
||||||
{
|
{
|
||||||
return scm_makfrom0str (VERSION);
|
return scm_from_locale_string (VERSION);
|
||||||
}
|
}
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
|
|
|
@ -123,44 +123,44 @@ vm_run (SCM vm, SCM program, SCM args)
|
||||||
/* Errors */
|
/* Errors */
|
||||||
{
|
{
|
||||||
vm_error_unbound:
|
vm_error_unbound:
|
||||||
err_msg = scm_makfrom0str ("VM: Unbound variable: ~A");
|
err_msg = scm_from_locale_string ("VM: Unbound variable: ~A");
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
vm_error_wrong_type_arg:
|
vm_error_wrong_type_arg:
|
||||||
err_msg = scm_makfrom0str ("VM: Wrong type argument");
|
err_msg = scm_from_locale_string ("VM: Wrong type argument");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
vm_error_wrong_num_args:
|
vm_error_wrong_num_args:
|
||||||
err_msg = scm_makfrom0str ("VM: Wrong number of arguments");
|
err_msg = scm_from_locale_string ("VM: Wrong number of arguments");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
vm_error_wrong_type_apply:
|
vm_error_wrong_type_apply:
|
||||||
err_msg = scm_makfrom0str ("VM: Wrong type to apply: ~S");
|
err_msg = scm_from_locale_string ("VM: Wrong type to apply: ~S");
|
||||||
err_args = SCM_LIST1 (program);
|
err_args = SCM_LIST1 (program);
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
vm_error_stack_overflow:
|
vm_error_stack_overflow:
|
||||||
err_msg = scm_makfrom0str ("VM: Stack overflow");
|
err_msg = scm_from_locale_string ("VM: Stack overflow");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
vm_error_stack_underflow:
|
vm_error_stack_underflow:
|
||||||
err_msg = scm_makfrom0str ("VM: Stack underflow");
|
err_msg = scm_from_locale_string ("VM: Stack underflow");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
|
|
||||||
#if VM_CHECK_IP
|
#if VM_CHECK_IP
|
||||||
vm_error_invalid_address:
|
vm_error_invalid_address:
|
||||||
err_msg = scm_makfrom0str ("VM: Invalid program address");
|
err_msg = scm_from_locale_string ("VM: Invalid program address");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if VM_CHECK_EXTERNAL
|
#if VM_CHECK_EXTERNAL
|
||||||
vm_error_external:
|
vm_error_external:
|
||||||
err_msg = scm_makfrom0str ("VM: Invalid external access");
|
err_msg = scm_from_locale_string ("VM: Invalid external access");
|
||||||
err_args = SCM_EOL;
|
err_args = SCM_EOL;
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue