/* disassembler.c -- Byte compiler and function evaluator */ /* Copyright (c) 2001, Juan Jose Garcia Ripoll. ECL is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file '../Copyright' for full details. */ #include "ecl.h" #include "ecl-inl.h" #include "bytecodes.h" #define next_code(v) (*(v++)) static cl_object *disassemble(cl_object *vector); static cl_object *base = NULL; static void print_noarg(const char *s) { princ_str(s, Cnil); } static void print_oparg(const char *s, cl_fixnum n) { princ_str(s, Cnil); princ(MAKE_FIXNUM(n), Cnil); } static void print_arg(const char *s, cl_object x) { princ_str(s, Cnil); princ(x, Cnil); } static void print_oparg_arg(const char *s, cl_fixnum n, cl_object x) { princ_str(s, Cnil); princ(MAKE_FIXNUM(n), Cnil); princ_str(",", Cnil); princ(x, Cnil); } static cl_object * disassemble_vars(const char *message, cl_object *vector, cl_index step) { cl_index n = fix(next_code(vector)); if (n) { terpri(Cnil); print_noarg(message); for (; n; n--, vector+=step) { prin1(vector[0], Cnil); if (n > 1) print_noarg(", "); } } return vector; } static void disassemble_lambda(cl_object *vector) { cl_object specials; cl_index n; /* Name of LAMBDA */ print_arg("\nName:\t\t", next_code(vector)); /* Variables that have been declared special */ specials = next_code(vector); /* Print required arguments */ vector = disassemble_vars("Required:\t", vector, 1); /* Print optional arguments */ vector = disassemble_vars("Optionals:\t", vector, 3); /* Print rest argument */ if (vector[0] != Cnil) { print_arg("\nRest:\t\t", vector[0]); } vector++; /* Print keyword arguments */ if (vector[0] != Cnil) { print_arg("\nOther keys:\t", vector[0]); } vector++; vector = disassemble_vars("Keywords:\t", vector, 4); /* Print aux arguments */ print_arg("\nDocumentation:\t", next_code(vector)); print_arg("\nDeclarations:\t", next_code(vector)); base = vector; while (vector[0] != MAKE_FIXNUM(OP_HALT)) vector = disassemble(vector); } /* -------------------- DISASSEMBLER AIDS -------------------- */ static inline cl_fixnum get_oparg(cl_object o) { return GET_OPARG(o); } static inline cl_fixnum packed_label(cl_object *v) { return v + get_oparg(v[0]) - base; } static inline cl_fixnum simple_label(cl_object *v) { return v + fix(v[0]) - base; } static cl_object search_symbol(register cl_object s) { return s; } /* -------------------- DISASSEMBLER CORE -------------------- */ /* OP_BLOCK label{arg}, block-name{symbol} ... OP_EXIT label: Executes the enclosed code in a named block. LABEL points to the first instruction after OP_EXIT. */ static cl_object * disassemble_block(cl_object *vector) { cl_object lex_old = lex_env; cl_fixnum exit = packed_label(vector-1); cl_object block_name = next_code(vector); lex_env = cl_listX(3, @':block', CONS(block_name, Cnil), lex_env); print_oparg_arg("BLOCK\t", exit, block_name); vector = disassemble(vector); print_noarg("\t\t; block"); lex_env = lex_old; return vector; } /* OP_CATCH label{arg} ... OP_EXIT label: Sets a catch point using the tag in VALUES(0). LABEL points to the first instruction after the end (OP_EXIT) of the block */ static cl_object * disassemble_catch(cl_object *vector) { print_oparg("CATCH\t", packed_label(vector - 1)); vector = disassemble(vector); print_noarg("\t\t; catch"); return vector; } /* OP_DO label ... ; code executed within a NIL block OP_EXIT label: High level construct for the DO and BLOCK forms. */ static cl_object * disassemble_do(cl_object *vector) { cl_fixnum exit; cl_object lex_old = lex_env; lex_copy(); exit = packed_label(vector-1); print_oparg("DO\t", exit); vector = disassemble(vector); print_noarg("\t\t; do"); lex_env = lex_old; return vector; } /* OP_DOLIST label ... ; code to bind the local variable OP_EXIT ... ; code executed on each iteration OP_EXIT ... ; code executed at the end OP_EXIT label: High level construct for the DOLIST iterator. The list over which we iterate is stored in VALUES(0). */ static cl_object * disassemble_dolist(cl_object *vector) { cl_fixnum exit; cl_object lex_old = lex_env; lex_copy(); exit = packed_label(vector-1); print_oparg("DOLIST\t", exit); vector = disassemble(vector); print_noarg("\t\t; dolist binding"); vector = disassemble(vector); print_noarg("\t\t; dolist body"); vector = disassemble(vector); print_noarg("\t\t; dolist"); lex_env = lex_old; return vector; } /* OP_TIMES label ... ; code to bind the local variable OP_EXIT ... ; code executed on each iteration OP_EXIT ... ; code executed at the end OP_EXIT label: High level construct for the DOTIMES iterator. The number of times we iterate is stored in VALUES(0). */ static cl_object * disassemble_dotimes(cl_object *vector) { cl_fixnum exit; cl_object lex_old = lex_env; lex_copy(); exit = packed_label(vector-1); print_oparg("DOTIMES\t", exit); vector = disassemble(vector); print_noarg("\t\t; dotimes times"); vector = disassemble(vector); print_noarg("\t\t; dotimes body"); vector = disassemble(vector); print_noarg("\t\t; dotimes"); lex_env = lex_old; return vector; } /* OP_FLET nfun{arg} fun1{object} ... funn{object} ... OP_EXIT Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". */ static cl_object * disassemble_flet(cl_object *vector) { cl_object lex_old = lex_env; cl_index nfun = get_oparg(vector[-1]); print_noarg("FLET"); lex_copy(); while (nfun--) { cl_object fun = next_code(vector); print_noarg("\n\tFLET\t"); @prin1(1, fun->bytecodes.data[0]); } vector = disassemble(vector); print_noarg("\t\t; flet"); lex_env = lex_old; return vector; } /* OP_LABELS nfun{arg} fun1{object} ... funn{object} ... OP_EXIT Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". */ static cl_object * disassemble_labels(cl_object *vector) { cl_object lex_old = lex_env; cl_index nfun = get_oparg(vector[-1]); print_noarg("LABELS"); lex_copy(); while (nfun--) { cl_object fun = next_code(vector); print_arg("\n\tLABELS\t", fun->bytecodes.data[0]); } vector = disassemble(vector); print_noarg("\t\t; labels"); lex_env = lex_old; return vector; } /* OP_MCALL ... OP_EXIT Saves the stack pointer, executes the enclosed code and funcalls VALUE(0) using the content of the stack. */ static cl_object * disassemble_mcall(cl_object *vector) { print_noarg("MCALL"); vector = disassemble(vector); print_noarg("\t\t; mcall"); return vector; } /* OP_PROG1 ... OP_EXIT Save the values in VALUES(..), execute the code enclosed, and restore the values. */ static cl_object * disassemble_mprog1(cl_object *vector) { print_noarg("MPROG1"); vector = disassemble(vector); print_noarg("\t\t; mprog1"); return vector; } /* OP_MSETQ n{arg} {fixnumn}|{symboln} ... {fixnum1}|{symbol1} Sets N variables to the N values in VALUES(), filling with NIL when there are values missing. Local variables are denoted with an integer which points a position in the lexical environment, while special variables are denoted just with the name. */ static cl_object * disassemble_msetq(cl_object *vector) { int i = get_oparg(vector[-1]); bool newline = FALSE; while (i--) { cl_object var = next_code(vector); if (newline) { print_noarg("\n\t"); } else newline = TRUE; if (FIXNUMP(var)) { @format(4, Ct, make_constant_string("MSETQ\t~D,VALUES(~D)"), var, MAKE_FIXNUM(i)); } else { @format(4, Ct, make_constant_string("MSETQS\t~A,VALUES(~D)"), var, MAKE_FIXNUM(i)); } } return vector; } /* OP_PROGV bindings{list} ... OP_EXIT Execute the code enclosed with the special variables in BINDINGS set to the values in the list which was passed in VALUES(0). */ static cl_object * disassemble_progv(cl_object *vector) { print_noarg("PROGV"); vector = disassemble(vector); print_noarg("\t\t; progv"); return vector; } /* OP_TAGBODY n{arg} tag1 label1 ... tagn labeln label1: ... labeln: ... OP_EXIT High level construct for the TAGBODY form. */ static cl_object * disassemble_tagbody(cl_object *vector) { cl_index i, ntags = get_oparg(vector[-1]); cl_object lex_old = lex_env; lex_copy(); print_noarg("TAGBODY"); for (i=0; ibytecodes.data); @(return v) } @(return Cnil) } cl_object si_bc_split(cl_object b) { cl_object vector; if (type_of(b) != t_bytecodes) @(return Cnil Cnil) vector = cl_alloc_simple_vector(b->bytecodes.size, aet_object); vector->vector.self.t = b->bytecodes.data; @(return b->bytecodes.lex vector) }