Previously we've cached the stack base and dereferenced from there, but when the
stack is resized, this reference is invalidated and there is no good fix it in
all frames (we don't store back references).
This commit replaces pointers with indexes, so the stack frame is always
displaced onto the current lisp stack.
Previously when unbinding we've skipped blocks and tags and let the frame exit
to collect the frame variable. This commit simplifies managing the environment
in the compiler.
Previously our calculations were off because:
- we've counted special variables
- we didn't decrement the env size when unbound
One could argue that we need only to increment it, but then we'd end up with the
size too big. Consider:
(progn
(let ((a 1)) (foobar))
(let ((b 1)) (foobar)))
In this snippet we have two local variables, but we never look at locals beyond
the first element.
env_size is not computed correctly (neither max size nor current size), these
assertions are meant to help with mending the issue in order to correctly
determine the size of the locals environment.
c_lcl_idx computes the location of the entry in the locals env. It does traverse
the list again, so it adds a little overhead, but this will allow us to
customize it later to compute a location from the bottom.
This commit replaces capturing whole LEX with an explicit vector of closed
variables. We introduce a set of additional opcodes that deal with closed
entities. Locals are referred as lcl and closed variables as lex.
This commit causes an intentional regression in the bytecodes compiler - we
don't carry over macros and symbol macros, so we can't recompile bytecompiled
function with the native compiler if they reference them.
That will be fixed in a more organized manner after flat closures are in place.
- split c_tag_ref into three functions c_{tag,blk,fun}_ref, clean c_var_ref
small differences between functions made the former harder to read
also update comments about the compiler environment
functions are refactored to have a similar shape and return the
same (internal) structure that denotes the object scope and purpose
- don't push special variables as locations in the environment
that was (an irrelevant) bug, because special variables are not in the en
- rename asm_c to asm_arg_data
This name better resembles the purpose of the operator
The previous function call sequence for ordinary global functions
looked as follows.
1. check whether the function is defined, i.e. whether
symbol->symbol.gfdef is not NULL
2. set the_env->function to symbol->symbol.gfdef
3. call the function pointer symbol->symbol.gfdef->cfun.entry
This commit implements a performance optimization that enables us to
skip the first step. The basic idea is to replace symbol->symbol.gfdef
with a closure that signals an undefined-function condition.
However, straightforwardly implementing this would have the
disadvantage that it would consume a larger amount of memory for each
symbol without a function definition. To get around this, we reorder
the fields of the ecl_symbol struct such that the symbol can serve as
the function object itself, introducing an entry point that is only
used for undefined functions.
Benchmarking shows an improvement of about 10% in thight loops
compared to the old method.
Introduce ecl_cmp_symbol_value and ecl_cmp_setq which do the minimal
amount of work needed to implement symbol-value and setq for dynamic
variables which we have checked to be non-null and of type symbol in
the compiler.
Also introduce a type check in ecl_symbol_value to be consistent with
ecl_setq which also checks the type. These two functions are mainly
used for the embedding interface now, so for that reason it is also
useful to have a type check in there.
The comment mentioned that aux variables (the sixth value) are returned the
same way as requireds, optionals and keywords however factually that was not
the case - the number of variables was not the first element of the list. This
commit updates the function and all its callers.
Previously, we unconditionally created closures when a lambda form was
encountered in a non-empty lexical environment. Now we check first if
something from the enclosing environment is actually used in the
function.
Was previously only initialized in si_eval_with_env. Due to the
introduction of si_bc_compile_from_stream, it was used uninitialized
in this new function, leading to segfaults.
We need to defer initialization forms until all dependent creation
forms have been compiled (see CLHS make-load-form). Closes#562.
Co-authored-by: Marius Gerbershagen <marius.gerbershagen@gmail.com>
When a literal appears in the file multiple times its identity should be
preserved.
CLHS 3.2.4.4:
> If two literal objects appearing in the source code for a single
> file processed with the file compiler are the identical, the
> corresponding objects in the compiled code must also be the identical.
Previously, every bytecode object created during ext::bc-compile-file
had its own vector of constants making it impossible to satisfy this
constraint. Thus, we change ext::bc-compile-file to use the same
constants vector for all bytecode objects from the same file. The
simplest way to achieve this is to use the same compiler environment
for all of the compilation process and push the read-compile loop
into the si_bc_compile_from_stream function implemented in C.
Function is rewritten in C in compiler.d to remove a dependency
between the bytecodes compiler and the clos module. It may be more
performant thanks to more precise type handing, however we use a list
instead of a hashtable, so it may be slower with lookup. To assess
that we should run some benchmarks against real code -- rewriting C
code to work with a hash table should be trivial.
clos::need-to-make-load-form-p is now si::need-to-make-load-form-p and
may be called from C code as si_need_to_make_load_form_p.
Many parts of the source code were bent backward to support builds
without long floats which are always present given we depend expect
c99 compiler.
The corresponding C macros (ECL_LONG_FLOAT) and the *feature*
entry (:long-float) are marked as deprecated in the documentation.
Issue comes from the fact that list and symbol types are not
disjoint. Fixes#475.
My personal opinion (to put some rambling in a commit message) is that
having NIL being so many things is a blatant mistake and shouldn't be
picked up for Common Lisp (though many programs would probably break
and it wouldn't be so Common then).
Only close around functions and variables when actually needed.
Reverse changes to compiler environment, since we need the
bytecode and native compiler environemnts to be
similar (si::eval-with-env is called in the native compiler with
its own compiler environment, so having symbol macros both
c_env->variables and c_env->macros could be problematic).