Commit e7fe0004 authored by Marius Gerbershagen's avatar Marius Gerbershagen

doc: update outdated information and examples in the developers guide

parent 61650f8e
......@@ -41,41 +41,58 @@ The format of the intermediate C code generated by the ECL compiler is the same
The compiler generates the following intermediate C code.
@verbatim
/* function definition for ADD1 */
static cl_object L1(cl_object V1)
{ VT2 VLEX2 CLSR2
cl_object value0;
value0=number_plus(symbol_value(VV[0]),V1); NVALUES=1;
return value0;
/* function definition for ADD1 */
/* optimize speed 3, debug 0, space 0, safety 2 */
static cl_object L1add1(cl_object v1x)
{
cl_object env0 = ECL_NIL;
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
ecl_cs_check(cl_env_copy,value0);
{
TTL:
value0 = ecl_plus(ecl_symbol_value(VV[0]),v1x);
cl_env_copy->nvalues = 1;
return value0;
}
}
/* initialization of this module */
void init_CODE(cl_object flag)
{ VT1 CLSR1
cl_object value0;
if (!FIXNUMP(flag)){
Cblock=flag;
#ifndef ECL_DYNAMIC_VV
flag->cblock.data = VV;
#endif
flag->cblock.self_destruct=0;
flag->cblock.data_size = VM;
flag->cblock.data_text = compiler_data_text;
flag->cblock.data_text_size = compiler_data_text_size;
return;}
#ifdef ECL_DYNAMIC_VV
VV = Cblock->cblock.data;
#endif
T0= MAKE_FIXNUM(2);
si_Xmake_special(VV[0])
if(SYM_VAL(T0)!=OBJNULL) cl_setq(VV[0],T0);
cl_def_c_function(VV[1],(void*)L1,1);
ECL_DLLEXPORT void init_fas_CODE(cl_object flag)
{
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
cl_object *VVtemp;
if (flag != OBJNULL){
Cblock = flag;
#ifndef ECL_DYNAMIC_VV
flag->cblock.data = VV;
#endif
flag->cblock.data_size = VM;
flag->cblock.temp_data_size = VMtemp;
flag->cblock.data_text = compiler_data_text;
flag->cblock.cfuns_size = compiler_cfuns_size;
flag->cblock.cfuns = compiler_cfuns;
flag->cblock.source = make_constant_base_string("test.lisp");
return;}
#ifdef ECL_DYNAMIC_VV
VV = Cblock->cblock.data;
#endif
Cblock->cblock.data_text = (const cl_object *)"@EcLtAg:init_fas_CODE@";
VVtemp = Cblock->cblock.temp_data;
ECL_DEFINE_SETF_FUNCTIONS
si_Xmake_special(VV[0]);
if (ecl_boundp(cl_env_copy,VV[0])) { goto L2; }
cl_set(VV[0],ecl_make_fixnum(2));
L2:;
ecl_cmp_defun(VV[2]); /* ADD1 */
}
@end verbatim
The C function L1 implements the Lisp function add1. This relation is established by @code{cl_def_c_function} in the initialization function @code{init_CODE}, which is invoked at load time. There, the vector @code{VV} consists of Lisp objects; @code{VV[0]} and @code{VV[1]} in this example hold the Lisp symbols @code{*delta*} and @code{add1}. @code{VM} in the definition of @code{L1} is a C macro declared in the corresponding H-file. The actual value of @code{VM} is the number of value stack locations used by this module, i.e., 2 in this example. Thus the following macro definition is found in the H-file.
The C function @code{L1add1} implements the Lisp function @code{add1}. This relation is established by @code{ecl_cmp_defun} in the initialization function @code{init_fas_CODE}, which is invoked at load time. There, the vector @code{VV} consists of Lisp objects; @code{VV[0]} and @code{VV[1]} in this example hold the Lisp symbols @code{*delta*} and @code{add1}, while @code{VV[2]} holds the function object for @code{add1}, which is created during initialization of the module. @code{VM} in the definition of @code{L1add1} is a C macro declared in the corresponding H-file. The actual value of @code{VM} is the number of value stack locations used by this module, i.e., 3 in this example. Thus the following macro definition is found in the H-file.
@verbatim
#define VM 2
#define VM 3
@end verbatim
@subsection Implementation of Compiled Closures
......@@ -133,37 +150,52 @@ Declarations, especially type and function declarations, increase the efficiency
@verbatim
(eval-when (:compile-toplevel)
(proclaim '(function tak (fixnum fixnum fixnum) fixnum))
(proclaim '(ftype (function (fixnum fixnum) fixnum) tak))
(proclaim '(optimize (speed 3) (debug 0) (safety 0))))
(defun tak (x y z)
(declare (fixnum x y z))
(defun tak (x y)
(declare (fixnum x y))
(if (not (< y x))
z
(tak (tak (1- x) y z)
(tak (1- y) z x)
(tak (1- z) x y))))
y
(tak (tak (1- x) y)
(tak (1- y) x))))
@end verbatim
The compiler generates the following C code:
The compiler generates the following C code (Note that the tail-recursive call of @code{TAK} was replaced by iteration):
@verbatim
/* local entry for function TAK */
static int LI1(register int V1,register int V2,register int V3)
{ VT3 VLEX3 CLSR3
/* function definition for TAK */
/* optimize speed 3, debug 0, space 0, safety 0 */
static cl_object L1tak(cl_object v1x, cl_object v2y)
{
cl_object env0 = ECL_NIL;
const cl_env_ptr cl_env_copy = ecl_process_env();
cl_object value0;
cl_fixnum v3x;
cl_fixnum v4y;
v3x = ecl_fixnum(v1x);
v4y = ecl_fixnum(v2y);
TTL:
if (V2 < V1) {
goto L2;}
return(V3);
L2:
{ int V5;
V5 = LI1((V1)-1,V2,V3);
{ int V6;
V6 = LI1((V2)-1,V3,V1);
V3 = LI1((V3)-1,V1,V2);
V2 = V6;
V1 = V5;}}
goto TTL;
;;; Note: Tail-recursive call of TAK was replaced by iteration.
if ((v4y)<(v3x)) { goto L1; }
value0 = ecl_make_fixnum(v4y);
cl_env_copy->nvalues = 1;
return value0;
L1:;
{
cl_fixnum v5;
{
cl_fixnum v6;
v6 = (v3x)-1;
v5 = ecl_fixnum(L1tak(ecl_make_fixnum(v6), ecl_make_fixnum(v4y)));
}
{
cl_fixnum v6;
v6 = (v4y)-1;
v4y = ecl_fixnum(L1tak(ecl_make_fixnum(v6), ecl_make_fixnum(v3x)));
}
v3x = v5;
}
goto TTL;
}
@end verbatim
......
......@@ -26,24 +26,36 @@ ECL uses the following stacks:
@subsection Procedure Call Conventions
ECL employs standard C calling conventions to achieve efficiency and
interoperability with other languages. Each Lisp function is
implemented as a C function which takes as many argument as the Lisp
original plus one additional integer argument which holds the number
of actual arguments. The function sets @code{NValues} to the number of
Lisp values produced, it returns the first one and the remaining ones
are kept in a global (per thread) array (@code{VALUES}).
implemented as a C function which takes as many arguments as the Lisp
original. If the function takes optional or keyword arguments, the
corresponding C function takes one additional integer argument which
holds the number of actual arguments. The function sets @code{nvalues}
in the thread local environment to the number of Lisp values produced,
it returns the first one and the remaining ones are kept in a global
(per thread) array (@code{values}).
To show the argument/value passing mechanism, here we list the actual
code for the Common-Lisp function cons.
code for the Common-Lisp function last.
@verbatim
cl_cons(int narg, object car, object cdr) {
object x;
check_arg(2);
x = alloc_object(t_cons);
CAR(x) = car;
CDR(x) = cdr;
NValues = 1;
return x;
cl_object
cl_last(cl_narg narg, cl_object l, ...)
{
const cl_env_ptr the_env = ecl_process_env();
cl_object k;
va_list ARGS;
va_start(ARGS, l);
if (ecl_unlikely(narg < 1|| narg > 2)) FEwrong_num_arguments(/* ... */);
if (narg > 1) {
k = va_arg(ARGS,cl_object);
} else {
k = ecl_make_fixnum(1);
}
cl_object __value0 = ecl_last(l, ecl_to_size(k));
the_env->nvalues = 1;
the_env->values[0] = __value0;
va_end(ARGS);
return __value0;
}
@end verbatim
......@@ -55,26 +67,26 @@ function. (Strictly speaking, `@code{-}' and `@code{*}' in the
Common-Lisp function name are replaced by `@code{_}' and `@code{A}',
respectively, to obey the syntax of C.)
@code{check_arg(2)} in the code of @code{cl_cons} checks that exactly
two arguments are supplied to @code{cons}. That is, it checks that
@code{narg} is 2, and otherwise, it causes an
error. @code{allocate_object(t_cons)} allocates a cons cell in the
heap and returns the pointer to the cell. After the @code{CAR} and the
@code{CDR} fields of the cell are set, the cell pointer is returned
directly. The number assigned to @code{NValues} set by the function (1
in this case) represents the number of values of the function.
The code for the function @code{last} first checks that the right
number of arguments are supplied to @code{cl_last}. That is, it checks
that @code{narg} is 1 or 2, and otherwise, it causes an error.
Following that, the optional variable @code{k} is initialized and the
return value @code{__value0} is computed. The number assigned to
@code{nvalues} set by the function (1 in this case) represents the
number of values of the function. The return value of the function is
copied in the @code{values} array as well as returned directly.
In general, if one is to play with the C kernel of ECL there is no
need to know about all these conventions. There is a preprocessor that
takes care of the details, by using a lisp representation of the
statements that output values, and of the function definitions. For
instance, the actual source code for @code{cl_cons} in
@code{src/c/lists.d}
instance, the actual source code for @code{cl_last} in
@code{src/c/list.d}
@verbatim
@(defun cons (car cdr)
@(defun last (l &optional (k ecl_make_fixnum(1)))
@
@(return CONS(car, cdr))
@(return ecl_last(l, ecl_to_size(k)));
@)
@end verbatim
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment