| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* vm.c (vm_make_desc): Do not walk ftab to resolve the
function bindings at VM instantiation time. Just let it be
done late in vm_ftab when a gcall or gapply instruction is
executing. We don't gain anything by doing it early; there
is no error checking or anything. This early resolution causes
the autoload semantics of the standard library modules to
change between interpreted and compiled. When a compiled
module is loaded, it immediately triggers autloads of
everything that it potentially references. This suddenly broke
the build under a newer GNU Make which doesn't sort the files
expanded by $(wildcard ...), causing the library to be
compiled in a different order.
|
|
|
|
|
|
|
| |
* vm.c (vm_closure_struct): New static function.
(vm_closure_desc, vm_closure_entry): New functions.
(vm_init): sys:vm-closure-desc and sys:vm-closure-entry
intrinsics registered.
|
|
|
|
|
| |
* vm.c (vm_insn_opcode): Conversion between integer types
requires convert rather than coerce.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* lisplib.c (compiler_set_entries): Autoload on compile-file.
* parser.c (parse_init): Expose get-parser, parser-errors and
parser-eof intrinsics in system package.
* share/txr/stdlib/compiler.tl (compiler): Wrap defstruct form
in compile-only. What this means is that when we invoke
comile-file on compiler.tl, the compiler will only compile
this defstruct and not evaluate it. I.e. it will not try to
redefine the structure. Redefining the core structure of the
compiler while it is compiling itself wreaks havoc on the
compilation.
(%fille-suff-rx%, *emit*, *eval*): New variables.
(open-compile-streams, list-from-vm-desc, usr:compile-file):
New functions.
* vm.c (vm_desc_nlevels, vm_desc_nregs): New static functions.
(vm_init): Register new intrinsics vm-desc-nlevels and
vn-desc-nregs in system package.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It doesn't Just Work out of the box. Here is why.
The struct vm state is declared somewhere on the stack,
and then the vm executes various recursive functions.
A block is established by vm_block(). Then if a continuation
is captured up to that block, it will not include that part
of the stack which holds the VM state. When the continuation
is restarted, the struct vm * pointers inside the stack will
be garbage.
The solution: when a continuation is captured to a prompt that
is set up by the VM block instruction (vm_block function),
we put information into the block which says "don't just
capture me plus some slack: please capture the stack all the
way up to this specific address here". That address, of
course, is just past the VM state, ensuring that the VM state
is included in the snapshot.
In short: a delimited continuation terminating in a prompt
set up by the VM just include the entire VM context from the
stack frame where the struct vm on down (i.e. up the stack)
to the capture point.
* unwind.c (uw_push_block): Initialize cont_bottom
member to zero. Interpreted blocks leave this as zero.
Blocks set up by the VM override it.
(revive_cont): Critical: the range check must include
the orig_end endpoint, because when the struct vm is captured
into the continuation it is right at the end of the capture
memory, and the prompt block's cont_bottom member points
exactly to orig_end: one element past the struct vm.
The cont_bottom member must be adjusted by delta
so that continuations captured by the revived VM
inside the continuation get the adjusted cont_bottom at their
current stack location.
(capture_cont): If the block is publishing a non-zer
cont_bottom value, then take that value if it is a higher
address than the lim (including the UW_CONT_FRAME_AFTER
slack).
* unwind.h (struct uw_block): New member, cont_bottom.
By means of this, a block can indicate a higher address
to which a continuation capture can extend.
* vm.c (vm_block): Publish the address one byte past the
virtual machine state as the stack bottom for continuations.
|
|
|
|
|
|
|
|
|
|
| |
* share/txr/stdlib/asm.tl (prof): New opcode.
(op-prof): New opcode class.
* vm.c (vm_prof_callback, vm_prof): New static functions.
(vm_execute): Handle PROF opcode via vm_prof.
* vmop.h: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* share/txr/stdlib/asm.tl (backpatch-low16, backpatch-high16):
New struct types.
(%backpatch-low16%, %backpatch-high16%): New global variables.
(swtch): New opcode.
(op-swtch): New opcode class.
* vm.c (vm_swtch): New static function.
(vm_execute): Handle SWTCH opcode via vm_swtch.
* vmop.h: Regenerated.
|
|
|
|
|
|
| |
* vm.c (vm_make_closure): Add missing scale factor to memcpy.
This is the memcpy which relocates display frame contents from
the stack to the frame.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* share/txr/stdlib/asm.tl (abscsr): New instruction.
(op-abscsr): New opcode class, derived from op-retsr.
* share/txr/stdlib/compiler.tl: Handle sys:abscond-from via
comp-return-from method.
(compiler comp-return-from): Handle sys:abscond-from by
switching to abscsr opcode instead of ret pseudo-op.
* vm.c (vm_abscsr): New static function.
(vm_execute): Dispatch ABSCSR opcode.
* vmop.h: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In most compiler uses of bindv, getv and setv,
the operand which names the dynamic symbol is the data table:
a d0-dff register. The source or destination register of the
transfer could be anything. Therefore, the existing encoding
is suboptimal: the symbol is being put into the full sized
operand field of the instruction, and the source or
destination register into the small, ten-bit extra field
in the upper half. This breaks on cases like (set x y)
where x is a deeply nested lexical variable and y is
a dynamic variable. Let's reverse the encoding.
* share/txr/stdlib/asm.tl (op-getv, op-setv): Reverse the
operands. All derived opcodes follow this since they
reuse the code via inheritance.
* vm.c (vm_get_binding): Fetch the symbol from the small
operand field rather than the main operand field.
(vm_getsym, vm_getbind, vm_setsym, vm_bindv): Pull the
destination or source from the main operand of the instruction
rather than the small opreand.
|
|
|
|
|
|
|
|
| |
* vm.c (vm_make_desc): Initialize vd->funvec to nil so that
when the object is created, it doesn't have a garbage field.
However, there is no risk here that the field will be
traversed by the garbage collector, since immediately after
allocating the objct, we initialize the fields.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Let's have a field in struct vm_desc that keeps track of the
ftab size. The problem is when we do length_vec(vd->funvec) in
vm_desc_mark, we are in the middle of garbage collection.
The object's tag has a reachable bit which blows up the
type check.
* vm.c (struct vm_desc): New member, ftsz.
(vm_make_desc): Store the length of the function table
into ftsz.
(vm_desc_mark): Use the stored length as the loop bound;
do not access vd->funvec.
|
|
|
|
|
|
| |
* vm.c (vm_no_block_err): New static function.
(vm_retsr, vm_retrs, vm_retrr): Call vm_no_block_err if
uw_block_return returns.
|
|
|
|
|
|
|
|
|
|
| |
* vm.c (struct vm_closure): Redeclare display member as array
of 1: old-fashioned version of C struct hack.
(vm_make_closure): Make the necessary adjustments to the
allocation code.
(vm_closure_destroy): Static function removed.
(vm_closure_mark): Wire in cobj_destroy_free_op once again,
since there is just one object to free.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This allows a virtual machine's funvec to refer to functions
that are not yet defined. We resolve all the ones that are
defined when the virtual machine description is constructed.
The others are resolved at vm execution time when accessed.
* vm.c (vm_make_desc): When filling ftab with resolved
function bindings, check that lookup_fun has returned nil; in
that case, initialize the binding location to zero,
instead of blowing up calling cdr_l(nil).
(vm_ftab): New static function. Implements the null check
and late resolution.
(vm_gcall, vm_gapply): Acces ftab through vm_ftab instead
of open-coded expression.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* share/txr/stdlib/compiler.tl (sys:env :postinit): The call
to register the environment with the compiler must be outside
of the unless form. Otherwise it never takes place, and so the
compiler doesn't find the maximum number of environment
levels, keeping the value at 2. The executing vm then accesses
out of bounds memory when setting up display frames.
(usr:compile-toplevel): Give the root environment the
compiler. Not strictly necessary since we are constent in
doing this elsewhere, so we are not relying on inheritance
of the compiler from parent environment to child.
* vm.c (vm_make_closure): assert added for the environment
levels of the closure not exceeding the display depth given
in the machine description. This was added during debugging
and going off; I'm keeping it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* vm.c (vm_execute_closure): Remove bogus nargs local
variable, and replace its uses by fixparam which is the
correct one to use for getting the list of trailing arguments
using args_get_rest and for the loop which extracts the fixed
arguments. The "if (variadic)" statement near the end
specifically depends on the variadic destination register not
having been extracted yet from the instruction space,
so the argument count used in the previousl loop cannot
include that register. This bug was causing that statement to
extract a zero, thus register t0, which then blew up in the vm
execution as an attempt to modify t0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The vm now supports gcall and gapply opcodes which index
numerically (using an immediate integer field in the
instruction word) into a table of pre-resolved global function
bindings.
* share/txr/stdlib/asm.tl (op-gcall, op-gapply): New opcodes.
(disassemble-c-d): Take the function vector as an argument and
dump it too.
(usr:disassemble): Extract function vector from VM description
and pass it to disassemble-c-d.
* share/txr/stdlib/compiler.tl (usr:compile-toplevel): Pass
empty function symbol vector to vm-make-desc; it's now a
required argument.
* vm.c (struct vm_desc): New members funvec and ftab.
(struct vm_ftent): New struct type.
(vm_make_desc): New argument, funvec. Store funvec in the
descriptor. Allocate a table of vm_ftent structures equal in
number of elements to the function table, and populate it with
resolved bindings.
(vm_desc_funvec, vm_desc_destroy): New static functions.
(vm_desc_mark): Mark the captured bindings in vd->ftab.
(vm_gcall, vm_gapply): New static functions.
(vm_execute): Handle GCALL and GAPPLY opcodes.
(vm_desc_ops): Wire vm_desc_destroy in place of
cobj_destroy_free_op.
(vm_init): Add argument to vm-make-desc intrinsic. Register
vm-desc-funvec intrinsic.
* vm.h (vm_make_desc): Declaration updated.
* vmop.h: Regenerated
|
|
|
|
|
|
| |
* vm.c (vm_closure_destroy): New static function.
(vm_closure_ops): Use vm_closure_destroy rather than
generic cobj_destroy_free_op.
|
|
|
|
|
|
|
|
|
|
| |
* share/txr/stdlib/asm.tl (op-ifq, op-ifql): New opcode
types.
* vm.c (vm_ifq, vm_ifql): New static functions.
(vm_execute): Handle IFQ and IFQL opcodes.
* vmop.h (vm_op_t): Regenerated.
|
|
|
|
|
|
| |
* vm.c (vm_make_desc): We can't call vecref_l on an empty
vector, because it has no index zero. Let's use a null
location in this case.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* lisplib.c (asm_set_entries): Autoload on usr:disassemble.
* share/txr/stdlib/asm.tl (assembler): Drop initializer
from bstr slot. Requires complex initialization for the
case when the buf is supplied by the constructor caller
for the sake of disassembling existing code.
(assembler :postinit): Handle cases when only one of
buf or bstr are set, and when both are not set,
for the greatest flexibility.
(disassemble-c-d, disassemble): New functions.
* vm.c (vm_desc_datavec): New static function.
(vm_init): Registered vm-desc-datavec intrinsic.
|
|
|
|
|
| |
* vm.c (vm_init): Register vm_execute_toplevel as
vm-execute-toplevel rather than vm-interpret-toplevel.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is for allocating a new frame purely on the stack. The
frame will not be captured by lexical closures, and so can
only be used for non-shared variables and additional
compiler-generated temporaries (if registers run out, for
instance).
* share/txr/stdlib/asm.tl (op-sframe, sframe): New opcode
class and opcode.
* vm.c (vm_do_frame): New static function for the common
implementation of frame and sframe.
(vm_frame): Now just a call with vm_do_frame, passing the flag
indicating that closure capture is enabled for this
environment frame.
(vm_sframe): New static function.
* vmop.h: Regenerated.
|
|
|
|
|
|
| |
* vm.c (vm_make_closure): When copying captured environment
from stack to heap, use memcpy instead of a loop with
assignments.
|
|
This commit is the start of compiler work to make TXR Lisp
execute faster. In six days of part time work, we now have a
register-style virtual machine with 32 instructions, handling
exceptions, unwind-protect, lexical closures, and global
environment access/mutation. We have a complete assembler and
disassembler for this machine. The assembler supports labels
with forward referencing with backpatching, and features
pseudo-ops: for instance the (mov ...) pseudo-instruction
chooses one of three kinds of specific move instruction based
on the operands.
* Makelfile (OBJS): Add vm.o.
* eval.c (lookup_sym_lisp1): Static function becomes external;
the virtual machine needs to use this to support that style
of lookup.
* genvmop.txr: New file. This is the generator for the
"vmop.h" header.
* lib.c (func_vm): New function.
(generic_funcall): Handle the FVM function type via new
vm_execute_closure function. In the variadic case, we want
to avoid the argument copying which we do for the sake of C
functions that get their fixed arguments directly, and then
just the trailing arguments. Thus the code is restructured a
bit in order to switch twice on the function type.
(init): Call vm_init.
* lib.h (functype_t): New enum member FVM.
(struct func): New member in the .f union: vm_desc.
(func_vm): Declared.
* lisplib.c (set_dlt_entries_impl): New static function,
formed from set_dlt_entries.
(set_dlt_entries): Reduced to wrapper for
set_dlt_entries_impl, passing in the user package.
(set_dlt_entries_sys): New static function: like
set_dlt_entries but targetting the sys package.
(asm_instantiate, asm_set_entries): New static functions.
(lisplib_init): Auto-load the sys:assembler class.
* share/txr/stdlib/asm.tl: New file.
* vm.c, vm.h, vmop.h: New files.
|