* doc/ref/vm.texi (Stack Layout): Update to remove references to the
"heap link".
* gdbinit: Update for "heap link" removal.
* libguile/frames.c:
* libguile/frames.h: Update macros and diagram for removal of "heap
link". As part of this, we also remove "heap frames", replacing them
with "vm frames", which are much like the interpreter's debug objects,
but for VM stacks. That is to say, they don't actually hold the stack
themselves, just the pointers into stack that's held by a continuation
(either captured or current).
* libguile/stacks.c (stack_depth, read_frames): Since a "stack" object is
really a copy of information that comes from somewhere else, it makes
sense to copy over info from the VM, just as `make-stack' does from the
evaluator. The tricky bit is to figure out how to interleave VM and
interpreter frames. We do that by starting in the interpreter, and
whenever the current frame's procedure is actually a program, we switch
to the VM stack, switching back when we reach a "bootstrap frame". The
last bit is hacky, but it does work...
(is_vm_bootstrap_frame): Hacky predicate to see if a VM frame is a
bootstrap frame.
(scm_make_stack): Accept a VM frame in addition to debug frames.
Probably has some bugs in this case. But in the case that the arg is
#t (a common case), do the right thing, capturing the top VM frame as
well, and interleaving those frames appropriately on the stack.
As an accident, we lost the ability to limit the number of frames in
the backtrace. We could add that back, but personally I always want
*all* frames in the trace... Narrowing still works fine, though there
are some hiccups sometimes -- e.g. an outer cut to a procedure that
does a tail-call in VM code will never find the cut, as it no longer
exists in the continuation.
* libguile/vm.h (struct scm_vm): So! Now that we have switched to save
stacks in the normal make-stack, there's no more need for `this_frame'
or `last_frame'. On the other hand, we can take this opportunity to fix
tracing: when we're in a trace hook, we set `trace_frame' on the VM,
so we know not to fire hooks when we're already in a hook.
(struct scm_vm_cont): Expose this, as make-stack needs it to make VM
frames from VM continuations.
* libguile/vm.c (scm_vm_trace_frame): New function, gets the current
trace frame.
(vm_mark, make_vm): Hook up the trace frame.
(vm_dispatch_hook): New hook dispatcher, with a dynwind so it does the
right thing if the hook exits nonlocally.
* libguile/vm-engine.c (vm_run): No more this_frame in the wind data.
* libguile/vm-engine.h (RUN_HOOK): Run hooks through the dispatcher.
(ALIGN_AS_NON_IMMEDIATE, POP_LIST_ON_STACK): Remove unused code.
(NEW_FRAME): Adapt for no HL in the frame.
* libguile/vm-i-system.c (goto/args, mv-call, return, return/values):
Adapt for no HL in the frame.
* module/system/vm/frame.scm:
* module/system/vm/vm.scm: Beginnings of some reworkings, needs more
thought.
* gdbinit (pp, inst): New commands.
* libguile/vm-engine.c (vm_error_not_a_pair): New error case.
* libguile/vm-i-scheme.c (VM_VALIDATE_CONS): New macro -- use this
instead of SCM_VALIDATE_* because SCM_VALIDATE will exit nonlocally
before we have a chance to sync the regs.
(car, cdr, set-car, set-cdr): Use VM_VALIDATE_CONS.
* libguile/vm-i-system.c (goto/args): Bugfix: when doing a
self-tail-recursion, allocate fresh externals. Fixes use of match.go.
* module/system/vm/assemble.scm (dump-object!): Add some checks that we
aren't dumping out values that the VM can't handle.
* module/system/vm/disasm.scm (disassemble-externals): Fix rotten call to
`print-info'.
* oop/goops/dispatch.scm: Add a FIXME.
* testsuite/Makefile.am (vm_test_files):
* testsuite/t-closure4.scm (extract-symbols): New test, distilled with
much effort out of match.scm.
* ice-9/Makefile.am (NOCOMP_SOURCES): Re-enable compilation of match.scm.
Yay!
I saw this problem when running elisp.test -- it tries to apply a
function to an arglist ending in nil, which obviously is not null.
* libguile/vm-engine.h (PUSH_LIST): New helper macro, pushes the elements
of a list onto the stack. Checks to make sure that the list is proper.
* libguile/vm-i-system.c (list-break, mv-call, apply, goto/apply)
(goto/cc): Use LIST_BREAK.
* libguile/vm-engine.c (vm_error_improper_list): New error case.
* libguile/vm-engine.c (vm_error_wrong_num_args): Sync the registers
before calling scm_wrong_num_args. (The other cases are handled more
uniformly.)
* libguile/vm.c (vm_heapify_frames_1): Add a FIXME: I don't think we
should be modifying the stack.
(scm_vm_save_stack): If stack nulling is enabled, verify the stack here
before reifying it.
* module/language/scheme/spec.scm (scheme): Use primitive-eval here
instead of eval, because at the repl we do want to allow evaluations to
have side effects like setting the current module.
* libguile/vm-engine.c: Call scm_wrong_num_args in the wrong-num-args
case, to be more like the interpreter.
* libguile/vm-engine.h (ASSERT): New macro.
* libguile/vm-i-system.c (apply, goto/apply): Assert that nargs >= 2,
because the compiler should always feed us correct instructions.
(call/cc): If no values are returned to the continuation, signal
no_values instead of wrong_num_args.
* libguile/vm-engine.c (vm_run): Add new error case for resolving @ or @@
references, but there is no such module. Possible if
module-public-interface returns #f.
* libguile/vm-i-loader.c (link-now): Allow the stack arg to be a sym, as
before, or a list, indicating an absolute reference. Could be two
separate instructions, but I'm lazy.
* libguile/vm-i-system.c (late-variable-ref, late-variable-set): As in
link-now, allow the lazy reference to be a list, for @ and @@.
* module/language/scheme/translate.scm (custom-transformer-table):
Compile @ and @@, and set! forms for both of them. This will ease the
non-hygienic pain for exported macros.
* module/system/il/compile.scm (make-glil-var): Translate public and
private module variable references into glil-module variables.
* module/system/il/ghil.scm (ghil-var-at-module!): New function, resolves
a variable for @ or @@.
* module/system/il/glil.scm (<glil-module>): Revival of <glil-module>,
this time with the semantics that it really links to a particular
module.
* module/system/vm/assemble.scm (<vlink-now>, <vlink-later>): Redefine as
taking a "key" as the argument, which may be a sym or a list; see the
notes on link-now for more details.
(codegen): Compile <glil-module> appropriately. Some duplication here,
probably could use some cleanup later.
* libguile/continuations.c (scm_make_continuation): Capture VM
continuations as well, as their stack is outside the C stack.
(copy_stack): Reinstate VM stacks with the C stack.
* libguile/continuations.h (scm_t_contregs): Add a pointer for VM stacks.
A binary-incompatible change -- hopefully not too many people were
messing around with this struct, though.
* libguile/vm-engine.c (vm_run): Add a note about possibly maintaining a
stack of vms.
* libguile/vm.c (struct scm_vm_cont): New struct, distinct from scm_vm.
(vm_cont_mark, vm_cont_free, capture_vm_cont, reinstate_vm_cont):
Reorder some code, and fix some bad assumptions about what part of the
stack to copy; obviously this code was never used.
* libguile/vm.h:
* libguile/vm.c (scm_vm_capture_continuations)
(scm_vm_reinstate_continuations): New public functions, used by
continuations.c.
* libguile/vm-engine.c (vm_run): Add new error case,
vm_error_not_enough_values.
* libguile/vm-i-system.c (goto/nargs, call/nargs): So, in these cases, if
we get too many values, we don't truncate the values like we do in the
single-value continuation case, or in the mvbind case. What to do? I
guess we either truncate them here, or only allow the correct number of
values. Dunno. Mark the code as a fixme.
(truncate-values): New instruction, for mv-bind: checks that the number
of values on the stack is compatible with the number of bindings we
have arranged for them, truncating if necessary.
* module/language/scheme/translate.scm (custom-transformer-table):
Compile receive as a primary form -- not so much because it is a
primary form, but more to test the mv-bind machinery. Also it's more
efficient, I think.
* module/system/il/compile.scm (lift-variables!): New helper, factored
out of `optimize'.
(optimize): Add a few more cases. Adapt `lambda' optimization, which
isn't much. I'm not happy with ghil as a mungeable language.
Add a case for call-with-values with the second argument is
a lambda: lift the lambda. Untested.
(codegen): Refactor the push-bindings! code. Compile mv-bind.
* module/system/il/ghil.scm (<ghil-mv-bind>): Add mv-bind construct,
along with its procedures.
* module/system/il/glil.scm (<glil-mv-bind>): Add mv-bind construct,
different from the high-level one. It makes sense in the source, I
think.
* module/system/vm/assemble.scm (codegen): Assemble glil-mv-bind by
pushing onto the bindings list, and actually push some code to truncate
the values.
* libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap
program, as the offset passed to mv-call now takes two bytes.
* module/system/vm/frame.scm (bootstrap-frame?): Update for the new
bootstrap length. Really we should just check for 'halt though.
* libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR().
(goto/nargs, call/nargs): Versions of goto/args and call, respectively,
that take the number of arguments from a value on the top of the stack.
(mv-call): Call FETCH_OFFSET to get the offset.
* module/language/scheme/translate.scm (custom-transformer-table):
Compile call-with-values to <ghil-mv-call>. There is some trickery
because of the r4rs.scm call-with-values trampolines.
* module/system/il/ghil.scm: Add <ghil-mv-call> and accessors.
* module/system/il/compile.scm (codegen): Compile <ghil-mv-call>.
* module/system/il/glil.scm: Add <glil-mv-call>, which needs some special
assembly because of the label. Fix some typos.
* module/system/vm/assemble.scm (byte-length): New helper, factored out
and made more general.
(codegen): Assemble mv-call, including the label.
(check-length): New helper, makes sure that the addressing is
consistent within the produced object code.
(stack->bytes): Rewrite to be more generic -- now `br' instructions
aren't the only ones jumping around in the instruction stream.
* module/system/vm/conv.scm (make-byte-decoder): Return two values in the
#f case.
* module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because
the previous implementation depended on a guile interpreter quirk:
namely, that multiple values could be represented within one value, and
destructured later.
* libguile/vm-engine.c (vm_run): Move nvalues to the top level, to avoid
(spurious, it seems) gcc warnings about it being used uninitialized.
* libguile/vm-i-system.c (halt, return/values): Adapt to gcc silliness.
Deindent some of return/values.
(return/values*): New instruction, does what (apply values . args)
would do.
* module/language/scheme/translate.scm (custom-transformer-table): Move
the apply and @apply cases here from inline.scm, because we need some
more cleverness when dealing with cases like (apply values . args).
(lookup-apply-transformer): Define an eval transformer for `values',
turning it into ghil-values*.
* module/system/il/compile.scm (codegen): Compile <ghil-values*> into
return/values*.
* module/system/il/ghil.scm: Add <ghil-values*> and accessors.
(ghil-lookup): Add optional argument, define?, which if false tells us
not to actually cache the binding if it is not found in the toplevel.
* module/system/il/inline.scm: Remove apply clauses.
* module/system/vm/frame.scm (bootstrap-frame?): Update heuristic for
bootstrap-frame?, as the bootstrap frame is now 5 bytes since it
accepts multiple values.
* libguile/vm-engine.c (vm_run): The bootstrap program now uses mv_call,
so as to allow multiple values out of the VM. (It did before, because
multiple values were represented internally as single scm_values
objects, but now that values go on the stack, we need to note the boot
frame as accepting multiple values.)
(vm_error_no_values): New error, happens if you pass no values into a
single-value continuation. Passing more than one is OK though, it just
takes the first one.
* libguile/vm-i-system.c (halt): Assume that someone has pushed the
number of values onto the stack, and package up that number of values
as a scm_values() object, for communication with the interpreter.
(mv-call): New instruction, calls a procedure with a multiple-value
continuation, even handling calls out to the interpreter.
(return/values): New instruction, returns multiple values to the
continuation. If the continuation is single-valued, takes the first
value or errors if there are no values. Otherwise it returns to the
multiple-value return address, pushing the number of values on top of
the values.
* module/system/il/compile.scm (codegen): Compile <ghil-values> forms.
* module/system/il/ghil.scm (<ghil-values>) Add new GHIL data structure
and associated procedures.
* module/language/scheme/translate.scm (custom-transformer-table):
Compile (values .. ) forms into <ghil-values>.
* ice-9/boot-9.scm: Only define load-compiled as #f if it's not already
defined, which won't normally be the case.
* libguile/guile-vm.c: Removed, there's no more guile-vm binary.
* libguile/frames.c: (with change frame? -> heap-frame?)
* libguile/frames.h:
* libguile/instructions.c:
* libguile/instructions.h:
* libguile/objcodes.c:
* libguile/objcodes.h:
* libguile/programs.c:
* libguile/programs.h:
* libguile/vm-bootstrap.h: (was bootstrap.h)
* libguile/vm-engine.c: (was vm_engine.c)
* libguile/vm-engine.h: (was vm_engine.h)
* libguile/vm-expand.h: (was vm_expand.h)
* libguile/vm-i-loader.c: (was vm_loader.c)
* libguile/vm-i-scheme.c: (was vm_scheme.c)
* libguile/vm-i-system.c: (was vm_system.c)
* libguile/vm.c:
* libguile/vm.h: These files moved here from src/, as guile-vm is now a
part of libguile.
* libguile/init.c: Bootstrap the VM. Yay!
* libguile/Makefile.am: The necessary chicanery here.
* module/system/vm/Makefile.am:
* module/system/vm/bootstrap.scm:
* module/system/vm/frame.scm:
* module/system/vm/instruction.scm:
* module/system/vm/objcode.scm:
* module/system/vm/program.scm:
* module/system/vm/vm.scm:
* pre-inst-guile-env.in: Add builddirs to the load path; add module/ to
the path in the empty-$GUILE_LOAD_PATH case as well.
* src/Makefile.am: Moved out everything except guilec and guile-disasm,
which probably should be moved to the scripts directory?
* testsuite/Makefile.am: Update to find guile-vm in the right place.
* module/system/vm/Makefile.am:
* module/system/vm/bootstrap.scm: Removed bootstrap.scm, scm_init_guile
handles the bootstrapping for us.
* module/system/vm/frame.scm:
* module/system/vm/instruction.scm:
* module/system/vm/objcode.scm:
* module/system/vm/program.scm:
* module/system/vm/vm.scm: Call the init functions in libguile; should
fix at some point to avoid the dlopen?