1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Removed a few more deprecated function calls; documented closures.

* src/Makefile.am (.c.x):  Fixed the rule.

* src/envs.c:  Use `scm_hash_get_handle ()' instead of
  `scm_sym2ovcell_soft ()' and `scm_hash_create_handle_x ()' instead of
  `scm_intern_symbol ()'.

* src/objcodes.c (bytecode->objcode):  Don't use `SCM_VALIDATE_INUM', use
  `SCM_VALIDATE_NUMBER' instead.
  (make_objcode_by_mmap):  Check whether the file is smaller than the
  magic cookies; check whether the magic cookies are there.

* src/frames.c (frame-local-ref):  Likewise, but use `SCM_MAKE_VALIDATE'.
  (frame-local-set!):  Likewise.

* src/instructions.c (opcode->instruction):  Likewise.

* src/programs.c (program-external-set!):  New function.

* src/guile-disasm.in:  New file.

* src/Makefile.am:  Produce `guile-disasm'.

* doc/guile-vm.texi:  Documented `external-ref', `external-set', `local-ref'
  and `local-set'.

* module/system/vm/disasm.scm (disassemble-bytecode):  Fixed the way
  `load-program' is represented.

git-archimport-id: lcourtes@laas.fr--2005-mobile/guile-vm--mobile--0.6--patch-1
This commit is contained in:
Ludovic Courtes 2005-06-24 17:25:36 +00:00 committed by Ludovic Courtès
parent 135b32ee84
commit 6208295910
11 changed files with 149 additions and 43 deletions

View file

@ -516,19 +516,80 @@ As an example, let us look at what a simple function call looks like:
This call yields the following sequence of instructions:
@example
(link "+") ;; lookup binding "x"
(link "+") ;; lookup binding "+"
(variable-ref) ;; dereference it
(make-int8 2) ;; push immediate value `2'
(make-int8 3) ;; push immediate value `3'
(tail-call 2) ;; call the proc at sp[-3] with two args
@end example
@itemize
@item %alloc
@item %bind
@item %export
@item %unbind
@end itemize
@deffn @insn{} local-ref offset
Push onto the stack the value of the local variable located at
@var{offset} within the current stack frame.
@end deffn
@deffn @insn{} local-set offset
Pop the Scheme object located on top of the stack and make it the new
value of the local variable located at @var{offset} within the current
stack frame.
@end deffn
@deffn @insn{} external-ref offset
Push the value of the closure variable located at position
@var{offset} within the program's list of external variables.
@end deffn
@deffn @insn{} external-set offset
Pop the Scheme object located on top of the stack and make it the new
value of the closure variable located at @var{offset} within the
program's list of external variables.
@end deffn
Let's look at a more complete example:
@example
(let ((x 2))
(lambda ()
(let ((x++ (+ 1 x)))
(set! x x++)
x++)))
@end example
The resulting program has one external (closure) variable, i.e. its
@var{nexts} is set to 1 (@pxref{Subprogram Control Instructions}).
This yields the following code:
@example
;; the traditional program prologue
0 (make-int8 2)
2 (external-set 0)
4 (make-int8 4)
6 (link "+") ;; lookup `+'
9 (vector 1) ;; create the external variable vector for
;; later use by `object-ref' and `object-set'
...
40 (load-program ##34#)
59 (return)
@end example
The program loaded here by @var{load-program} contains the following
sequence of instructions:
@example
0 (object-ref 0) ;; push the variable for `+'
2 (variable-ref) ;; dereference `+'
3 (make-int8:1) ;; push 1
4 (external-ref 0) ;; push the value of `x'
6 (call 2) ;; call `+' and push the result
8 (local-set 0) ;; make it the new value of `x++'
10 (local-ref 0) ;; push the value of `x++'
12 (external-set 0) ;; make it the new value of `x'
14 (local-ref 0) ;; push the value of `x++'
16 (return) ;; return it
@end example
At this point, you know pretty much everything about the three types
of variables a program may need to access.
@node Branch Instructions, Subprogram Control Instructions, Environment Control Instructions, Instruction Set
@ -619,7 +680,7 @@ This yields the following assembly code:
(make-int8 64) ;; number of args, vars, etc. (see below)
(link "frob")
(link "%magic")
(vector 2)
(vector 2) ;; object table (external bindings)
...
(load-program #u8(20 0 23 21 0 20 1 23 36 2))
(return)
@ -637,7 +698,7 @@ argument which is the bytecode of the program itself. Disassembled,
this bytecode looks like:
@example
(object-ref 0) ;; push the variable object of `frob'
z(object-ref 0) ;; push the variable object of `frob'
(variable-ref) ;; dereference it
(local-ref 0) ;; push the value of `x'
(object-ref 1) ;; push the variable object of `%magic'
@ -646,7 +707,9 @@ this bytecode looks like:
@end example
This clearly shows that there is little difference between references
to local variables and references to externally bound variables.
to local variables and references to externally bound variables since
lookup of externally bound variables if performed only once before the
program is run.
@deffn @insn{} load-program bytecode
Load the program whose bytecode is @var{bytecode} (a u8vector), pop
@ -664,8 +727,8 @@ object table);
representing respectively the number of arguments taken by the
function (@var{nargs}), the number of @dfn{rest arguments}
(@var{nrest}, 0 or 1), the number of local variables (@var{nlocs}) and
the number of external variables (@var{nexts}) (see the example
above).
the number of external variables (@var{nexts}) (@pxref{Environment
Control Instructions}).
@end itemize
@end deffn
@ -684,12 +747,16 @@ Call the procedure, continuation or program located at
@code{sp[-nargs]} with the @var{nargs} arguments located from
@code{sp[0]} to @code{sp[-nargs + 1]}. The
procedure/continuation/program and its arguments are dropped from the
stack and the result is pushed.
stack and the result is pushed. When calling a program, the
@code{call} instruction reserves room for its local variables on the
stack, and initializes its list of closure variables and its vector of
externally bound variables.
@end deffn
@deffn @insn{} tail-call nargs
Same as @code{call} except that, for tail-recursive calls to a
program, the current stack frame is re-used, as required by RnRS.
This instruction is otherwise similar to @code{call}.
@end deffn

View file

@ -26,7 +26,7 @@
:use-module (srfi srfi-4)
:use-module (srfi srfi-1)
:export (code-pack code-unpack object->code code->object code->bytes
make-byte-decoder))
make-byte-decoder))
;;;
;;; Code compress/decompression

View file

@ -76,7 +76,7 @@
(('load-program x)
(let ((sym (gensym "")))
(set! programs (acons sym x programs))
(print-info addr (format #f "load-program #~A" sym) #f)))
(print-info addr (format #f "(load-program #~A)" sym) #f)))
(else
(let ((info (list->info code))
(extra (original-value addr code objs)))

View file

@ -1,5 +1,5 @@
bin_PROGRAMS = guile-vm
bin_SCRIPTS = guilec
bin_SCRIPTS = guilec guile-disasm
guile_vm_SOURCES = guile-vm.c
guile_vm_LDADD = libguilevm.la
guile_vm_LDFLAGS = $(GUILE_LDFLAGS)
@ -14,7 +14,8 @@ libguilevm_la_SOURCES = \
vm_engine.h vm_expand.h
libguilevm_la_LDFLAGS = -version-info 0:0:0 -export-dynamic
libguilevm_la_LDFLAGS += -pg
EXTRA_DIST = vm_engine.c vm_system.c vm_scheme.c vm_loader.c
EXTRA_DIST = vm_engine.c vm_system.c vm_scheme.c vm_loader.c \
guilec.in guile-disasm.in
BUILT_SOURCES = vm_system.i vm_scheme.i vm_loader.i \
envs.x frames.x instructions.x objcodes.x programs.x vm.x
@ -32,7 +33,7 @@ SUFFIXES = .i .x
grep '^VM_DEFINE' $< > $@
.c.x:
$(SNARF) $< $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< > $@ \
$(SNARF) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< > $@ \
|| { rm $@; false; }
@ -44,9 +45,9 @@ SUFFIXES = .i .x
%.s: %.c
$(CC) -S -dA $(DEFS) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) -o $@ $<
GUILE = "$(bindir)/guile"
guilec: guilec.in
sed "s!@guile@!$(GUILE)!" guilec.in > guilec
@chmod 755 guilec
%: %.in
sed "s!@guile@!$(GUILE)!" $^ > $@
@chmod 755 $@
$(BUILT_SOURCES): config.h vm_expand.h

View file

@ -85,7 +85,7 @@ SCM
scm_c_lookup_env (SCM identifier)
{
/* Check if the env is already loaded */
SCM vcell = scm_sym2ovcell_soft (identifier, env_table);
SCM vcell = scm_hash_get_handle (env_table, identifier);
/* If not, load the env */
if (SCM_FALSEP (vcell))
@ -95,21 +95,24 @@ scm_c_lookup_env (SCM identifier)
if (!SCM_ENV_P (env))
scm_misc_error ("scm_c_lookup_env",
"Invalid env: ~S", SCM_LIST1 (env));
scm_intern_symbol (env_table, identifier);
vcell = scm_sym2ovcell_soft (identifier, env_table);
SCM_SETCDR (vcell, env);
vcell = scm_hash_create_handle_x (env_table, identifier, env);
}
return SCM_CDR (vcell);
return (SCM_CDR (vcell));
}
SCM
scm_c_env_vcell (SCM env, SCM name, int intern)
{
SCM vcell;
SCM ob = SCM_ENV_OBARRAY (env);
if (intern)
scm_intern_symbol (ob, name);
return scm_sym2ovcell_soft (name, ob);
vcell = scm_hash_create_handle_x (ob, name, SCM_UNSPECIFIED);
else
vcell = scm_hash_get_handle (ob, name);
return vcell;
}
@ -162,10 +165,13 @@ SCM_DEFINE (scm_env_bound_p, "env-bound?", 2, 0, 0,
"")
#define FUNC_NAME s_scm_env_bound_p
{
SCM vcell;
SCM obarray, vcell;
SCM_VALIDATE_ENV (1, env);
SCM_VALIDATE_SYMBOL (2, name);
vcell = scm_sym2ovcell_soft (name, SCM_ENV_OBARRAY (env));
obarray = SCM_ENV_OBARRAY (env);
vcell = scm_hash_get_handle (obarray, name);
return SCM_BOOL (!SCM_FALSEP (vcell) && !SCM_UNBNDP (SCM_CDR (vcell)));
}
#undef FUNC_NAME
@ -178,7 +184,7 @@ SCM_DEFINE (scm_env_ref, "env-ref", 2, 0, 0,
SCM vcell;
SCM_VALIDATE_ENV (1, env);
SCM_VALIDATE_SYMBOL (2, name);
vcell = scm_sym2ovcell_soft (name, SCM_ENV_OBARRAY (env));
vcell = scm_hash_get_handle (name, SCM_ENV_OBARRAY (env));
if (SCM_FALSEP (vcell) || SCM_UNBNDP (SCM_CDR (vcell)))
SCM_MISC_ERROR ("Unbound variable in env: ~A, ~A",
SCM_LIST2 (env, name));
@ -194,11 +200,12 @@ SCM_DEFINE (scm_env_set_x, "env-set!", 3, 0, 0,
SCM vcell;
SCM_VALIDATE_ENV (1, env);
SCM_VALIDATE_SYMBOL (2, name);
vcell = scm_sym2ovcell_soft (name, SCM_ENV_OBARRAY (env));
vcell = scm_hash_get_handle (name, SCM_ENV_OBARRAY (env));
if (SCM_FALSEP (vcell))
SCM_MISC_ERROR ("Unbound variable in env: ~A, ~A",
SCM_LIST2 (env, name));
SCM_SETCDR (vcell, val);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME

View file

@ -47,10 +47,12 @@
extern scm_t_bits scm_tc16_env;
struct scm_env {
struct scm_env
{
SCM identifier;
SCM obarray;
};
typedef struct scm_env scm_env_t;
#define SCM_ENV_P(x) SCM_SMOB_PREDICATE (scm_tc16_env, x)
#define SCM_ENV_DATA(x) ((struct scm_env *) SCM_SMOB_DATA (x))

View file

@ -115,7 +115,7 @@ SCM_DEFINE (scm_frame_local_ref, "frame-local-ref", 2, 0, 0,
#define FUNC_NAME s_scm_frame_local_ref
{
SCM_VALIDATE_HEAP_FRAME (1, frame);
SCM_VALIDATE_INUM (2, index); /* FIXME: Check the range! */
SCM_MAKE_VALIDATE (2, index, I_INUMP); /* FIXME: Check the range! */
return SCM_FRAME_VARIABLE (SCM_HEAP_FRAME_POINTER (frame),
SCM_I_INUM (index));
}
@ -127,7 +127,7 @@ SCM_DEFINE (scm_frame_local_set_x, "frame-local-set!", 3, 0, 0,
#define FUNC_NAME s_scm_frame_local_set_x
{
SCM_VALIDATE_HEAP_FRAME (1, frame);
SCM_VALIDATE_INUM (2, index); /* FIXME: Check the range! */
SCM_MAKE_VALIDATE (2, index, I_INUMP); /* FIXME: Check the range! */
SCM_FRAME_VARIABLE (SCM_HEAP_FRAME_POINTER (frame),
SCM_I_INUM (index)) = val;
return SCM_UNSPECIFIED;

11
src/guile-disasm.in Normal file
View file

@ -0,0 +1,11 @@
#!@guile@ -s
!#
;; Obviously, this is -*- Scheme -*-.
(use-modules (system vm core)
(system vm disasm))
(for-each (lambda (file)
(disassemble-objcode (load-objcode file)))
(cdr (command-line)))

View file

@ -147,7 +147,7 @@ SCM_DEFINE (scm_opcode_to_instruction, "opcode->instruction", 1, 0, 0,
#define FUNC_NAME s_scm_opcode_to_instruction
{
int i;
SCM_VALIDATE_INUM (1, op);
SCM_MAKE_VALIDATE (1, op, I_INUMP);
i = SCM_I_INUM (op);
SCM_ASSERT_RANGE (1, op, 0 <= i && i < scm_op_last);
return scm_from_locale_symbol (scm_instruction_table[i].name);

View file

@ -82,10 +82,15 @@ make_objcode_by_mmap (int fd)
struct scm_objcode *p;
ret = fstat (fd, &st);
if (ret < 0) SCM_SYSERROR;
if ((ret < 0) || (st.st_size <= strlen (OBJCODE_COOKIE)))
SCM_SYSERROR;
addr = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) SCM_SYSERROR;
if (addr == MAP_FAILED)
SCM_SYSERROR;
if (memcmp (addr, OBJCODE_COOKIE, strlen (OBJCODE_COOKIE)))
SCM_SYSERROR;
p = scm_gc_malloc (sizeof (struct scm_objcode), "objcode");
p->size = st.st_size;
@ -179,8 +184,8 @@ SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 3, 0, 0,
if (scm_u8vector_p (bytecode) != SCM_BOOL_T)
scm_wrong_type_arg (FUNC_NAME, 1, bytecode);
SCM_VALIDATE_INUM (2, nlocs);
SCM_VALIDATE_INUM (3, nexts);
SCM_VALIDATE_NUMBER (2, nlocs);
SCM_VALIDATE_NUMBER (3, nexts);
c_bytecode = scm_u8vector_elements (bytecode, &handle, &size, &increment);
assert (increment == 1);
@ -191,8 +196,8 @@ SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 3, 0, 0,
base = SCM_OBJCODE_BASE (objcode);
memcpy (base, OBJCODE_COOKIE, 8);
base[8] = SCM_I_INUM (nlocs);
base[9] = SCM_I_INUM (nexts);
base[8] = scm_to_uint8 (nlocs);
base[9] = scm_to_uint8 (nexts);
memcpy (base + 10, c_bytecode, size - 10);

View file

@ -186,6 +186,19 @@ SCM_DEFINE (scm_program_external, "program-external", 1, 0, 0,
}
#undef FUNC_NAME
SCM_DEFINE (scm_program_external_set_x, "program-external-set!", 2, 0, 0,
(SCM program, SCM external),
"Modify the list of closure variables of @var{program} (for "
"debugging purposes).")
#define FUNC_NAME s_scm_program_external_set_x
{
SCM_VALIDATE_PROGRAM (1, program);
SCM_VALIDATE_LIST (2, external);
SCM_PROGRAM_DATA (program)->external = external;
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE (scm_program_bytecode, "program-bytecode", 1, 0, 0,
(SCM program),
"Return a u8vector containing @var{program}'s bytecode.")