diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-02-19 16:03:28 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-02-19 16:03:28 +0000 |
commit | 0ac77af5894772ce957a3ecb7dd4faef82380c6a (patch) | |
tree | 98835ce33fa71944e95b1c7fd850016ca9f66816 | |
parent | bf7f3deb8c4263d0f7d26f17f807d7ee7275b5f9 (diff) | |
download | gcc-0ac77af5894772ce957a3ecb7dd4faef82380c6a.tar.gz |
added most of my (Basile Starynkevitch's) files
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@132436 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | contrib/cold-basilys.lisp | 5422 | ||||
-rw-r--r-- | contrib/simple-probe.c | 1496 | ||||
-rw-r--r-- | gcc/Makefile.in | 46 | ||||
-rw-r--r-- | gcc/basic-block.h | 14 | ||||
-rw-r--r-- | gcc/basilys.c | 5645 | ||||
-rw-r--r-- | gcc/basilys.h | 2096 | ||||
-rw-r--r-- | gcc/common.opt | 39 | ||||
-rw-r--r-- | gcc/compiler-probe.c | 2078 | ||||
-rw-r--r-- | gcc/compiler-probe.h | 482 | ||||
-rw-r--r-- | gcc/config.in | 18 | ||||
-rw-r--r-- | gcc/configure.ac | 206 | ||||
-rw-r--r-- | gcc/diagnostic.c | 6 | ||||
-rw-r--r-- | gcc/gdbinit.in | 11 | ||||
-rw-r--r-- | gcc/gengtype.c | 4 | ||||
-rw-r--r-- | gcc/params.def | 16 | ||||
-rw-r--r-- | gcc/passes.c | 30 | ||||
-rw-r--r-- | gcc/run-basilys.h | 63 | ||||
-rw-r--r-- | gcc/system.h | 9 | ||||
-rw-r--r-- | gcc/timevar.def | 3 | ||||
-rw-r--r-- | gcc/toplev.c | 51 | ||||
-rw-r--r-- | gcc/tree-flow-inline.h | 10 | ||||
-rw-r--r-- | gcc/tree-pass.h | 4 |
22 files changed, 17737 insertions, 12 deletions
diff --git a/contrib/cold-basilys.lisp b/contrib/cold-basilys.lisp new file mode 100644 index 00000000000..1c07310b8bf --- /dev/null +++ b/contrib/cold-basilys.lisp @@ -0,0 +1,5422 @@ +;; file cold-basilys.lisp +;; -*- Lisp -*- +;; $Id: cold-basilys.lisp 289 2008-02-07 22:07:30Z basile $ + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Copyright 2008 Free Software Foundation, Inc. +;; Contributed by Basile Starynkevitch <basile@starynkevitch.net> + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not, write to +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; conventionally, our names contain underscores _ so the minus sign - +;; is only in CommonLisp names, in particular in names generated by +;; defstruct + +(defvar this_compilation nil "the current compilation") + +(warn "should add disc_super to class_discr") + +(defun cpusec () (float (/ (get-internal-run-time) internal-time-units-per-second ))) + + +;; program sbstract syntax tree +(defstruct prog_src) + +(defstruct (prog_if (:include prog_src)) + cond_expr then_expr else_expr) + +(defstruct (prog_setq (:include prog_src)) + setq_var setq_expr) + +(defstruct (prog_apply (:include prog_src)) + appl_fun appl_args) + +(defstruct (prog_primitive (:include prog_src)) + prim_oper prim_args) + +(defstruct (prog_chunk (:include prog_src)) ;chunks are used in primitive normalization + chunk_args chunk_type) + +(defstruct (prog_cstring (:include prog_src)) ;A C string constant + c_str) + +(defstruct (prog_quotesym (:include prog_src)) ;A quoted symbol or keyword + qsym) + +;;; the normalisation of a primitive requires its expansion as +;;; primitive calls ans primitive chunks + +(defstruct (prog_let (:include prog_src)) + let_bindings let_body) + +(defstruct (prog_send (:include prog_src)) + send_sel send_recv send_args) + +(defstruct (prog_unsafe_get_field (:include prog_src)) + uget_field uget_obj) + +(defstruct (prog_unsafe_put_fields (:include prog_src)) + uput_obj uput_keys) + +;; make an instance at runtime ; +(defstruct (prog_make_instance (:include prog_src)) + mki_class mki_keys mki_classdef ;the classdef is internal, neede for normal forms +) + +(defstruct (prog_forever (:include prog_src)) + forever_bind forever_body) + +(defstruct (prog_progn (:include prog_src)) + progn_body) + +(defstruct (prog_exit (:include prog_src)) + exit_bind exit_body) + +;internal representation of closed variable occurrence +(defstruct (prog_closedvar (:include prog_src)) + clv_var ;the closed variable + clv_fun ;the closing function or lambda + clv_bind ;the binding of the closed variable +) + +; internal representation of closure allocation and fill +(defstruct (prog_makeclosure (:include prog_src)) + mkclos_fun ; the normalized function or lambda + mkclos_closvars ; the list of closed variables +) + +(defstruct (prog_def (:include prog_src)) + def_name) + +(defstruct (prog_predef (:include prog_def)) + predef_rank) + + +;;prog_defun are for defun and for normalized anonymous lambda +(defstruct (prog_defun (:include prog_def)) ;defined name + fun_lambda ;if this defun comes from a lambda otherwise nil + fun_formals ;list of formal arguments + fun_body ;sequence of body + fun_argbindings ;computed argument bindings + fun_closvars ;computed closed variable list + fun_constants ;computed list of quoted constants +) + +;; prog_lambda are for source lambda +(defstruct (prog_lambda (:include prog_src)) + lambda_formals ;list of formal arguments + lambda_body ;sequence for body + lambda_argbindings ;computed arguments bindings + lambda_closvars ;computed closed variable list + lambda_uniq ;unique number +) + + + +;; prog_multicall are for multiple-binding of secondary results of calls +(defstruct (prog_multicall (:include prog_src)) + multicall_formals ;formal list of result variables + multicall_call ;the call or send + multicall_body ;body +) + + +(defstruct (prog_defvar (:include prog_predef)) ;@!not yet implemented + var_expr) + +(defstruct (prog_defclass (:include prog_predef)) + class_super class_ownfields class_allfields) + +(defstruct (prog_definstance (:include prog_predef)) + inst_class inst_objnum inst_slots) + +(defstruct (prog_defselector (:include prog_definstance)) +) + + + +(defstruct instance_slot + slot_field slot_value) + +(defstruct (prog_field (:include prog_def)) + field_class field_offset) + +(defstruct (prog_return (:include prog_src)) + retexprs) + +(defstruct (prog_defprimitive (:include prog_def)) + primitive_formals primitive_type primitive_expansion) + +;; for each variable occurrence, we need to know if the variable is +;; closed within the current function (or lambda) or bound inside + +(defstruct cold_compenv + serial ;serial number + dict ;dictionnary of bindings (by name) + prev ;link to previous environment + for ;optional function for which this env is made +) + +;; flag to set to revert to default compenv printing +(defvar cold_compenv_defprint nil) + +;; variable counting the number of compenv printing +(defvar count_compenv_print 0) + +;; internal function to compute an hashcode for the dict of an environment +(defun envdicthash (env) + (let ( (h (cold_compenv-serial env)) ) + (maphash (lambda (k v) + (setq h (logand #xFFFFFFFF (+ h (* 8 (sxhash k)) (sxhash v))))) + (cold_compenv-dict env)) + h +)) + + +;; internal hashtable to avoid printing manytimes the same environ +;; we map an environment to its envdicthash and its printing counter +(defvar envprintdict (make-hash-table :size 1000)) + +;; for less verbose traces & debugs +(defmethod print-object ((ob cold_compenv) st) + (if cold_compenv_defprint + (call-next-method ob st) + (progn + (incf count_compenv_print) + (format st "CompEnv/~d<#~d>{~:@_" (cold_compenv-serial ob) count_compenv_print) + (let ( (curenv ob) + (curdepth 0) + ) + (loop while curenv do + (finish-output st) + (let* ( (edict (cold_compenv-dict curenv)) + (edicthash (envdicthash curenv)) + (eprev (cold_compenv-prev curenv)) + (efor (cold_compenv-for curenv)) + (eserial (cold_compenv-serial curenv)) + (epri (gethash curenv envprintdict)) + (eprihash (and epri (car epri))) + (epricnt (and epri (cdr epri))) + ) + (if (and + (> curdepth 0) + (eq eprihash edicthash) + (> epricnt (- count_compenv_print 64))) + (format st "!!*seecompenv/~d <<^^h~x#~d>>~:@_" eserial edicthash epricnt) + (let ( (newpri (cons edicthash count_compenv_print)) ) + (setf (gethash curenv envprintdict) newpri) + (format st "!compenv/~d [~d] <H~x>:~:@_" + eserial (hash-table-count edict) (envdicthash curenv)) + ;; display bindings in a sorted order + (let ( (revkeylist nil) ) + (maphash (lambda (k v) + (declare (ignore v)) + (push k revkeylist)) edict) + (mapcar + (lambda (k) (format st " *~a== ~S~:@_" k (gethash k edict))) + (sort revkeylist (lambda (k1 k2) (string< (symbol-name k1) (symbol-name k2)))) + ) + ) + (if efor + (cond ( (prog_defun-p efor) + (format st "!compenv/~d - for defun ~S~:@_" eserial (prog_defun-def_name efor)) ) + ( (prog_lambda-p efor) + (format st "compenv/~d - for lambda #~d~:@_" eserial (prog_lambda-lambda_uniq efor)) ) + ( t + (format st "compenv/~d - for? ~S~:_" eserial efor) )) + ) + )) + (if eprev + (format st "!compenv/~d prev/~d: ~:@_" eserial (cold_compenv-serial eprev))) + (setq curenv eprev) + (incf curdepth) + ) + ) + ) + (format st "}~:@_") + (finish-output st) + ))) + +;; for less verbose traces & debugs +(defmethod print-object ((ob prog_primitive) st) + (let ( (poper (prog_primitive-prim_oper ob)) + (pargs (prog_primitive-prim_args ob)) ) + (if (prog_defprimitive-p poper) + (format st "#{Primitive/~a ~<~S~>}" (prog_defprimitive-def_name poper) pargs) + (call-next-method ob st)))) + + +;; for less verbose +(defmethod print-object ((ob prog_closedvar) st) + (let ( (cvar (prog_closedvar-clv_var ob)) + (cfun (prog_closedvar-clv_fun ob)) + (cbind (prog_closedvar-clv_bind ob)) ) + (format st "#{ProgClosedVar/~a" cvar) + (if (prog_defun-p cfun) + (format st " cfun/~a" (prog_defun-def_name cfun)) + (format st " cfun=~S" cfun)) + (cond + ( (cold_class_binding-p cbind) + (format st " cbind<class:~S>" (cold_class_binding-bname cbind)) ) + ( t + (format st " cbind=~S" cbind))) + (format st "}") +)) +;; for less verbose traces +(defmethod print-object ((ob prog_defclass) st) + (let ( (cname (prog_defclass-def_name ob)) + (crank (prog_defclass-predef_rank ob)) + (csuper (prog_defclass-class_super ob)) + (cownf (prog_defclass-class_ownfields ob)) + (callf (prog_defclass-class_allfields ob)) ) + (format st "#{ProgDefClass/~a" cname) + (if crank (format st " predefrank/~S" crank)) + (if (prog_defclass-p csuper) + (format st " super:~a" (prog_defclass-def_name csuper)) + (format st " super=~S" csuper)) + (if cownf (format st " ownfl=~S" cownf)) + (if callf (format st " allfl=~S" callf)) + (format st "}") +)) + + +(defmethod print-object ((ob prog_field) st) + (let ( (fname (prog_field-def_name ob)) + (fclass (prog_field-field_class ob)) + (foff (prog_field-field_offset ob)) ) + (format st "#{ProgField/~a#~d" fname foff) + (if (prog_defclass-p fclass) + (format st " FldClass/~a" (prog_defclass-def_name fclass)) + (format st " FldClass=~S" fclass)) + (format st "}") + )) + +(defmethod print-object ((ob prog_return) st) + (let ( (re (prog_return-retexprs ob)) ) + (cond ( (and (consp re) (cdr re)) + (progn + (format st "#{ProgReturn~d" (length re)) + (mapc (lambda (x) (format st " ~S" x)) re) + (format st "}") + )) + ( (null re) (format st "{ProgReturn0}")) + ( t (format st "{Prog_RETURN ~S}" (car re)))) + )) + + +(defconstant cold_valid_types_list (list ':value ':long ':bool ':tree ':void ':cstring ;and others + )) + +;; test for valid cold type keyword +(defun cold_valid_type_keyword_p (k) + (member k cold_valid_types_list)) + + +(defvar cold_compenv_serial_count 0) + +(defconstant cold_first_env + (progn + (incf cold_compenv_serial_count) + (make-cold_compenv :serial cold_compenv_serial_count))) + +(defun cold_fresh_env (parenv) + (if parenv (or (cold_compenv-p parenv) + (error "invalid parent env ~a ~%<::cold_fresh_env>" parenv))) + (incf cold_compenv_serial_count) + (make-cold_compenv :prev parenv + :dict (make-hash-table :size 11) + :serial cold_compenv_serial_count)) + +(defstruct cold_any_binding + bname) + +(defstruct (cold_macro_binding (:include cold_any_binding)) + expanser) + + +;; for less verbose traces & debugs +(defmethod print-object ((ob cold_macro_binding) st) + (format st "#<!cold_macro_binding ~A!>" (cold_macro_binding-bname ob)) +) + +(defstruct (cold_class_binding (:include cold_any_binding)) + classdef ;the prog_defclass + classdata ;the obj_datainstance +) + +(defstruct (cold_field_binding (:include cold_any_binding)) + fieldef ;the prog_field + fieldata ;the obj_datainstance +) + + + +(defstruct (cold_primitive_binding (:include cold_any_binding)) + primitive +) + +;; for less verbose traces & debugs +(defmethod print-object ((ob cold_primitive_binding) st) + (if (prog_defprimitive-p (cold_primitive_binding-primitive ob)) + (format st "#<!cold_primitive_binding ~A!>" (cold_primitive_binding-bname ob)) + (call-next-method ob st) +)) + + + + +(defstruct (cold_function_binding (:include cold_any_binding)) + function + fclodata ;function closure data +) + +;; for less verbose traces & debugs +(defmethod print-object ((ob cold_function_binding) st) + (if (prog_defun-p (cold_function_binding-function ob)) + (format st "#<!cold_function_binding ~A!>" (cold_function_binding-bname ob)) + (call-next-method ob st) +)) + +(defstruct (cold_typed_binding (:include cold_any_binding)) + type) + +(defstruct (cold_instance_binding (:include cold_typed_binding)) + instancedef instancedata) + +(defstruct (cold_selector_binding (:include cold_typed_binding)) + selectordef selectordata) + +(defstruct (cold_let_binding (:include cold_typed_binding)) + expr +) + +(defstruct (cold_value_binding (:include cold_typed_binding)) + val + compilrole ;optional compiler role, eg SELECTOR +) +;;; maybe we need a cold_fieldvalue_binding which is a +;;; cold_value_binding and also knows about the field at compile time +;;; and likewise for classes and instances and selectors + +(defstruct (cold_code_binding (:include cold_typed_binding)) + code +) + + +(defstruct (cold_formal_binding (:include cold_typed_binding)) + rank + ) + + +(defstruct (cold_cdata_binding (:include cold_typed_binding)) + cdata) + +(defstruct (cold_forever_binding (:include cold_typed_binding)) + uniq ;unique gensymed id +) + +(defstruct (cold_obforever_binding (:include cold_forever_binding)) + lobvar ;forever objvar +) + + +;; for ease of trace & debugging +(defmethod print-object ((ob cold_let_binding) st) + (let ( (bna (cold_any_binding-bname ob)) + (bty (cold_typed_binding-type ob)) + (bex (cold_let_binding-expr ob)) ) + (format st "{LetBi[~a" bna) + (if bty (format st " :~s" bty)) + (format st " := ~S ]}" bex) +)) + + +;; convert a keyword :AA to symbol AA +(defun keyword2symbol (k) + (if (keywordp k) (intern (symbol-name k)) k)) + + +;; function to find a binding +(defun cold_find_binding (nam env) + (and (cold_compenv-p env) + (let ((dict (cold_compenv-dict env))) + (or (and + (hash-table-p dict) + (gethash nam dict)) + (cold_find_binding nam (cold_compenv-prev env)) + )) + )) + +;;; function to find a binding and also return the reversed list of enclosing functions +(defun cold_enclosed_find_binding (nam env) + (labels ( + (recscan (nam env lifun) + (and (cold_compenv-p env) + (let ( (dict (cold_compenv-dict env)) + (envprev (cold_compenv-prev env)) + (newlifun + (let ( (forf (cold_compenv-for env)) ) + (if forf (cons forf lifun) lifun))) ) + (if (hash-table-p dict) + (let ( (bi (gethash nam dict)) ) + (if bi (values bi lifun) + (recscan nam envprev newlifun))) + (recscan nam envprev newlifun) + )))) + ) + (recscan nam env ()))) + + + + +(defun cold_tested_find_binding (nam env test) + (and (cold_compenv-p env) + (let ((dict (cold_compenv-dict env))) + (or (and + (hash-table-p dict) + (gethash nam dict)) + (and + (funcall test env) + (cold_find_binding nam (cold_compenv-prev env)) + ))))) + + + +(defun cold_put_binding (cbind env) + (assert (cold_compenv-p env)) + (or (cold_any_binding-p cbind) + (error "bad cold binding ~S to put in env ~S~%<::cold_put_binding>" cbind env)) + (let ( (bnam (cold_any_binding-bname cbind)) + (dict (cold_compenv-dict env))) + (or (hash-table-p dict) + (progn + (setq dict (make-hash-table :size 13)) + (setf (cold_compenv-dict env) dict) + )) + (setf (gethash bnam dict) cbind) + ) +) + +(defun cold_define_macro (nam expans env) + (let ( (mbind (make-cold_macro_binding + :bname nam :expanser expans)) ) + (cold_put_binding mbind env)) +) + + +(defun cold_macroexpand (sexpr env) + (flet + ( (makeapply + (f args) + (assert (not (keywordp f)) + (f sexpr) + "invalid fun f=~S to makeapply in macroexpand sexpr=~S" f sexpr) + (make-prog_apply :appl_fun f :appl_args args)) + (makeprim + (p args) + (make-prog_primitive :prim_oper p :prim_args args)) + (expandlist + (l) + (mapcar (lambda (e) (cold_macroexpand e env)) l) + ) + ) + (if (consp sexpr) + (let ( (oper (first sexpr)) + (args (rest sexpr)) ) + (if (listp oper) + (makeapply + ;; maybe this is too simple, what if the macroexapsnion + ;; yields a slector... + (cold_macroexpand oper env) (expandlist args)) + (let ( (obind (cold_find_binding oper env)) ) + (cond ((cold_macro_binding-p obind) + (let ( (mexp (cold_macro_binding-expanser obind)) ) + (apply mexp (list oper args env)) + )) + ((cold_primitive_binding-p obind) + (makeprim (cold_primitive_binding-primitive obind) + (expandlist args)) + ) + ((cold_field_binding-p obind) + (error "field application not yet implemented ~S~%<::cold_macroexpand>" oper)) + ( (or (cold_selector_binding-p obind) + (and (cold_value_binding-p obind) + (eq (cold_value_binding-compilrole obind) + 'SELECTOR))) + (let ( (expargs (expandlist args)) ) + (if (null expargs) + (error "send requires a reciever argument but got none ~S~%<::cold_macroexpand>" oper)) + (make-prog_send + :send_sel oper + :send_recv (first expargs) + :send_args (rest expargs) + )) + ) + (t (makeapply oper (expandlist args))) + )))) + sexpr + ))) + +(defun cold_list_macroexpand (l env) + (mapcar (lambda (e) (cold_macroexpand e env)) l)) + + +(defmacro defcoldmacro (nam formals &rest body) + `(cold_define_macro ',nam (lambda ,formals ,@body) cold_first_env) +) + +(defun write_c_comment (outs coms) + (write-string "/**!" outs) + (let ((lencom (length coms))) + (loop + for rk from 0 to (- lencom 2) do + (let ( (c (char coms rk)) + (nc (char coms (+ rk 1))) + ) + (case c + (#\/ (if (eq nc #\*) (write-string "/+" outs) (write-char #\/ outs))) + (#\* (if (eq nc #\/) (write-string "*+" outs) (write-char #\* outs))) + (otherwise (write-char c outs)) + )) + ) + ) + (write-string "!**/" outs) + (if (find #\Newline coms) (write-char #\Newline outs)) +) + +(defmacro format_c_comment (str fmtstr &rest args) + (let ((sy (gentemp "FORMATCCOMM_"))) + `(let ( (,sy (format nil ,fmtstr ,@args)) ) + (write_c_comment ,str ,sy) + ) + ) +) + +(defun str2cstr (istr) + (assert (stringp istr)) + (with-output-to-string + (s) + (write-char #\" s) + (map nil + (lambda (c) + (case c + (#\\ (write-string "\\\\" s)) + (#\" (write-string "\\\"" s)) + (#\' (write-string "\\\'" s)) + (#\Newline (write-string "\\\n" s)) + (#\Tab (write-string "\\\t" s)) + (otherwise (if (standard-char-p c) + (write-char c s) + (format s "\\x~2,'0x" (char-code c)))) + ) + ) + istr + ) + (write-char #\" s) + ) + ) + +(defun lambda_args_bindings (formals) + (let ( (argrk 0) + (argtype :value) + (arglist formals) + (revargbind nil) + ) + (loop + (if (null arglist) + (return (reverse revargbind))) + (let ( (curarg (car arglist)) + (restarglist (cdr arglist)) ) + (setq arglist restarglist) + (cond + ( (keywordp curarg) + (or (cold_valid_type_keyword_p curarg) + (error "invalid formal keyword ~a in formals list ~s ~% <::lambda_args_binding>" + curarg formals)) + (setq argtype curarg) + ) + ( (symbolp curarg) + (let ( (abind (make-cold_formal_binding :bname curarg + :rank argrk + :type argtype)) ) + (push abind revargbind) + (setq argrk (1+ argrk)) + ) + ) + ( t (error "invalid formal (not a symbol or keyword) ~a in formals list ~s ~% <::lambda_args_binding>" curarg formals) ) + ) + )))) + + +(defvar cold_delayed_task_revlist nil) + +(defun cold_delayed_do (msg taskfun) + (assert (stringp msg)) + (or (functionp taskfun) + (error "cold_delayed_do bad taskfun ~s of type ~s ~% <::cold_delayed_do>" + taskfun (type-of taskfun))) + (push (cons msg taskfun) cold_delayed_task_revlist) +) + +(defmacro cold_delay (msg &rest body) + `(cold_delayed_do ,msg (function (lambda () ,@body)))) + +(defun cold_run_delayed_tasks (&optional msg) + (and msg (or (stringp msg) (error "bad msg in cold_run_delayed_tasks ~S" msg))) + (loop + (if (null cold_delayed_task_revlist) (return)) + (let ( (taskslist (reverse cold_delayed_task_revlist)) ) + (setq cold_delayed_task_revlist nil) + (map nil (lambda (taskcons) + ; (warn "delay running task ~S~%" (car taskcons)) + (apply (cdr taskcons) ())) taskslist) + )) + ) + + +(defcoldmacro defprimitive (nam args env) + (declare (ignore nam)) + (destructuring-bind + (primnam formals type &rest body) args + (or (cold_valid_type_keyword_p type) + (error "bad type ~S in defprimitive ~S" type args)) + (assert (every (lambda (x) (or (symbolp x) (numberp x) (stringp x) (not (prog_src-p x)))) body)) + (let ( (prim + (make-prog_defprimitive + :def_name primnam + :primitive_formals (lambda_args_bindings formals) + :primitive_type type + :primitive_expansion body)) ) + (let ( (pbind (make-cold_primitive_binding + :bname primnam :primitive prim)) ) + (cold_put_binding pbind env)) + prim + ) + ) + ) + +;; a defun function should be expanded in an environment where the +;; defined function is bound, hence we use cold_delay, and the body +;; should be expaned with the formals bound +(defcoldmacro defun (nam args env) + (declare (ignore nam)) + (destructuring-bind + (funam formals &rest body) args + (let* ( + (argbindseq (lambda_args_bindings formals)) + (newenv + (let ( (nenv (cold_fresh_env env)) ) + (map nil + (lambda (abind) (cold_put_binding abind nenv)) + argbindseq) + nenv + )) + (fun + (make-prog_defun + :def_name funam + :fun_formals formals + :fun_argbindings argbindseq + )) + (fbind (make-cold_function_binding :bname funam :function fun + :fclodata (make-obj_dataclosure + :comname funam) + )) + ) + (cold_put_binding fbind env) + (cold_delay + (format nil "expand defun ~S" funam) + (setf (prog_defun-fun_body fun) + (mapcar + (lambda (e) (cold_macroexpand e newenv)) + body) + ) + ) + fun + ))) + + + +;;; a class binding +(defcoldmacro defclass (nam args env) + (declare (ignore nam)) + (destructuring-bind + (cname &key predef super fields) args + (assert (symbolp cname) (cname) "invalid class name ~S" cname) + (let* + ( (pdefclass (make-prog_defclass :def_name cname :predef_rank predef)) + (clabind (make-cold_class_binding :bname cname :classdef pdefclass)) + (superclass + (and super + ;;;; we really should consider macro expansion on super + (or (symbolp super) (error "bas super ~S in defclass ~S" super args)) + (let ( (superbind (cold_find_binding super env)) ) + (or (cold_class_binding-p superbind) + (error "bad superbinding ~S in defclass ~S" superbind args)) + (cold_class_binding-classdef superbind)))) + (superallfields + (and super + (prog_defclass-class_allfields superclass))) + (off (if super (length superallfields) 0)) + ) + (cold_put_binding clabind env) + (setf (prog_defclass-class_super pdefclass) superclass) + (let ( (fieldseq + (mapcar + (lambda (f) + (or (symbolp f) (error "bad field ~S in defclass ~S" f args)) + (if (cold_find_binding f env) + (error "field ~S already bound in defclass ~S" f args)) + (let* + ( (field (make-prog_field :def_name f :field_class pdefclass :field_offset off)) + (fieldbind (make-cold_field_binding :bname f :fieldef field)) ) + (incf off) + (cold_put_binding fieldbind env) + field)) + fields)) ) + ;; copy-list just to avoid lots of circular ref in debug + (setf (prog_defclass-class_ownfields pdefclass) + (copy-list fieldseq)) + (setf (prog_defclass-class_allfields pdefclass) + (copy-list (append superallfields fieldseq))) + pdefclass ;expansion result for defclass + ) + ))) + + + +;;; common code to definstance and defselector +(defun instancemakerfun (iname iclassname idata env msg makfun bindfun) + (let ( (revslots ()) + (iobjnum ()) + (ipredef ()) + (curdata idata) + (bindclass (cold_find_binding iclassname env)) + ) + (or (symbolp iname) + (error "~A: expecting name but got ~S" msg iname)) + (or (cold_class_binding-p bindclass) + (error "~A: ~A bad classname ~A" msg iname iclassname)) + (let ((iclass (cold_class_binding-classdef bindclass))) + (assert (prog_defclass-p iclass)) + (loop while (consp curdata) do + (or (rest curdata) + (error "~A: odd arg ~A ~S" msg iname idata)) + (let ((curk (first curdata)) + (cura (second curdata)) ) + (setq curdata (cddr curdata)) + (or (keywordp curk) + (error "~A: expecting slot keyword but got ~S ~A ~S" msg curk iname idata)) + (cond ( (eq curk ':obj_num) + (setq iobjnum (cold_macroexpand cura env)) ) + ( (eq curk ':predef) + (setq ipredef (cold_macroexpand cura env)) ) + ( t + (let ((fld (find-if + (lambda (f) (equal (string (prog_field-def_name f)) (string curk))) + (prog_defclass-class_allfields iclass) + ))) + (or fld (error "~A: unexpected field ~S in ~A ~S" msg curk iname idata)) + (let ((slodef (make-instance_slot + :slot_field fld + :slot_value + (cold_macroexpand cura env)))) + (push slodef revslots)) + ))))) + (let* ( + (nval + (funcall makfun + iname + ipredef + iclass + iobjnum + (reverse revslots))) + (nbind (funcall bindfun iname nval)) + ) + (cold_put_binding nbind env) + nval + )))) + +;;; a class binding +(defcoldmacro definstance (nam args env) + (declare (ignore nam)) + (destructuring-bind + (iname iclassname &rest idata) args + (instancemakerfun iname iclassname idata env "definstance coldmacro" + ;; make value function + (lambda (iname ipredef iclass iobjnum islots) + (make-prog_definstance :def_name iname + :predef_rank ipredef + :inst_class iclass + :inst_objnum iobjnum + :inst_slots islots)) + ;; make binding function + (lambda (iname nval) + (make-cold_instance_binding + :bname iname + :type ':value + :instancedef nval + )) + ))) + + + +(defcoldmacro defselector (nam args env) + (declare (ignore nam)) + (destructuring-bind + (iname iclassname &rest idata) args + (instancemakerfun iname iclassname idata env "defselector coldmacro" + ;; make value function + (lambda (iname ipredef iclass iobjnum islots) + (make-prog_defselector :def_name iname + :predef_rank ipredef + :inst_class iclass + :inst_objnum iobjnum + :inst_slots islots)) + ;; make binding function + (lambda (iname nval) + (make-cold_selector_binding + :bname iname + :type ':value + :selectordef nval + )) + ))) + + +;; the body of a lambda should be macroexpanded with the formals bound +(defvar lambda_counter 0) +(defcoldmacro lambda (nam args env) + (declare (ignore nam)) + (destructuring-bind + (formals &rest body) args + (let* ( + (argbindseq (lambda_args_bindings formals)) + (newenv + (let ( (nenv (cold_fresh_env env)) ) + (map nil + (lambda (abind) (cold_put_binding abind nenv)) + argbindseq) + nenv + )) + (newlamb + (make-prog_lambda :lambda_formals formals + :lambda_body + (mapcar + (lambda (e) (cold_macroexpand e newenv)) + body) + :lambda_argbindings argbindseq + :lambda_uniq (incf lambda_counter) + :lambda_closvars nil)) + ) + newlamb +))) + + +;; the forever syntax (FOREVER <label> [<type>] <body...>) +(defcoldmacro forever (nam args env) + (declare (ignore nam)) + (let ( (foreverlab (pop args)) + (forevertype :value) + (foreverbody nil) + (newenv (cold_fresh_env env)) + ) + (or (symbolp foreverlab) (error "bad forever label in forever ~S" args)) + (if (cold_valid_type_keyword_p (first args)) + (setq forevertype (pop args))) + (if (eq forevertype ':void) (error "forever type cannot be void in forever ~S" args)) + (setq foreverbody args) + (let ( (foreverbind (make-cold_forever_binding + :bname foreverlab + :type forevertype + :uniq (gentemp "_FOREVER_"))) ) + (cold_put_binding foreverbind newenv) + (make-prog_forever :forever_bind foreverbind + :forever_body (mapcar (lambda (c) (cold_macroexpand c newenv)) foreverbody)) + ))) + +;; the progn syntax (PROGN <body....>) +(defcoldmacro progn (nam args env) + (declare (ignore nam)) + (make-prog_progn + :progn_body (mapcar (lambda (c) (cold_macroexpand c env)) args)) +) + +;; the UNSAFE_GET_FIELD syntax (UNSAFE_GET_FIELD field objexpr) +(defcoldmacro unsafe_get_field (nam args env) + (declare (ignore nam)) + (let ( + (iargs args) + (ifldnam (pop args)) + (iobjexpr (pop args)) ) + (if args (error "too many arguments to unsafe_get_field ~S" iargs)) + (or (keywordp ifldnam) + (error "first arg should be a keyword fieldname: unsafe_get_field ~S" iargs)) + (make-prog_unsafe_get_field + :uget_field ifldnam + :uget_obj (cold_macroexpand iobjexpr env) + ) +)) + +;; the UNSAFE_PUT_FIELDS syntax (UNSAFE_PUT_FIELDS objexpr fld1name fld1expr ...) +(defcoldmacro unsafe_put_fields (nam args env) + (declare (ignore nam)) + (let ( + (iargs args) + (iobjexpr (pop args)) + (irevkeys nil) + ) + (loop while (and (consp args) (second args)) do + (let ( + (curfldnam (pop args)) + (curvalexpr (pop args)) + ) + (or (keywordp curfldnam) + (error "expecting keyword fieldname but got ~S in unsafe_put_fields ~S" + curfldnam iargs)) + (push (cons curfldnam (cold_macroexpand curvalexpr env)) irevkeys) + )) + (make-prog_unsafe_put_fields + :uput_obj iobjexpr + :uput_keys (reverse irevkeys) + ) +)) + + +;; the MAKE_INSTANCE syntax (MAKE_INSTANCE objexpr fld1name fld1expr ...) +(defcoldmacro make_instance (nam args env) + (declare (ignore nam)) + (let ( + (iargs args) + (iclass (pop args)) + (irevkeys nil) + ) + (or (symbolp iclass) (error "make_instance need a class symbol ~S" iargs)) + (loop while (and (consp args) (second args)) do + (let ( + (curfldnam (pop args)) + (curvalexpr (pop args)) + ) + (or (keywordp curfldnam) + (error "expecting keyword fieldname but got ~S in make_instance ~S" + curfldnam iargs)) + (push (cons curfldnam (cold_macroexpand curvalexpr env)) irevkeys) + )) + (make-prog_make_instance + :mki_class (normalize_symbol iclass env) + :mki_classdef iclass + :mki_keys (reverse irevkeys) + ) +)) + +;; the EXIT syntax (EXIT <label> [<expr>]) +(defcoldmacro exit (nam args env) + (declare (ignore nam)) + (let ( (exitlab (pop args)) + (exitexprs args) + ) + (or (symbolp exitlab) + (error "EXIT need a symbol label: ~S" args)) + (flet ((testnoforenv (env) (null (cold_compenv-for env)))) + (let ( (exitbind (cold_tested_find_binding exitlab env (function testnoforenv))) ) + (if (null exitbind) + (error "EXIT label ~S is not bound" exitlab)) + (or (cold_forever_binding-p exitbind) + (error "label EXIT label ~S not bound to forever ~S" exitlab exitbind)) + (make-prog_exit + :exit_bind exitbind + :exit_body (mapcar (lambda (c) (cold_macroexpand c env)) exitexprs) + ))))) + + +;; SETQ syntax +(defcoldmacro setq (nam args env) + (declare (ignore nam)) + (if (rest (rest args)) (error "SETQ with more than two args ~S" args)) + (destructuring-bind + (var expr) args + (or (symbolp var) (error "bad setq macro args ~S" args)) + (make-prog_setq :setq_var var + :setq_expr (cold_macroexpand expr env) + ))) + + +;;; QUOTE syntax (only for symbols or keywords) +(defcoldmacro quote (nam args env) + (declare (ignore nam)) + (if (rest args) (error "quote with more than one arg ~S" args)) + (let ((qarg (first args))) + (or (symbolp qarg) (keywords qarg) + (error "quote a non-symbol ~S" qarg)) + (make-prog_quotesym :qsym qarg) +)) + +;; IF syntax +(defcoldmacro if (nam args env) + (declare (ignore nam)) + (destructuring-bind + (scond sthen &optional selse) args + (make-prog_if + :cond_expr (cold_macroexpand scond env) + :then_expr (cold_macroexpand sthen env) + :else_expr (if selse (cold_macroexpand selse env))))) + +;;; COND pseudo syntax +;;; (COND ( t1 a1_1 a1_2 ) ( t2 a2_1 )) is expansed into +;;;; (IF t1 (PROGN a1_1 a1_2) (IF t2 a2_1)) +(defcoldmacro cond (nam args env) + (declare (ignore nam)) + (let ( (rescond nil) ) + (loop + for clause in (reverse args) + for rk from 1 + do + ; (warn "COND clause ~#d == ~S~%" rk clause) + ;; special case for last (t ...) or (:else ...) clause + (if (and (<= rk 1) (member (first clause) '(t :else else))) + (if (rest (rest clause)) + (setq rescond (make-prog_progn + :progn_body (mapcar + (lambda (i) (cold_macroexpand i env)) + (rest clause)))) + (setq rescond (cold_macroexpand (second clause) env))) + (let ( (lenclause (length clause)) ) + (case lenclause + ( 1 (let ( (cndexp (cold_macroexpand (first clause) env)) ) + (setq rescond (make-prog_if + :cond_expr cndexp + :then_expr cndexp + :else_expr rescond)))) + ( 0 ) + ( 2 (let ( (cndexp (cold_macroexpand (first clause) env)) + (thnexp (cold_macroexpand (second clause) env)) ) + (setq rescond (make-prog_if + :cond_expr cndexp + :then_expr thnexp + :else_expr rescond)))) + (otherwise + (let ( (cndexp (cold_macroexpand (first clause) env)) + (progexprs (mapcar (lambda (i) (cold_macroexpand i env)) (rest clause))) ) + (setq rescond (make-prog_if + :cond_expr cndexp + :then_expr (make-prog_progn :progn_body progexprs) + :else_expr rescond)))) + ))) + ; (warn "COND partial rescond #~d == ~S~%" rk rescond) + ) + ; (warn "COND ~s expands to ~S ;;COND expansion~%" args rescond) + rescond + )) + +;;; AND pseudo syntax +;;; (AND a1 a2) is expansed into (IF a1 a2) +;;; (AND a1 a2 a3) is expansed into (IF a1 (IF a2 a3)) +(defcoldmacro and (nam args env) + (declare (ignore nam)) + ;; reject (and) without arguments + (if (null args) (error "(and) without any arguments")) + (labels ( (expand (a) + (if (null (rest a)) + (first a) + (let ( (a1 (first a)) ) + (make-prog_if + :cond_expr a1 + :then_expr (expand (rest a)))))) + ) + (expand (mapcar (lambda (c) (cold_macroexpand c env)) args)) + )) + +;;; OR pseudo syntax +;;; (OR a1) is expanded as a1 +;;; (OR a1 a2) is expanded as (IF a1 a1 a2) +;;; (OR a1 a2 a3) is expanded as (IF a1 a1 (IF a2 a2 a3)) +(defcoldmacro or (nam args env) + (declare (ignore nam)) + ;; reject (or) without arguments + (if (null args) (error "(or) without any arguments")) + (labels ( (expand (a) + (if (null (rest a)) (first a) + (let ( (a1 (first a)) ) + (make-prog_if + :cond_expr a1 + :then_expr a1 + :else_expr (expand (rest a)))))) ) + (expand (mapcar (lambda (c) (cold_macroexpand c env)) args)) ) + ) + +;; LET syntax +(defcoldmacro let (nam args env) + (declare (ignore nam)) + (let ( (srcbinds (first args)) + (srcbody (rest args)) ) + (let ( (revbindseq nil) + (newenv (cold_fresh_env env)) + ) + (flet ( (bindhandle + (sbind) + (or (consp sbind) (error "bad src binding ~S in let ~S" sbind args)) + (let ( (f (first sbind)) + (lensbind (length sbind)) + ) + (let ( (newbind + (cond + ( (and (eq lensbind 3) (keywordp f)) + (let ( (sy (second sbind)) + (ex (third sbind)) ) + (or (cold_valid_type_keyword_p f) + (error "bad type keyword ~S in let ~S" f args)) + (or (symbolp sy) + (error "non symbol ~S to bind in let ~S" sy args)) + (let ( (expa (cold_macroexpand ex newenv)) ) + (if (consp expa) (error "bad expa ~S in let ~S" expa args)) + (make-cold_let_binding :bname sy + :expr expa + :type f) + ))) + ( (eq lensbind 2) + (let ( (sy (first sbind)) + (ex (second sbind)) ) + (or (symbolp sy) + (error "non symbol ~S to bind in let ~S" sy args)) + (let ( (expa (cold_macroexpand ex newenv)) ) + (if (consp expa) (error "bad expa ~S in let ~S" expa args)) + (make-cold_let_binding :bname sy + :expr expa)))) + ( t (error "bad binding ~S in let ~S" sbind args) ) + ))) + (push newbind revbindseq) + (cold_put_binding newbind newenv) + )))) + (mapc (function bindhandle) srcbinds) + (let ( (res + (make-prog_let + :let_bindings (reverse revbindseq) + :let_body (cold_list_macroexpand srcbody newenv) + )) ) + res + ))))) + + +;;; MULTICALL syntax +(defcoldmacro multicall (nam args env) + (declare (ignore nam)) + (if (< (length args) 3) (error "too few arguments to multicall ~S" args)) + (let* ( + (arglist args) + (muformalseq (pop args)) + (mucall (pop args)) + (mubody args) + (muformalist (lambda_args_bindings muformalseq)) + (mufirst (first muformalist)) + (xcall (cold_macroexpand mucall env)) + (newenv (cold_fresh_env env)) + ) + (or (prog_apply-p xcall) (prog_send-p xcall) + (error "multicall not of ~S application or send ~S" xcall arglist)) + (assert (cold_formal_binding-p mufirst)) + (mapc (lambda (b) (cold_put_binding b newenv)) muformalist) + (or (eq (cold_typed_binding-type mufirst) ':value) + (error "first formal of multicall should be a :value in multicall ~S" + arglist)) + (let ( (mc + (make-prog_multicall + :multicall_formals muformalist + :multicall_call xcall + :multicall_body (mapcar (lambda (b) (cold_macroexpand b newenv)) mubody)) + ) ) + mc + ))) + + +(defcoldmacro return (nam args env) + (declare (ignore nam)) + (let ( (retpr + (make-prog_return :retexprs (mapcar (lambda (b) (cold_macroexpand b env)) args))) ) + ;(break "return macro retptr ~S~%" retpr) + retpr)) + + +(defgeneric bind_normal_code (cod env) + (:documentation "normalization of (any) Basilys code, gives binding+normal code") +) + + +(defgeneric normalize_toplev (def env) + (:documentation "normalize a toplev definition or code")) + +(defmethod bind_normal_code ((cod prog_src) env) + (declare (ignore env)) + ;; some stuff are already normal, eg defprimitive or quotsym + (values nil cod) +) + + +; we frequently may need to make an optional let around something +(defun cold_wrap_let (revbindings cod) + (assert (listp revbindings)) + (if revbindings + (progn + (assert (cold_let_binding-p (first revbindings))) + (make-prog_let + :let_bindings (reverse revbindings) + :let_body cod)) + cod + ) + ) + +; likewise, but needing a sequence +(defun cold_wrap_letseq (revbindings cod) + (assert (listp revbindings)) + (if revbindings + (progn + (assert (cold_let_binding-p (first revbindings))) + (make-prog_let + :let_bindings (reverse revbindings) + :let_body cod)) + cod) + ) + +;; likewise, producing a list +(defun cold_wrap_letlist (revbindings cod) + (assert (listp revbindings)) + (if revbindings + (progn + (assert (cold_let_binding-p (first revbindings))) + (list (make-prog_let + :let_bindings (reverse revbindings) + :let_body cod))) + (if (listp cod) cod (list cod)) + )) + + +;;; executable toplev normalisation +(defmethod normalize_toplev ((cod prog_src) env) + (multiple-value-bind + (rbind ncod) + (bind_normal_code cod env) + (assert (listp rbind)) + (cold_wrap_let rbind ncod) +)) + + + +;;- ;; normalization of a symbol occurrence means seeking if the symbol is +;;- ;; closed or not and returning a prog_closedvar when appropriate +;;- (defun normalize_symbol (symb env) +;;- (or (symbolp symb) +;;- (error "normalize_symbol bad symb ~s ~%... in env ~s~%" symb env)) +;;- (let ( (resnorm nil) +;;- (sbind (cold_find_binding symb env)) +;;- ) +;;- (labels +;;- ( +;;- ( knownsymb +;;- (sym closvars) +;;- (or (symbolp sym) (error "bad symbol ~S in knownsymb" sym)) +;;- (some (lambda (cv) (eq (prog_closedvar-clv_var cv) sym)) closvars) +;;- ) +;;- ( envtest +;;- (env) +;;- (or (symbolp symb) (error "bad symbol ~S in envtest" symb)) +;;- (let ( (forf (cold_compenv-for env)) ) +;;- (cond +;;- ( (null forf) +;;- (warn "normalize_symbol symb ~S null forf ~%" symb) +;;- ) +;;- ( (prog_defun-p forf) +;;- (or (symbolp symb) (error "bad symbol ~S inside envtest defun forf ~S" symb forf)) +;;- (or resnorm +;;- (setq resnorm (make-prog_closedvar :clv_var symb +;;- :clv_fun forf +;;- :clv_bind sbind))) +;;- (let ( (oldclosvars (prog_defun-fun_closvars forf)) ) +;;- (or (knownsymb symb oldclosvars) +;;- (setf (prog_defun-fun_closvars forf) (cons resnorm oldclosvars))) +;;- ) +;;- ) +;;- ( (prog_lambda-p forf) +;;- (or (symbolp symb) (error "bad symbol ~S inside envtest lambda forf ~S" symb forf)) +;;- (let ( (oldclosvars (prog_lambda-lambda_closvars forf)) ) +;;- (or resnorm +;;- (setq resnorm (make-prog_closedvar :clv_var symb +;;- :clv_fun forf +;;- :clv_bind sbind))) +;;- (or (knownsymb symb oldclosvars) +;;- (setf (prog_lambda-lambda_closvars forf) (cons resnorm oldclosvars))) +;;- ) +;;- ) +;;- ( t +;;- (error "normalize_symbol ~S strange forf ~S ~%" symb forf) +;;- ))) +;;- t ;as a test, envtest return +;;- ;true to continue scan of +;;- ;environment lists +;;- ) +;;- ) +;;- (or (symbolp symb) +;;- (error "normalize_symbol bad symb before tested ~s ~%... in env ~s~%" symb env)) +;;- (if (or (cold_class_binding-p sbind) +;;- (cold_instance_binding-p sbind)) +;;- symb +;;- (progn +;;- (cold_tested_find_binding symb env (function envtest)) +;;- (or resnorm symb) ;return value for normalize_symbol +;;- ))))) + +(defun normalize_symbol (symb env) + (or (symbolp symb) + (error "normalize_symbol bad symb ~s ~%... in env ~s~%" symb env)) + (multiple-value-bind + (bnd revlis) + (cold_enclosed_find_binding symb env) + (cond ( (null symb) + symb ;nil is always nil + ) + ( (cold_class_binding-p bnd) + symb ;should make some progconst + ) + ( (cold_instance_binding-p bnd) + symb ;should make some progconst of it + ) + ( (cold_selector_binding-p bnd) + symb ;should make some progconst of it + ) + ( (cold_function_binding-p bnd) + symb ;should make some progconst of it + ) + ( (cold_value_binding-p bnd) + symb ;should make some progconst of it + ) + ( (cold_field_binding-p bnd) + symb ;should make some progconst of it + ) + ( (null bnd) + (error "normalize_symbol ~S unbound in env ~S <:::normalize_symbol unbound ~S in ~S~%" + symb env symb (and (prog_defun-p normalized_defun) (prog_defun-def_name normalized_defun)))) + ( (null revlis) + symb) + (t (progn + ;; check that a closed symbol is indeed a value + (and (cold_typed_binding-p bnd) + (not (null (cold_typed_binding-type bnd))) + (not (eq (cold_typed_binding-type bnd) ':value)) + (error "normalize_symbol ~S closed not value ~S" symb bnd)) + ; (break "normalize_symbol symb ~S bnd ~S revlis ~S~%" symb bnd revlis) + (let ( (clovs + (mapcar + (lambda (lr) + (assert (prog_lambda-p lr)) + (or + (find-if + (lambda (cv) + (assert (prog_closedvar-p cv)) + (eq (prog_closedvar-clv_var cv) symb)) + (prog_lambda-lambda_closvars lr)) + (let ( (ncv (make-prog_closedvar + :clv_var symb + :clv_fun lr + :clv_bind bnd)) ) + (push ncv (prog_lambda-lambda_closvars lr)) + ncv))) + revlis)) ) + (first clovs) + )))))) + + + +;; we need to normalize a sequence, possibly adding new let_bindings +;; to complex arguments this function returns two results: the +;; normalized sequence and the reversed list of bindings the prefix is +;; for gentemp-ing the variables; the revbindseq argument is the +;; initial value of reversed list of bindings (usually nil) +(defun normalize_code_sequence (seq env prefix revbindseq) + (or (listp seq) + (error "normalize_code_sequence bad seq ~s" seq)) + (or (cold_compenv-p env) + (error "normalize_code_sequence bad env ~s" env)) + (or (stringp prefix) + (error "normalize_code_sequence bad prefix ~s" prefix)) + (or (listp revbindseq) + (error "normalize_code_sequence bad revbindseq ~s" revbindseq)) + (flet ( (handlexpr + (exp) + (cond + ( (prog_src-p exp) + (let ( (nsym (gentemp prefix)) ) + (multiple-value-bind + (normrevbind normexp) + (bind_normal_code exp env) + (assert (listp normrevbind)) + (if (consp normexp) + (error "bad normexp ~S in normalize_code_sequence seq ~S exp ~S" normexp seq exp)) + (setq revbindseq (append normrevbind revbindseq)) + (let ( (newbind + (make-cold_let_binding :bname nsym :expr normexp)) ) + (if (prog_chunk-p normexp) + (setf (cold_typed_binding-type newbind) + (prog_chunk-chunk_type normexp))) + (push newbind + revbindseq)) + nsym + ) )) + ( (symbolp exp) + (normalize_symbol exp env) ) + ( t exp ))) + ) + (values (mapcar (function handlexpr) seq) revbindseq))) + + +(defmethod bind_normal_code ((cod null) env) + (declare (ignore env)) + (values nil nil) +) + +(defmethod bind_normal_code ((cod t) env) + (declare (ignore env)) +; (warn "bind_normal_code t ~S env ~S" cod env) + (values nil cod) +) + +(defmethod bind_normal_code ((cod symbol) env) + (values nil (normalize_symbol cod env))) + + +(defmethod bind_normal_code ((cod prog_setq) env) + (let ( (va (prog_setq-setq_var cod)) + (ex (prog_setq-setq_expr cod)) ) + (or (symbolp va) (error "prog_setq bad variable ~S~%")) + (let ((nva (normalize_symbol va env))) + (multiple-value-bind + (nexs pbindseqrev) + (normalize_code_sequence (list ex) env "_SETQ_" nil) + (assert (null (rest nexs))) + (values nil + (cold_wrap_let pbindseqrev + (make-prog_setq + :setq_var nva + :setq_expr (first nexs) + ))))))) + + +(defun expand_primitive (srcod poper pargs) + (let* ( + (pformals (prog_defprimitive-primitive_formals poper)) + (pexpansion (prog_defprimitive-primitive_expansion poper)) + (pnbformals (length pformals)) + (htb (make-hash-table :size (+ (* 2 pnbformals) 3))) + ) + (if (/= pnbformals (length pargs)) + (error "formals/args mismatch in primitive ~S" srcod)) + ;; associate each formal with its actual argument in htb + (loop + for rk from 0 + for curform in pformals + for curarg in pargs + do + (let ((curname (cold_any_binding-bname curform))) + (setf (gethash curname htb) curarg) + )) + ;; make the expansion + (let ( (resexp + (mapcar + (lambda (e) + (cond + ((numberp e) e) + ((stringp e) e) + ((symbolp e) + (multiple-value-bind + (symval symhere) + (gethash e htb) + (cond + ( (stringp symval) (make-prog_cstring :c_str symval)) + ( symhere symval ) + ( t + (warn "unbound symbol ~S in primitive poper ~S pargs ~S" + e poper pargs) + e )) + )) + (t (error "bad element ~S in expansion of ~S" e poper)) + )) + pexpansion)) + ) + (make-prog_chunk :chunk_args resexp :chunk_type (prog_defprimitive-primitive_type poper)) + ) + )) + +(defmethod bind_normal_code ((cod prog_primitive) env) + (let* ( (poper (prog_primitive-prim_oper cod)) + (pargs (prog_primitive-prim_args cod)) + ) + (multiple-value-bind + (normargs pbindseqrev) + (normalize_code_sequence pargs env "_PARG_" nil) + (values pbindseqrev + (expand_primitive cod poper normargs)) + ))) + + + + +(defmethod normalize_call ((cod prog_apply) env) + (let ( (afun (prog_apply-appl_fun cod)) + (aargs (prog_apply-appl_args cod)) + (abindseqrev nil) ) + ;; normalize the applied function if needed + (cond + ( (prog_src-p afun) + (multiple-value-bind + (frbind nfun) + (bind_normal_code afun env) + (assert (listp frbind)) + (assert (prog_src-p nfun)) + (let* ( + (fsym (gentemp "_AFUN_")) + (fbind (make-cold_let_binding + :bname fsym :expr nfun)) + ) + (setq abindseqrev (append frbind abindseqrev)) + (push fbind abindseqrev) + (setq afun fsym)))) + ( (symbolp afun) + (setq afun (normalize_symbol afun env)) ) + ( t + (error "bad function to apply in ~s" cod)) + ) + ;; normalize the arguments + (multiple-value-bind + (normargs pbindseqrev) + (normalize_code_sequence aargs env "_FARG_" abindseqrev) + (values + (make-prog_apply + :appl_fun afun + :appl_args normargs) + pbindseqrev + )))) + +(defmethod bind_normal_code ((cod prog_apply) env) + (multiple-value-bind + (cod bindrev) + (normalize_call cod env) + (values bindrev cod) + )) + +;;; normalize a let (gotten from source code) +(defmethod bind_normal_code ((cod prog_let) env) + (let* ( (lbinds (prog_let-let_bindings cod)) + (lbody (prog_let-let_body cod)) + (newenv (cold_fresh_env env)) + (nbinds + (mapcar + (lambda (b) + (let ((nb (copy-cold_let_binding b))) + (multiple-value-bind + (pbindrev pbody) + (bind_normal_code (cold_let_binding-expr b) newenv) + (assert (listp pbindrev)) + (setf (cold_let_binding-expr nb) + (cold_wrap_let + pbindrev + pbody)) + (cold_put_binding nb newenv) + nb))) + lbinds)) + ) + (multiple-value-bind + (nbody pbindseqrev) + (normalize_code_sequence lbody newenv "_LETBODY_" nil) +;;; since the new bindings are gensymed, no risk of conflict with old ones + (values + nil + (cold_wrap_letseq + (append pbindseqrev (reverse nbinds)) + nbody) + ) + ))) + + +;; normalize an if +(defmethod bind_normal_code ((cod prog_if) env) + (let* ( (icond (prog_if-cond_expr cod)) + (ithen (prog_if-then_expr cod)) + (ielse (prog_if-else_expr cod)) ) + (multiple-value-bind + (ncond condbindseqrev) + (normalize_code_sequence (list icond) env "_IFCOND_" nil) + ;; if the condition has been gentemp-ed force its binding of type long + ;; if it had no type + (let ( (nc1 (first ncond)) ) + (if (symbolp nc1) + (let ( (bc1 (find-if (lambda (b) + (and (cold_let_binding-p b) + (eq nc1 (cold_any_binding-bname b)))) + condbindseqrev)) ) + (if (cold_typed_binding-p bc1) + (or (cold_typed_binding-type bc1) + (setf (cold_typed_binding-type bc1) :long)) + )))) + (multiple-value-bind + (thenrevbind normthen) + (bind_normal_code ithen env) + (assert (listp thenrevbind)) + (values + condbindseqrev + (make-prog_if + :cond_expr (first ncond) + :then_expr (cold_wrap_let thenrevbind normthen) + :else_expr + (if ielse + (multiple-value-bind + (elserevbind normelse) + (bind_normal_code ielse env) + (assert (listp elserevbind)) + (cold_wrap_let elserevbind normelse)) + ) + )))))) + + +;; normalize a forever + +(defmethod bind_normal_code ((cod prog_forever) env) + (let* ( (ibind (prog_forever-forever_bind cod)) + (ibody (prog_forever-forever_body cod)) + (newenv (cold_fresh_env env)) + ) + (cold_put_binding ibind newenv) + (multiple-value-bind + (nbody bindseqrev) + (normalize_code_sequence ibody newenv "_FOREVERB_" nil) + (assert (listp bindseqrev)) + (values + nil + (make-prog_forever + :forever_bind ibind + :forever_body + (cold_wrap_letlist + bindseqrev nbody + )))))) + + + +;; normalize an exit +(defmethod bind_normal_code ((cod prog_exit) env) + (let* ( (ibind (prog_exit-exit_bind cod)) + (ibody (prog_exit-exit_body cod)) ) + (multiple-value-bind + (nbody bindseqrev) + (normalize_code_sequence ibody env "_EXIT_" nil) + (assert (listp bindseqrev)) + (values + bindseqrev + (make-prog_exit + :exit_bind ibind + :exit_body nbody + ))))) + + + + +;; normalize a progn +(defmethod bind_normal_code ((cod prog_progn) env) + (let ((ibody (prog_progn-progn_body cod))) + (values + nil + (make-prog_progn + :progn_body + (mapcar + (lambda (comp) + (multiple-value-bind + (sbind scod) + (bind_normal_code comp env) + (assert (listp sbind)) + (cold_wrap_let + sbind scod) + )) + ibody))))) + + + +;; normalize a multicall +(defmethod bind_normal_code ((cod prog_multicall) env) + (let ( (iformals (prog_multicall-multicall_formals cod)) ;list of formal bindings + (icall (prog_multicall-multicall_call cod)) + (ibody (prog_multicall-multicall_body cod)) + (newenv (cold_fresh_env env)) + ) + (mapc (lambda (b) (cold_put_binding b newenv)) iformals) + (multiple-value-bind + (normcall pcallbindseqrev) + ;;; we should normalize only the sequence of args of the call or send + ;;; it should stay a call or a send + (normalize_call icall env) + (assert (or (prog_send-p normcall) (prog_apply-p normcall))) + (assert (listp pcallbindseqrev)) + (multiple-value-bind + (normbody pbodybindseqrev) + (normalize_code_sequence ibody newenv "_MULCALLBODY_" nil) + (assert (listp pbodybindseqrev)) + (values + pcallbindseqrev + (make-prog_multicall + :multicall_formals iformals + :multicall_call normcall + :multicall_body + (cold_wrap_letlist + pbodybindseqrev normbody + ))))))) + + + +;; normalize a send +(defmethod normalize_call ((cod prog_send) env) + (let ( (isel (prog_send-send_sel cod)) + (irecv (prog_send-send_recv cod)) + (iargs (prog_send-send_args cod)) ) + (assert (symbolp isel)) + (multiple-value-bind + (normrecvargs pbindseqrev) + (normalize_code_sequence (cons irecv iargs) env "_SEND_" nil) + (let ( (nrecv (first normrecvargs)) + (nargs (rest normrecvargs)) + ) + (values + (make-prog_send + :send_sel (normalize_symbol isel env) + :send_recv nrecv + :send_args nargs) + pbindseqrev + ))))) + +(defmethod bind_normal_code ((cod prog_send) env) + (multiple-value-bind + (nsend pbindseqrev) + (normalize_call cod env) + (assert (listp pbindseqrev)) + (values pbindseqrev nsend))) + +;;; normalize an unsafe_get_field +(defmethod bind_normal_code ((cod prog_unsafe_get_field) env) + (let ( (ifldname (prog_unsafe_get_field-uget_field cod)) + (iobjexpr (prog_unsafe_get_field-uget_obj cod)) ) + (let ( (ifldbind (cold_find_binding (keyword2symbol ifldname) env)) ) + (assert (cold_field_binding-p ifldbind) (ifldbind) + "invalid fldbind ~S for fldname ~S in unsafe_get_field ~S env ~S <:::bad get_field ~S" + ifldbind ifldname cod env ifldname) + (let ( (fld (cold_field_binding-fieldef ifldbind)) ) + (multiple-value-bind + (nobjbind nobjexpr) + (bind_normal_code iobjexpr env) + (assert (listp nobjbind)) + (values + nobjbind + (make-prog_unsafe_get_field + :uget_field fld + :uget_obj nobjexpr) + )))))) + + +;;; normalize an unsafe_put_fields +(defmethod bind_normal_code ((cod prog_unsafe_put_fields) env) + (let ( (iobjexpr (prog_unsafe_put_fields-uput_obj cod)) + (ikeys (prog_unsafe_put_fields-uput_keys cod)) + (nrevkeys nil) + ) + ;; check key symbols and make the list of fields + (let ( + (fieldlist + (mapcar (lambda (kpair) + (let* ( (ifldname (car kpair)) + (ifldbind (cold_find_binding (keyword2symbol ifldname) env)) ) + (assert (cold_field_binding-p ifldbind) (ifldbind) + "invalid fldbind ~S in unsafe_put_fields ~S fldname ~S env ~S" ifldbind cod ifldname env) + (cold_field_binding-fieldef ifldbind) + )) + ikeys)) + ) + ;; normalize the object expression + (multiple-value-bind + (nobjbinds nobjexpr) + (bind_normal_code iobjexpr env) + ;;; normalize the field expressions + (multiple-value-bind + (nkeyexprs nkeybinds) + (normalize_code_sequence + (mapcar #'cdr ikeys) + env "_UPUTF_" nobjbinds) + ;;; make the normalized key pairs + (mapc + (lambda (fld nexpk) + (push (cons fld nexpk) nrevkeys) + ) fieldlist nkeyexprs) + (values + nkeybinds + (make-prog_unsafe_put_fields + :uput_obj nobjexpr + :uput_keys (reverse nrevkeys)) + )))))) + + + + +;;; normalize an make_instance +(defmethod bind_normal_code ((cod prog_make_instance) env) + (let ( (iclass (prog_make_instance-mki_class cod)) + (ikeys (prog_make_instance-mki_keys cod)) + (nrevkeys nil) + ) + ;; check class & key symbols and make the list of fields + (let* ( + (classbind (cold_find_binding iclass env)) + (classdef (if (cold_class_binding-p classbind) + (cold_class_binding-classdef classbind) + (error "make_instance ~S not a class bind ~S env ~S" + iclass classbind env))) + (fieldlist + (mapcar (lambda (kpair) + (let* ( (ifldname (car kpair)) + (ifldbind (cold_find_binding (keyword2symbol ifldname) env)) ) + (assert (cold_field_binding-p ifldbind) (ifldbind) + "invalid fldbind ~S in make_instance ~S for fldname ~S env ~S<:: bad make_instance fieldname ~S~%" + ifldbind cod ifldname env ifldname) + (let* ( (fld (cold_field_binding-fieldef ifldbind)) + (fldoff (prog_field-field_offset fld)) + ) + (assert (eq (nth fldoff (prog_defclass-class_allfields classdef)) fld) + (fld) + "bad field ~S in make_instance ~S" fld cod) + fld + ) + )) + ikeys)) + ) +;;; normalize the field expressions + (multiple-value-bind + (nkeyexprs nkeybinds) + (normalize_code_sequence + (mapcar #'cdr ikeys) + env "_UMKI_" nil) +;;; make the normalized key pairs + (mapc + (lambda (fld nexpk) + (push (cons fld nexpk) nrevkeys) + ) fieldlist nkeyexprs) + (values + nkeybinds + (make-prog_make_instance + :mki_class (normalize_symbol iclass env) + :mki_classdef classdef + :mki_keys (reverse nrevkeys)) + ))))) + + + +;; normalize the body of a lambda or a function +;; hence put an implicit return on last element +(defun normalize_body (body env) + (assert (cold_compenv-p env)) + (or (listp body) (error "bad body ~S for normalize_body ~%" body)) + (multiple-value-bind + (nseq nbind) + (normalize_code_sequence body env "_BODY_" nil) + (assert (listp nbind)) + (if (listp nseq) + (let ( (bl (butlast nseq)) + (l (last nseq)) ) + (if (prog_return-p (first l)) + (cold_wrap_letseq nbind nseq) + (cold_wrap_letlist + nbind + (append bl (list (make-prog_return :retexprs l))) + ) + ))))) + + + +;;;;;;; normalize a lambda +(defmethod bind_normal_code ((cod prog_lambda) env) + (let* ( (formals (prog_lambda-lambda_formals cod)) + (body (prog_lambda-lambda_body cod)) + (argbs (prog_lambda-lambda_argbindings cod)) + (newenv (cold_fresh_env env)) + (ncod (copy-prog_lambda cod)) + ) + (setf (cold_compenv-for newenv) ncod) + (mapc (lambda (b) (cold_put_binding b newenv)) argbs) + (let*( (nbody (normalize_body body newenv)) + (nfnam (gentemp "_LAMBDAFUN_")) + (nclosv (prog_lambda-lambda_closvars ncod)) + (nfun (make-prog_defun + :def_name nfnam + :fun_formals formals + :fun_argbindings argbs + :fun_body nbody + :fun_lambda cod + :fun_closvars nclosv)) + ;; call normalize_symbol on each closed variable in the lambda + ;; with the side-effect of propagating, if necessary, the closed + ;; variables into the current function + (closvseq (mapcar (lambda (cv) + (normalize_symbol (prog_closedvar-clv_var cv) env)) + nclosv)) + ) + (push nfun (compilation-functions this_compilation)) + (setf (prog_lambda-lambda_body ncod) nbody) + (cold_delay + "addobjcode lambda" + (let ( (cofun (compile_obj nfun newenv)) ) + (add_objcode cofun) + ) + ) + (let( (mkclos + (make-prog_makeclosure + :mkclos_fun nfun + :mkclos_closvars closvseq)) ) + (values nil mkclos) + )))) + + + +(defmethod bind_normal_code ((cod prog_return) env) + (let ( (retargs (prog_return-retexprs cod)) ) + ;; normalize the arguments + (multiple-value-bind + (normargs pbindseqrev) + (normalize_code_sequence retargs env "_RETARG_" ()) + (values pbindseqrev + (make-prog_return + :retexprs normargs) + )))) + + + + +(defvar normalized_defun nil) + +(defmethod normalize_toplev ((cod prog_defun) env) + (let* ( (ncod (copy-prog_defun cod)) + (fbody (prog_defun-fun_body cod)) + (argbs (prog_defun-fun_argbindings cod)) + (newenv (cold_fresh_env env)) + ) + (setq normalized_defun cod) + (setf (cold_compenv-for newenv) ncod) + (mapc (lambda (b) (cold_put_binding b newenv)) argbs) + (let( (nbody (normalize_body fbody newenv)) ) + (setf (prog_defun-fun_body ncod) nbody)) + (setq normalized_defun ()) + ncod + )) + + + +(defmethod normalize_toplev ((cod prog_definstance) env) + (let* ( (ncod (copy-prog_definstance cod)) + (slots (prog_definstance-inst_slots cod)) + (nslots + (mapcar + (lambda (s) + (assert (instance_slot-p s)) + (make-instance_slot + :slot_field (instance_slot-slot_field s) + :slot_value + (multiple-value-bind + (sbind sexpr) + (bind_normal_code + (instance_slot-slot_value s) + env) + (cold_wrap_let sbind sexpr)))) + slots)) ) + (setf (prog_definstance-inst_slots ncod) nslots) + ncod) + ) + +(defmethod normalize_toplev ((cod prog_defselector) env) + (let* ( (ncod (copy-prog_defselector cod)) + (slots (prog_defselector-inst_slots cod)) + (nslots + (mapcar + (lambda (s) + (assert (instance_slot-p s)) + (make-instance_slot + :slot_field (instance_slot-slot_field s) + :slot_value + (multiple-value-bind + (sbind sexpr) + (bind_normal_code + (instance_slot-slot_value s) + env) + (cold_wrap_let sbind sexpr)))) + slots)) ) + (setf (prog_defselector-inst_slots ncod) nslots) + ncod) + ) + +;;;;;;;;;;;; compile to object +(defstruct compilation + functions ;list of prog- functions + currout ;current routine + initrout ;initialization routine + revobjcode ;generated object code reversed list + cdata ;constructed data + symboldict ;dictonnary of gererated symbols +) + + + +;; sometimes we need to take the length of a stuff and round it to 1 if it is empty +(defun my_length_gt_1 (s) + (let ( (l (length s)) ) + (if (> l 0) l 1))) + +(defstruct obj_instr +) + +(defgeneric output_ccode (obj str) + (:documentation "output C code from Basilys code") +) + +(defgeneric output_cdecl (obj str) + (:documentation "output C declaration from Basilys code") +) + +(defmethod output_ccode ((obj t) str) + (error "invalid arg (type ~A) to output_ccode ~S" (type-of obj) obj) +) + +(defmethod output_ccode ((obj symbol) str) + (format str "/*@Symb*/((void*)(BASILYSG(~S)))" obj)) + +(defmethod output_ccode ((obj null) str) + (format str "/*@Nil*/NULL")) + +(defmethod output_ccode ((obj string) str) + (format str "/*@String*/~S" obj)) + +(defmethod output_ccode ((obj integer) str) + (format str "/*@Integer*/~S" obj)) + +(defmethod output_cdecl ((obj t) str) + (error "unexpected output_cdecl (type ~A) ~S~%" (type-of obj) obj) + (format_c_comment str "**@declobj t![~A]~%~S~%**" (type-of obj) obj)) + +(defstruct (obj_get_arguments (:include obj_instr)) + instrs +) + +(defstruct (obj_verbatim) + vstr) + +(defstruct (obj_verbatiminstr (:include obj_instr)) + vstr) + +(defmethod print-object ((ob obj_verbatim) st) + (let ((*print-circle* nil)) + (format st "{ObVerb ~S}" (obj_verbatim-vstr ob)))) + +(defmethod output_ccode ((obj obj_verbatim) str) + (write-string (obj_verbatim-vstr obj) str) +) + +(defmethod print-object ((ob obj_verbatiminstr) st) + (let ((*print-circle* nil)) + (format st "{ObVerbIns ~S}" (obj_verbatiminstr-vstr ob)))) + +(defmethod output_ccode ((obj obj_verbatiminstr) str) + (write-string (obj_verbatiminstr-vstr obj) str) +) + +(defstruct (obj_cstring) + obcstr) + +(defmethod output_ccode ((obj obj_cstring) str) + (let ( (cstri (obj_cstring-obcstr obj)) + ) + (format_c_comment str "obj_cstring ~S" cstri) + (write-string " \"" str) + (map nil + (lambda (c) + (case c + (#\Newline (write-string "\\n" str)) + (#\Tab (write-string "\\t" str)) + (#\\ (write-string "\\\\" str)) + (#\' (write-string "\\'" str)) + (#\" (write-string "\\\"" str)) + (otherwise (if (standard-char-p c) + (write-char c str) + (format str "\\x~2,'0x" (char-code c)))) + ) + ) + cstri) + (write-string "\" " str) + )) + + +(defmethod output_ccode ((obj prog_src) str) + (format_c_comment str "~%*** progsrc ~S ***~%~%" obj)) + +(defgeneric query_ctype (obj) + (:documentation "query type of C code") +) + +(defmethod query_ctype ((obj t)) +nil) + +(defgeneric put_destination (obj dest) + (:documentation "set the destination of C code from Basilys code & return nil or a new objectocde") +) + +(defgeneric get_destination (obj) + (:documentation "retrieve the destination of C code from Basilys code") +) + +(defmethod put_destination ((obj t) dest) +; (warn "default put_destination obj ~S dest ~S" obj dest) + (if (prog_src-p obj) (error "put_destination prog_src obj ~S" obj)) + (build_obj_compute + dest + (list obj) + (query_ctype obj)) +) + +(defmethod put_destination ((obj integer) dest) + (build_obj_compute + dest + (list obj) + :long) +) + +(defmethod put_destination ((obj string) dest) + (error "put_destination stringobj ~S dest ~S" obj dest) + (build_obj_compute + dest + (list obj) + nil) +) + +(defmethod get_destination ((obj t)) + nil ;do nothing by default +) + +(defmethod output_ccode ((obj cons) str) + (format str "/*@list ~d*/ " (length obj)) + (mapc (lambda (o) + (format str "~%") + (output_ccode o str)) + obj) + (format str "/*@endlist ~d*/ " (length obj))) + +(defmethod output_ccode ((obj obj_get_arguments) str) + (let (( instrs (obj_get_arguments-instrs obj))) + (format str "/*obj_get_arguments ~d*/~%" (length instrs)) + (mapc (lambda (i) (format str "~%") (output_ccode i str)) instrs) + (format str " goto lab_endargs;~%") + (format str "lab_endargs: ;~%") + ) +) + + +(defstruct (obj_clearptr (:include obj_instr)) + clrptrvar +) + +(defmethod output_ccode ((obj obj_clearptr) str) + (format str "/*clearptr*/ ") + (output_ccode (obj_clearptr-clrptrvar obj) str) + (format str " = NULL;~%") +) + +(defstruct (obj_clearlong (:include obj_instr)) + clrlongvar +) + +(defmethod output_ccode ((obj obj_clearlong) str) + (format str "/*clearlong*/ ") + (output_ccode (obj_clearlong-clrlongvar obj) str) + (format str " = 0L;~%") +) + + +(defstruct (obj_data) + discr ;the discriminant + comname ;comment name + ) + + +;; add a data to the constdata pool of the compilation; so append the +;; data to cdata, create a cdata binding for it an a pointerobjvar for +;; it in the initial routine +(defun add_cdata (da &optional why) + (assert (listp (compilation-cdata this_compilation))) + (and (listp da) (error "bad list cdata ~S" da)) + (assert (obj_data-p da) (da) "bad cdata ~S" da) + (assert (not (member da (compilation-cdata this_compilation)))) + (push da (compilation-cdata this_compilation)) + (assert (listp (compilation-cdata this_compilation))) + (let* ( (nbdata (length (compilation-cdata this_compilation))) + (initrout (compilation-initrout this_compilation)) + (dbind (make-cold_cdata_binding + :bname (gentemp "CDATA_") + :type :value + :cdata da)) + (ovar (newobjptrvar initrout dbind + (if why + (concatenate 'string "addCdata " (string why)) + "added cdata"))) ) + (setf (gethash da (obj_initroutine-inirou_datarankdict initrout)) nbdata) + (routine_link_data2ptr initrout da ovar) + ) + ;; (format *error-output* "add_cdata da ~S~%" da) + da + ) + +(defun add_objcode (ob) + (assert (listp (compilation-revobjcode this_compilation))) + (assert (obj_routine-p ob) (ob) "adding bad objcode ~S" ob) + (push ob (compilation-revobjcode this_compilation)) + (assert (listp (compilation-revobjcode this_compilation))) + nil +) + +;(defun put_progdata (pro &optional datagetfun) +; (assert (prog_src-p pro) (pro) "put bad progdata ~S" pro) +; (or (gethash pro (compilation-progdict this_compilation)) +; (if datagetfun +; (let ((data (apply datagetfun (list pro)))) +; (assert (obj_data-p data) (data) "bad computed data ~S for progdata ~S" data pro) +; (setf (gethash pro (compilation-progdict this_compilation)) +; data) +; (or (currout_data2ptr data) (add_cdata data)) +; data +; )))) +; +;(defun progdata (pro) +; (gethash pro (compilation-progdict this_compilation))) +; +;(defun checked_progdata (pro) +; (or (gethash pro (compilation-progdict this_compilation)) +; (error "prog without data ~S" pro))) +; + +(defmethod output_ccode ((obj obj_data) str) + (format str " /*-*ccode objdata ~S */ " (obj_data-comname obj)) + (let ( (optr (currout_data2ptr obj)) ) + (assert optr (obj optr) "output_ccode data ~S without ptr" obj) + (output_ccode optr str)) +; (finish-output str) +) + +(defgeneric output_cassign (obda str) + (:documentation "output the code to assign the data")) + +(defgeneric output_cinit (obda str) + (:documentation "output the code to initialize the data")) + +(defgeneric output_cfill (obda str) + (:documentation "output the code to fill the initialized data")) + +(defgeneric output_cverify (obda str) + (:documentation "output the code to verify the initialized data")) + +(defgeneric output_cref (obda str) + (:documentation "output the code to reference the data")) + +(defmethod output_cassign ((obda obj_data) str) + (let ( (cmsg (with-output-to-string + (s) + (format s "cassign/data cleared ~S #~d [~S]" + (obj_data-comname obda) (initrout_rank obda) (type-of obda)))) ) + (format str "basilys_assertmsg(~a, NULL==" + (str2cstr cmsg))) + (output_ccode (currout_data2ptr obda) str) + (format str ");~%") + (format str "/*cassign data ~S #~d [~S] */~%" + (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (output_ccode (currout_data2ptr obda) str) + (format str " = (void*) (&cdat->inidat_~d_);~%" (initrout_rank obda)) + (format str "#if COLD_BASILYS_DEBUG~%") + (format str " debugeprintf(\" %s %p @%d\", ") + (write-string + (str2cstr + (with-output-to-string (s) + (format s "cassign data ~S #~d [~S]" + (obj_data-comname obda) + (initrout_rank obda) + (type-of obda)))) + str) + (format str ", (void*) (&cdat->inidat_~d_), " (initrout_rank obda)) + (format str " (int)offsetof(cdata_t, inidat_~d_));~%" (initrout_rank obda)) + (format str "#endif /*COLD_BASILYS_DEBUG*/~%") + ) + + +(defmethod output_cinit ((obda obj_data) str) + (finish-output str) + (error "cannot output_cinit objdata ~S~%" obda) +) + + +(defmethod output_cfill ((obda obj_data) str) + (finish-output str) + (error "cannot output_cfill objdata ~S~%" obda) +) + + + +(defmethod output_cref ((obda obj_data) str) + (format str " /*cref ~S [~S] #~d*/" (obj_data-comname obda) (type-of obda) (initrout_rank obda)) + (format str " ((void*) (&cdat->inidat_~d_)) " (initrout_rank obda)) +; (finish-output str) +) + +(defstruct (obj_dataclosure (:include obj_data)) + rout ;the routine + clodata ;closed data + ) + +(defmethod output_ccode ((obj obj_dataclosure) str) + (format str " /*-*ccode objdataclosure ~S:*/ " (obj_data-comname obj)) + (output_ccode (currout_data2ptr obj) str) +; (finish-output str) +) + +(defmethod output_cverify ((obda obj_dataclosure) str) +; (finish-output str) + (format str "/*cverify dataclosure ~S #~d [~S] */~%" (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (format str "basilys_assertmsg(\"cverify dataclosure ~S #~d\", basilys_magic_discr((" + (obj_data-comname obda) (initrout_rank obda)) + (output_ccode (currout_data2ptr obda) str) + (format str ")) == OBMAG_CLOSURE);~%") +) + +(defmethod print-object ((ob obj_dataclosure) st) + (let ( (obcna (obj_data-comname ob)) + (dis (obj_data-discr ob)) + (rou (obj_dataclosure-rout ob)) + (cld (obj_dataclosure-clodata ob)) ) + (if (obj_routine-p rou) + (format st "#{ObjDataClosure ~S discr=~S rout/~a clodata=~S}" + obcna dis (prog_defun-def_name (obj_routine-pfun rou)) cld) + (call-next-method ob st) + )) +) + +(defstruct (obj_dataroutine (:include obj_data)) + rout ;the routine + roudata ;routine data (reversed order), ie quoted constants +) + + + +(defmethod print-object ((ob obj_dataroutine) st) + (let ( (obcna (obj_data-comname ob)) + (pvar (currout_data2ptr ob)) + (dis (obj_data-discr ob)) + (rou (obj_dataroutine-rout ob)) + (rd (obj_dataroutine-roudata ob)) ) + (if (obj_routine-p rou) + (format st "#{ObjDataRoutine ~S ptrva=~S discr=~S rout/~a roudata*~d=~S}" + obcna pvar dis (prog_defun-def_name (obj_routine-pfun rou)) (length rd) rd) + (call-next-method ob st) + )) +) + + +(defmethod output_ccode ((obj obj_dataroutine) str) + (format str " /*-*ccode objdataroutine ~S:*/ " (obj_data-comname obj)) + (output_ccode (currout_data2ptr obj) str) +; (finish-output str) +) + +(defmethod output_cverify ((obda obj_dataroutine) str) +; (finish-output str) + (format str "/*cverify dataroutine ~S #~d [~S] */~%" (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (format str "basilys_assertmsg(\"cverify dataroutine ~S #~d\", basilys_magic_discr((" + (obj_data-comname obda) (initrout_rank obda)) + (output_ccode (currout_data2ptr obda) str) + (format str ")) == OBMAG_ROUTINE);~%") +) + +(defstruct (obj_datainstance (:include obj_data)) + predef ;name of predefined rank or nil + objnum ;number (maybe magic) in instance + slots ;list of slot values +) + +(defmethod print-object ((ob obj_datainstance) st) + (let ( (obcna (obj_data-comname ob)) + (obdiscr (obj_data-discr ob)) + (obpredef (obj_datainstance-predef ob)) + (obnum (obj_datainstance-objnum ob)) + (obslots (obj_datainstance-slots ob)) ) + (if (obj_datainstance-p obdiscr) + (progn + (format st "#{ObjDataInst ~S Discr:~S" obcna (obj_data-comname obdiscr)) + (if obpredef (format st " Predef:~S" obpredef)) + (if obnum (format st " ObjNum:~S" obnum)) + (if obslots (format st " Slots:~S" obslots)) + ) + (call-next-method ob st) + ))) + +(defmethod output_ccode ((obj obj_datainstance) str) + (format str " /*-*ccode objdatainstance ~S :*/ " (obj_data-comname obj)) + (let ( (op (currout_data2ptr obj)) ) + (or op (error "output_ccode obj datainst ~S without data2ptr" obj)) + (output_ccode op str) +; (finish-output str) + )) + +(defmethod output_cverify ((obda obj_datainstance) str) +; (finish-output str) + (format str "/*cverify datainstance ~S #~d [~S] */~%" (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (format str "basilys_assertmsg(\"cverify datainstance ~S #~d\", basilys_magic_discr((" + (obj_data-comname obda) (initrout_rank obda)) + (output_ccode (currout_data2ptr obda) str) + (format str ")) == OBMAG_OBJECT);~%") +) + +(defstruct (obj_datamultiple (:include obj_data)) + values +) + +(defstruct (obj_datastring (:include obj_data)) + string +) + +(defstruct (obj_dataqsymbol (:include obj_data)) + qsymb) + +(defstruct (obj_dataqkeyword (:include obj_data)) + qkeyword) + +;;;;;; quoted symbol data +(defmethod output_cdecl ((obj obj_dataqsymbol) str) + (format str "/*cdecl dataqsymbol ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) + (format str "char* iniqsymb_~d;~%" (initrout_rank obj)) + ) + +(defmethod output_cassign ((obj obj_dataqsymbol) str) + (format str "/*cassign dataqsymbol ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) + (output_ccode (currout_data2ptr obj) str) + (format str " = basilysgc_new_symbol(~a);~%" (str2cstr (string (obj_dataqsymbol-qsymb obj)))) + (format str "#if COLD_BASILYS_DEBUG~%") + (format str " debugeprintf(\" quoted symbol ~S @%p\"," (obj_dataqsymbol-qsymb obj)) + (output_ccode (currout_data2ptr obj) str) + (format str ");~%") + (format str "#endif /*COLD_BASILYS_DEBUG*/~%") +) + +(defmethod output_cinit ((obj obj_dataqsymbol) str) + (format str "/*cinit dataqsymbol ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) + (format str " cdat->iniqsymb_~d = ~a;~%" (initrout_rank obj) + (str2cstr (string (obj_dataqsymbol-qsymb obj)))) +) + +(defmethod output_cfill ((obj obj_dataqsymbol) str) + (format str "/*no cfill dataqsymbol ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) +) + +(defmethod output_cref ((obj obj_dataqsymbol) str) + (format str "/*no cref dataqsymbol ~S #~d [~S] - '~S*/~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) +) + +(defmethod output_cverify ((obj obj_dataqsymbol) str) + (format str "/*no cverify dataqsymbol ~S #~d [~S] - '~S*/~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqsymbol-qsymb obj)) +) + + + +;;;;;;;; quoted keyword data +(defmethod output_cdecl ((obj obj_dataqkeyword) str) + (format str "/*cdecl dataqkeyword ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) + (format str "char* iniqkey_~d;~%" (initrout_rank obj)) + ) + +(defmethod output_cassign ((obj obj_dataqkeyword) str) + (format str "/*cassign dataqkeyword ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) + (output_ccode (currout_data2ptr obj) str) + (format str " = basilysgc_new_keyword(~a);~%" (str2cstr (string (obj_dataqkeyword-qkeyword obj)))) + (format str "#if COLD_BASILYS_DEBUG~%") + (format str " debugeprintf(\" quoted keyword ~S @%p\"," (obj_dataqkeyword-qkeyword obj)) + (output_ccode (currout_data2ptr obj) str) + (format str ");~%") + (format str "#endif /*COLD_BASILYS_DEBUG*/~%") +) + +(defmethod output_cinit ((obj obj_dataqkeyword) str) + (format str "/*cinit dataqkeyword ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) + (format str " cdat->iniqkey_~d = ~a;~%" (initrout_rank obj) + (str2cstr (string (obj_dataqkeyword-qkeyword obj)))) +) + +(defmethod output_cfill ((obj obj_dataqkeyword) str) + (format str "/*no cfill dataqkeyword ~S #~d [~S] - '~S */~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) +) + +(defmethod output_cref ((obj obj_dataqkeyword) str) + (format str "/*no cref dataqkeyword ~S #~d [~S] - '~S*/~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) +) + +(defmethod output_cverify ((obj obj_dataqkeyword) str) + (format str "/*no cverify dataqkeyword ~S #~d [~S] - '~S*/~%" + (obj_data-comname obj) (initrout_rank obj) (type-of obj) (obj_dataqkeyword-qkeyword obj)) +) + +;;;;;;;;;;;;;;; + + +(defmethod output_cdecl ((obj obj_dataclosure) str) + (format str "/*- decl dataclosure ~S -*/~%" (obj_data-comname obj)) + (format str " struct BASILYS_CLOSURE_STRUCT(~d) inidat_~d_;~%" + (my_length_gt_1 (obj_dataclosure-clodata obj)) (initrout_rank obj)) +) + + +(defmethod output_cinit ((obj obj_dataclosure) str) + (format str "/*- init dataclosure ~S-*/~%" (obj_data-comname obj)) + (let ( (irk (initrout_rank obj)) ) + (assert (integerp irk)) + (format str " cdat->inidat_~d_.discr = " irk) + (output_ccode (obj_data-discr obj) str) + (format str ";~%") + (format str " cdat->inidat_~d_.rout = " irk) + (output_cref (obj_routine-datarout (obj_dataclosure-rout obj)) str) + (format str ";~%") + (format str " cdat->inidat_~d_.nbval = ~d;~%" irk (length (obj_dataclosure-clodata obj))) +)) + + +(defmethod output_cfill ((obj obj_dataclosure) str) + (let ( (ov (currout_data2ptr obj)) + ) + (format str "/*- cfill dataclosure ~S -*/~%" (obj_data-comname obj)) + (format str " basilys_assertmsg(\"cfill dataclosure ~S\", basilys_magic_discr((" (obj_data-comname obj)) + (output_ccode ov str) + (format str ")) == OBMAG_CLOSURE);~%") + (let ( (nbd (length (obj_dataclosure-clodata obj))) ) + (if (> nbd 0) + (progn + (format str " basilys_assertmsg(\"cfill len dataclosure ~S\", ((basilysclosure_ptr_t)(" + (obj_data-comname obj)) + (output_ccode ov str) + (format str "))->nbval >= ~d);~%" nbd)))) + (loop + for crk from 0 + for cda in (obj_dataclosure-clodata obj) + do + (format str " ((basilysclosure_ptr_t)(") + (output_ccode ov str) + (format str "))->tabval[~d] = " crk) + (output_ccode cda str) + (format str ";~%") + ) + (format str " basilysgc_touch(") + (output_ccode ov str) + (format str ");~%") + )) + +(defmethod output_cdecl ((obj obj_dataroutine) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- decl dataroutine ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " struct BASILYS_ROUTINE_STRUCT(~d) inidat_~d_;~%" + (my_length_gt_1 (obj_dataroutine-roudata obj)) irk) + )) + +(defmethod output_cinit ((obj obj_dataroutine) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- init dataroutine ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " cdat->inidat_~d_.discr = " irk) + (output_ccode (obj_data-discr obj) str) + (format str ";~%") + (format str " strncpy(cdat->inidat_~d_.routdescr, \"~S\", BASILYS_ROUTDESCR_LEN-1);~%" + irk (prog_defun-def_name (obj_routine-pfun (obj_dataroutine-rout obj)))) + (format str " *(basilysroutfun_t **)(cdat->inidat_~d_.routaddr) = ~a;~%" + irk (routinecname (obj_dataroutine-rout obj))) + (format str " cdat->inidat_~d_.nbval = ~d;~%" irk (length (obj_dataroutine-roudata obj))) + )) + + +(defmethod output_cfill ((obj obj_dataroutine) str) + (let ( + (op (currout_data2ptr obj)) + (irk (initrout_rank obj)) + ) + (format str "/*-cfill dataroutine ~S #~d -*/~%" (obj_data-comname obj) irk) + (format str " basilys_assertmsg(\"cfill dataroutine ~S #~d\", basilys_magic_discr((" (obj_data-comname obj) irk) + (output_ccode op str) + (format str ")) == OBMAG_ROUTINE);~%") + (let ( (nbd (length (obj_dataroutine-roudata obj))) ) + (if (> nbd 0) + (progn + (format str " gcc_assert(((basilysroutine_ptr_t)(") + (output_ccode op str) + (format str "))->nbval >= ~d);~%" nbd)))) + (loop + for crk from 0 + for cda in (reverse (obj_dataroutine-roudata obj)) + do + (format str "((basilysroutine_ptr_t)(") + (output_ccode op str) + (format str "))->tabval[~d] = " crk) + (output_ccode cda str) + (format str ";~%") + ) + (format str " basilysgc_touch(") + (output_ccode op str) + (format str ");~%") +; (finish-output str) + )) + +(defmethod output_cdecl ((obj obj_datainstance) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- decl datainstance ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " struct BASILYS_OBJECT_STRUCT(~d) inidat_~d_;~%" + (my_length_gt_1 (obj_datainstance-slots obj)) irk) +; (finish-output str) +)) + + +(defmethod output_cinit ((obj obj_datainstance) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- init datainstance ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " cdat->inidat_~d_.obj_class = " irk) + (output_ccode (obj_data-discr obj) str) + (format str ";~%") + (format str " cdat->inidat_~d_.obj_len = ~d;~%" irk (length (obj_datainstance-slots obj))); + (format str " cdat->inidat_~d_.obj_vartab = cdat->inidat_~d_.obj__tabfields; ~%" irk irk) + ;; 134217728 is 2**27 so the hash is >0 + (format str " cdat->inidat_~d_.obj_hash = ~d;~%" irk (+ 1 (random 134217728))) + (let ((onu (obj_datainstance-objnum obj))) + (if onu + (format str " cdat->inidat_~d_.obj_num = ~S;~%" irk onu) + ))) + ) + +(defmethod output_cassign ((obda obj_datainstance) str) + (let ( (irk (initrout_rank obda)) ) + (format str "/*cassign datainstance ~S #~d*/" (obj_data-comname obda) irk) + (format str "basilys_assertmsg(\"cassign datainstance ~S #~d cleared\", NULL==" + (obj_data-comname obda) irk) + (output_ccode (currout_data2ptr obda) str) + (format str ");~%") + (let ((prd (obj_datainstance-predef obda))) + (cond (( null prd) ) + ((symbolp prd) (format str "/*predef sym*/BASILYSG(~S) = " prd)) + ((integerp prd) (format str "/*predef num*/basilys_globarr[~d] = " prd)) + (t (error "bad predef ~S in obj_datainstance ~S" prd obda))) + ) + (output_ccode (currout_data2ptr obda) str) + (format str " = (void*) (&cdat->inidat_~d_);~%" irk) +; (finish-output str) + )) + +(defmethod output_cfill ((obda obj_datainstance) str) + (let ( (sl (obj_datainstance-slots obda)) + (ov (currout_data2ptr obda)) + (irk (initrout_rank obda)) + ) + (format str "/*cfill datainstance ~S #~d */~%" (obj_data-comname obda) irk) + (format str " basilys_assertmsg(\"cfill datainstance ~S #~d\", basilys_magic_discr((" + (obj_data-comname obda) irk) + (output_ccode ov str) + (format str " )) == OBMAG_OBJECT);~%") + (format str " basilys_assertmsg(\"cfill len datainstance ~S #~d\", ((basilysobject_ptr_t)(" + (obj_data-comname obda) irk) + (output_ccode ov str) + (format str "))->obj_len >= ~d);~%" (length sl)) +; (finish-output str) + (if sl + (loop + for crk from 0 + for csl in sl + when csl ;don't bother filling nil slots + do +; (finish-output str) + ;; this is a dirty hack, csl should have cold_tempslot_var as + ;; destination but some make-obj_datainstance don't do it. + ;; if I wanted to code properly I would correct the callers. + (or (get_destination csl) + (let ((ncsl (put_destination csl cold_tempslot_var))) + (assert ncsl) + (setq csl ncsl))) + (assert (eq (get_destination csl) cold_tempslot_var)) + (output_ccode csl str) + (format str ";~%") + (format str "((basilysobject_ptr_t)(") + (output_ccode ov str) + (format str ")) ->obj_vartab[~d] = " crk) + (output_ccode cold_tempslot_var str) + (format str ";~%") + )) + (format str " basilysgc_touch(") + (output_ccode ov str) + (format str ");~%") +; (finish-output str) + )) + +(defmethod output_cdecl ((obj obj_datamultiple) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- decl datamultiple ~S #~d -*/~%" (obj_data-comname obj) irk) + (format str " struct BASILYS_MULTIPLE_STRUCT(~d) inidat_~d_;~%" + (my_length_gt_1 (obj_datamultiple-values obj)) irk) + )) + +(defmethod output_cinit ((obj obj_datamultiple) str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- init datamultiple ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " cdat->inidat_~d_.discr = " irk) + (output_ccode (obj_data-discr obj) str) + (format str ";~%") + (format str " cdat->inidat_~d_.nbval = ~d;~%" irk (length (obj_datamultiple-values obj))) +)) + +(defmethod output_cfill ((obj obj_datamultiple) str) + (let ( (op (currout_data2ptr obj)) + (irk (initrout_rank obj)) ) + (format str "/*- fill datamultiple ~S #~d -*/~%" (obj_data-comname obj) irk) + (format str " gcc_assert(basilys_magic_discr((") + (output_ccode op str) + (format str ")) == OBMAG_MULTIPLE);~%") + (let ( (nbd (length (obj_datamultiple-values obj))) ) + (if (> nbd 0) + (progn + (format str " gcc_assert(((basilysmultiple_ptr_t)(") + (output_ccode op str) + (format str "))->nbval >= ~d);~%" nbd)))) +; (finish-output str) + (loop + for crk from 0 + for cda in (obj_datamultiple-values obj) + do + (format str "((basilysmultiple_ptr_t)(") + (output_ccode op str) + (format str "))->tabval[~d] = " crk) + (output_ccode cda str) + (format str ";~%") + ) + (format str " basilysgc_touch(") + (output_ccode op str) + (format str ");~%") +; (finish-output str) + )) + +(defmethod output_cverify ((obda obj_datamultiple) str) +; (finish-output str) + (format str "/*cverify datamultiple ~S #~d [~S] */~%" (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (format str "gcc_assert(basilys_magic_discr((") + (output_ccode (currout_data2ptr obda) str) + (format str ")) == OBMAG_MULTIPLE);~%") +) + +(defmethod output_cdecl ((obj obj_datastring) str) +; (finish-output str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- decl datastring ~S #~d -*/~%" (obj_data-comname obj) irk) + (format str " struct BASILYS_STRING_STRUCT(~d) inidat_~d_;~%" + (my_length_gt_1 (obj_datastring-string obj)) irk) +)) + + +(defmethod output_cinit ((obj obj_datastring) str) +; (finish-output str) + (let ( (irk (initrout_rank obj)) ) + (format str "/*- init datastring ~S #~d-*/~%" (obj_data-comname obj) irk) + (format str " cdat->inidat_~d_.discr = " irk) + (output_ccode (obj_data-discr obj) str) + (format str ";~%") + (format str " strcpy(cdat->inidat_~d_.val, ~s);~%" irk (obj_datastring-string obj)) +; (finish-output str) + )) + +(defmethod output_cfill ((obj obj_datastring) str) + (finish-output str) +) + +(defmethod output_cverify ((obda obj_datastring) str) +; (finish-output str) + (format str "/*cverify datastring ~S #~d [~S] */~%" (obj_data-comname obda) (initrout_rank obda) (type-of obda)) + (format str "gcc_assert(basilys_magic_discr((") + (output_ccode (currout_data2ptr obda) str) + (format str ")) == OBMAG_STRING);~%") +) + +(defstruct (obj_getptrarg_instr (:include obj_instr)) + dest + rk +) + +(defmethod output_ccode ((obj obj_getptrarg_instr) str) + (format str "/*-*obj_getptrarg_instr*/~%") + (let ( (dest (obj_getptrarg_instr-dest obj)) + (rk (obj_getptrarg_instr-rk obj)) ) + (if (= rk 0) + (progn + (format str "basilys_checked_assign(/*ptrarg0*/") + (output_ccode dest str) + (format str " = firstargp_);") + ) + (progn + (format str "if (xargdescr_[~d] == BPAR_PTR)~% " (- rk 1)) + (format str "basilys_checked_assign(/*ptrarg~d*/" rk) + (output_ccode dest str) + (format str + " = *(xargtab_[~d].bp_aptr));~% else goto lab_endargs;~%" + (- rk 1)) + ) + ) +; (finish-output str) + )) + +(defstruct (obj_getlongarg_instr (:include obj_instr)) + dest + rk +) + +(defmethod output_ccode ((obj obj_getlongarg_instr) str) + (format_c_comment str "*obj_getlongarg_instr ~S*~%" obj) + (let ( (dest (obj_getlongarg_instr-dest obj)) + (rk (obj_getlongarg_instr-rk obj)) ) + (if (= rk 0) + (error "long arg cannot be first ~S" obj)) + (format str "if (xargdescr_[~d] == BPAR_LONG)~% " (- rk 1)) + (output_ccode dest str) + (format str " = xargtab_[~d].bp_long;~% else goto lab_endargs;~%" + (- rk 1)) +; (finish-output str) + ) + ) + + +;;; actually an obj_compute may have several destination (for example +;;; for a setq whose value is used) + +(defstruct (obj_compute (:include obj_instr)) + dest ;last destination + sons ;either strings or expr or atoms + otype ;type + compserial ;unique serial number + ) + +(defvar compute_serial_count 0) + +(defun build_obj_compute (dest sons otype) + (assert (listp sons)) + (if (some (function prog_src-p) sons) + (error "build_obj_compute bad sons {prog_src} ~S" sons)) + (if (some (function obj_instr-p) sons) + (error "build_obj_compute bad sons {obj_instr} ~S" sons)) + (incf compute_serial_count) + (make-obj_compute :dest dest + :sons (if dest (append (list dest " = ") sons) sons) + :otype otype :compserial compute_serial_count) +) + + +;;; set a closed variable +(defstruct (obj_closetq (:include obj_instr)) + cldest ;closed destination + val) + +;;; obj_vars are variables (eg pointers, longs...) in the current stack frame +(defstruct obj_var + vbind ;the binding defing the program variable + voffset ;the offset or index in the C frame + vrout ;the routine containing the variable + vwhy ;the reason why this stuff has been made + vfree ;set when freed in the curframe +);; obj_ptrvar & obj_longvar are actually the relevant subclasses see +;; also obj_closedvar (for variables in closures), obj_routconst (for +;; constants inside routines), obj_initdata (for data in the initialization routine) + +(defmethod output_ccode ((obj obj_var) str) + (error "output_ccode obj_var ~s" obj) +) + +(defmethod put_destination ((obj obj_var) dest) + (build_obj_compute + dest + (list obj) + (cond ((obj_ptrvar-p obj) :value) + ((obj_longvar-p obj) :long) + (t (error "put_destination obj strangevar ~S dest ~S" obj dest))) + )) + + +(defmethod output_ccode ((obj obj_compute) str) + (format str "/* obj_compute.#~d */~%" (obj_compute-compserial obj)) + (let ( (dest (obj_compute-dest obj)) ) + (cond ((null dest) + (format str " (void) (")) + ((obj_ptrvar-p dest) (format str "basilys_checked_assign(/*comput*/"))) + (mapc (lambda (s) (cond ;order matters here! + ( (stringp s) (format str "~a" s) ) + ( (integerp s) (format str "~d" s) ) + ( (null s) (format str "/*coputenil*/NULL") ) + ( (symbolp s) + (format str "(/*compute symb*/BASILYSG(~S))" s) ) + ( (or (obj_instr-p s) (obj_var-p s) (obj_data-p s) + (obj_closedvar-p s) + (obj_routconst-p s) (obj_verbatim-p s) + (obj_cstring-p s) + ) ;before the atom test! + (output_ccode s str) ) + ( (atom s) + (format str "(/*compute son [~S]*/~s)" (type-of s) s) ) + ( t (error "output_ccode obj_compute ~s !!invalid son ~s" obj s)))) + (obj_compute-sons obj)) + (cond ((null dest) + (format str ");~%")) + ((obj_ptrvar-p dest) (format str ");~%")) + ((obj_longvar-p dest) (format str ";~%")) + ) + )) + + +(defmethod put_destination ((obj obj_compute) dest) + (let ( (otyp (obj_compute-otype obj)) + (destyp (query_ctype dest)) + ) + (cond ( (eq ':void otyp) + (let ( (nblo (make-obj_block :instrs (list obj (make-obj_verbatim :vstr "/*Void*/NULL")))) ) + (put_destination nblo dest)) + ) + ( + (or (null otyp) (null destyp) (eq otyp destyp)) + (setf (obj_compute-sons obj) (append (list dest " = ") (obj_compute-sons obj))) + (setf (obj_compute-dest obj) dest) + nil) + (t + (make-obj_block :instrs + (list + obj + (make-obj_verbatiminstr :vstr (format nil "/*incompatible put_destination dest ~S otyp ~S*/" dest otyp)) + (build_obj_compute + dest + (case otyp + (:long (list (make-obj_verbatim :vstr "/*incompatput:long*/0L"))) + (:value (list (make-obj_verbatim :vstr "/*incompatput:value*/(void*)0"))) + (otherwise (list (make-obj_verbatim :vstr (format nil "/*incompatput- ~S */0" otyp)))) + ) + otyp + ) + )))))) + +(defmethod get_destination ((obj obj_compute)) + (obj_compute-dest obj) +) + +(defstruct (obj_ptrvar (:include obj_var))) + +(defstruct (obj_longvar (:include obj_var))) + +(defmethod print-object ((ov obj_ptrvar) st) + (if (cold_any_binding-p (obj_ptrvar-vbind ov)) + (format st "ObjPtrVar@~d/~S?~S" + (obj_ptrvar-voffset ov) + (cold_any_binding-bname (obj_ptrvar-vbind ov)) + (obj_ptrvar-vwhy ov) + ) + (call-next-method ov st) +)) + +(defmethod print-object ((ov obj_longvar) st) + (if (cold_any_binding-p (obj_longvar-vbind ov)) + (format st "ObjLongVar@~d/~S?~S" + (obj_longvar-voffset ov) + (cold_any_binding-bname (obj_longvar-vbind ov)) + (obj_longvar-vwhy ov) + ) + (call-next-method ov st) + )) + + +(defconstant cold_return_var + (make-obj_ptrvar :vbind (make-cold_typed_binding :bname '_RETVAL_ :type :value) + :voffset 0)) + +(defconstant cold_tempslot_var + (make-obj_ptrvar :vbind (make-cold_typed_binding :bname '_TMPSLOT_ :type :value) + :voffset 1)) + +(defconstant cold_tempnum_var + (make-obj_longvar :vbind (make-cold_typed_binding :bname '_TMPNUM_ :type :long) + :voffset 0)) + + +(defmethod output_ccode ((obj obj_ptrvar) str) + (let ((b (obj_var-vbind obj)) + (o (obj_var-voffset obj))) + (if b (format str "/*~S ? ~S*/" (cold_any_binding-bname b) + (obj_var-vwhy obj) + ) + (format str "/*??~S*/" (obj_var-vwhy obj))) + (format str "curfram__.varptr[~d]" o) + ) +) + +(defmethod query_ctype ((obj obj_ptrvar)) +':value) + + + +(defmethod query_ctype ((obj obj_compute)) + (obj_compute-otype obj)) + +(defmethod output_ccode ((obj obj_longvar) str) + (let ((b (obj_var-vbind obj)) + (o (obj_var-voffset obj))) + (if b (format str "/*~S ? ~S*/" + (cold_any_binding-bname b) + (obj_var-vwhy obj) + ) + (format str "/*??~S*/" (obj_var-vwhy obj))) + (format str "curfram__.varnum[~d]" o) + ) + ) + + +(defmethod output_ccode ((obj obj_closetq) str) + (let ((d (obj_closetq-cldest obj)) + (s (obj_closetq-val obj))) + (or (obj_closedvar d) + (error "not closedvar in obj_closetq ~S~%" obj)) + (format str "/*closetq*/ {~% void* d = ") + (output_ccode d str) + (format str " = ") + (output_ccode s str) + (format str ";~%") + (format str "basilysgc_touch_dest(curfram__.clos, d); }~%") +)) + +(defmethod query_ctype ((obj obj_longvar)) +':long) + +(defmethod query_ctype ((obj integer)) +':long) + +(defstruct obj_closedvar + cvar ;the name of the closed variable + cfun ;the function of the closure + coffset ;the offset inside the closure +) + +(defmethod put_destination ((obj obj_closedvar) dest) + (build_obj_compute + dest + (list obj) + :value + )) + +(defmethod output_ccode ((obj obj_closedvar) str) + (format str "/*clovar ~s*/ curfram__.clos->tabval[~d]" + (obj_closedvar-cvar obj) (obj_closedvar-coffset obj)) +) + +(defstruct obj_routconst + krout ;the routine quoting this constant + kval ;the value of the constant + koffset ;the offset inside the function + kwhy ;string why +) + + +(defun newobjconst (val &optional why) + (let + ( (curout (compilation-currout this_compilation) ) + ) + (assert (obj_data-p val) (val) "non-data values for newobjconst ~S" val) + (if (and (obj_routine-p curout) (not (obj_initroutine-p curout))) + ;; usual case, we are in some routine + (let + ( (datarout (obj_routine-datarout curout)) ) + (or (obj_dataroutine-p datarout) + (error "newobjconst bad datarout ~S in curout ~S~%" datarout curout)) + (let ( (off (position val (obj_dataroutine-roudata datarout))) + (ln (length (obj_dataroutine-roudata datarout))) ) + (if off + (progn + ;;(warn "newobjconst val=~S found off=~S ln=~S~%" val off ln) + (make-obj_routconst :krout curout + :kval val + :koffset (- ln off 1) + :kwhy why + ) + ) + (let ( (ln (length (obj_dataroutine-roudata datarout))) ) + (push val (obj_dataroutine-roudata datarout)) + (let ( (newconst (make-obj_routconst :krout curout :kval val :koffset ln :kwhy why)) ) + newconst + ) + )))) + ;; otherwise it is a global data + (progn + (if (null (currout_data2ptr val)) + (add_cdata val (concatenate 'string "newobjconst-" (string why))) + val) + ) + ))) + + +(defmethod output_ccode ((obj obj_routconst) str) + (let ((kval (obj_routconst-kval obj)) + (kwhy (obj_routconst-kwhy obj)) + ) + (cond ( (symbolp kval) + (format str "/*constsymb ~S ? ~S*/" kval kwhy) ) + ( (obj_data-p kval) + (format str "/*const[~S] ~S ? ~S*/" + (type-of kval) (obj_data-comname kval) kwhy) + ) + ( t + (format str "/*const/ty[~S] ? ~S*/" (type-of kval) kwhy))) + (format str "curfram__.clos->rout->tabval[~d]" + (obj_routconst-koffset obj)) + )) + + +(defstruct (obj_mkclosure (:include obj_instr)) + dest ;optional destination + cfun ;closure function + cvals ;closed values + kobjrout ;closure object routine constant +) + +(defmethod put_destination ((obj obj_mkclosure) dest) + (setf (obj_mkclosure-dest obj) dest) + nil +) + +(defmethod get_destination ((obj obj_mkclosure)) + (obj_mkclosure-dest obj) +) + +(defmethod output_ccode ((obj obj_mkclosure) str) + (format str "{") + (format_c_comment str "**mkclosure ~S ~%**~%" obj) + (let ( ( cvals (obj_mkclosure-cvals obj)) + ( dest (obj_mkclosure-dest obj)) + ( cfun (obj_mkclosure-cfun obj)) + ( kobjrout (obj_mkclosure-kobjrout obj)) + ) + (format str " struct BASILYS_CLOSURE_STRUCT(~d) *newclos_=0;~%" + (my_length_gt_1 cvals)) + (format str " newclos_ = basilysgc_allocate(sizeof(*newclos_),0);~%") + (format str " newclos_->discr = (void*)BASILYSG(DISCR_CLOSURE);~%") + (format str " newclos_->nbval = ~d;~%" (length cvals)) + (if dest + (progn (output_ccode dest str) (format str " = (void*)newclos_;~%"))) + (format str " newclos_->rout = ") + (output_ccode kobjrout str) + (format str ";~%") + (loop + for crk from 0 + for cva in cvals + do + (format str "newclos_->tabval[~d] = " crk) + (output_ccode cva str) ; + (format str ";~%") + ) + ) + (format str "}/**end mkclosure*/~%") +; (finish-output str) + ) + +(defstruct (obj_block (:include obj_instr)) + instrs) + +(defmethod output_ccode ((obj obj_block) str) + (let ((instrs (obj_block-instrs obj))) + (format str "{~%") + (mapc (lambda (i) + (if (obj_instr-p i) + (progn + (output_ccode i str) (format str ";~%")))) + instrs) + (format str "}~%") +; (finish-output str) +)) + +(defmethod query_ctype ((obj obj_block)) + (let ((lastinstr (last (obj_block-instrs obj)))) + (and lastinstr (query_ctype (first lastinstr)))) +) + +(defmethod put_destination ((obj obj_block) dest) + (let ((instrs (obj_block-instrs obj))) + (let ( (l (last instrs) )) + (if (consp l) + (let ( (nd (put_destination (first l) dest)) ) + (if nd (setf (first l) nd)) + ) + )) + nil + )) + +(defmethod get_destination ((obj obj_block)) + (let ((instrs (obj_block-instrs obj))) + (let ( (l (last instrs) )) + (if (consp l) (get_destination (first l)))))) + + +(defstruct (obj_if (:include obj_instr)) + ob_cond ob_then ob_else) + +(defmethod output_ccode ((obj obj_if) str) + (let ( (ocond (obj_if-ob_cond obj)) + (othen (obj_if-ob_then obj)) + (oelse (obj_if-ob_else obj)) ) + (format str "{ /*if*/~%") + (if (obj_instr-p ocond) (error "too complex (objinstr) cond in obj_if ~S" obj)) + (format str " if (") + (output_ccode ocond str) + (format str ") {/*then*/~%") + (output_ccode othen str) + (if oelse + (progn + (format str "} else {~%") + (output_ccode oelse str) + (format str "}~%")) + (format str "}/*noelse*/;~%")) + (format str "} /*endif*/~%") +)) + + +(defmethod query_ctype ((obj obj_if)) + (let ( (ocond (obj_if-ob_cond obj)) + (othen (obj_if-ob_then obj)) + (oelse (obj_if-ob_else obj)) ) + (let ( (tythen (query_ctype othen))) + (if oelse + (and (eq (query_ctype oelse) tythen) tythen) + tythen) +))) + + + +(defmethod put_destination ((obj obj_if) dest) + (let ( (ocond (obj_if-ob_cond obj)) + (othen (obj_if-ob_then obj)) + (oelse (obj_if-ob_else obj)) ) +; (and othen (get_destination othen) oelse (get_destination oelse) +; (error "obj_if ~S already got destination in ~S" +; obj (obj_routine-syname (compilation-currout this_compilation)))) + (let ((dthen (put_destination othen dest)) + (delse (if oelse (put_destination oelse dest) + (build_obj_compute dest (list "NULL") (query_ctype othen))))) + (if dthen (setf (obj_if-ob_then obj) dthen)) + (if delse (setf (obj_if-ob_else obj) delse)) + ) + nil +)) + + +(defmethod get_destination ((obj obj_if)) + (let ( (ocond (obj_if-ob_cond obj)) + (othen (obj_if-ob_then obj)) + (oelse (obj_if-ob_else obj)) ) + (if oelse + (and (eq (get_destination othen) (get_destination oelse)) + (get_destination othen)) + (get_destination othen) + ))) + + + +;;;;;;;;;;; calls & sends + +;;;; calls +(defstruct (obj_call (:include obj_instr)) + dest ;main destination + clos ;called closure + xtraresults ;other results + args ;arguments + ) + + + +(defmethod output_ccode ((obj obj_call) str) + (let* ( (dest (obj_call-dest obj)) + (clos (obj_call-clos obj)) + (xresults (obj_call-xtraresults obj)) + (argseq (obj_call-args obj)) + (arg1 (and (consp argseq) (car argseq))) + (revargtypeseq nil) + (revrestypeseq nil) + (oargs (and (consp argseq) (cdr argseq))) + ) + (format str "/*-*call:*/~%{" obj) + (if xresults + (format str " union basilysparam_un restab[~d];~%" (length xresults))) + (if oargs + (format str " union basilysparam_un argtab[~d];~%" (length oargs))) + (if xresults + (format str " memset(restab, 0, sizeof(restab));~%")) + (if oargs + (format str " memset(argtab, 0, sizeof(argtab));~%")) + (loop for ark from 0 for arg in oargs do + (case (query_ctype arg) + (:long (format str " argtab[~d].bp_long = " ark) + (output_ccode arg str) + (push "BPARSTR_LONG" revargtypeseq) + (format str ";~%") + ) + ((:value nil) + (if arg + (progn + (format str " argtab[~d].bp_aptr = (basilys_ptr_t*) &(" ark) + (output_ccode arg str) + (push "BPARSTR_PTR" revargtypeseq) + (format str ");~%")) + (format str " argtab[~d].bp_aptr /*nil arg*/ = NULL;~%"))) + (otherwise (error "output_ccode obj_callcannot handle arg ~s in ~s" arg obj))) + ) + (loop for resrk from 0 for xres in xresults do + (case (query_ctype xres) + (:long (format str " restab[~d].bp_longptr = & (" resrk) + (output_ccode xres str) + (push "BPARSTR_LONG" revrestypeseq) + (format str ");~%")) + ((:value nil) (format str " restab[~d].bp_aptr = (basilys_ptr_t*) &(" resrk) + (output_ccode xres str) + (push "BPARSTR_PTR" revrestypeseq) + (format str ");~%")) + (otherwise (error "output_ccode obj_call cannot handle res ~s in ~s" xres obj))) + ) + (cond + ((obj_ptrvar-p dest) + (format str "/*ptrappl*/ basilys_checked_assign(") + (output_ccode dest str) + (format str " = ")) + ((null dest) + (format str "/*nodestappl*/ (void) ")) + (dest + (assert (not (obj_longvar-p dest))) + (format str "/*noptrappl*/") + (output_ccode dest str) + (format str " = ")) + ) + (format str "basilysgc_apply(((void*)(") + (output_ccode clos str) + (format str ")), (") + (output_ccode arg1 str) + (format str "),~% (") + (loop for argtype in (reverse revargtypeseq) do + (format str " ~a" argtype)) + (format str " \"\"), ") + (if oargs (format str "argtab") (format str "/*no args*/ (union basilysparam_un*)0")) + (format str ", ~% (") + (loop for restype in (reverse revrestypeseq) do + (format str " ~a" restype)) + (format str " \"\"), ") + (if xresults (format str "restab") (format str "/*no res*/ (union basilysparam_un*)0")) + (if + (obj_ptrvar-p dest) + (format str "));~%") + (format str ");~%")) + (format str "~%} /*endcall*/ ~%") +; (finish-output str) + ) + ) + +(defmethod put_destination ((obj obj_call) dest) + (setf (obj_call-dest obj) dest) + nil +) + +(defmethod get_destination ((obj obj_call)) + (obj_call-dest obj) +) + + + +;;;; sends +(defstruct (obj_send (:include obj_instr)) + obs_dest ;main destination result + obs_sel ;selector + obs_xtraresults ;other results + obs_recv ;reciever + obs_args ;arguments + ) + +(defmethod output_ccode ((obj obj_send) str) + (let ( (odest (obj_send-obs_dest obj)) + (osel (obj_send-obs_sel obj)) + (oxtrares (obj_send-obs_xtraresults obj)) + (orecv (obj_send-obs_recv obj)) + (oargs (obj_send-obs_args obj)) + (revargtypeseq nil) + (revrestypeseq nil) + ) + (format str "/*-*send:*/~%{" obj) + (if oxtrares + (format str " union basilysparam_un restab[~d];~%" (length oxtrares))) + (if oargs + (format str " union basilysparam_un argtab[~d];~%" (length oargs))) + (if oxtrares + (format str " memset(restab, 0, sizeof(restab));~%")) + (if oargs + (format str " memset(argtab, 0, sizeof(argtab));~%")) + (loop for ark from 0 for arg in oargs do + (case (query_ctype arg) + (:long (format str " argtab[~d].bp_long = " ark) + (output_ccode arg str) + (push "BPARSTR_LONG" revargtypeseq) + (format str ";~%") + ) + ((:value nil) (format str " argtab[~d].bp_aptr = (basilys_ptr_t*) &(" ark) + (output_ccode arg str) + (push "BPARSTR_PTR" revargtypeseq) + (format str ");~%")) + (otherwise (error "output_ccode obj_callcannot handle arg ~s in ~s" arg obj))) + ) + (loop for resrk from 0 for xres in oxtrares do + (case (query_ctype xres) + (:long (format str " restab[~d].bp_longptr = & (" resrk) + (output_ccode xres str) + (push "BPARSTR_LONG" revrestypeseq) + (format str ");~%")) + ((:value nil) (format str " restab[~d].bp_aptr = (basilys_ptr_t*) &(" resrk) + (output_ccode xres str) + (push "BPARSTR_PTR" revrestypeseq) + (format str ");~%")) + (otherwise (error "output_ccode obj_call cannot handle res ~s in ~s" xres obj))) + ) + (if odest + (progn + (output_ccode odest str) + (format str " = ")) + (format str "(void) ")) + (format str "basilysgc_send(((void*)(") + (output_ccode orecv str) + (format str ")), (") + (output_ccode osel str) + (format str "),~% (") + (loop for argtype in (reverse revargtypeseq) do + (format str " ~a" argtype)) + (format str " \"\"), ") + (if oargs (format str "argtab") (format str "/*no args*/ (union basilysparam_un*)0")) + (format str ", ~% (") + (loop for restype in (reverse revrestypeseq) do + (format str " ~a" restype)) + (format str " \"\"), ") + (if oxtrares (format str "restab") (format str "/*no res*/ (union basilysparam_un*)0")) + (format str ");~%") + (format str "~%} /*endsend*/ ~%") +; (finish-output str) + )) + + +(defmethod put_destination ((obj obj_send) dest) + (setf (obj_send-obs_dest obj) dest) + nil +) + +(defmethod get_destination ((obj obj_send)) + (obj_send-obs_dest obj) +) + +;;;;;;;;;;; forever instruction + +(defstruct (obj_forever (:include obj_instr)) + obforever_bind ;forever binding + obforever_res ;result + obforever_dest ;forever destination + obforever_body ;body + obforever_epilogue ;epilogue + ) + +(defmethod put_destination ((obj obj_forever) dest) + (setf (obj_forever-obforever_dest obj) dest) + nil +) + +(defmethod get_destination ((obj obj_forever)) + (obj_forever-obforever_dest obj) +) + + +(defmethod output_ccode ((obj obj_forever) str) + (let* ( (lbind (obj_forever-obforever_bind obj)) + (lres (obj_forever-obforever_res obj)) + (ldest (obj_forever-obforever_dest obj)) + (lepil (obj_forever-obforever_epilogue obj)) + (lbody (obj_forever-obforever_body obj)) + (luniq (cold_forever_binding-uniq lbind)) + ) + (format str "/*forever ~S*/{~%" luniq) + (output_ccode lres str) + (format str " = 0;~%") + (format str " lab_startforever_~a:;~%" (string luniq)) + (loop for rk from 1 for ins in lbody do + (format str "/*forever ~S instr#~d*/" luniq rk) + (output_ccode ins str) + (format str ";~%")) + (format str "/*againforever*/ goto lab_startforever_~a;~%" (string luniq)) + (format str " lab_endforever_~a:;~%" (string luniq)) + (if ldest + (progn + (format str "/*foreverdest ~S*/~%" luniq) + (output_ccode ldest str) + (format str " = ") + (output_ccode lres str) + (format str ";~%") + )) + (if lepil + (progn + (format str "/*foreverdest ~S*/~%" lepil) + (output_ccode lepil str) + (format str ";~%") + )) + (format str "/*endforever ~S*/}~%" luniq) +; (finish-output str) + )) + +;;;; + +(defstruct (obj_exit (:include obj_instr)) + obxit_bind + obxit_body +) + +(defmethod put_destination ((obj obj_exit) dest) + nil +) + +(defmethod output_ccode ((obj obj_exit) str) + (let ( (xuniq (cold_forever_binding-uniq (obj_exit-obxit_bind obj))) ) + (format str "{ /*Exit ~S*/~%" xuniq) + (loop for irk from 1 + for ins in (obj_exit-obxit_body obj) + do + (format str "/*exiting ~S ins#~d*/~%" xuniq irk) + (output_ccode ins str) + (format str ";~%")) + (format str " /*exitjump*/ goto lab_endforever_~a;~%" (string xuniq)) + (format str "} /*end Exit ~S*/~%" xuniq) +)) + +;;;;;;;;;;; return instruction +(defstruct (obj_return (:include obj_instr)) + mainreturn ;the main returned value + extrareturns ;the sequence of extra returned values +) + +(defmethod put_destination ((obj obj_return) dest) + (let ((nmd (put_destination (obj_return-mainreturn obj) dest))) + (if nmd (setf (obj_return-mainreturn obj) nmd)) + )) + + +(defmethod output_ccode ((obj obj_return) str) + (format str "/*-*Returning**/ {~%") + (format_c_comment str "objreturn ~s" obj) + (let ( + (mainret (obj_return-mainreturn obj)) + (xtrarets (obj_return-extrareturns obj)) + ) + (if (null mainret) + (format str "/*no retval*/ curfram__.varptr[0] = (void*)0 ") + (let ( (maindest (get_destination mainret)) ) + (format_c_comment str "mainret ~S maindest ~S" mainret maindest) + (if (not (eq maindest cold_return_var)) + (format str "/*simple retval*/ curfram__.varptr[0] = ") + (format str "/*got retval*/ ")) + (output_ccode mainret str) + )) + (format str ";~%") + (if xtrarets + (format str " if (!xrestab_ || !xresdescr_) goto lab_endrout;~%")) + (loop + for ark from 0 + for ret in xtrarets + do + (format_c_comment str "*!* extra result #~d = ~s *~%" ark ret) + (let ( (rettype (query_ctype ret)) ) + (case rettype + (:long + (format str " if (xresdescr_[~d] != BPAR_LONG) goto lab_endrout;~%" ark) + (format str " if (xrestab_[~d].bp_longptr)~% *(xrestab_[~d].bp_longptr) = (" ark ark) + (output_ccode ret str) + (format str ");~%") + ) + ((:value nil) + (format str " if (xresdescr_[~d] != BPAR_PTR) goto lab_endrout;~%" ark) + (format str " if (xrestab_[~d].bp_rptr)~% *(xrestab_[~d].bp_rptr) = (void*) (" ark ark) + (output_ccode ret str) + (format str ");~%") + ) + (otherwise (error "bad return type ~s in ~s" rettype obj)) + ) + ))) + (format str " goto lab_endrout;~%") + (format str "} /*end return*/~%") +; (finish-output str) + ) + + +(defstruct (obj_routine (:include obj_instr)) + pfun ;prog function + syname ;symbol for easier naming it (or nil) + rank ;integer rank of this function + obody ;sequence of C instr + nbptr ;total number of pointer variables + nbnum ;total number of long variables + nbdouble ;total number of double variables + freevptrs ;list of free varptr to be reused + freevnums ;list of free varlong to be reused + freevdbls ;list of free vardbl to be reused + dataclos ;the associated dataclosure + datarout ;the associated dataroutine + data2ptrhash ;hash associating data to pointers +) + +(defmethod print-object ((ob obj_routine) st) + (format st "ObjRoutine{SyName=~S Obody=~S DataClos=~S DataRout=~S}" + (obj_routine-syname ob) + (obj_routine-obody ob) + (obj_routine-dataclos ob) + (obj_routine-datarout ob) + )) + + +(defun routine_link_data2ptr (orout odata ptr) + (assert (obj_routine-p orout)) + (assert (obj_data-p odata)) + (assert ptr) + (setf (gethash odata (obj_routine-data2ptrhash orout)) ptr) +) + +(defun routine_get_ptr4data (orout odata) + (assert (obj_routine-p orout)) + (assert (obj_data-p odata)) + (gethash odata (obj_routine-data2ptrhash orout)) +) + +(defun currout_data2ptr (odata) + (assert (obj_data-p odata)) + (let ( (currout + (or (compilation-currout this_compilation) + (compilation-initrout this_compilation))) ) + (assert (obj_routine-p currout)) + (routine_get_ptr4data currout odata) +)) + +(defun currout_link_data2ptr (odata ptr) + (assert (obj_data-p odata)) + (let ( (currout + (or (compilation-currout this_compilation) + (compilation-initrout this_compilation))) ) + (assert (obj_routine-p currout)) + (routine_link_data2ptr currout odata ptr) +)) + +(defun routinecname (rou) + (if (obj_routine-p rou) + (let ( (rk (obj_routine-rank rou)) + (sn (obj_routine-syname rou)) ) + (if (symbolp sn) + (let ( (tsn (map 'string (lambda (c) (if (alphanumericp c) c #\_)) (symbol-name sn))) ) + (format nil "rout__~d__~a" rk tsn)) + (format nil "rout__~d" rk))))) + +(defmethod output_ccode ((obj obj_routine) str) + (let ( (rk (obj_routine-rank obj)) + (nbptr (obj_routine-nbptr obj)) + (nbnum (obj_routine-nbnum obj)) + (nbdouble (obj_routine-nbdouble obj)) + (oldcurout (compilation-currout this_compilation)) + ) + (setf (compilation-currout this_compilation) obj) + (format str "~%~% /*** C routine ~d <~S> **/~%" rk (obj_routine-syname obj)) + ;; (format_c_comment str "** routine ~S ~& routine rank ~d **~%" obj rk) + (format str "static basilys_ptr_t ~a (basilysclosure_ptr_t closp_,~&" (routinecname obj)) + (format str " basilys_ptr_t firstargp_,~%") + (format str " const char xargdescr_[],~%") + (format str " union basilysparam_un* xargtab_,~%") + (format str " const char xresdescr_[],~%") + (format str " union basilysparam_un* xrestab_)~%{") + (format str "#if ENABLE_CHECKING~%") + (format str " static long thiscallcounter__;~%") + (format str " long callcount_ = ++thiscallcounter__;~%") + (format str "#define callcount callcount_~%") + (format str "#else~%") + (format str "#define callcount 0L~%") + (format str "#endif~%") + (format str " struct {~%") + (format str " unsigned nbvar;~%") + (format str " struct basilysclosure_st* clos;~%") + (format str " struct excepth_basilys_st* exh;~%") + (format str " struct callframe_basilys_st* prev;~%") + (format str " void* varptr[~d];" (+ nbptr 1)) + (format str " long varnum[~d];" (+ nbnum 1)) + (format str " double vardbl[~d];" (+ nbdouble 1)) + (format str " long _spare_;") + (format str " } curfram__ = { /*nbvar*/~d,~%" nbptr) + (format str " (struct basilysclosure_st*)0,~%") + (format str " (struct excepth_basilys_st*)0,~%") + (format str " (struct callframe_basilys_st*)0, ~%") + (progn + (format str "/*~d ptrvars:*/ {" nbptr) + (loop for ix from 1 to nbptr do (format str " (void*)0,")) + (format str "}, ~%") + ) + (progn + (format str "/*~d numvars:*/ {" nbnum) + (loop for ix from 1 to nbnum do (format str " 0L,")) + (format str " 0L }, ~%") + ) + (progn + (format str "/*~d doublevars:*/ {" nbdouble) + (loop for ix from 1 to nbdouble do (format str " 0.0,")) + (format str " 0.0 }, ~%") + ) + (format str " 0L };~% curfram__.prev = (void*)basilys_topframe;~%") + (format str " curfram__.clos = closp_;~%") + (format str " basilys_topframe= (void*)(&curfram__);~%") + (format str "/* body ~d start */~%" rk) + (format str "basilys_check_call_frames(BASILYS_ANYWHERE, \"start ~a\");~%" (routinecname obj)) + (output_ccode (obj_routine-obody obj) str) + (format str "/* body ~d end */~%" rk) + (format str " lab_endrout:~%") + (format str "basilys_check_call_frames(BASILYS_ANYWHERE, \"end ~a\");~%" (routinecname obj)) + (format str " basilys_topframe= (void*)(curfram__.prev); return curfram__.varptr[0];") + (format str "#undef callcount~%") + (format str "} /* end rout_~d */~%~%" rk) + (setf (compilation-currout this_compilation) oldcurout) + (finish-output str) + )) + + + +(defmethod output_cdecl ((obj obj_routine) str) + (let ((rk (obj_routine-rank obj))) + (format str "~%/** declroutine routine rank ~d **/~%" + rk) + (format str "static basilys_ptr_t ~a (basilysclosure_ptr_t closp_,~&" (routinecname obj)) + (format str " basilys_ptr_t firstargp_,~%") + (format str " const char xargdescr_[],~%") + (format str " union basilysparam_un* xargtab_,~%") + (format str " const char xresdescr_[],~%") + (format str " union basilysparam_un* xrestab_);~%") + )) + + +;; make a pointer variable inside a routine, using the free list if possible +;; orout is the object routine inside which it is used +;; bind is the binding +;; why is some explanation string +(defun newobjptrvar (orout bind why) + (assert (obj_routine-p orout)) + (assert (cold_any_binding-p bind)) + (if why (assert (stringp why))) + (if (consp (obj_routine-freevptrs orout)) + (let ( (fvar (pop (obj_routine-freevptrs orout))) ) + (assert (obj_ptrvar-p fvar)) + (assert (obj_var-vfree fvar)) + (assert (eq (obj_var-vrout fvar) orout)) + ;; don't reuse fvar for ease of debugging but make a new var of same offset + (let ( (rvar (copy-obj_ptrvar fvar)) ) + (setf (obj_var-vbind rvar) bind) + (setf (obj_var-vwhy rvar) why) + (setf (obj_var-vfree fvar) rvar) + (setf (obj_var-vfree rvar) nil) + rvar + )) + (let ( (nvar (make-obj_ptrvar :vbind bind + :voffset (incf (obj_routine-nbptr orout)) + :vwhy why + :vrout orout)) ) + nvar + ))) + +;; free a pointer variable to enable its reuse +(defun freeobjptrvar (ovar) + (assert (obj_ptrvar-p ovar)) + (assert (cold_any_binding-p (obj_var-vbind ovar))) + (let ( (orout (obj_var-vrout ovar)) + (oname (cold_any_binding-bname (obj_var-vbind ovar))) + ) + (assert (obj_routine-p orout)) + (push ovar (obj_routine-freevptrs orout)) + (setf (obj_var-vfree ovar) t) + nil +)) + + +;; make a long variable inside a routine, using the free list if possible +;; orout is the object routine inside which it is used +;; bind is the binding +;; why is some explanation string +(defun newobjlongvar (orout bind why) + (assert (obj_routine-p orout)) + (assert (cold_any_binding-p bind)) + (if why (assert (stringp why))) + (if (consp (obj_routine-freevnums orout)) + (let ( (fvar (pop (obj_routine-freevnums orout))) ) + (assert (obj_longvar-p fvar)) + (assert (obj_var-vfree fvar)) + (assert (eq (obj_var-vrout fvar) orout)) + ;; don't reuse fvar for ease of debugging but make a new var of same offset + (let ( (rvar (copy-obj_longvar fvar)) ) + (setf (obj_var-vbind rvar) bind) + (setf (obj_var-vwhy rvar) why) + (setf (obj_var-vfree fvar) rvar) + (setf (obj_var-vfree rvar) nil) + rvar + )) + (let ( (nvar (make-obj_longvar :vbind bind + :voffset (incf (obj_routine-nbnum orout)) + :vwhy why + :vrout orout)) ) + nvar + ))) + +;; free a long variable to enable its reuse +(defun freeobjlongvar (ovar) + (assert (obj_longvar-p ovar)) + (assert (cold_any_binding-p (obj_var-vbind ovar))) + (let ( (orout (obj_var-vrout ovar)) + (oname (cold_any_binding-bname (obj_var-vbind ovar))) + ) + (assert (obj_routine-p orout)) + (push ovar (obj_routine-freevnums orout)) + (setf (obj_var-vfree ovar) t) + nil +)) + + +(defgeneric compile_obj (cod env) + (:documentation "compilation of (any) Basilys code") +) + +(defmethod compile_obj ((cod t) env) + (break "compile_obj t cod ~S~%! env ~S~%! ~% <<<compilobj t" + cod env) + cod +) + +(defmethod compile_obj ((cod cons) env) + (error "compile_obj consp cod ~S~%! env ~S~%! ~% <<<compilobj cons" + cod env) + cod +) + +(defmethod compile_obj ((cod integer) env) + cod +) + +(defmethod compile_obj ((cod string) env) + cod +) + +(defmethod compile_obj ((cod prog_cstring) env) + (make-obj_cstring :obcstr (prog_cstring-c_str cod)) +) + +;; the sole init routine has to be a subclass of objoutine to handle +;; appropriately objpointers +(defstruct (obj_initroutine (:include obj_routine)) + inirou_datarankdict ;dictionnary mapping data to its rank +) + +;; given a data, returns its integer rank in the initial routine or else nil +(defun initrout_rank (obda) + (let ( (hrk + (gethash obda + (obj_initroutine-inirou_datarankdict + (compilation-initrout this_compilation)))) ) + ; to ease readability of the initrout we try to match the rank + ; with the varptr index into which it is usually stored + (if (integerp hrk) (+ hrk 2)) +)) + +(defmethod output_cdecl ((obj obj_initroutine) str) + (format str "~%~%/*-* declinitroutine *-*/~%") + (format str "void* start_module_basilys(void*modata_);~%") +) + + +(defmethod output_ccode ((obj obj_initroutine) str) + (let ( (nbptr (obj_routine-nbptr obj)) + (nbnum (obj_routine-nbnum obj)) + (nbdouble (obj_routine-nbdouble obj)) + (cdata (reverse (compilation-cdata this_compilation))) + (oldcurout (compilation-currout this_compilation)) + ) + (setf (compilation-currout this_compilation) obj) + ;; (format str "~%~%/*-* initroutine~% ~S **/~%" obj) + (format str "~%~%~%~%~%~%/*######### ccode initroutine ############*/~%") + (format str "void* start_module_basilys(void*modata_) {~%") + (format str "/*-*cdatalen ~d **/~%" (length cdata)) + (format str " typedef struct cdata_st {~%") + (loop for rk from 0 for da in cdata do + (format str "/*cdata ~d*/~%" rk) + ;(format_c_comment str "**cdata #~d = ~s~%" rk da) + (output_cdecl da str) + ) + (format str " long _extragap[2];} cdata_t;~%") + (format str " cdata_t*cdat=0;~%") + (format str " struct {~%") + (format str " unsigned nbvar;~%") + (format str " struct basilysclosure_st* clos;~%") + (format str " struct excepth_basilys_st* exh;~%") + (format str " struct callframe_basilys_st* prev;~%") + (format str " void* varptr[~d];~%" (+ nbptr 1)) + (format str " long varnum[~d];~%" (+ nbnum 1)) + (format str " double vardbl[~d];~%" (+ nbdouble 1)) + (format str " long _extra_;~%" ) + (format str " } curfram__ = { /*nbvar*/~d,~%" nbptr) + (format str " (struct basilysclosure_st*)0,~%") + (format str " (struct excepth_basilys_st*)0,~%") + (format str " (struct callframe_basilys_st*)0, ~%") + (progn + (format str "/*~d ptrvars:*/ {" nbptr) + (loop for ix from 1 to nbptr do (format str " (void*)0,")) + (format str "}, ~%") + ) + (if (> nbnum 0) (progn + (format str "/*~d numvars:*/ {" nbnum) + (loop for ix from 1 to nbnum do (format str " 0L,")) + (format str "}, ~%") + )) + (if (> nbdouble 0) (progn + (format str "/*~d doublevars:*/ {" nbdouble) + (loop for ix from 1 to nbdouble do (format str " 0.0,")) + (format str "}, ~%") + )) + (format str " 0L};~% curfram__.prev = basilys_topframe;~%") + (format str " basilys_topframe= (void*)(&curfram__);~%") + (format str "/*allocating and assigning cdata*/ {~%;~%") + (format str " debugeprintf(\"generated cdatlen ~d : size %d bytes\", (int)sizeof(cdata_t));~%" + (length cdata)) + (format str " cdat = basilysgc_allocate(sizeof(cdata_t),0);~%") + (format str " debugeprintf(\" cdat %p - %p\", (void*)cdat, (void*)((char*)cdat + sizeof(cdata_t)));~%") + (loop for rk from 0 for da in cdata do + (format str "~%/* assign cdata #~d*/~%" rk) + (output_cassign da str) + ) + (format str "/***** initcdata ***/~%") + (loop for rk from 0 for da in cdata do + (format str "~%/* init cdata #~d*/~%" rk) + (output_cinit da str) + (format str "~%/* endinit cdata #~d*/~%" rk) + ) + (format *error-output* ";;wrote ~d init cdata ~g cpusec~%" (length cdata) (cpusec)) + (finish-output str) + (format str "} /*allocated, assigned, inited cdata*/~%") + (format str "/*filling cdata ****/~%") + (loop for rk from 0 for da in cdata do + (format str "~%/* fill cdata #~d*/~%" rk) + (output_cfill da str) + ) + (finish-output str) + (format *error-output* ";;wrote ~d fill cdata ~g cpusec~%" (length cdata) (cpusec)) + (format str "/*verifying cdata ****/~%") + (loop for rk from 0 for da in cdata do + (format str "~%/* verify cdata #~d*/~%" rk) + (output_cverify da str) + ) + (format str "/*body of initrout*/~%") + (format *error-output* ";;before writing init body ~g cpusec~%" (cpusec)) + (format str " debugeprintf(\"before init routine body\");~%") + (if (obj_routine-obody obj) (output_ccode (obj_routine-obody obj) str)) + (format str "; /* initrout body end */~%") + (let ( (nbsym (hash-table-count(compilation-symboldict this_compilation))) ) + (format str "/*intern ~d symbols*/~%" nbsym) + (format *error-output* ";;writing init ~d interning ~g cpusec~%" nbsym (cpusec)) + ) + (let ( (symlist nil) ) + (maphash (lambda (sym data) (push sym symlist)) + (compilation-symboldict this_compilation)) + (let ( (sortedsymlist (sort symlist (lambda (s1 s2) (string< (symbol-name s1) (symbol-name s2))))) ) + (mapc (lambda (sym) + (let ( (sydata (gethash sym (compilation-symboldict this_compilation))) ) + ; (format_c_comment str "symbol ~S data ~S~%" sym sydata) + (format str "/*interning ~S*/~%" sym) + (if (keywordp sym) + (format str "(void) basilysgc_intern_keyword(") + (format str "(void) basilysgc_intern_symbol(")) + (output_ccode sydata str) + (format str ");~%") + )) + sortedsymlist))) + (format str " goto lab_endrout;~%") + (format str " lab_endrout:~% debugeprintf(\"end init routine returning %p\", curfram__.varptr[0]);~%") + (format str " basilys_topframe= (void*)(curfram__.prev); return curfram__.varptr[0];") + (format str "}/* end start_module_basilys */~%") + (setf (compilation-currout this_compilation) oldcurout) + (finish-output str) + )) + +;;; compilation of nil +(defmethod compile_obj ((cod null) env) + (make-obj_verbatim :vstr "/*Nil*/NULL") +) + + +;; compilation of symbols +(defmethod compile_obj ((cod symbol) env) + (let ((bnd (cold_find_binding cod env))) + (or bnd (error "compile_obj symbol: unbound symbol ~s in env ~s~% <::compile_obj unboundsym ~S in ~S>" + cod env cod (obj_routine-syname (compilation-currout this_compilation)))) + (cond ( (cold_value_binding-p bnd) + (let ( (sdata (cold_value_binding-val bnd)) ) + (cond + ( (eq (cold_value_binding-type bnd) :void) + (make-obj_verbatim :vstr (format nil "/*Void ~S*/NULL" cod))) + ( (obj_var-p sdata) sdata) + ( (currout_data2ptr sdata) ) + ( t (newobjconst sdata "symb val")) + ))) + ( (cold_class_binding-p bnd) + ;; a class is a constant, to be put in the routine's constant data + (let ( (cladata (cold_class_binding-classdata bnd)) ) + (assert (obj_data-p cladata) () "compilobj: bad data ~S for class ~S bnd ~S" cladata cod bnd) + (or (currout_data2ptr cladata) (newobjconst cladata "symb class")) + )) + ( (cold_field_binding-p bnd) + (let ( (fldata (cold_field_binding-fieldata bnd)) ) + (assert (obj_data-p fldata) () "compilobj: bad data ~S for field ~S bnd ~S" fldata cod bnd) + (or (currout_data2ptr fldata) (newobjconst fldata "symb field")) + )) + ( (cold_instance_binding-p bnd) + (let ( (insdata (cold_instance_binding-instancedata bnd)) ) + (assert (obj_data-p insdata) () "compilobj: bad data ~S for instance ~S bnd ~S" insdata cod bnd) + (or (currout_data2ptr insdata) (newobjconst insdata "symb inst")) + )) + ( (cold_selector_binding-p bnd) + (let ( (seldata (cold_selector_binding-selectordata bnd)) ) + (assert (obj_data-p seldata) () "compilobj: bad data ~S for selector ~S bnd ~S" seldata cod bnd) + (or (currout_data2ptr seldata) (newobjconst seldata "symb sel")) + )) + ( (cold_function_binding-p bnd) + (let ( (fundata (cold_function_binding-fclodata bnd)) ) + (assert (obj_data-p fundata) () "compilobj: bad data ~S for function ~S bnd ~S" fundata cod bnd) + (or (currout_data2ptr fundata) (newobjconst fundata "symb fun")) + )) + ( (cold_code_binding-p bnd) + (compile_obj (cold_code_binding-code bnd) env) ) + (t (error "unexpected compile_obj symbol ~s~%!! bnd ~s~%!!env ~s~% <::compile_obj unexpectedsym ~S {bnd ~S} in ~S>" + cod bnd env cod (type-of bnd) + (obj_routine-syname (compilation-currout this_compilation))))) + )) + + +;;; compilation of quoted symbols +(defmethod compile_obj ((cod prog_quotesym) env) + (declare (ignore env)) + (let ( (qs (prog_quotesym-qsym cod)) ) + (cond ( (or (symbolp qs) (keywordp qs)) +; (warn "compilobj-quotesym cod=~S~%" cod) + (let* ( (odatsym (get_obj_symbol qs "quotesym")) + (osymptr (currout_data2ptr odatsym)) + ) +; (warn "compilobj-quotesym odatsym ~S osymptr ~S~%" odatsym osymptr) + (or osymptr (newobjconst odatsym "quotsym")))) + ( t (error "compile_obj bad prog_quotesym ~S" cod) ) + ) +)) + +;; compilation of closed variable occurrences +(defmethod compile_obj ((cod prog_closedvar) env) + (let ( (cfun (prog_closedvar-clv_fun cod)) + (cvar (prog_closedvar-clv_var cod)) ) + (let* ( (clovarseq + (cond + ( (prog_defun-p cfun) (prog_defun-fun_closvars cfun) ) + ( (prog_lambda-p cfun) (prog_lambda-lambda_closvars cfun) ) + ( t (cerror "compile_obj prog_closedvar bad cfun ~s for cod ~s" cfun cod)))) + (coff + (progn + (position cvar clovarseq + :test (lambda (c1 cv2) + (eq (if (symbolp c1) c1 (prog_closedvar-clv_var c1)) + (prog_closedvar-clv_var cv2))))) + ) + ) + (or coff (error "compile_obj prog_closedvar no offset for cod ~s ~%... in clovarseq ~S~%" + cod)) + (make-obj_closedvar :cvar cvar :cfun cfun :coffset coff) + ))) + + +;; handling of closed variables in functions' closed variables and constants +(defun handleclosvar (pcv env) + (if (and (prog_closedvar-p pcv) + (prog_defun-p (prog_closedvar-clv_fun pcv))) + (let ( + (cva (prog_closedvar-clv_var pcv)) + ) + (or (symbolp cva) (error "bad cva in handleclosvar pcv ~S" pcv)) + (let ( (vbi (cold_find_binding cva env)) ) + (cond ( (cold_value_binding-p vbi) + (cold_value_binding-val vbi) ) + ( (cold_class_binding-p vbi) + (cold_class_binding-classdata vbi) ) + ( (cold_field_binding-p vbi) + (cold_field_binding-fieldata vbi) ) + ( (cold_instance_binding-p vbi) + (cold_instance_binding-instancedata vbi) ) + ( (cold_selector_binding-p vbi) + (cold_selector_binding-selectordata vbi) ) + ( (cold_function_binding-p vbi) + (cold_function_binding-fclodata vbi) ) + ( t + (error "handleclosdata unexpected binding vbi=~S cva=~S" + vbi cva)) + ) + )) + (progn + pcv) + ) + ) + +;;;; compilation of progns +(defmethod compile_obj ((cod prog_progn) env) + (let ( (pbody (prog_progn-progn_body cod)) ) + (make-obj_block :instrs + (mapcar (lambda (comp) (compile_obj comp env)) pbody)) +)) + + +;;;; compilation of forevers + +(defmethod compile_obj ((cod prog_forever) env) + (let* ( (lbind (prog_forever-forever_bind cod)) + (lbody (prog_forever-forever_body cod)) + (lbnam (cold_any_binding-bname lbind)) + (luniq (cold_forever_binding-uniq lbind)) + (ltype (cold_forever_binding-type lbind)) + (epilo nil) + (obody nil) + (lvar nil) + (nbind (make-cold_obforever_binding + :bname lbnam + :type ltype + :uniq luniq + :lobvar nil)) + (newenv (cold_fresh_env env)) + ) + (cold_put_binding nbind newenv) + (case ltype + ( :value + (let ( (vvar + (newobjptrvar (compilation-currout this_compilation) lbind + "forever value")) ) + (setf (cold_obforever_binding-lobvar nbind) vvar) + (setq epilo (make-obj_clearptr :clrptrvar vvar)) + (setq lvar vvar) + )) + ( :long + (let ( (vvar + (newobjlongvar (compilation-currout this_compilation) lbind + "forever num" + )) ) + (setf (cold_obforever_binding-lobvar nbind) vvar) + (setq epilo (make-obj_clearlong :clrlongvar vvar)) + (setq lvar vvar) + )) + (otherwise (error "bad forever ltype ~S in ~S" ltype cod)) + ) + (setq obody (mapcar (lambda (i) (compile_obj i newenv)) lbody)) + (if lvar (case ltype + (:value (freeobjptrvar lvar)) + (:long (freeobjlongvar lvar)) + )) + (make-obj_forever + :obforever_bind nbind + :obforever_res (cold_obforever_binding-lobvar nbind) + :obforever_dest nil + :obforever_body obody + :obforever_epilogue epilo + ) + )) + + +;;;; +(defmethod compile_obj ((cod prog_exit) env) + (let* ( (ebind (prog_exit-exit_bind cod)) + (ebody (prog_exit-exit_body cod)) + (lvar (cold_any_binding-bname ebind)) + (nbind (cold_find_binding lvar env)) + (nbody (mapcar (lambda (i) (compile_obj i env)) ebody)) + (lasti (last nbody)) + ) + (or (cold_obforever_binding-p nbind) + (error "bad binding in compile_obj prog_exit ~S" cod)) + (if (consp lasti) + (let* ( (nobv (cold_obforever_binding-lobvar nbind)) + (li (first lasti)) + (nli (put_destination li nobv)) ) + (if nli + (setf (car lasti) + nli)))) + (make-obj_exit + :obxit_bind nbind + :obxit_body nbody) + )) + +;;;; compilation of multicall, using the obj_call +(defmethod compile_obj ((cod prog_multicall) env) + (let ( (pformalist (prog_multicall-multicall_formals cod)) + (pcall (prog_multicall-multicall_call cod)) + (pbody (prog_multicall-multicall_body cod)) + (newenv (cold_fresh_env env)) + (revinstrseq nil) + (revresultvars nil) + ) + (assert (or (prog_apply-p pcall) (prog_send-p pcall))) + (flet ( + (handleformalbind + (bnd) + (let ( (bname (cold_any_binding-bname bnd)) + (btype (cold_typed_binding-type bnd)) + ) + (case btype + (:value + (let ( (vvar + (newobjptrvar (compilation-currout this_compilation) bnd + "multicall value" + )) ) + (cold_put_binding + (make-cold_value_binding :bname bname :val vvar :type btype) + newenv) + (push (build_obj_compute vvar (list "(void*)0") btype) + revinstrseq) + (push vvar revresultvars) + )) + (:long + (let ( (nvar + (newobjlongvar (compilation-currout this_compilation) bnd + "multicall long" + )) ) + (cold_put_binding + (make-cold_value_binding :bname bname :val nvar :type btype) + newenv) + (push (build_obj_compute nvar (list "0L") btype) + revinstrseq) + (push nvar revresultvars) + )) + (otherwise (error "compile_obj prog_multicall unexpected bnd ~S" + bnd)))) + )) + (mapc (function handleformalbind) pformalist) + ) + (let* ( (resultvars (reverse revresultvars)) + ) + (cond + ( (prog_apply-p pcall) + (push (make-obj_call + :dest (first resultvars) + :clos (compile_obj (prog_apply-appl_fun pcall) env) + :xtraresults (rest resultvars) + :args (mapcar (lambda (e) (compile_obj e env)) + (prog_apply-appl_args pcall)) + ) revinstrseq)) + ( (prog_send-p pcall) + (push (make-obj_send + :obs_dest (first resultvars) + :obs_sel (compile_obj (prog_send-send_sel pcall) env) + :obs_recv (compile_obj (prog_send-send_recv pcall) env) + :obs_args (mapcar (lambda (e) (compile_obj e env)) + (prog_send-send_args pcall)) + :obs_xtraresults (rest resultvars) + ) revinstrseq)) + ( t + (error "unexpected call ~S in multicall" pcall)) + ) + ) + (mapc (lambda (e) (push (compile_obj e newenv) revinstrseq)) pbody) + (make-obj_block + :instrs (reverse revinstrseq)) + )) + +;;;;;;;;;;;;;;;;;;; compilation of toplev definitions + +(defmethod compile_obj ((cod prog_defun) env) + (push cod (compilation-functions this_compilation)) + ;; (format *error-output* "compile_obj prog_defun cod <ici> ~S~%" cod) + (let* ( + ;; if the defun originated from a lambda, we do not need to + ;; build a dataclosure + (slambda (prog_defun-fun_lambda cod)) + (orout (make-obj_routine + :pfun cod + :nbptr 1 ;reserve slot for result ptr + :nbnum 0 + :nbdouble 0 + :obody nil + :syname (prog_def-def_name cod) + :rank (length (compilation-functions this_compilation)) + :data2ptrhash (make-hash-table :size 31) + )) + (odatarout (add_cdata (make-obj_dataroutine + :comname (prog_def-def_name cod) + :discr 'DISCR_ROUTINE + :rout orout + ) + "defun datarout" + )) + (funbind (and + (null slambda) + (cold_find_binding (prog_def-def_name cod) env) + )) + (odatacl (and + (null slambda) + (cold_function_binding-p funbind) + (let ( (ofunclo (cold_function_binding-fclodata funbind)) ) + (assert (obj_dataclosure-p ofunclo)) + (setf (obj_dataclosure-rout ofunclo) orout) + (setf (obj_dataclosure-discr ofunclo) 'DISCR_CLOSURE) + (add_cdata ofunclo "defun dataclo") + ))) + (oarginsrev nil) + (fbind (prog_defun-fun_argbindings cod)) + (newenv (cold_fresh_env env)) + (oldcurrout (compilation-currout this_compilation)) + ) + (setf (obj_routine-dataclos orout) odatacl) + (setf (obj_routine-datarout orout) odatarout) + (setf (compilation-currout this_compilation) orout) + ;; bind the name to the dataclosure if available + (if odatacl + (cold_put_binding + (make-cold_value_binding :bname (prog_def-def_name cod) + :val odatacl :type ':value) + env)) + (cold_delay + (format nil "compilobj defun ~S closvar" (prog_def-def_name cod)) + (if odatacl + (setf (obj_dataclosure-clodata odatacl) + (mapcar (lambda (var) (handleclosvar var env)) + (prog_defun-fun_closvars cod)))) + (mapcar (lambda (var) + (push + (handleclosvar var env) + (obj_dataroutine-roudata odatarout) + )) + (prog_defun-fun_constants cod))) + (labels + ( (bindvar (nam val type) + (let ( (nbi (make-cold_value_binding + :bname nam :val val :type type))) + (cold_put_binding nbi newenv + ))) + ( doptr (b) ;add a value arg + (let ( (ovar (newobjptrvar orout b + "defun doptr" + )) ) + (bindvar (cold_formal_binding-bname b) ovar ':value) + (push (make-obj_getptrarg_instr + :dest ovar :rk (cold_formal_binding-rank b)) oarginsrev) + ) ) + ( dolong (b) ;add a numerical arg + (let ( (ovar (newobjlongvar orout b + "defun dolong" + )) ) + (bindvar (cold_formal_binding-bname b) ovar ':long) + (push (make-obj_getlongarg_instr + :dest ovar :rk (cold_formal_binding-rank b)) oarginsrev) + ) ) + ( doit (b) ;handle both + (case (cold_formal_binding-type b) + (:value (doptr b)) + (:long (dolong b)) + (otherwise (error "compile_obj progdefun unexpected binding ~s" b))) + ) + (comp1 (i) ;compile 1 instruction + (compile_obj i newenv) + ) + (comp (i) ;compile 1 or many instr + (if (listp i) (mapcar #'comp1 i) (comp1 i)) + ) + ) + (mapcar (function doit) fbind) + (let* ( (funbody (prog_defun-fun_body cod)) ;compile the entire body + (objbody (comp funbody)) + (insarg (make-obj_get_arguments :instrs (reverse oarginsrev))) ) +;;; put the proper list of instructions + (setf (obj_routine-obody orout) + (if (listp objbody) (cons insarg objbody) (list insarg objbody))) +;;; restore compilation & return the routine + (setf (compilation-currout this_compilation) oldcurrout) + orout + )))) + + +;;;; compilation of a primitive +(defmethod compile_obj ((cod prog_defprimitive) env) + ;; create an object with 3 fields: the name, the formal tuple, the expansion tuple + (let* + ( + (pname (prog_def-def_name cod)) + (pformals (prog_defprimitive-primitive_formals cod)) + (ptype (prog_defprimitive-primitive_type cod)) + (pexpand (prog_defprimitive-primitive_expansion cod)) + (onamestr (add_cdata (make-obj_datastring + :comname pname + :discr 'DISCR_STRING + :string (string pname)) + "defprimit namstr" + )) + (oformals + (mapcar + (lambda (forbi) + (add_cdata (make-obj_datainstance + :comname pname + :discr 'CLASS_FORMAL_BINDING + :slots (list + (get_obj_symbol (cold_formal_binding-bname forbi) "defprimi forbi") + (get_obj_type (cold_formal_binding-type forbi))) + ) + "defprimit formal" + )) + pformals)) + (oexptuple + (add_cdata + (make-obj_datamultiple + :comname pname + :discr 'DISCR_MULTIPLE + :values + (mapcar + (lambda (e) + (cond + ((symbolp e) + (let ((po (position-if + (lambda (bi) (eq (cold_formal_binding-bname bi) e)) + pformals))) + (or po + (error "unexpected symbol ~S in defprimitive ~S" e cod)) + (nth po oformals) + ) + ) + ((stringp e) + (add_cdata (make-obj_datastring + :comname pname + :discr 'DISCR_STRING + :string e) + "defprimit string" + )) + (t (error "unexpected stuff ~S in defprimitive ~S" e cod)) + )) + pexpand)) + "defprimit exptuple" + )) + (oformaltuple + (add_cdata + (make-obj_datamultiple + :comname (prog_def-def_name cod) + :discr 'DISCR_MULTIPLE + :values oformals) + "defprimit formtuple" + )) + (oprim (add_cdata (make-obj_datainstance + :comname pname + :discr 'CLASS_PRIMITIVE + :slots (list nil onamestr oformaltuple oexptuple)) + "defprimit oprim" + ) + ) + ) + nil + )) + + + + +;; recursive ancestors in reversed order +(defun revancestors_defclass (dc) + (if dc + (let + ((supdc (prog_defclass-class_super dc))) + (if supdc (cons supdc (revancestors_defclass supdc)))))) + +;; recursive fields in reversed order +(defun revfields_defclass (dc) + (if dc + (let ((supdc (prog_defclass-class_super dc))) + (revappend (prog_defclass-class_ownfields dc) (revfields_defclass supdc))))) + + +;;;;; compilation of a defclass +(defmethod compile_obj ((cod prog_defclass) env) + (let ( + (pname (prog_def-def_name cod)) + (ppredef (prog_predef-predef_rank cod)) + (allfields (reverse (revfields_defclass cod))) + (allancestors (reverse (revancestors_defclass cod))) + ) + (let* ( + (obstrname (add_cdata + (make-obj_datastring + :comname pname + :discr 'DISCR_STRING :string (string pname)) + "defclass strname" + )) + (obclass (add_cdata + (make-obj_datainstance + :comname pname + :discr 'CLASS_CLASS + :predef ppredef + :objnum 'OBMAG_OBJECT) + "defclass obclass" + )) + (clabind (cold_find_binding (prog_defclass-def_name cod) env)) + (obancestorstuple + (add_cdata + (make-obj_datamultiple + :comname (prog_def-def_name cod) + :discr 'DISCR_SEQCLASS + :values + (mapcar + (lambda (anc) + (assert (prog_defclass-p anc)) + (let* ( (ancbind (cold_find_binding + (prog_defclass-def_name anc) env)) + (ancdata (cold_class_binding-classdata ancbind)) + ) + ancdata + )) + allancestors) + ) + "defclass seqancestors" + )) + (obsuper + (if allancestors + (let* ( + (anc (first (last allancestors))) + (ancbind (cold_find_binding + (prog_defclass-def_name anc) env)) + (ancdata (cold_class_binding-classdata ancbind)) + ) + ancdata + ))) + (obfieldstuple + (add_cdata + (make-obj_datamultiple + :comname (prog_def-def_name cod) + :discr 'DISCR_SEQFIELD + :values + (mapcar + (lambda (f) + (assert (prog_field-p f)) + (let ( (fldata + (add_cdata + (make-obj_datainstance + :comname (prog_field-def_name f) + :discr 'CLASS_FIELD + :objnum (prog_field-field_offset f) + :slots + (list nil + (add_cdata + (make-obj_datastring + :comname (prog_def-def_name f) + :discr 'DISCR_STRING + :string (string (prog_def-def_name f)))) + nil)))) + (flbind + (cold_find_binding (prog_field-def_name f) env)) + ) + (assert (cold_field_binding-p flbind)) + (setf (cold_field_binding-fieldata flbind) fldata) + ) + ) + allfields) + ) + "defclass fieldtupl" + )) + ) + (setf (cold_class_binding-classdata clabind) obclass) + (setf (obj_datainstance-slots obclass) + (list + nil ;no prop + obstrname + nil ;no methodict + nil ;no sendclosure + obsuper ;disc_super + obancestorstuple + obfieldstuple + nil ;no objnumdescr + nil ;nod classdata + )) + nil ;result of compile_obj + ))) + + +;;; compile a definstance (not a defselector!) +(defmethod compile_obj ((cod prog_definstance) env) + (let ( (iname (prog_def-def_name cod)) + (ipredef (prog_predef-predef_rank cod)) + (iclass (prog_definstance-inst_class cod)) + (iobjnum (prog_definstance-inst_objnum cod)) + (islots (prog_definstance-inst_slots cod)) ) + (assert (prog_defclass-p iclass)) + (let ( (slovec (make-array (length (prog_defclass-class_allfields iclass)))) + (insbind (cold_find_binding iname env)) + (clabind (cold_find_binding (prog_def-def_name iclass) env)) + ) + (assert (cold_instance_binding-p insbind)) + (assert (cold_class_binding-p clabind)) + (assert (cold_class_binding-classdata clabind)) + (let ( (ob + (make-obj_datainstance + :comname (prog_def-def_name cod) + :discr (cold_class_binding-classdata clabind) + :objnum + ;;special hack for OBMAG_* names or others + (if (symbolp iobjnum) iobjnum + (compile_obj iobjnum env)) + :predef ipredef)) + ) + (add_cdata ob "definstance ob") + (setf (cold_instance_binding-instancedata insbind) ob) + ;; fill the slot, should be here to allow + ;; a slot to refer to the newly made + ;; instance + (mapc (lambda (s) + (setf (aref slovec + (prog_field-field_offset (instance_slot-slot_field s)) ) + (let* ( (cobs + (compile_obj (instance_slot-slot_value s) env)) + ;; we put the tempslot variable as destination + (pobs + (put_destination cobs cold_tempslot_var)) + ) + (or pobs cobs) + ))) + islots) + (setf (obj_datainstance-slots ob) + (concatenate 'list slovec)) ;; convert slovec to a list + ob + ) + ) + nil)) + +;;; compile a defselector is quite similar to a definstance +(defmethod compile_obj ((cod prog_defselector) env) + (let ( (iname (prog_def-def_name cod)) + (ipredef (prog_predef-predef_rank cod)) + (iclass (prog_definstance-inst_class cod)) + (iobjnum (prog_definstance-inst_objnum cod)) + (islots (prog_definstance-inst_slots cod)) ) + (assert (prog_defclass-p iclass)) + (let ( (slovec (make-array (length (prog_defclass-class_allfields iclass)))) + (insbind (cold_find_binding iname env)) + (clabind (cold_find_binding (prog_def-def_name iclass) env)) + ) + (assert (cold_selector_binding-p insbind)) + (assert (cold_class_binding-p clabind)) + (assert (cold_class_binding-classdata clabind)) + (let ( (ob + (make-obj_datainstance + :comname (prog_def-def_name cod) + :discr (cold_class_binding-classdata clabind) + :objnum + ;;special hack for OBMAG_* names or others + (if (symbolp iobjnum) iobjnum + (compile_obj iobjnum env)) + :predef ipredef)) + ) + (add_cdata ob "defselector ob") + (setf (cold_selector_binding-selectordata insbind) ob) + ;; fill the slot, should be here to allow + ;; a slot to refer to the newly made + ;; instance + (mapc (lambda (s) + (setf (aref slovec + (prog_field-field_offset (instance_slot-slot_field s)) ) + (let* ( (cobs + (compile_obj (instance_slot-slot_value s) env)) + ;; we put the tempslot variable as destination + (pobs + (put_destination cobs cold_tempslot_var)) + ) + (or pobs cobs) + ))) + islots) + (setf (obj_datainstance-slots ob) + (concatenate 'list slovec)) ;; convert slovec to a list + ob + ) + ) + nil)) + + + + +;; get (and generate if needed) the objinstance for a symbol +(defun get_obj_symbol (sym &optional why) + (assert (symbolp sym) (sym) "bad argument to get_obj_symbol ~S" sym) + (let ((sydict (compilation-symboldict this_compilation))) + (or (gethash sym sydict) + (let* ( + (onamestr (add_cdata (make-obj_datastring + :comname sym + :discr 'DISCR_STRING + :string (string sym)) + (if why (concatenate 'string "GetObjSymb namstr " why) + "getobjsymb namstr") + )) + (osym (add_cdata (make-obj_datainstance + :discr (if (keywordp sym) 'CLASS_KEYWORD 'CLASS_SYMBOL) + :comname sym + :slots (list nil onamestr nil)) + (if why (concatenate 'string "GetObjSymb osym " why) + "getobsymb osym") + )) + ) + (setf (gethash sym sydict) osym) + osym + ) + #| ; + (let* ( (odatasym (make-obj_dataqsymbol :comname sym :qsymb sym)) + (osym (or (currout_data2ptr odatasym) (newobjconst odatasym))) ) + (setf (gethash sym sydict) osym) + osym + ) + |# +))) + +;; translate a type +(defun get_obj_type (ty) + (case ty + (:value 'CTYPE_VALUE) + (:long 'CTYPE_LONG) + (:cstring 'CTYPE_CSTRING) + (t (error "bad type to get_obj_type ~S" ty)))) + + + +;;;;;;;;;;;;;;;;;;; compilation of instructions +(defmethod compile_obj ((cod prog_let) env) + (let ( (lbind (prog_let-let_bindings cod)) + (lbody (prog_let-let_body cod)) + (newenv (cold_fresh_env env)) + (locptrvars nil) ;list of local pointers vars (to be freed & cleared) + (loclongvars nil) ;list of local long vars (to be freed & cleared) + (revinstrseq nil) + ) + (labels + ( (checkbinding + (bnd) ; compute the type of each binding if it didn't have one + (assert (cold_let_binding-p bnd)) + (if (null (cold_let_binding-type bnd)) + (let ( (bexpr (cold_let_binding-expr bnd)) ) + (cond ( (prog_primitive-p bexpr) + (setf (cold_let_binding-type bnd) + (prog_defprimitive-primitive_type + (prog_primitive-prim_oper bexpr))) + ) + ( (and (atom bexpr) + (cold_find_binding bexpr env)) + (let ( (exbnd (cold_find_binding bexpr env)) ) + (and + (cold_typed_binding-p exbnd) + (cold_typed_binding-type exbnd) + (setf (cold_let_binding-type bnd) + (cold_typed_binding-type exbnd)) + ) + ) + )))) + ;; by default set the type to :value + (if (null (cold_let_binding-type bnd)) + (setf (cold_let_binding-type bnd) ':value)) + ) + (handlebinding + (bnd) + (let ( (bexpr (cold_let_binding-expr bnd)) + (btype (cold_typed_binding-type bnd)) + (bname (cold_any_binding-bname bnd)) + ) + (case btype + (:value + (let ( (vvar + (newobjptrvar (compilation-currout this_compilation) bnd + "compilet ptr" )) ) + (push vvar locptrvars) + (cold_put_binding + (make-cold_value_binding :bname bname :val vvar :type btype) + newenv) + (let ( (compexp + (compile_obj (cold_let_binding-expr bnd) newenv)) ) + (push (or (put_destination compexp vvar) compexp) revinstrseq) + ))) + (:long + (let ( (nvar + (newobjlongvar (compilation-currout this_compilation) bnd + "compilet long")) ) + (push nvar loclongvars) + (cold_put_binding + (make-cold_value_binding :bname bname :val nvar :type btype) + newenv) + (let ( (compexp + (compile_obj (cold_let_binding-expr bnd) newenv)) ) + (push (or (put_destination compexp nvar) compexp) revinstrseq) + ))) + (:void + ;; dont use any objvar and dont putdest + (cold_put_binding + (make-cold_value_binding :bname bname :val nil :type btype) + newenv) + (let ( (compexp + (compile_obj (cold_let_binding-expr bnd) newenv)) ) + (push compexp revinstrseq) + )) + (otherwise (error "compile_obj prog_let unexpected binding ~s" bnd)) + ) + ) + ) + (comp1 + (cod) + (push (compile_obj cod newenv) revinstrseq) + ) + (comp + (cod) + (if (listp cod) (mapcar (function comp1) cod) (comp1 cod))) + ) + (mapc (function checkbinding) lbind) + (mapc (function handlebinding) lbind) + (comp lbody) + (let ( (lbc (first revinstrseq)) );; lbc is the last body compiled ... + ;;; generates clears only if the compiled body is a variable + ;;; which we don't clear + (mapcar (lambda (pv) + (if (and (obj_var-p lbc) (not (eql lbc pv))) + (push (make-obj_clearptr :clrptrvar pv) revinstrseq)) + (freeobjptrvar pv) + ) locptrvars) + (mapcar (lambda (lv) + (if (and (obj_var-p lbc) (not (eql lbc lv))) + (push (make-obj_clearlong :clrlongvar lv) revinstrseq)) + (freeobjlongvar lv) + ) loclongvars) + ;;; push again the lbc to make it the result of the block + (if (obj_var-p lbc) + (push lbc revinstrseq)))) + (make-obj_block :instrs (reverse revinstrseq)) + ) + ) + +(defmethod compile_obj ((cod prog_primitive) env) + (error "unexpected call to compile_obj prog_primitive cod ~S env ~S" cod env) + ) + +(defmethod compile_obj ((cod prog_chunk) env) + (let* ( (chargs (prog_chunk-chunk_args cod)) + (objc (build_obj_compute + nil + (mapcar (lambda (a) + (cond ((stringp a) (make-obj_verbatim :vstr a)) + ((numberp a) a) + (t (compile_obj a env))) + ) + chargs) + (prog_chunk-chunk_type cod) + )) ) + objc + )) + + +(defmethod compile_obj ((cod prog_unsafe_get_field) env) + (let* ( (ugfield (prog_unsafe_get_field-uget_field cod)) + (ugobj (prog_unsafe_get_field-uget_obj cod)) ) + (assert (prog_field-p ugfield)) + (build_obj_compute + nil + (list "/*unsafe_get*/ (basilys_field_object((" + (compile_obj ugobj env) + "), (" + (prog_field-field_offset ugfield) + "))" + (format nil "/**.~a.**/" (prog_field-def_name ugfield)) + ")" + ) + :value + ))) + + +(defmethod compile_obj ((cod prog_unsafe_put_fields) env) + (let* ( (upobj (prog_unsafe_put_fields-uput_obj cod)) + (upkeys (prog_unsafe_put_fields-uput_keys cod)) + (revinstrs nil) ) + ;; push the destination in a register + (push (make-obj_verbatiminstr :vstr "/*unsafeput dest*/register basilysobject_ptr_t obdest= 0;") + revinstrs) + (push (make-obj_verbatiminstr :vstr "/*unsafeput dest*/register int oblen= 0;") + revinstrs) + (push + (build_obj_compute + nil + (list "/*unsafe_put setdest*/ obdest = (void*)" + (compile_obj upobj env)) + :value + ) + revinstrs) + (push (make-obj_verbatiminstr :vstr "gcc_assert(basilys_magic_discr(obdest) == OBMAG_OBJECT);") + revinstrs) + (push (make-obj_verbatiminstr :vstr "oblen = basilys_object_length(obdest);") + revinstrs) + (let ( (maxfldoff 0) ) + (loop + for curkpair in upkeys do + (let ( (curfld (car curkpair)) + (curexp (cdr curkpair)) + ) + (assert (prog_field-p curfld)) + (setq maxfldoff (max maxfldoff (prog_field-field_offset curfld))) + )) + (push (make-obj_verbatiminstr :vstr (format nil "gcc_assert(oblen > ~d);" maxfldoff)) + revinstrs) + ) + ;; push the field initializations + (mapc + (lambda (curkpair) + (let ( (curfld (car curkpair)) + (curexp (cdr curkpair)) + ) + (assert (prog_field-p curfld)) + (push + (build_obj_compute + nil + (list + "/*unsafe_put field*/ obdest->obj_vartab[" + (prog_field-field_offset curfld) + "] " + (format nil "/**.~a.**/" (prog_field-def_name curfld)) + " = (basilys_ptr_t)(" + (compile_obj curexp env) + ")" + ) + :value + ) + revinstrs) + )) + upkeys) + ;; push the touch of the destination + (push + (build_obj_compute + nil + (list "/*unsafe_put touch*/ basilysgc_touch(obdest)") + :void + ) + revinstrs) + ;; push the destination itself as the result + (push + (compile_obj upobj env) + revinstrs) + ;; return the block + (make-obj_block :instrs (reverse revinstrs)) + )) + + +(defmethod compile_obj ((cod prog_make_instance) env) + (let ( (classv (prog_make_instance-mki_class cod)) + (mikeys (prog_make_instance-mki_keys cod)) + (classd (prog_make_instance-mki_classdef cod)) + (revinstrs nil) + ) + ;; push the destination in a register + (push (make-obj_verbatiminstr :vstr "/*makeinst*/register basilysobject_ptr_t obnew= 0;") + revinstrs) + (let ( (compclass (compile_obj classv env)) + (siznew (length (prog_defclass-class_allfields classd))) + ) + (if (and (compilation-currout this_compilation) + (obj_data-p compclass)) + (setq compclass (newobjconst compclass "makeinst class"))) + ; (warn "compile_obj make_instance cod ~S compclass ~S env ~S ~%...compilobj make_inst currout ~S" + ; cod compclass env (compilation-currout this_compilation)) + (push + (build_obj_compute + nil + (list "/*make_instance*/obnew = basilysgc_new_raw_object( (void*)" + compclass + "," + siznew + ")") + :value + ) + revinstrs) + ;; push the field initializations + (mapc + (lambda (curkpair) + (let ( (curfld (car curkpair)) + (curexp (cdr curkpair)) + ) + (assert (prog_field-p curfld)) + (assert (< (prog_field-field_offset curfld) siznew)) + (push + (build_obj_compute + nil + (list + "/*make_inst field*/ obnew->obj_vartab[" + (prog_field-field_offset curfld) + "] " + (format nil "/**.~a.**/" (prog_field-def_name curfld)) + " = (basilys_ptr_t)(" + (compile_obj curexp env) + ")" + ) + :value + ) + revinstrs) + )) + mikeys) + ) + ;; push the new object itself as the result + (push + (make-obj_verbatim :vstr "obnew") + revinstrs) + ;; return the block + (make-obj_block :instrs (reverse revinstrs)) + )) + + +(defun compile_argobj (cod env) + (if (stringp cod) + (let* ( (obstrdata + (add_cdata (make-obj_datastring + :comname cod + :discr 'DISCR_STRING + :string cod) + "argobj strdata") + ) + (constri (newobjconst obstrdata "argobj constri")) + ) + ;;; (warn "compile_argobj cod ~S obstrdata ~S constr ~S env ~S~%" cod obstrdata constri env) + constri) + (compile_obj cod env) + )) + + +(defmethod compile_obj ((cod prog_apply) env) + (let ( (apfun (prog_apply-appl_fun cod)) + (apargs (prog_apply-appl_args cod)) ) + (make-obj_call + :clos (compile_obj apfun env) + :args (mapcar (lambda (c) (compile_argobj c env)) apargs) + ) + ) +) + +(defmethod compile_obj ((cod prog_send) env) + (let ( (isel (prog_send-send_sel cod)) + (irecv (prog_send-send_recv cod)) + (iargs (prog_send-send_args cod)) ) + (make-obj_send + :obs_dest nil + :obs_sel (compile_obj isel env) + :obs_xtraresults nil + :obs_recv (compile_obj irecv env) + :obs_args (mapcar (lambda (c) (compile_argobj c env)) iargs) + ) +)) + + + + +(defmethod compile_obj ((cod prog_lambda) env) + (error "should never be called compile_obj prog_lambda cod=~S ~%" cod) +) + + +(defmethod compile_obj ((cod prog_makeclosure) env) + (flet + ( (comp (c) (compile_obj c env)) ) + (let* + ( (cfun (prog_makeclosure-mkclos_fun cod)) + (cvars (prog_makeclosure-mkclos_closvars cod)) + (mkc + (make-obj_mkclosure + :cfun cfun + :cvals (mapcar (function comp) cvars) + ) + ) + ) + (let ((obr + (find-if + (lambda (o) + (and (obj_dataroutine-p o) + (eq (obj_routine-pfun (obj_dataroutine-rout o)) cfun))) + (compilation-cdata this_compilation)))) + (or obr (error "compile_obj makeclosure ~S ~%..cannot find dataroutine for ~S" + cod cfun)) + (setf (obj_mkclosure-kobjrout mkc) (newobjconst obr "makeclos objro")) + mkc + )))) + + + +(defmethod compile_obj ((cod prog_return) env) + (let ( (progrets (prog_return-retexprs cod)) ) + (or (listp progrets) (error "bad prog_return without list return ~s" cod)) + (let ( (compexprs (mapcar (lambda (c) (compile_obj c env)) progrets)) ) + (let ( (retmain (and (consp compexprs) (first compexprs))) + (retextras (and (consp compexprs) (rest compexprs))) ) + (and (prog_src-p retmain) (not (eq (query_ctype retmain) :value)) + (error "prog_return has bad main value ~s" cod)) + (if retmain + (progn +; (warn "compilobjreturn retmain ~S retextras ~S~%" retmain retextras) + (let ( (newretmain (put_destination retmain cold_return_var)) ) + (if newretmain (setq retmain newretmain))))) + (make-obj_return + :mainreturn retmain + :extrareturns retextras) + ) +))) + + +(defmethod compile_obj ((cod prog_setq) env) + (let* ( (pva (prog_setq-setq_var cod)) + (pex (prog_setq-setq_expr cod)) + (cva (compile_obj pva env)) + (cex (compile_obj pex env)) + (typcva (query_ctype cva)) + (typcex (query_ctype cex)) + ) + (and typcva typcex + (or (eq typcva typcex) + (error "setq incompatible type cod ~S~%.. cva ~S~%.. cex ~S~%" cod cva cex))) + (if (consp cex) (error "setq multi-expr cod ~S cex ~S" cod cex)) + (if (obj_var-p cva) + (build_obj_compute + cva + (if (listp cex) cex (list cex)) + typcex + ) + (make-obj_closetq + :cldest cva + :val cex) + ))) + + +(defmethod compile_obj ((cod prog_if) env) + (let ( (pcond (prog_if-cond_expr cod)) + (pthen (prog_if-then_expr cod)) + (pelse (prog_if-else_expr cod)) ) + (let ( (ocond (compile_obj pcond env)) + (othen (and pthen (compile_obj pthen env))) + (oelse (and pelse (compile_obj pelse env))) ) + (if (and othen oelse) + (let ( (thenctype (if othen (or (query_ctype othen) :value))) + (elsectype (if oelse (or (query_ctype oelse) :value))) ) + (or + (eq thenctype elsectype) + (eq thenctype ':void) + (eq elsectype ':void) + (warn "if incompatible type cod ~S~%.. othen ~S~%... thenctype ~S ~%.. oelse ~S~%... elsectype ~S~%" + cod othen thenctype oelse elsectype)))) + (make-obj_if + :ob_cond ocond + :ob_then othen + :ob_else oelse + ) + ))) + + + + +;;;;;;;;;;;;; parsing a source file +(defun ctime () + (multiple-value-bind + (second minute hour date month year day-of-week dst-p tz) + (get-decoded-time) + (format nil "~4,'0d ~a ~2,'0d @ ~2,'0d:~2,'0d:~2,'0d (GMT~@d)" + year (nth month '("???" "Jan" "Feb" "Mar" "Apr" "May" "Jun" + "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")) + date hour minute second tz)) +) + + +(defun compile_toplev (cod freshenv) + ;; if it is a definition, compile it + (if (prog_def-p cod) + (progn +; (format *error-output* "compile_toplev def cod=~S" cod) + (let ( (ce (compile_obj cod freshenv)) ) +; (format *error-output* "compile_toplev def ce=~S" cod) + (if ce (add_objcode ce)) + ) + ) + ;; not a definition, compile it appropriately and add it to the + ;; initial routine's body + (let* ( + (oldcurrout (compilation-currout this_compilation)) + (initrout (compilation-initrout this_compilation)) + (initbody (obj_routine-obody initrout)) + ) + (setf (compilation-currout this_compilation) initrout) +; (format *error-output* "compile_toplev avant compile_obj cod=~S~%" cod) + (let ( (ce (compile_obj cod freshenv)) ) +; (format *error-output* "compile_toplev apres compile_obj cod=~S ce=~S~%" cod ce) + (if ce (setf (obj_routine-obody initrout) + (append initbody (list ce)))) + ) + (setf (compilation-currout this_compilation) oldcurrout) + ))) + + +;; limit the CPU time to 1000 sec on Clisp +;; sometimes a clisp.run process remains.... eg when killing xemacs... +#+CLISP +(setf (posix:rlimit :cpu) (values 1000 1200)) + +(defun handle-source-file (filename) + (with-open-file + (istr filename) + (format *error-output* "reading file ~s ~%" filename) + (let ( (*readtable* (copy-readtable)) + (readrevseq nil) + (outpathname (make-pathname :name (pathname-name filename) :type "c")) + ) + (loop + (let ((rditem (read istr nil))) + (if (null rditem) + (return) + (push rditem readrevseq) + ) + ) + ) + (let* ( (readseq (reverse readrevseq)) + (initrout (make-obj_initroutine + :nbptr 3 + :nbnum 1 + :nbdouble 0 + :pfun 'init + :data2ptrhash (make-hash-table :size 281) + :inirou_datarankdict (make-hash-table :size 281) + )) + (thiscompil (make-compilation + :symboldict (make-hash-table) + :initrout initrout + )) + ) + (setq this_compilation thiscompil) + (with-open-file + (outstr outpathname :direction :output :if-exists :rename) + (format outstr "/* generated file ~a on ~a */~%#include \"run-basilys.h\"~%" outpathname (ctime)) + (format outstr "/*** read ~d inputs ***/ ~%~%" (length readseq)) + (loop + for rk from 1 + for curinp in readseq + do + (format_c_comment outstr "++ input #~d~%~S~% ++~%~%" rk curinp)) +; (finish-output outstr) + (format *error-output* "read ~d items from file ~s ~%" + (length readseq) filename) + (let ( (freshenv (cold_fresh_env cold_first_env)) + ) + (labels + ( (expand-task + (inp) + ; (cold_run_delayed_tasks "start expandtask") + (let* ( + (exp (cold_macroexpand inp freshenv)) ) + (cold_delay "normalize after expand" (normalize-task exp))) + ; (cold_run_delayed_tasks "end expandtask") + ) + (normalize-task + (exp) + ; (cold_run_delayed_tasks "start normalizetask") + (let ( (normexp (normalize_toplev exp freshenv)) ) + (cold_delay "compile after normalize" (compile-task normexp)) + ) + (cold_run_delayed_tasks "end normalizetask") + ) + (compile-task + (cod) + ; (cold_run_delayed_tasks "start compiletask") +; (finish-output outstr) + (compile_toplev cod freshenv) + (cold_run_delayed_tasks "end compiletask") + ) + ) + (mapc (lambda (inp) (cold_delay "initial expand" (expand-task inp))) readseq) + ) ;end of labels + (cold_run_delayed_tasks "initial") + ; output the declarations + (format *error-output* ";before writing ~d declarations ~g cpusec~%" + (length (compilation-revobjcode this_compilation)) + (cpusec)) + (loop + for rk from 1 + for ob in (reverse (compilation-revobjcode this_compilation)) + do + (format outstr "~%~%/*** declobj #~d ***/~%" rk) + (output_cdecl ob outstr) + ) + (cold_run_delayed_tasks "after decl") + ; output the bodies + (format *error-output* ";before writing ~d bodies ~g cpusecs~%" + (length (compilation-revobjcode this_compilation)) (cpusec)) + (loop + for rk from 1 + for ob in (reverse (compilation-revobjcode this_compilation)) + do + (if (zerop (rem rk 32)) + (format *error-output* ";;writing body #~d of ~a : ~g cpusecs~%" + rk (obj_routine-syname ob) (cpusec))) + (format outstr "~%~%~%/*** obj #~d ***/~%" rk) + (output_ccode ob outstr) +; (finish-output outstr) + ) + (cold_run_delayed_tasks "after bodies") + (finish-output outstr) + (format *error-output* ";before writing start routine ~g cpusecs~%" (cpusec)) + (cold_run_delayed_tasks "after initrout preparation") + (format outstr "~%~%/*** initial routine is ***/~%") + (output_cdecl initrout outstr) + (finish-output outstr) + (output_ccode initrout outstr) +; (finish-output outstr) + ) + (finish-output outstr) + (format outstr "~%~%/*** end of generated file ~a ***/~%~%" outpathname) + ) + (format *error-output* ";end of generation of ~S in ~g cpusecs- before basilys-gcc compilation~%" + outpathname (cpusec)) + (finish-output *error-output*) + #+CLISP + (progn + (ext:run-program "indent" :arguments (list outpathname)) + (ext:run-program "basilys-gcc" :arguments (list outpathname)) + ) + #+SBCL + (progn + (sb-ext:run-program "/usr/bin/indent" (list outpathname)) + (sb-ext:run-program "/home/basile/scripts/basilys-gcc" (list outpathname)) + ) + (format *error-output* ";end of basilys-gcc compilation of ~S in ~g cpusec~%" outpathname (cpusec)) + (finish-output *error-output*) + )))) + +(setq *print-circle* t) + + +;; eof $Id: cold-basilys.lisp 289 2008-02-07 22:07:30Z basile $ diff --git a/contrib/simple-probe.c b/contrib/simple-probe.c new file mode 100644 index 00000000000..96b51d78d2b --- /dev/null +++ b/contrib/simple-probe.c @@ -0,0 +1,1496 @@ +/* Simple probe example (with GTK) + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +/* +This standalone program is a simple compiler probe client - it is a +single source file using gtksourceview & gtk; it is not compiled by +the GCC building process. The compilation command is given near the +end of file (as a local.var to emacs) +*/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <sys/mman.h> +#include <ctype.h> + +#include <glib.h> +#include <glib/gprintf.h> +#include <gtk/gtk.h> +#include <gtk/gtktextbuffer.h> +#include <gtksourceview/gtksourceview.h> +#include <gtksourceview/gtksourcelanguage.h> +#include <gtksourceview/gtksourcelanguagesmanager.h> + +#define PROBE_PROTOCOL_NUMBER 200701 + +/* from /usr/share/xemacs21/xemacs-packages/etc/ediff/ediff-next.xpm */ +/* XPM */ +static const char *arrow_right_15x15_xpm[] = { +/* width height num_colors chars_per_pixel */ + "15 15 5 1", + " c Gray75 s backgroundToolBarColor", + ". c black", + "X c white", + "o c black", + "O c black", + " ", + " . ", + " .. ", + " .X. ", + " .......XX. ", + " .XXXXXXXoX. ", + " .XooooooooX. ", + " .Xoooooooooo. ", + " .XooooooooO. ", + " .oOOOOOOoO. ", + " .......OO. ", + " .O. ", + " .. ", + " . ", + " ", +}; +GdkPixbuf *arrow_right_15x15_pixbuf; + +/* from /usr/share/xemacs21/xemacs-packages/etc/smilies/indifferent.xpm */ +static const char *indifferent_13x14_xpm[] = { + "13 14 3 1", + " c None", + ". c #000000", + "+ c #FFDD00", + " ....... ", + " ..+++++.. ", + " .+++++++++. ", + ".+++++++++++.", + ".++..+++..++.", + ".++..+++..++.", + ".+++++++++++.", + ".+++++++++++.", + ".+++++++++++.", + ".++.......++.", + ".+++++++++++.", + " .+++++++++. ", + " ..+++++.. ", + " ....... " +}; +GdkPixbuf *indifferent_13x14_pixbuf; + +/* from /usr/share/xemacs21/xemacs-packages/lisp/speedbar/sb-info.xpm */ +/* XPM */ +static const char *sb_info_10x15_xpm[] = { + "10 15 4 1", + " c None", + ". c #BEBEBE", + "+ c #0000FF", + "@ c #FFFFFF", + " .. ", + " ..+++. ", + " .+++@++. ", + " .+++++++ ", + " .+++++++ ", + ".++@@@++++", + ".++++@++++", + ".++++@++++", + ".++++@++++", + " .+++@++++", + " .+++@+++ ", + " .+@@@@@+ ", + " .+++++++ ", + " .+++++ ", + " ++ " +}; +GdkPixbuf *sb_info_10x15_pixbuf; + +/* from /usr/share/xemacs21/xemacs-packages/etc/xwem/mini-info.xpm */ +/* XPM */ +static const char *mini_info_12x14_xpm[] = { +/* width height num_colors chars_per_pixel */ + "12 14 3 1", +/* colors */ + " c None", + ". c #cccc00", + "# c #dddd00", +/* pixels */ + " .#. ", + " ### ", + " .#. ", + " ", + " ... ", + ".###. ", + "..##. ", + " .##. ", + ".### ", + ".##. .# .# ", + ".##. ######", + "###.. #. #.", + "####. ####. ", + ".#.. .# ##." +}; +GdkPixbuf *mini_info_12x14_pixbuf; + + +/* from /usr/lib/sourcenav/share/bitmaps/key.xpm */ +/* XPM */ +const static char *key_7x11_xpm[] = { +/* width height num_colors chars_per_pixel */ + "7 11 3 1", +/* colors */ + " c None", + ". c black", + "X c #fefe00", +/* pixels */ + " ..... ", + ".XXXXX.", + ".XX.XX.", + ".XXXXX.", + " ..XX. ", + " .X. ", + " .XX. ", + " .X. ", + " .XX. ", + " .X. ", + " . " +}; +GdkPixbuf *key_7x11_pixbuf; + +/* from /usr/lib/sourcenav/share/bitmaps/tree.xpm */ +/* XPM */ +const static char *tree_24x24_xpm[] = { +/* width height ncolors cpp [x_hot y_hot] */ + "24 24 7 1 0 0", +/* colors */ + " s none m none c none", + ". s iconColor5 m black c blue", + "X s iconColor2 m white c white", + "o s iconColor4 m white c green", + "O s iconColor1 m black c black", + "+ s iconColor6 m white c yellow", + "@ s iconColor3 m black c red", +/* pixels */ + " ", + " ..... ", + " ..XXX. ", + " ooooo . ..... ", + " OOOOOOOOoXXXo. ", + " ooooo+ ", + " + ", + " ++++++ ", + " +XXX+ ", + " ++++++ ", + " @@@@@ + ", + " O@XXX@+ ", + " OOOOO O @@@@@ ", + " OXXXOO ", + " OOOOO O ..... ooooo ", + " O.XXX.ooooXXXo ", + " .....@ ooooo ", + " @ ", + " @ ", + " @@@@@ ", + " @XXX@ ", + " @@@@@ ", + " ", + " " +}; +GdkPixbuf *tree_24x24_pixbuf; + +#ifndef NDEBUG +FILE *dbgfile; +#define dbgprintf(Fmt, ...) do{if (dbgfile) { \ + fprintf(dbgfile,"+=simple-probe@%d:" Fmt "\n", (int)__LINE__, ##__VA_ARGS__); \ + fflush(dbgfile);}}while(0) +#else +#define dbgprintf(Fmt, ...) do{}while(0) +#endif + +#define SIMPLE_GTK_TEXTBUFFER(B) GTK_TEXT_BUFFER(B) + +GHashTable *action_table; + +GtkWidget *window, *vbox, *notebook, *mainlabel, *stabar; +GtkWidget *menubar, *versionlab, *aboutdialog; +GtkTextBuffer *tractxtbuf; /* the textbuffer for trace */ +GtkWidget *tracwindow; /* trace window */ +GtkWidget *tracbox; /* trace box */ +GtkWidget *traccheck; /* check button for scroll following */ +GtkWidget *tracscroll; /* the scrollbox for trace */ +GtkWidget *tracview; /* the textview for trace */ +GtkTextTagTable *tractagtbl; /* tag table for trace */ +GtkTextTag *tractag_tim; /* tag for time display & requests/commands counters */ +GtkTextTag *tractag_title; /* tag for title display */ +GtkTextTag *tractag_imp; /* tag for important display */ +GtkTextTag *tractag_in; /* tag for input display */ +GtkTextTag *tractag_out; /* tag for output display */ + +int trac_followout; /* flag toggled by traccheck to scroll output */ + +GtkSourceLanguagesManager *lang_mgr; + +struct fileinfo_st +{ + int fi_rank; /* positive index inside fileinfo_array */ + char *fi_path; /* strdup-ed file path */ + GtkWidget *fi_srcview; /* main source view */ + GtkSourceBuffer *fi_srcbuf; /* source buffer */ +}; +GPtrArray *fileinfo_array; + + +struct pointinfo_st +{ + int pi_rank; /* rank of this pointinfo in pointinfo_array */ + int pi_filenum; /* file number in fileinfo_array */ + int pi_line; /* line number */ + GtkTextChildAnchor *pi_txanchor; /* text anchor */ + GtkWidget *pi_txbutton; /* button (in text) inside anchor */ +}; +GPtrArray *pointinfo_array; + +struct dialogitem_st +{ + int di_rank; /* rank of this item in the dialog menu */ + struct infodialog_st *di_dialog; /* owning info dialog */ +}; + +struct infodialog_st +{ + int id_rank; /* rank of this infodialog in infodialog_array */ + int id_pinfrank; /* originating point info rank */ + GtkWidget *id_dialog; /* the dialog widget */ + GtkWidget *id_showcombo; /* the combo widget to show */ + GtkWidget *id_menubar; /* the mavigation menubar inside the widget */ + GtkWidget *id_infolab; /* the information label inside the dialog */ + GPtrArray *id_showitems; /* array of dialogitem-s for show combo */ + GPtrArray *id_navitems; /* array dialogitem-s for navigation */ + GtkWidget *id_navtitle; /* the navigation title item in menubar */ + GtkWidget *id_navmenu; /* the navigation menu */ + GtkTooltips *id_tooltips; /* the dialog tooltips */ +}; +GPtrArray *infodialog_array; + + +guint stid_pass; + +typedef void action_handler_t (GString * act, void *data); + +struct action_entry_st +{ + action_handler_t *handler; + void *data; +}; + +/* requests are from probe to compiler, single line */ +static void requestprintf (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void +register_action (const char *action, action_handler_t * handler, void *data) +{ + struct action_entry_st *ae = g_malloc0 (sizeof (struct action_entry_st)); + ae->handler = handler; + ae->data = data; + g_assert (action_table != 0); + g_hash_table_insert (action_table, g_strdup (action), ae); +} + +/*** + * decode an encoded string, return the malloc-ed string and fil *PLEN + * with its length and *PEND with the ending pointer + ***/ +static char * +decode_string (const char *s, int *plen, char **pend) +{ + char *res = 0; + int len = 0, pos = 0, ix = 0; + if (!s) + return (char *) 0; + if (sscanf (s, " STR%d'%n", &len, &pos) > 0 && pos > 0) + { + res = g_malloc0 (len + 1); + s += pos; + for (ix = 0; ix < len; ix++) + { + char c = *s; + if (c == '%') + { + int d = 0; + char c1, c2; + if ((c1 = s[1]) && isxdigit (c1) + && (c2 = s[2]) && isxdigit (c2)) + { + d = (((c1 >= '0' && c1 <= '9') ? (c1 - '0') + : (c1 >= 'A' && c1 <= 'F') ? (10 + c1 - 'A') + : (c1 >= 'a' && c1 <= 'f') ? (10 + c1 - 'a') + : 0) << 4) + + ((c2 >= '0' && c2 <= '9') ? (c2 - '0') + : (c2 >= 'A' && c2 <= 'F') ? (10 + c2 - 'A') + : (c2 >= 'a' && c2 <= 'f') ? (10 + c2 - 'a') : 0); + res[ix] = (char) d; + s += 3; + } + else + goto error; + } + else if (c == '+') + { + res[ix] = ' '; + s++; + } + else if (c > ' ' && c != '\'' && c != '\"') + { + res[ix] = c; + s++; + } + else + goto error; + }; + if (*s != '\'') + goto error; + s++; + if (plen) + *plen = len; + if (pend) + *pend = (char *) s; + return res; + } +error: + if (res) + g_free (res); + return 0; +} + + +/*** follow the trace window by scrolling to end ***/ +void +trac_follow_end () +{ + if (trac_followout && tracview) + { + GtkTextIter titer; + gtk_text_buffer_get_end_iter (tractxtbuf, &titer); + gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (tracview), &titer, + /*margin */ 0.05, + /*usalign */ FALSE, + /*xalign */ 0.0, + /* yalign */ 0.9); + } +} + +gboolean +delayed_follow_end_oncecb (gpointer data) +{ + g_assert (data == NULL); + trac_follow_end (); + if (tractxtbuf && tracview) + gtk_widget_show (tracview); + return FALSE; /* remove this idle callback immediately */ +} + +/**************************** actions **************************/ + + +static void +message_act (GString * s, void *d) +{ + char *msg = 0, *end = 0; + int pos = 0, len = 0; + g_assert (d != s); /* just to use the arguments */ + dbgprintf ("message action %s", s->str); + if (sscanf (s->str, " PROB_message msg: %n", &pos) >= 0 && pos > 0) + msg = decode_string (s->str + pos, &len, &end); + if (msg) + { + gtk_statusbar_pop (GTK_STATUSBAR (stabar), stid_pass); + gtk_statusbar_push (GTK_STATUSBAR (stabar), stid_pass, msg); + gtk_widget_show (stabar); + g_free (msg); + } + else + dbgprintf ("invalid message action %s", s->str); +} + +static void +version_act (GString * s, void *d) +{ + char *msg = 0, *markup = 0, *end = 0; + int pos = -1, len = 0, protonum = 0; + g_assert (d != s); /* just to use the arguments */ + dbgprintf ("version action %s", s->str); + if (sscanf (s->str, " PROB_version proto: %d msg:%n", &protonum, &pos) >= 0 + && pos > 0) + msg = decode_string (s->str + pos, &len, &end); + if (protonum != PROBE_PROTOCOL_NUMBER) + { + dbgprintf ("invalid protocol number %d expecting %d", protonum, + PROBE_PROTOCOL_NUMBER); + exit (1); + } + if (msg) + { + markup = + g_markup_printf_escaped + ("<small>(protocol %d)</small> - GCC " + "<span style='italic' foreground='darkgreen'>" "%s" "</span>", + protonum, msg); + gtk_label_set_markup (GTK_LABEL (versionlab), markup); + gtk_widget_show_all (window); + g_free (markup); + } + else + dbgprintf ("invalid version action (pos%d protonum%d no msg): %s", + pos, protonum, s->str); + +} + + +static void +file_act (GString * s, void *d) +{ + int filerank = -1, pos = -1, len = 0; + int fd = -1; + char *file_path = 0, *end = 0; + gchar *basename = 0; + gchar *mime_type = 0; + char *suffix = 0, *markup = 0; + GtkSourceLanguage *language = NULL; + GtkSourceBuffer *srcbuf = NULL; + GtkWidget *srcview = NULL; + GtkWidget *scrolwin = NULL; + GtkWidget *label = NULL; + GtkWidget *tablab = NULL; + GtkWidget *box = NULL; + struct stat filestat; + struct fileinfo_st *filinf = NULL; + const gchar *fcontent = 0; + size_t filesize = 0; + size_t mapsize = 0; + static size_t pgsiz; + g_assert (d != s); /* just to use the arguments */ + memset (&filestat, 0, sizeof (filestat)); + if (sscanf (s->str, " PROB_file rank: %d fpath: %n", &filerank, &pos) + > 0 && filerank >= 0 && pos > 0) + { + file_path = decode_string (s->str + pos, &len, &end); + if ((fd = open (file_path, O_RDONLY)) < 0) + { + dbgprintf ("failed to open %s : %m", file_path); + return; + } + basename = g_path_get_basename ((const gchar *) file_path); + suffix = g_strrstr (basename, (const gchar *) "."); + if (!strcmp (suffix, ".cc") + || !strcmp (suffix, ".cxx") + || !strcmp (suffix, ".cpp") + || !strcmp (suffix, ".cp") + || !strcmp (suffix, ".ii") + || !strcmp (suffix, ".CPP") + || !strcmp (suffix, ".hh") + || !strcmp (suffix, ".hxx") + || !strcmp (suffix, ".hpp") + || !strcmp (suffix, ".C") || !strcmp (suffix, ".H")) + mime_type = "text/x-c++src"; + else if (!strcmp (suffix, ".c") + || !strcmp (suffix, ".i") || !strcmp (suffix, ".h")) + mime_type = "text/x-csrc"; + else if (!strcmp (suffix, ".f") + || !strcmp (suffix, ".F") + || !strcmp (suffix, ".FOR") + || !strcmp (suffix, ".F77") + || !strcmp (suffix, ".f77") + || !strcmp (suffix, ".F95") + || !strcmp (suffix, ".f95") + || !strcmp (suffix, ".F90") + || !strcmp (suffix, ".f90") || !strcmp (suffix, ".for")) + mime_type = "text/x-fortran"; + else if (!strcmp (suffix, ".adb") + || !strcmp (suffix, ".ads") || !strcmp (suffix, ".ada")) + mime_type = "text/x-ada"; + if (!mime_type) + mime_type = "text/x-c++src"; + dbgprintf ("file %s mimetype %s", file_path, mime_type); + if (!fstat (fd, &filestat)) + filesize = filestat.st_size; + language = + gtk_source_languages_manager_get_language_from_mime_type (lang_mgr, + mime_type); + g_assert (language != NULL); + srcbuf = gtk_source_buffer_new_with_language (language); + srcview = gtk_source_view_new_with_buffer (srcbuf); + g_object_set (G_OBJECT (srcview), "editable", FALSE, NULL); + gtk_source_buffer_set_highlight (srcbuf, TRUE); + gtk_source_buffer_begin_not_undoable_action (srcbuf); + if (!pgsiz) + pgsiz = getpagesize (); + if (filesize > (off_t) 0) + { + gchar *convcont = 0; + gsize convsize = 0; + mapsize = filesize; + if (mapsize % pgsiz) + mapsize = (filesize | (pgsiz - 1)) + 1; + fcontent = (const gchar *) mmap ((void *) 0, mapsize, PROT_READ, + MAP_SHARED, fd, (off_t) 0); + if (fcontent != MAP_FAILED) + { + convcont = + g_locale_to_utf8 (fcontent, filesize, NULL, &convsize, + (GError **) 0); + g_assert (convcont); + if (convcont) + gtk_text_buffer_set_text (SIMPLE_GTK_TEXTBUFFER (srcbuf), + convcont, convsize); + g_free (convcont); + munmap ((char *) fcontent, mapsize); + fcontent = 0; + } + else + fprintf (stderr, "mmap file %s size %ld failed: %m\n", + file_path, filesize); + }; + close (fd); + gtk_source_buffer_end_not_undoable_action (srcbuf); + gtk_source_view_set_show_line_numbers (GTK_SOURCE_VIEW (srcview), TRUE); + gtk_source_view_set_show_line_markers (GTK_SOURCE_VIEW (srcview), TRUE); + markup = g_markup_printf_escaped + ("<span weight=\"bold\" size=\"larger\">%d</span>\n" + "<small><tt>%s</tt></small>", filerank, basename); + tablab = gtk_label_new ((char *) 0); + gtk_label_set_markup (GTK_LABEL (tablab), markup); + g_free (markup); + label = gtk_label_new ((char *) 0); + markup = g_markup_printf_escaped + ("<span weight=\"bold\" size=\"larger\">#%d</span>\n" + "<span color='navy' style='italic'>file " + "<small><tt>%s</tt></small>\n" + "of %ld bytes</span>", filerank, file_path, (long) filesize); + gtk_label_set_markup (GTK_LABEL (label), markup); + g_free (markup); + g_free (basename); + basename = suffix = markup = NULL; + scrolwin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolwin), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (scrolwin), srcview); + box = gtk_vbox_new (FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), scrolwin, TRUE, TRUE, 1); + gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), box, tablab, + (gint) filerank); + if (fileinfo_array->len <= filerank) + g_ptr_array_set_size (fileinfo_array, 5 * filerank / 4 + 16); + filinf = g_malloc0 (sizeof (*filinf)); + g_assert (g_ptr_array_index (fileinfo_array, filerank) == NULL); + g_ptr_array_index (fileinfo_array, filerank) = filinf; + filinf->fi_rank = filerank; + filinf->fi_path = g_strdup (file_path); + filinf->fi_srcview = srcview; + filinf->fi_srcbuf = srcbuf; + gtk_source_view_set_marker_pixbuf (GTK_SOURCE_VIEW (srcview), "info", + sb_info_10x15_pixbuf); + gtk_widget_show_all (window); + g_free (file_path); + } +} + +/* GTK callback called when an info dialog is responded */ +static void +infodialog_cb (GtkWidget * widget, int respid, gpointer data) +{ + struct infodialog_st *dia = data; + g_assert (dia && dia->id_dialog == widget); + switch (respid) + { + case GTK_RESPONSE_ACCEPT: + requestprintf ("prob_UPDATEINFODIALOG dia:%d\n", dia->id_rank); + break; + case GTK_RESPONSE_CLOSE: + default: + requestprintf ("prob_REMOVEINFODIALOG dia:%d\n", dia->id_rank); + gtk_widget_hide (dia->id_dialog); + break; + } +} + +/* internal routine to create a new info dialog (still empty and not + displayed) */ +static struct infodialog_st * +make_infodialog (struct pointinfo_st *pi) +{ + int ix = 0, k; + struct infodialog_st *dia = NULL; + struct fileinfo_st *fi = NULL; + GtkWidget *dialog = NULL, *hbox = NULL, *menubar = NULL, *combo = NULL, + *showlabel = NULL, *pointlabel = NULL, *infolabel = NULL, + *infoscroll = NULL; + GtkTooltips *tooltips = NULL; + char titbuf[64]; + char *pointmarkup = 0; + g_assert (pi != NULL && pi->pi_rank >= 0 + && pi->pi_rank < pointinfo_array->len); + g_assert (g_ptr_array_index (pointinfo_array, pi->pi_rank) == pi); + g_assert (pi->pi_filenum >= 0 && fileinfo_array + && pi->pi_filenum < fileinfo_array->len); + fi = g_ptr_array_index (fileinfo_array, pi->pi_filenum); + dia = g_malloc0 (sizeof (*dia)); + memset (titbuf, 0, sizeof (titbuf)); + ix = -1; + if (infodialog_array) + { + for (k = 0; k < infodialog_array->len; k++) + if (!g_ptr_array_index (infodialog_array, k)) + { + ix = k; + break; + } + } + if (ix >= 0) + { + dia->id_rank = ix; + g_ptr_array_index (infodialog_array, ix) = dia; + } + else + { + dia->id_rank = infodialog_array->len; + g_ptr_array_add (infodialog_array, dia); + } + dbgprintf ("make_infodialog dia %p rank %d", dia, dia->id_rank); + dia->id_pinfrank = pi->pi_rank; + snprintf (titbuf, sizeof (titbuf) - 1, "InfoPt#%d", dia->id_rank); + dialog = dia->id_dialog + = gtk_dialog_new_with_buttons + (titbuf, + GTK_WINDOW (window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_HOME, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + tooltips = dia->id_tooltips = gtk_tooltips_new (); + pointlabel = gtk_label_new ((char *) 0); + pointmarkup = g_markup_printf_escaped + ("<span size='large' foreground='darkgreen'>" + "info point #%d" "</span>\n" + "<b>file #%d</b> <tt>%s</tt> <i>line %d</i>", + dia->id_rank, pi->pi_filenum, fi->fi_path, pi->pi_line); + gtk_label_set_markup (GTK_LABEL (pointlabel), pointmarkup); + g_free (pointmarkup); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + pointlabel, /*expand: */ FALSE, /*fill: */ FALSE, + 1); + hbox = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + hbox, /*expand: */ FALSE, /*fill: */ FALSE, + 1); + showlabel = gtk_label_new ((char *) 0); + gtk_label_set_markup (GTK_LABEL (showlabel), + "<span foreground='navy' weight='bold'>" + "show:" "</span>"); + gtk_box_pack_start (GTK_BOX (hbox), showlabel, + /*expand: */ FALSE, /*fill: */ FALSE, + 1); + combo = dia->id_showcombo = gtk_combo_box_new_text (); + gtk_tooltips_set_tip (tooltips, combo, + "Select information to show", + "Choose the information to show in this dialog\n" + "for this info point"); + gtk_box_pack_start (GTK_BOX (hbox), combo, + /*expand: */ TRUE, /*fill: */ TRUE, + 1); + menubar = dia->id_menubar = gtk_menu_bar_new (); + gtk_tooltips_set_tip (tooltips, menubar, + "Navigation menu", + "Choose where to go in this dialog\n" + "for this info point"); + gtk_box_pack_start (GTK_BOX (hbox), menubar, + /*expand: */ FALSE, /*fill: */ FALSE, + 2); + infoscroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (infoscroll), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + dia->id_infolab = infolabel = gtk_label_new ((char *) 0); + gtk_label_set_markup (GTK_LABEL (infolabel), + "<span size='large' foreground='darkred'>" + "* select info to show *" "</span>\n"); + gtk_label_set_selectable (GTK_LABEL (infolabel), TRUE); + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (infoscroll), + infolabel); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + infoscroll, /*expand: */ TRUE, /*fill: */ TRUE, 1); + dia->id_showitems = g_ptr_array_sized_new (6); + g_signal_connect (G_OBJECT (dialog), + "response", G_CALLBACK (infodialog_cb), dia); + dbgprintf ("make_infodialog dia %p rank %d", dia, dia->id_rank); + return dia; +} + + +/* GTK callback called when an info button is clicked; should create a + dialog and ask it to be filled */ +static void +txinfobutton_cb (GtkWidget * widget, gpointer data) +{ + struct pointinfo_st *pi = data; + struct infodialog_st *dia = NULL; + g_assert (pi && pi->pi_txbutton == widget); + dia = make_infodialog (pi); + requestprintf ("prob_NEWINFODIALOG pt:%d dia:%d\n", + pi->pi_rank, dia->id_rank); +} + + +/* GTK callback called when about information has been asked */ +static void +aboutwin_cb (GtkWidget * widget, gpointer data) +{ + if (!aboutdialog) + { + aboutdialog = gtk_about_dialog_new (); + gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog), + "GCC simple compiler probe"); + gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (aboutdialog), + "Copyright (C) 2007 Free Software Foundation, Inc"); + gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (aboutdialog), + "GNU General Public License version 2 or later"); + gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (aboutdialog), + "http://gcc.gnu.org/"); + gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog), + "A simple compiler probe to be used with GCC\n" + " [Gnu Compiler Collection] \n" + "with its -fcompiler-probe option\n" + "(simple-probe built " __DATE__ "@" + __TIME__ ")"); + }; + gtk_dialog_run (GTK_DIALOG (aboutdialog)); +} + + +static void +infopoint_act (GString * s, void *d) +{ + int filerk = 0; + int lineno = 0; + int infonum = 0; + struct fileinfo_st *filinf = NULL; + struct pointinfo_st *pi = NULL; + char *filepath = NULL; + GtkTextIter txiter; + GtkSourceBuffer *srcbuf = NULL; + GtkWidget *srcview = NULL; + GtkWidget *txbutton = NULL; + GtkTextChildAnchor *anch = NULL; + g_assert (s != d); + if (sscanf + (s->str, " PROB_infopoint fil:%d lin:%d rk:%d", &filerk, &lineno, + &infonum) > 0 && infonum >= 0) + { + dbgprintf ("infopoint act filerk %d lineno %d infonum %d", + filerk, lineno, infonum); + memset (&txiter, 0, sizeof (txiter)); + if (filerk >= 0 && filerk < fileinfo_array->len) + filinf = g_ptr_array_index (fileinfo_array, filerk); + if (!filinf) + return; + if (pointinfo_array->len <= infonum) + g_ptr_array_set_size (pointinfo_array, 5 * infonum / 4 + 16); + if (g_ptr_array_index (pointinfo_array, infonum) != NULL) + return; + filepath = filinf->fi_path; + g_assert (filepath); + srcbuf = filinf->fi_srcbuf; + srcview = filinf->fi_srcview; + g_assert (srcbuf); + pi = g_malloc0 (sizeof (struct pointinfo_st)); + g_ptr_array_index (pointinfo_array, infonum) = pi; + pi->pi_rank = infonum; + pi->pi_filenum = filerk; + pi->pi_line = lineno; + gtk_text_buffer_get_iter_at_line (GTK_TEXT_BUFFER (srcbuf), &txiter, + lineno - 1); + anch = + gtk_text_buffer_create_child_anchor (GTK_TEXT_BUFFER (srcbuf), + &txiter); + txbutton = gtk_button_new (); + gtk_button_set_image (GTK_BUTTON (txbutton), + gtk_image_new_from_pixbuf (key_7x11_pixbuf)); + gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (srcview), txbutton, + anch); + gtk_widget_show_all (txbutton); + gtk_widget_show_all (srcview); + gtk_widget_show_all (window); + pi->pi_txanchor = anch; + pi->pi_txbutton = txbutton; + g_signal_connect (G_OBJECT (txbutton), "clicked", + G_CALLBACK (txinfobutton_cb), pi); + } + else + dbgprintf ("invalid infopoint_act %s", s->str); +} + +/* GTK callback of show items */ +static void +showcombochanged_cb (GtkComboBox * combo, struct infodialog_st *dia) +{ + gint rk = -1; + g_assert (combo && dia && dia->id_showcombo == GTK_WIDGET (combo)); + rk = gtk_combo_box_get_active (combo); + if (rk >= 0) + requestprintf ("prob_SHOWINFODIALOG dia:%d ch:%d\n", dia->id_rank, rk); +} + +static void +dialogchoice_act (GString * s, void *d) +{ + int diark = -1, pos = -1, len = 0, chrk = -1; + char *end = 0, *msg = 0; + struct infodialog_st *dia = NULL; + struct dialogitem_st *itm = NULL; + g_assert (s != d); + dbgprintf ("dialogchoice_act start %s", s->str); + if (sscanf + (s->str, " PROB_dialogchoice dia: %d msg: %n", &diark, &pos) > 0 + && diark >= 0 && pos > 0) + { + dbgprintf ("dialogchoice_act diark%d", diark); + if (!infodialog_array || diark >= infodialog_array->len) + return; + dia = g_ptr_array_index (infodialog_array, diark); + if (!dia || dia->id_rank != diark) + return; + dbgprintf ("dialogchoice_act dia %p", dia); + msg = decode_string (s->str + pos, &len, &end); + if (sscanf (end, " ch: %d", &chrk) <= 0 || chrk < 0) + { + g_free (msg); + return; + } + itm = g_malloc0 (sizeof (*itm)); + itm->di_rank = chrk; + itm->di_dialog = dia; + g_ptr_array_add (dia->id_showitems, itm); + gtk_combo_box_insert_text (GTK_COMBO_BOX (dia->id_showcombo), chrk, + msg); + g_signal_connect (G_OBJECT (dia->id_showcombo), "changed", + G_CALLBACK (showcombochanged_cb), (gpointer) dia); + g_free (msg); + dbgprintf ("dialogchoice_act done dia %p", dia); + } +} + + +static void +dialogcontent_act (GString * s, void *d) +{ + int diark = -1, pos = -1; + struct infodialog_st *dia = NULL; + char *ps = 0; + g_assert (s != d); + if (sscanf (s->str, " PROB_dialogcontent dia: %d %n", &diark, &pos) > 0 + && diark >= 0 && pos > 0) + { + dbgprintf ("dialogcontent_act diark%d", diark); + if (!infodialog_array || diark >= infodialog_array->len) + return; + dia = g_ptr_array_index (infodialog_array, diark); + if (!dia || dia->id_rank != diark) + return; + ps = s->str + pos; + dbgprintf ("dialogcontent_act dia %p", dia); + gtk_label_set_text (GTK_LABEL (dia->id_infolab), ps); + /* destroy the navigation items & menu */ + if (dia->id_navitems) + { + g_ptr_array_free (dia->id_navitems, TRUE); + dia->id_navitems = NULL; + } + if (dia->id_navmenu) + { + gtk_object_destroy (GTK_OBJECT (dia->id_navmenu)); + dia->id_navmenu = NULL; + } + if (dia->id_navtitle) + { + gtk_object_destroy (GTK_OBJECT (dia->id_navtitle)); + dia->id_navtitle = NULL; + } + } +} + +static void +showdialog_act (GString * s, void *d) +{ + int diark = -1; + struct infodialog_st *dia = NULL; + g_assert (s != d); + if (sscanf (s->str, " PROB_showdialog dia:%d", &diark) > 0 && diark >= 0) + { + dbgprintf ("showdialog_act diark%d", diark); + if (!infodialog_array || diark >= infodialog_array->len) + return; + dia = g_ptr_array_index (infodialog_array, diark); + if (!dia || dia->id_rank != diark) + return; + dbgprintf ("showdialog_act dia %p", dia); + gtk_widget_show_all (dia->id_dialog); + } +} + + +/*GTK callback for dialog navigation items */ +static void +navigitem_cb (GtkMenuItem * menuitem, gpointer data) +{ + struct dialogitem_st *itm = data; + g_assert (itm != 0 && itm->di_dialog); + requestprintf ("prob_NAVIGINFODIALOG dia:%d nav:%d\n", + itm->di_dialog->id_rank, itm->di_rank); + +} + + +static void +dialognavig_act (GString * s, void *d) +{ + int diark = -1, pos = -1, len = 0, navrk = -1; + char *end = 0, *msg = 0; + struct infodialog_st *dia = NULL; + struct dialogitem_st *itm = NULL; + GtkWidget *menuitem = NULL, *sepitem = NULL, *navigitem = NULL; + g_assert (s != d); + dbgprintf ("dialognavig_act start %s", s->str); + if (sscanf + (s->str, " PROB_dialognavig dia: %d msg: %n", &diark, &pos) > 0 + && diark >= 0 && pos > 0) + { + dbgprintf ("dialognavig_act diark%d", diark); + if (!infodialog_array || diark >= infodialog_array->len) + return; + dia = g_ptr_array_index (infodialog_array, diark); + if (!dia || dia->id_rank != diark) + return; + dbgprintf ("dialognavig_act dia %p", dia); + msg = decode_string (s->str + pos, &len, &end); + if (sscanf (end, " nav: %d", &navrk) <= 0 || navrk < 0) + { + dbgprintf ("dialognavig_act bad end %s", end); + g_free (msg); + return; + } + itm = g_malloc0 (sizeof (*itm)); + dbgprintf ("dialognavig_act navrk %d msg %s", navrk, msg); + itm->di_rank = navrk; + itm->di_dialog = dia; + if (!dia->id_navitems) + dia->id_navitems = g_ptr_array_sized_new (6); + g_ptr_array_add (dia->id_navitems, itm); + menuitem = gtk_menu_item_new_with_label (msg); + if (!dia->id_navmenu) + { + dia->id_navmenu = gtk_menu_new (); + dbgprintf ("dialognavig_act navmenu %p", dia->id_navmenu); + sepitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (dia->id_navmenu), sepitem); + g_assert (GTK_IS_MENU_SHELL (dia->id_menubar)); + navigitem = dia->id_navtitle = + gtk_menu_item_new_with_label ("navigation"); + gtk_menu_shell_append (GTK_MENU_SHELL (dia->id_menubar), navigitem); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (navigitem), + dia->id_navmenu); + gtk_widget_show (dia->id_navmenu); + } + gtk_menu_shell_append (GTK_MENU_SHELL (dia->id_navmenu), menuitem); + gtk_widget_show (menuitem); + g_free (msg); + msg = NULL; + g_signal_connect (G_OBJECT (menuitem), + "activate", G_CALLBACK (navigitem_cb), itm); + dbgprintf ("dialognavig_act done dia %p", dia); + } +} + + +static void +destroydialog_act (GString * s, void *d) +{ + int diark = -1; + struct infodialog_st *dia = NULL; + g_assert (s != d); + if (sscanf (s->str, " PROB_destroydialog dia: %d", &diark) > 0 + && diark >= 0) + { + dbgprintf ("destroydialog_act diark%d", diark); + if (!infodialog_array || diark >= infodialog_array->len) + return; + dia = g_ptr_array_index (infodialog_array, diark); + if (!dia || dia->id_rank != diark) + return; + dbgprintf ("destroydialog_act dia %p", dia); + if (dia->id_dialog) + gtk_widget_hide (dia->id_dialog); + if (dia->id_navitems) + { + g_ptr_array_free (dia->id_navitems, TRUE); + dia->id_navitems = NULL; + } + if (dia->id_navmenu) + { + gtk_object_destroy (GTK_OBJECT (dia->id_navmenu)); + dia->id_navmenu = NULL; + } + if (dia->id_navtitle) + { + gtk_object_destroy (GTK_OBJECT (dia->id_navtitle)); + dia->id_navtitle = NULL; + } + gtk_object_destroy (GTK_OBJECT (dia->id_dialog)); + g_ptr_array_free (dia->id_showitems, TRUE); + memset (dia, 0, sizeof (dia)); + g_ptr_array_index (infodialog_array, diark) = NULL; + g_free (dia); + dbgprintf ("destroydialog_act done diark%d", diark); + } +} + +/*********************** request & trace ***********************/ +static void +insert_trace_time (int dated, const char *buf) +{ + struct + { + char buf[200]; + GTimeVal tv; + struct tm tm; + char sec[10]; + } t; + time_t tim; + GtkTextIter itend; + memset (&t, 0, sizeof (t)); + memset (&itend, 0, sizeof (itend)); + g_get_current_time (&t.tv); + tim = t.tv.tv_sec; + localtime_r (&tim, &t.tm); + strftime (t.buf, sizeof (t.buf) - 10, dated ? " %G %b %d @ %T" : " %T", + &t.tm); + sprintf (t.sec, ".%03d ", (int) t.tv.tv_usec / 1000); + strcat (t.buf, t.sec); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), &itend); + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, "\n", -1, + tractag_tim, (void *) 0); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), &itend); + if (buf) + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, buf, -1, + tractag_tim, (void *) 0); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), &itend); + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, t.buf, -1, + tractag_tim, (void *) 0); +} + + +static void +requestprintf (const char *fmt, ...) +{ + va_list ar; + gchar *buf = 0; + gint len = 0; + static int nbreq; + GtkTextIter itend; + char bufn[64]; + va_start (ar, fmt); + nbreq++; + len = g_vasprintf (&buf, (const gchar *) fmt, ar); + va_end (ar); + dbgprintf ("begin requestprintf %.30s", fmt); + if (tractxtbuf) + { + memset (&itend, 0, sizeof (itend)); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + memset (bufn, 0, sizeof (bufn)); + snprintf (bufn, sizeof (bufn) - 1, "!request %d:", nbreq); + insert_trace_time (0, bufn); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, buf, len, + tractag_out, (void *) 0); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + }; + fputs (buf, stdout); + if (len <= 0 || buf[len - 1] != '\n') + { + putchar ('\n'); + if (tractxtbuf) + gtk_text_buffer_insert (tractxtbuf, &itend, "\n", 1); + }; + fflush (stdout); + if (tractxtbuf) + { + trac_follow_end (); + gtk_widget_show_all (tracwindow); + } + dbgprintf ("request #%d: %s\n", nbreq, buf); + g_free (buf); + if (tractxtbuf && trac_followout) + g_idle_add (delayed_follow_end_oncecb, (void *) 0); + buf = 0; +} + +static gboolean +ioreader (GIOChannel * chan, GIOCondition cond, gpointer data) +{ + gchar *end = 0, *line = 0; + gsize len = 0; + gsize eolpos = 0; + GIOStatus stat = 0; + GError *err = 0; + GString *str = 0; + int leftmagic = 0, rightmagic = 0, pos = 0; + char verb[64]; + char bufn[48]; + static int nbcmd; + g_assert (cond == G_IO_IN); + line = end = 0; + len = eolpos = 0; + dbgprintf ("ioreader begin"); + stat = g_io_channel_read_line (chan, &line, &len, &eolpos, &err); + dbgprintf ("ioreader stat %d", stat); + if (stat == G_IO_STATUS_NORMAL) + { + if (line[0] == '!' + && sscanf (line, "!#%x/%X[%n", &leftmagic, &rightmagic, &pos) >= 2 + && rightmagic != 0 && pos > 0) + { /* multi-line command */ + str = g_string_sized_new (1000 + eolpos); + str = g_string_append (str, line + pos); + g_free (line); + line = 0; + while ((stat = + g_io_channel_read_line (chan, &line, &len, &eolpos, + &err)) == G_IO_STATUS_NORMAL) + { + int left, right; + left = right = pos = 0; + if (line[0] == '!' + && sscanf (line, "!#%x/%X] %n", &left, &right, &pos) >= 2 + && pos > 0 && left == leftmagic && right == rightmagic + && line[pos] == '\0') + { + g_free (line); + line = 0; + break; + }; + str = g_string_append (str, line); + g_free (line); + line = 0; + + }; + } + else + { /* ordinary single line command */ + str = g_string_sized_new (1000 + eolpos); + str = g_string_append (str, line); + g_free (line); + line = 0; + } + } + if (str && str->len == 1 && str->str[0] == '\n') + return TRUE; + nbcmd++; + dbgprintf ("command #%d: %s\n", nbcmd, str->str); + if (tractxtbuf) + { + GtkTextIter itend; + memset (&itend, 0, sizeof (itend)); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + memset (bufn, 0, sizeof (bufn)); + snprintf (bufn, sizeof (bufn) - 1, "?command %d:", nbcmd); + insert_trace_time (0, bufn); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, str->str, + str->len, tractag_in, (void *) 0); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + if (str->len > 0 && str->str[str->len - 1] != '\n') + gtk_text_buffer_insert (tractxtbuf, &itend, "\n", 1); + trac_follow_end (); + }; + memset (verb, 0, sizeof (verb)); + if (str && sscanf (str->str, " %62[a-zA-Z0-9_] ", verb) > 0) + { + struct action_entry_st *ae = g_hash_table_lookup (action_table, verb); + dbgprintf ("command verb %s", verb); + if (ae && ae->handler) + { + (*ae->handler) (str, ae->data); + if (tractxtbuf) + trac_follow_end (); + } + else if (tractxtbuf) + { + static char unknownmsg[200]; + GtkTextIter itend; + memset (&itend, 0, sizeof (itend)); + gtk_text_buffer_get_end_iter (SIMPLE_GTK_TEXTBUFFER (tractxtbuf), + &itend); + memset (unknownmsg, 0, sizeof (unknownmsg)); + snprintf (unknownmsg, sizeof (unknownmsg) - 1, + "*?* unknown command verb '%s'\n", verb); + dbgprintf ("*? unknown command verb '%s'", verb); + gtk_text_buffer_insert_with_tags (tractxtbuf, &itend, + unknownmsg, strlen (unknownmsg), + tractag_tim, (void *) 0); + trac_follow_end (); + } + if (tractxtbuf) + gtk_widget_show_all (tracwindow); + } + else + dbgprintf ("invalid command string %s", str->str); + if (str) + g_string_free (str, TRUE); + if (tractxtbuf && trac_followout) + g_idle_add (delayed_follow_end_oncecb, (void *) 0); + str = 0; + /* remove the handler on eof */ + dbgprintf ("stat=%d isnormal=%d", stat, stat != G_IO_STATUS_EOF); + /* the function should return FALSE if the event source should be removed. */ + return stat != G_IO_STATUS_EOF; +} + +static void +destroy_cb (GtkWidget * widget, gpointer data) +{ + requestprintf ("prob_STOP\n"); + gtk_main_quit (); +} + +static void +tracdestroy_cb (GtkWidget * widget, gpointer data) +{ + g_assert (widget == tracwindow); + tracwindow = (void *) 0; + tracbox = (void *) 0; + tracscroll = (void *) 0; + tracview = (void *) 0; + tractagtbl = (void *) 0; + tractag_tim = tractag_title = tractag_imp = tractag_in = tractag_out = 0; + tractxtbuf = 0; +} + + +static GtkItemFactoryEntry menu_items[] = { + {"/_File", NULL, NULL, 0, "<Branch>"}, + {"/File/_Quit", "<CTRL>Q", gtk_main_quit, 0, "<StockItem>", GTK_STOCK_QUIT}, + {"/_Help", NULL, NULL, 0, "<LastBranch>"}, + {"/_Help/About", NULL, aboutwin_cb, 0, "<Item>"}, +}; + +/* Returns a menubar widget made from the above menu */ +static GtkWidget * +get_menubar_menu (GtkWidget * window) +{ + GtkItemFactory *item_factory; + GtkAccelGroup *accel_group; + + /* Make an accelerator group (shortcut keys) */ + accel_group = gtk_accel_group_new (); + + /* Make an ItemFactory (that makes a menubar) */ + item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", + accel_group); + + /* This function generates the menu items. Pass the item factory, + the number of items in the array, the array itself, and any + callback data for the the menu items. */ + gtk_item_factory_create_items (item_factory, + sizeof (menu_items) / sizeof (menu_items[0]), + menu_items, NULL); + + /* Attach the new accelerator group to the window. */ + gtk_window_add_accel_group (GTK_WINDOW (window), accel_group); + + /* Finally, return the actual menu bar created by the item factory. */ + return gtk_item_factory_get_widget (item_factory, "<main>"); +} + +static void +trac_toggled_cb (GtkWidget * w, void *data) +{ + trac_followout = !trac_followout; + trac_follow_end (); +} + +int +main (int argc, char *argv[]) +{ + GIOChannel *chan = 0; + GtkSourceLanguagesManager *lm; + guint inputio; + int traced = 0, ix; + GError *err = 0; + char buf[200]; + char hn[64]; + /* initialization */ + gtk_init (&argc, &argv); + for (ix = 1; ix < argc; ix++) + { + if (!strcmp (argv[ix], "--traced") || !strcmp (argv[ix], "-T")) + traced = 1; +#ifndef NDEBUG + if (!strcmp (argv[ix], "--debug") || !strcmp (argv[ix], "-D")) + dbgfile = stderr; +#endif + } + arrow_right_15x15_pixbuf = + gdk_pixbuf_new_from_xpm_data (arrow_right_15x15_xpm); + indifferent_13x14_pixbuf = + gdk_pixbuf_new_from_xpm_data (indifferent_13x14_xpm); + sb_info_10x15_pixbuf = gdk_pixbuf_new_from_xpm_data (sb_info_10x15_xpm); + mini_info_12x14_pixbuf = gdk_pixbuf_new_from_xpm_data (mini_info_12x14_xpm); + key_7x11_pixbuf = gdk_pixbuf_new_from_xpm_data (key_7x11_xpm); + tree_24x24_pixbuf = gdk_pixbuf_new_from_xpm_data (tree_24x24_xpm); + action_table = g_hash_table_new (g_str_hash, g_str_equal); + lm = gtk_source_languages_manager_new (); + chan = g_io_channel_unix_new (STDIN_FILENO); + g_io_channel_set_encoding (chan, (const gchar *) "latin1", &err); + inputio = g_io_add_watch (chan, G_IO_IN, ioreader, (gpointer) 0); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (window), 1); + gtk_window_set_default_size (GTK_WINDOW (window), 450, 300); + gtk_window_set_title (GTK_WINDOW (window), "simple GCC probe"); + vbox = gtk_vbox_new (FALSE, 2); + gtk_container_add (GTK_CONTAINER (window), vbox); + menubar = get_menubar_menu (window); + gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, TRUE, 1); + gethostname (hn, sizeof (hn)); + snprintf (buf, sizeof (buf), "GCC simple probe pid %d on %s", + (int) getpid (), hn); + buf[sizeof (buf) - 1] = 0; + fileinfo_array = g_ptr_array_sized_new (200); + pointinfo_array = g_ptr_array_sized_new (400); + infodialog_array = g_ptr_array_sized_new (300); + mainlabel = gtk_label_new (buf); + gtk_box_pack_start (GTK_BOX (vbox), mainlabel, FALSE, FALSE, 1); + versionlab = gtk_label_new ((char *) 0); + gtk_label_set_selectable (GTK_LABEL (versionlab), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), versionlab, FALSE, FALSE, 1); + notebook = gtk_notebook_new (); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 1); + stabar = gtk_statusbar_new (); + stid_pass = + gtk_statusbar_get_context_id (GTK_STATUSBAR (stabar), "passctx"); + gtk_statusbar_push (GTK_STATUSBAR (stabar), stid_pass, "no pass"); + gtk_box_pack_start (GTK_BOX (vbox), stabar, FALSE, FALSE, 1); + lang_mgr = gtk_source_languages_manager_new (); + g_signal_connect (G_OBJECT (window), "destroy", + G_CALLBACK (destroy_cb), NULL); + register_action ("PROB_destroydialog", destroydialog_act, (void *) 0); + register_action ("PROB_dialogchoice", dialogchoice_act, (void *) 0); + register_action ("PROB_dialogcontent", dialogcontent_act, (void *) 0); + register_action ("PROB_dialognavig", dialognavig_act, (void *) 0); + register_action ("PROB_file", file_act, (void *) 0); + register_action ("PROB_infopoint", infopoint_act, (void *) 0); + register_action ("PROB_message", message_act, (void *) 0); + register_action ("PROB_showdialog", showdialog_act, (void *) 0); + register_action ("PROB_version", version_act, (void *) 0); + if (traced) + { + char buf[100]; + memset (buf, 0, sizeof (buf)); + snprintf (buf, sizeof (buf) - 1, "GCC simple probe trace pid %ld", + (long) getpid ()); + tracwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (tracwindow), 500, 400); + g_signal_connect (G_OBJECT (tracwindow), "destroy", + G_CALLBACK (tracdestroy_cb), NULL); + gtk_container_set_border_width (GTK_CONTAINER (tracwindow), 1); + gtk_window_set_title (GTK_WINDOW (tracwindow), "simple GCC trace"); + tracbox = gtk_vbox_new (FALSE, 2); + dbgprintf ("tracbox %p", tracbox); + traccheck = + gtk_check_button_new_with_label ("autoscroll follow output"); + g_signal_connect (traccheck, "toggled", G_CALLBACK (trac_toggled_cb), + NULL); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (traccheck), 1); + tracscroll = gtk_scrolled_window_new (0, 0); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tracscroll), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (tracwindow), tracbox); + gtk_box_pack_start (GTK_BOX (tracbox), gtk_label_new (buf), FALSE, + FALSE, 1); + gtk_box_pack_start (GTK_BOX (tracbox), traccheck, FALSE, FALSE, 1); + tractagtbl = gtk_text_tag_table_new (); + dbgprintf ("tractagtbl %p", tractagtbl); + tractxtbuf = gtk_text_buffer_new (tractagtbl); + dbgprintf ("tractxtbuf %p", tractxtbuf); + tractag_tim = gtk_text_buffer_create_tag (tractxtbuf, "tim", + "weight", PANGO_WEIGHT_BOLD, + "scale", PANGO_SCALE_SMALL, + "foreground", + "DarkGoldenrod4", (void *) 0); + tractag_title = + gtk_text_buffer_create_tag (tractxtbuf, "title", "scale", + PANGO_SCALE_X_LARGE, "foreground", "red", + (void *) 0); + tractag_imp = + gtk_text_buffer_create_tag (tractxtbuf, "imp", "scale", + PANGO_SCALE_LARGE, "weight", + PANGO_WEIGHT_BOLD, "foreground", "red", + (void *) 0); + tractag_in = + gtk_text_buffer_create_tag (tractxtbuf, "in", "foreground", "blue", + (void *) 0); + tractag_out = + gtk_text_buffer_create_tag (tractxtbuf, "out", "style", + PANGO_STYLE_ITALIC, "foreground", + "darkgreen", (void *) 0); + tracview = gtk_text_view_new_with_buffer (tractxtbuf); + dbgprintf ("tracview %p", tracview); + gtk_text_view_set_editable (GTK_TEXT_VIEW (tracview), FALSE); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tracview), GTK_WRAP_CHAR); + dbgprintf ("tracscroll %p", tracscroll); + gtk_container_add (GTK_CONTAINER (tracscroll), tracview); + dbgprintf ("tracbox %p", tracbox); + gtk_box_pack_start (GTK_BOX (tracbox), tracscroll, TRUE, TRUE, 1); + insert_trace_time (1, "TRACE [compiled " __DATE__ "@" __TIME__ "]: "); + gtk_widget_show_all (tracwindow); + }; + gtk_widget_show_all (window); + gtk_main (); + return 0; +} + +/**** for emacs + ++ Local Variables: ++ + ++ compilation-directory: "." ++ + ++ compile-command: "gcc -Wall -O -g $(pkg-config --cflags --libs gtksourceview-1.0 gtk+-2.0) -o $HOME/bin/simple-probe simple-probe.c" ++ + ++ End: ++ + ****/ + +/* eof simple-probe.c */ diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 9c91fb5fab6..990b7d81bd0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -194,6 +194,9 @@ build/gengtype-lex.o-warn = -Wno-error # SYSCALLS.c misses prototypes SYSCALLS.c.X-warn = -Wno-strict-prototypes -Wno-error +## basilys.c contain tricky stuff +basilys.o-warn = -Wno-error + # All warnings have to be shut off in stage1 if the compiler used then # isn't gcc; configure determines that. WARN_CFLAGS will be either # $(GCC_WARN_CFLAGS), or nothing. @@ -278,6 +281,17 @@ ZLIBINC = @zlibinc@ GMPLIBS = @GMPLIBS@ GMPINC = @GMPINC@ +### for Basilys +# How to find PPL (Parma Polyhedra Library) +PPLLIBS = @ppllibs@ +PPLINC = @pplinc@ + +# How to file LTDL (LibTool DynLoader) +LTDLLIBS = @ltdllibs@ +LTDLINC = @ltdlinc@ +LTDL_LDFLAGS= @ltdl_ldflags@ +#### end of Basilys stuff + CPPLIB = ../libcpp/libcpp.a CPPINC = -I$(srcdir)/../libcpp/include @@ -658,7 +672,7 @@ COMPILERS = cc1$(exeext) @all_compilers@ # List of things which should already be built whenever we try to use xgcc # to compile anything (without linking). -GCC_PASSES=xgcc$(exeext) cc1$(exeext) specs $(EXTRA_PASSES) +GCC_PASSES=xgcc$(exeext) cc1$(exeext) specs compile-basilys-defs $(EXTRA_PASSES) # Directory to link to, when using the target `maketest'. DIR = ../gcc @@ -873,7 +887,8 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY) # How to link with both our special library facilities # and the system's installed libraries. -LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) +LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) \ + $(PPLLIBS) $(GMPLIBS) $(LTDLLIBS) $(GMPLIBS) # Any system libraries needed just for GNAT. SYSLIBS = @GNAT_LIBEXC@ @@ -898,6 +913,7 @@ BUILD_ERRORS = build/errors.o # libintl.h will be found in ../intl if we are using the included libintl. INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ -I$(srcdir)/../include @INCINTL@ \ + $(PPLINC) $(LTDLINC) \ $(CPPINC) $(GMPINC) $(DECNUMINC) .c.o: @@ -1003,6 +1019,7 @@ OBJS-common = \ alias.o \ alloc-pool.o \ auto-inc-dec.o \ + basilys.o \ bb-reorder.o \ bitmap.o \ bt-load.o \ @@ -1250,7 +1267,8 @@ OBJS = $(OBJS-common) $(OBJS-md) $(OBJS-archive) OBJS-onestep = libbackend.o $(OBJS-archive) -BACKEND = main.o @TREEBROWSER@ libbackend.a $(CPPLIB) $(LIBDECNUMBER) +COMPILER_PROBE_OBJ = @COMPILER_PROBE@ +BACKEND = main.o @TREEBROWSER@ $(COMPILER_PROBE_OBJ) libbackend.a $(CPPLIB) $(LIBDECNUMBER) MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \ @@ -1262,6 +1280,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \ protoize$(exeext) unprotoize$(exeext) \ $(SPECS) collect2$(exeext) \ + compile-basilys-defs \ gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \ *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a libgcc.mk @@ -1553,7 +1572,7 @@ gcc-cross$(exeext): xgcc$(exeext) dummy-checksum.o : dummy-checksum.c cc1-dummy$(exeext): $(C_OBJS) dummy-checksum.o $(BACKEND) $(LIBDEPS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) dummy-checksum.o \ + $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LTDL_LDFLAGS) -o $@ $(C_OBJS) dummy-checksum.o \ $(BACKEND) $(LIBS) $(GMPLIBS) cc1-checksum.c : cc1-dummy$(exeext) build/genchecksum$(build_exeext) @@ -1562,7 +1581,7 @@ cc1-checksum.c : cc1-dummy$(exeext) build/genchecksum$(build_exeext) cc1-checksum.o : cc1-checksum.c cc1$(exeext): $(C_OBJS) cc1-checksum.o $(BACKEND) $(LIBDEPS) - $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) cc1-checksum.o \ + $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LTDL_LDFLAGS) -o $@ $(C_OBJS) cc1-checksum.o \ $(BACKEND) $(LIBS) $(GMPLIBS) # @@ -2322,6 +2341,12 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ $(MACHMODE_H) $(TARGET_DEF_H) $(TARGET_H) $(GGC_H) gt-targhooks.h \ $(OPTABS_H) +#### added for Basilys +basilys.o: basilys.c \ + $(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) $(TM_H) $(TREE_H) $(GGC_H) \ + tree-pass.h basilys.h gt-basilys.h +### end of Basilys stuff + toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ version.h $(RTL_H) $(FUNCTION_H) $(FLAGS_H) xcoffout.h input.h \ $(INSN_ATTR_H) output.h $(DIAGNOSTIC_H) debug.h insn-config.h intl.h \ @@ -3099,6 +3124,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/dojump.c \ $(srcdir)/emit-rtl.c $(srcdir)/except.c $(srcdir)/explow.c $(srcdir)/expr.c \ $(srcdir)/function.c $(srcdir)/except.h \ + $(srcdir)/basilys.h \ $(srcdir)/gcse.c $(srcdir)/integrate.c $(srcdir)/lists.c $(srcdir)/optabs.c \ $(srcdir)/profile.c $(srcdir)/regclass.c \ $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/cfglayout.h \ @@ -3116,6 +3142,8 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/tree-ssa-structalias.c $(srcdir)/tree-parloops.c \ $(srcdir)/omp-low.c $(srcdir)/varpool.c \ $(srcdir)/targhooks.c $(out_file) $(srcdir)/passes.c $(srcdir)/cgraphunit.c \ + $(patsubst %.o, $(srcdir)/%.c, $(COMPILER_PROBE_OBJ) ) \ + $(srcdir)/basilys.c \ @all_gtfiles@ GTFILES_H = $(subst /,-, $(patsubst $(srcdir)/%,gt-%, $(patsubst %.c,%.h, \ @@ -4464,3 +4492,11 @@ po/gcc.pot: force $(MAKE) srcextra AWK=$(AWK) $(SHELL) $(srcdir)/po/exgettext \ $(XGETTEXT) gcc $(srcdir) + + +## definition for basilys internal compilation +compile-basilys-defs: + echo '#generated compile-basilys-defs' > $@ + echo 'ALL_CFLAGS="' $(ALL_CFLAGS) '"' >> $@ + echo 'ALL_CPPFLAGS="' -I$(PWD) $(ALL_CPPFLAGS) '"' >> $@ +### end of basilys stuff
\ No newline at end of file diff --git a/gcc/basic-block.h b/gcc/basic-block.h index c04c6f6ee53..c04ef896102 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -335,6 +335,20 @@ enum bb_flags BB_NONTHREADABLE_BLOCK = 1 << 11 }; + +/* Basile adds a flag to accept RTL basic blocks in some special code + (like the compiler probe); declared in compiler-probe.h if enabled; + used to disable some asserts of BB_RTL flags in some + tree-flow-inline.h functons */ +#if ENABLE_COMPILER_PROBE +extern int comprobe_bb_ok_rtl; +#else +#define comprobe_bb_ok_rtl 0 +#endif /*ENABLE_COMPILER_PROBE*/ + + + + /* Dummy flag for convenience in the hot/cold partitioning code. */ #define BB_UNPARTITIONED 0 diff --git a/gcc/basilys.c b/gcc/basilys.c new file mode 100644 index 00000000000..fbad1b7295c --- /dev/null +++ b/gcc/basilys.c @@ -0,0 +1,5645 @@ +/* Basile's static analysis (should have a better name) basilys.c + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + Indented with GNU indent + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + */ + +/* for debugging -fbasilys-debug is useful */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "obstack.h" +#include "tm.h" +#include "tree.h" +#include "tree-pass.h" +#include "tree-dump.h" +#include "basic-block.h" +#include "timevar.h" +#include "errors.h" +#include "ggc.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "flags.h" +#include "toplev.h" +#include "options.h" +#include "params.h" +#include "real.h" +#include "prefix.h" + +#include "compiler-probe.h" + + +#if HAVE_PARMAPOLY +#include <ppl_c.h> +#else +#error required parma polyedral library PPL +#endif /*HAVE_PARMAPOLY */ + +#if HAVE_LIBTOOLDYNL +#include <ltdl.h> +#else +#error required libtool dynamic loader library LTDL +#endif /*HAVE_LIBTOOLDYNL */ + +#include "basilys.h" + + +#define MINOR_SIZE_KILOWORD PARAM_VALUE(PARAM_BASILYS_MINOR_ZONE) +#define FULL_FREQ PARAM_VALUE(PARAM_BASILYS_FULL_FREQ) + +/* *INDENT-OFF* */ +basilys_ptr_t basilys_globarr[BGLOB__LASTGLOB]; +void* basilys_startalz=NULL; +void* basilys_endalz; +char* basilys_curalz; +void** basilys_storalz; + +struct callframe_basilys_st* basilys_topframe; +struct basilyslocalsptr_st* basilys_localtab; +struct basilysspecial_st* basilys_newspeclist; +struct basilysspecial_st* basilys_oldspeclist; +unsigned long basilys_kilowords_sincefull; +/* number of full & any basilys garbage collections */ +unsigned long basilys_nb_full_garbcoll; +unsigned long basilys_nb_garbcoll; +void* basilys_touched_cache[BASILYS_TOUCHED_CACHE_SIZE]; +bool basilys_prohibit_garbcoll; + +long basilys_dbgcounter; + +void (*basilys_extra_scanrout_p)(void); + +int basilys_last_global_ix = BGLOB__LASTGLOB; + +/* our copying garbage collector needs a vector of basilys_ptr_t to + scan and an hashtable of basilys_ptr_t which are local variables + copied into GGC heap; */ +static GTY(()) VEC(basilys_ptr_t,gc) *bscanvec; + + +struct basilocalsptr_st GTY(()) { + unsigned char lenix; /* length is prime, this is the index of length */ + int nbent; + basilys_ptr_t GTY((length("basilys_primtab[%h.lenix]"))) ptrtab[FLEXIBLE_DIM]; +}; + +static GTY(()) struct basilocalsptr_st* blocaltab; + + + + +/* *INDENT-ON* */ + +/* to code case ALL_OBMAG_SPECIAL_CASES: */ +#define ALL_OBMAG_SPECIAL_CASES \ + OBMAG_SPEC_FILE: \ + case OBMAG_SPEC_MPFR: \ + case OBMAG_SPECPPL_COEFFICIENT: \ + case OBMAG_SPECPPL_LINEAR_EXPRESSION: \ + case OBMAG_SPECPPL_CONSTRAINT: \ + case OBMAG_SPECPPL_CONSTRAINT_SYSTEM: \ + case OBMAG_SPECPPL_GENERATOR: \ + case OBMAG_SPECPPL_GENERATOR_SYSTEM + +/* Obstack used for reading names */ +static struct obstack bname_obstack; + + +/* random data for generating hashcodes */ +static struct drand48_data randata; + +long +basilys_lrand (void) +{ + long lh = 0; + lrand48_r (&randata, &lh); + return lh; +} + + +static inline void +delete_special (struct basilysspecial_st *sp) +{ + switch (sp->discr->object_magic) + { + case OBMAG_SPEC_FILE: + if (sp->val.sp_file) + { + fclose (sp->val.sp_file); + sp->val.sp_file = NULL; + }; + break; + case OBMAG_SPEC_MPFR: + if (sp->val.sp_mpfr) + { + mpfr_clear (sp->val.sp_mpfr); + free (sp->val.sp_mpfr); + sp->val.sp_mpfr = NULL; + }; + break; + case OBMAG_SPECPPL_COEFFICIENT: + if (sp->val.sp_coefficient) + ppl_delete_Coefficient (sp->val.sp_coefficient); + sp->val.sp_coefficient = NULL; + break; + case OBMAG_SPECPPL_LINEAR_EXPRESSION: + if (sp->val.sp_linear_expression) + ppl_delete_Linear_Expression (sp->val.sp_linear_expression); + sp->val.sp_linear_expression = NULL; + break; + case OBMAG_SPECPPL_CONSTRAINT: + if (sp->val.sp_constraint) + ppl_delete_Constraint (sp->val.sp_constraint); + sp->val.sp_constraint = NULL; + break; + case OBMAG_SPECPPL_CONSTRAINT_SYSTEM: + if (sp->val.sp_constraint_system) + ppl_delete_Constraint_System (sp->val.sp_constraint_system); + sp->val.sp_constraint_system = NULL; + break; + case OBMAG_SPECPPL_GENERATOR: + if (sp->val.sp_generator) + ppl_delete_Generator (sp->val.sp_generator); + sp->val.sp_generator = NULL; + break; + case OBMAG_SPECPPL_GENERATOR_SYSTEM: + if (sp->val.sp_generator_system) + ppl_delete_Generator_System (sp->val.sp_generator_system); + sp->val.sp_generator_system = NULL; + break; + default: + break; + } +} + +#define FORWARDED_DISCR (basilysobject_ptr_t)1 +static basilys_ptr_t forwarded_copy (basilys_ptr_t); + +#ifdef ENABLE_CHECKING +/* only for debugging, to be set from the debugger */ +static void *bstrangelocal; +static long nbaddlocalptr; + +static FILE *debughack_file; +void *basilys_checkedp_ptr1; +void *basilys_checkedp_ptr2; + +#endif + + +static inline void * +forwarded (void *ptr) +{ + basilys_ptr_t p = ptr; + if (p && basilys_is_young (p)) + { + if (p->u_discr == FORWARDED_DISCR) + p = ((struct basilysforward_st *) p)->forward; + else + p = forwarded_copy (p); + } + return p; +} + +#if ENABLE_CHECKING +#define FORWARDED(P) do {if (P) { \ + if (debughack_file) \ + fprintf(debughack_file,"%s:%d forwarded %p\n", \ + basename(__FILE__), __LINE__, (void*)(P)); \ + (P) = forwarded((P));} } while(0) +#else +#define FORWARDED(P) do {if (P) { \ + (P) = forwarded((P));} } while(0) +#endif +static void scanning (basilys_ptr_t); + + +static void +add_localptr (basilys_ptr_t p) +{ + HOST_WIDE_INT ix; + int h, k; + long primsiz = basilys_primtab[blocaltab->lenix]; + if (!p) + return; +#ifdef ENABLE_CHECKING + nbaddlocalptr++; + if (p == bstrangelocal) + { + debugeprintf ("adding #%ld bstrangelocal %p", nbaddlocalptr, + (void *) p); + } +#endif + gcc_assert ((void *) p != (void *) FORWARDED_DISCR); + gcc_assert (primsiz > 0); + ix = (HOST_WIDE_INT) p; + ix ^= ((HOST_WIDE_INT) p) >> 11; + ix &= 0x3fffffff; + h = (int) ix % primsiz; + for (k = h; k < primsiz; k++) + { + if (!blocaltab->ptrtab[k]) + { + blocaltab->ptrtab[k] = p; + blocaltab->nbent++; + return; + } + else if (blocaltab->ptrtab[k] == p) + return; + } + for (k = 0; k < h; k++) + { + if (!blocaltab->ptrtab[k]) + { + blocaltab->ptrtab[k] = p; + blocaltab->nbent++; + return; + } + else if (blocaltab->ptrtab[k] == p) + return; + } + /* the only way to reach this point is that blocaltab is + full; this should never happen, since it was allocated bigger + than the number of locals! */ + gcc_unreachable (); +} + + +#if ENABLE_CHECKING +/*** + * check our call frames + ***/ +static inline void +check_pointer_at (const char msg[], long count, basilys_ptr_t * pptr, + const char *filenam, int lineno) +{ + basilys_ptr_t ptr = *pptr; + if (!ptr) + return; + if (!ptr->u_discr) + fatal_error + ("<%s#%ld> corrupted pointer %p (at %p) without discr at %s:%d", msg, + count, (void *) ptr, (void *) pptr, basename (filenam), lineno); + switch (ptr->u_discr->object_magic) + { + case OBMAG_OBJECT: + case OBMAG_DECAY: + case OBMAG_BOX: + case OBMAG_MULTIPLE: + case OBMAG_CLOSURE: + case OBMAG_ROUTINE: + case OBMAG_LIST: + case OBMAG_PAIR: + case OBMAG_TRIPLE: + case OBMAG_INT: + case OBMAG_MIXINT: + case OBMAG_REAL: + case OBMAG_STRING: + case OBMAG_STRBUF: + case OBMAG_TREE: + case OBMAG_BASICBLOCK: + case OBMAG_EDGE: + case OBMAG_MAPOBJECTS: + case OBMAG_MAPTREES: + case OBMAG_MAPSTRINGS: + case OBMAG_MAPBASICBLOCKS: + case OBMAG_MAPEDGES: + case ALL_OBMAG_SPECIAL_CASES: + break; + default: + fatal_error ("<%s#%ld> bad pointer %p (at %p) bad magic %d at %s:%d", + msg, count, (void *) ptr, (void *) pptr, + (int) ptr->u_discr->object_magic, basename (filenam), + lineno); + } +} + +static long nbcheckcallframes; +static long thresholdcheckcallframes; + + +void +basilys_check_call_frames_at (int noyoungflag, const char *msg, + const char *filenam, int lineno) +{ + struct callframe_basilys_st *cfram = NULL; + int nbfram = 0, nbvar = 0; + nbcheckcallframes++; + if (!msg) + msg = "/"; + if (thresholdcheckcallframes > 0 + && nbcheckcallframes > thresholdcheckcallframes) + { + debugeprintf + ("start check_call_frames#%ld {%s} from %s:%d", + nbcheckcallframes, msg, basename (filenam), lineno); + } + for (cfram = basilys_topframe; cfram != NULL; cfram = cfram->prev) + { + int varix = 0; + nbfram++; + if (cfram->clos) + { + if (noyoungflag && basilys_is_young (cfram->clos)) + fatal_error + ("bad frame <%s#%ld> unexpected young closure %p in frame %p at %s:%d", + msg, nbcheckcallframes, + (void *) cfram->clos, (void *) cfram, basename (filenam), + lineno); + + check_pointer_at (msg, nbcheckcallframes, + (basilys_ptr_t *) (void *) &cfram->clos, filenam, + lineno); + if (cfram->clos->discr->object_magic != OBMAG_CLOSURE) + fatal_error + ("bad frame <%s#%ld> invalid closure %p in frame %p at %s:%d", + msg, nbcheckcallframes, + (void *) cfram->clos, (void *) cfram, basename (filenam), + lineno); + } + for (varix = ((int) cfram->nbvar) - 1; varix >= 0; varix--) + { + nbvar++; + if (noyoungflag && cfram->varptr[varix] != NULL + && basilys_is_young (cfram->varptr[varix])) + fatal_error + ("bad frame <%s#%ld> unexpected young pointer %p in frame %p at %s:%d", + msg, nbcheckcallframes, (void *) cfram->varptr[varix], + (void *) cfram, basename (filenam), lineno); + + check_pointer_at (msg, nbcheckcallframes, &cfram->varptr[varix], + filenam, lineno); + } + } + if (thresholdcheckcallframes > 0 + && nbcheckcallframes > thresholdcheckcallframes) + debugeprintf ("end check_call_frames#%ld {%s} %d frames/%d vars %s:%d", + nbcheckcallframes, msg, nbfram, nbvar, basename (filenam), + lineno); + if (debughack_file) + { + fprintf (debughack_file, + "check_call_frames#%ld {%s} %d frames/%d vars %s:%d\n", + nbcheckcallframes, msg, nbfram, nbvar, basename (filenam), + lineno); + fflush (debughack_file); + } +} + +void +basilys_caught_assign_at (void *ptr, const char *fil, int lin) +{ + if (debughack_file) + { + fprintf (debughack_file, "caught assign %p at %s:%d\n", ptr, + basename (fil), lin); + fflush (debughack_file); + } + debugeprintf ("caught assign %p at %s:%d", ptr, basename (fil), lin); +} + +static long nbcbreak; + +void +basilys_cbreak_at (const char *msg, const char *fil, int lin) +{ + nbcbreak++; + if (debughack_file) + { + fprintf (debughack_file, "CBREAK#%ld AT %s:%d - %s\n", nbcbreak, + basename (fil), lin, msg); + fflush (debughack_file); + }; + debugeprintf_raw ("%s:%d: CBREAK#%ld %s\n", basename (fil), lin, nbcbreak, + msg); +} + +#endif + +/*** + * our copying garbage collector + ***/ +void +basilys_garbcoll (size_t wanted, bool needfull) +{ + long primix = 0; + int locdepth = 0; + int nbloc = 0; + int nbglob = 0; + int locsiz = 0; + int ix = 0; + struct callframe_basilys_st *cfram = NULL; + basilys_ptr_t *storp = NULL; + struct basilysspecial_st *specp = NULL; + struct basilysspecial_st **prevspecptr = NULL; + struct basilysspecial_st *nextspecp = NULL; + if (basilys_prohibit_garbcoll) + fatal_error ("basilys garbage collection prohibited"); + basilys_nb_garbcoll++; +#if ENABLE_CHECKING +#warning debug message garbcoll start + if (debughack_file) + { + fprintf (debughack_file, "%s:%d start garbcoll #%ld", + basename (__FILE__), __LINE__, basilys_nb_garbcoll); + fflush (debughack_file); + } +#endif + basilys_check_call_frames (BASILYS_ANYWHERE, "before garbage collection"); + gcc_assert ((char *) basilys_startalz < (char *) basilys_endalz); + gcc_assert ((char *) basilys_curalz >= (char *) basilys_startalz + && (char *) basilys_curalz < (char *) basilys_storalz); + gcc_assert ((char *) basilys_storalz < (char *) basilys_endalz); + bscanvec = VEC_alloc (basilys_ptr_t, gc, 1024 + 32 * MINOR_SIZE_KILOWORD); + wanted += wanted / 4 + MINOR_SIZE_KILOWORD * 1000; + wanted |= 0x3fff; + wanted++; + if (wanted < MINOR_SIZE_KILOWORD * sizeof (void *) * 1024) + wanted = MINOR_SIZE_KILOWORD * sizeof (void *) * 1024; + /* compute number of locals and depth of call stack */ + nbglob = BGLOB__LASTGLOB; + for (cfram = basilys_topframe; cfram != NULL; cfram = cfram->prev) + { + locdepth++; + /* we should never have more than a few thousand locals in a + call frame, so we check this */ + gcc_assert (cfram->nbvar < (int) BASILYS_MAXNBLOCALVAR); + nbloc += cfram->nbvar; + } + locsiz = 200 + (5 * (locdepth + nbloc + nbglob + 100)) / 4; + locsiz |= 0xff; + for (primix = 5; + basilys_primtab[primix] > 0 + && basilys_primtab[primix] <= locsiz; primix++); + locsiz = basilys_primtab[primix]; + gcc_assert (locsiz > 10); + blocaltab = + ggc_alloc_cleared (sizeof (struct basilocalsptr_st) + + locsiz * sizeof (void *)); + blocaltab->lenix = primix; + for (ix = 0; ix < BGLOB__LASTGLOB; ix++) + FORWARDED (basilys_globarr[ix]); + if (basilys_extra_scanrout_p) + (*basilys_extra_scanrout_p) (); + for (cfram = basilys_topframe; cfram != NULL; cfram = cfram->prev) + { + int varix; + if (cfram->clos) + { + FORWARDED (cfram->clos); + add_localptr ((basilys_ptr_t) (cfram->clos)); + } + for (varix = ((int) cfram->nbvar) - 1; varix >= 0; varix--) + { + if (!cfram->varptr[varix]) + continue; + FORWARDED (cfram->varptr[varix]); + add_localptr (cfram->varptr[varix]); + } + }; + /* scan the store list */ + for (storp = (basilys_ptr_t *) basilys_storalz; + (char *) storp < (char *) basilys_endalz; storp++) + { + if (*storp) + scanning (*storp); + } + memset (basilys_touched_cache, 0, sizeof (basilys_touched_cache)); + /* sort of Chesney loop */ + while (!VEC_empty (basilys_ptr_t, bscanvec)) + { + basilys_ptr_t p = VEC_pop (basilys_ptr_t, bscanvec); + if (!p) + continue; +#if ENABLE_CHECKING + if (debughack_file) + fprintf (debughack_file, "chesney scan %p\n", (void *) p); +#endif + scanning (p); + } + /* delete every unmarked special on the new list and clear it */ + for (specp = basilys_newspeclist; specp; specp = specp->nextspec) + { + gcc_assert (basilys_is_young (specp)); + if (specp->mark) + continue; + delete_special (specp); + } + basilys_newspeclist = NULL; + /* free the previous young zone and allocate a new one */ +#if ENABLE_CHECKING + if (debughack_file) + { + fprintf (debughack_file, + "%s:%d free previous young %p - %p GC#%ld\n", + basename (__FILE__), __LINE__, basilys_startalz, + basilys_endalz, basilys_nb_garbcoll); + fflush (debughack_file); + } + memset (basilys_startalz, 0, + (char *) basilys_endalz - (char *) basilys_startalz); +#endif + free (basilys_startalz); + basilys_startalz = basilys_endalz = basilys_curalz = NULL; + basilys_storalz = NULL; + basilys_kilowords_sincefull += wanted / (1024 * sizeof (void *)); + if (basilys_kilowords_sincefull > + (unsigned long) MINOR_SIZE_KILOWORD * FULL_FREQ) + needfull = TRUE; + basilys_startalz = basilys_curalz = + xcalloc (sizeof (void *), wanted / sizeof (void *)); + basilys_endalz = (char *) basilys_curalz + wanted; + basilys_storalz = ((void **) basilys_endalz) - 2; + if (needfull) + { + bool wasforced = ggc_force_collect; + basilys_nb_full_garbcoll++; + debugeprintf ("basilys_garbcoll #%ld fullgarbcoll #%ld", + basilys_nb_garbcoll, basilys_nb_full_garbcoll); + /* clear marks on the old spec list */ + for (specp = basilys_oldspeclist; specp; specp = specp->nextspec) + specp->mark = 0; + /* force major collection */ + ggc_force_collect = true; + ggc_collect (); + ggc_force_collect = wasforced; + /* delete the unmarked spec */ + prevspecptr = &basilys_oldspeclist; + for (specp = basilys_oldspeclist; specp; specp = nextspecp) + { + nextspecp = specp->nextspec; + if (specp->mark) + { + prevspecptr = &specp->nextspec; + continue; + } + delete_special (specp); + memset (specp, 0, sizeof (*specp)); + ggc_free (specp); + *prevspecptr = nextspecp; + } + basilys_kilowords_sincefull = 0; + } + ggc_free (blocaltab); + blocaltab = NULL; + ggc_free (bscanvec); + bscanvec = NULL; + basilys_check_call_frames (BASILYS_NOYOUNG, "after garbage collection"); +#if ENABLE_CHECKING +#warning debug message garbcoll end + if (debughack_file) + { + fprintf (debughack_file, "%s:%d end %s garbcoll #%ld", + basename (__FILE__), __LINE__, + needfull ? "full" : "minor", basilys_nb_garbcoll); + fflush (debughack_file); + } +#endif +} + + +static basilys_ptr_t +forwarded_copy (basilys_ptr_t p) +{ + basilys_ptr_t n = 0; + int mag = 0; + gcc_assert (basilys_is_young (p)); + gcc_assert (p->u_discr && p->u_discr != FORWARDED_DISCR); + if (p->u_discr->obj_class == FORWARDED_DISCR) + mag = + ((basilysobject_ptr_t) + (((struct basilysforward_st *) p->u_discr)->forward))->object_magic; + else + mag = p->u_discr->object_magic; + switch (mag) + { + case OBMAG_OBJECT: + { + struct basilysobject_st *src = (void *) p; + struct basilysobject_st *dst = + ggc_alloc_cleared (offsetof (struct basilysobject_st, + obj__tabfields)); + unsigned oblen = src->obj_len; + int ix; + *dst = *src; + if (oblen > 0) + { + dst->obj_vartab = ggc_alloc_cleared (sizeof (void *) * oblen); + for (ix = (int) oblen - 1; ix >= 0; ix--) + dst->obj_vartab[ix] = src->obj_vartab[ix]; + } + else + dst->obj_vartab = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_DECAY: + { + struct basilysdecay_st *src = (void *) p; + struct basilysdecay_st *dst = + ggc_alloc_cleared (sizeof (struct basilysdecay_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_BOX: + { + struct basilysbox_st *src = (void *) p; + struct basilysbox_st *dst = + ggc_alloc_cleared (sizeof (struct basilysbox_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MULTIPLE: + { + struct basilysmultiple_st *src = (void *) p; + unsigned nbv = src->nbval; + int ix; + struct basilysmultiple_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmultiple_st) + + nbv * sizeof (void *)); + *dst = *src; + for (ix = (int) nbv; ix >= 0; ix--) + dst->tabval[ix] = src->tabval[ix]; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_CLOSURE: + { + struct basilysclosure_st *src = (void *) p; + unsigned nbv = src->nbval; + int ix; + struct basilysclosure_st *dst = + ggc_alloc_cleared (sizeof (struct basilysclosure_st) + + nbv * sizeof (void *)); + *dst = *src; + for (ix = (int) nbv; ix >= 0; ix--) + dst->tabval[ix] = src->tabval[ix]; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_ROUTINE: + { + struct basilysroutine_st *src = (void *) p; + unsigned nbv = src->nbval; + int ix; + struct basilysroutine_st *dst = + ggc_alloc_cleared (sizeof (struct basilysroutine_st) + + nbv * sizeof (void *)); + *dst = *src; + for (ix = (int) nbv; ix >= 0; ix--) + dst->tabval[ix] = src->tabval[ix]; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_LIST: + { + struct basilyslist_st *src = (void *) p; + struct basilyslist_st *dst = + ggc_alloc_cleared (sizeof (struct basilyslist_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_PAIR: + { + struct basilyspair_st *src = (void *) p; + struct basilyspair_st *dst = + ggc_alloc_cleared (sizeof (struct basilyspair_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_TRIPLE: + { + struct basilystriple_st *src = (void *) p; + struct basilystriple_st *dst = + ggc_alloc_cleared (sizeof (struct basilystriple_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_INT: + { + struct basilysint_st *src = (void *) p; + struct basilysint_st *dst = + ggc_alloc_cleared (sizeof (struct basilysint_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MIXINT: + { + struct basilysmixint_st *src = (void *) p; + struct basilysmixint_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmixint_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_REAL: + { + struct basilysreal_st *src = (void *) p; + struct basilysreal_st *dst = + ggc_alloc_cleared (sizeof (struct basilysreal_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case ALL_OBMAG_SPECIAL_CASES: + { + struct basilysspecial_st *src = (void *) p; + struct basilysspecial_st *dst = + ggc_alloc_cleared (sizeof (struct basilysspecial_st)); + *dst = *src; + /* add the new copy to the old (major) special list */ + dst->nextspec = basilys_oldspeclist; + basilys_oldspeclist = dst; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_STRING: + { + struct basilysstring_st *src = (void *) p; + int srclen = strlen (src->val); + struct basilysstring_st *dst = + ggc_alloc_cleared (sizeof (struct basilysstring_st) + srclen + 1); + *dst = *src; + memcpy (dst->val, src->val, srclen); + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_STRBUF: + { + struct basilysstrbuf_st *src = (void *) p; + unsigned blen = basilys_primtab[src->buflenix]; + struct basilysstrbuf_st *dst = + ggc_alloc_cleared (sizeof (struct basilysstrbuf_st)); + *dst = *src; + if (blen > 0) + { + dst->bufzn = ggc_alloc_cleared (1 + blen); + memcpy (dst->bufzn, src->bufzn, blen); + } + else + dst->bufzn = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_TREE: + { + struct basilystree_st *src = (void *) p; + struct basilystree_st *dst = + ggc_alloc_cleared (sizeof (struct basilystree_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_BASICBLOCK: + { + struct basilysbasicblock_st *src = (void *) p; + struct basilysbasicblock_st *dst = + ggc_alloc_cleared (sizeof (struct basilysbasicblock_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_EDGE: + { + struct basilysedge_st *src = (void *) p; + struct basilysedge_st *dst = + ggc_alloc_cleared (sizeof (struct basilysedge_st)); + *dst = *src; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MAPOBJECTS: + { + struct basilysmapobjects_st *src = (void *) p; + int siz = basilys_primtab[src->lenix]; + struct basilysmapobjects_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmapobjects_st)); + *dst = *src; + if (siz > 0 && src->entab) + { + dst->entab = ggc_alloc_cleared (siz * sizeof (dst->entab[0])); + memcpy (dst->entab, src->entab, siz * sizeof (dst->entab[0])); + } + else + dst->entab = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MAPTREES: + { + struct basilysmaptrees_st *src = (void *) p; + int siz = basilys_primtab[src->lenix]; + struct basilysmaptrees_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmaptrees_st)); + *dst = *src; + if (siz > 0 && src->entab) + { + dst->entab = ggc_alloc_cleared (siz * sizeof (dst->entab[0])); + memcpy (dst->entab, src->entab, siz * sizeof (dst->entab[0])); + } + else + dst->entab = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MAPSTRINGS: + { + struct basilysmapstrings_st *src = (void *) p; + int siz = basilys_primtab[src->lenix]; + struct basilysmapstrings_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmapstrings_st)); + *dst = *src; + if (siz > 0 && src->entab) + { + dst->entab = ggc_alloc_cleared (siz * sizeof (dst->entab[0])); + memcpy (dst->entab, src->entab, siz * sizeof (dst->entab[0])); + } + else + dst->entab = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MAPBASICBLOCKS: + { + struct basilysmapbasicblocks_st *src = (void *) p; + int siz = basilys_primtab[src->lenix]; + struct basilysmapbasicblocks_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmapbasicblocks_st)); + *dst = *src; + if (siz > 0 && src->entab) + { + dst->entab = ggc_alloc_cleared (siz * sizeof (dst->entab[0])); + memcpy (dst->entab, src->entab, siz * sizeof (dst->entab[0])); + } + else + dst->entab = NULL; + n = (basilys_ptr_t) dst; + break; + } + case OBMAG_MAPEDGES: + { + struct basilysmapedges_st *src = (void *) p; + int siz = basilys_primtab[src->lenix]; + struct basilysmapedges_st *dst = + ggc_alloc_cleared (sizeof (struct basilysmapedges_st)); + *dst = *src; + if (siz > 0 && src->entab) + { + dst->entab = ggc_alloc_cleared (siz * sizeof (dst->entab[0])); + memcpy (dst->entab, src->entab, siz * sizeof (dst->entab[0])); + } + else + dst->entab = NULL; + n = (basilys_ptr_t) dst; + break; + } + default: + debugeprintf ("forward invalid p=%p discr=%p magic=%d", + (void *) p, (void *) p->u_discr, mag); + gcc_unreachable (); + } + if (n) + { + p->u_forward.discr = FORWARDED_DISCR; + p->u_forward.forward = n; +#ifdef ENABLE_CHECKING + if (debughack_file) + { + fprintf (debughack_file, "forwarded pushing %p to scan\n", + (void *) n); + } +#endif + VEC_safe_push (basilys_ptr_t, gc, bscanvec, n); + } + return n; + /* end of forwarded_copy */ +} + + + +/* the scanning routine is mostly chesney like; however some types, + including objects, strbuf, stringmaps, objectmaps, all the other + *maps, contain a pointer to a non value; this pointer should be + carefully updated if it was young */ +static void +scanning (basilys_ptr_t p) +{ + if (!p) + return; + gcc_assert (p != (void *) 1); +#if ENABLE_CHECKING + if (debughack_file) + { + fprintf (debughack_file, "scanning %p\n", (void *) p); + } +#endif + gcc_assert (p->u_discr && p->u_discr != (basilysobject_ptr_t) 1); + FORWARDED (p->u_discr); + gcc_assert (!basilys_is_young (p)); + switch (p->u_discr->object_magic) + { + case OBMAG_OBJECT: + { + int ix; + struct basilysobject_st *src = (void *) p; + if (basilys_is_young (src->obj_vartab)) + { + basilys_ptr_t *newtab = + ggc_alloc_cleared (sizeof (void *) * src->obj_len); + int ix; + for (ix = (int) src->obj_len - 1; ix >= 0; ix--) + newtab[ix] = src->obj_vartab[ix]; + src->obj_vartab = newtab; + } + for (ix = (int) (src->obj_len) - 1; ix >= 0; ix--) + FORWARDED (src->obj_vartab[ix]); + break; + } + case OBMAG_DECAY: + { + struct basilysdecay_st *src = (void *) p; + FORWARDED (src->val); + break; + } + case OBMAG_BOX: + { + struct basilysbox_st *src = (void *) p; + FORWARDED (src->val); + break; + } + case OBMAG_MULTIPLE: + { + struct basilysmultiple_st *src = (void *) p; + unsigned nbval = src->nbval; + int ix; + for (ix = (int) nbval - 1; ix >= 0; ix--) + FORWARDED (src->tabval[ix]); + break; + } + case OBMAG_CLOSURE: + { + struct basilysclosure_st *src = (void *) p; + unsigned nbval = src->nbval; + int ix; + FORWARDED (src->rout); + for (ix = (int) nbval - 1; ix >= 0; ix--) + FORWARDED (src->tabval[ix]); + break; + } + case OBMAG_ROUTINE: + { + struct basilysroutine_st *src = (void *) p; + unsigned nbval = src->nbval; + int ix; + for (ix = (int) nbval - 1; ix >= 0; ix--) + FORWARDED (src->tabval[ix]); + break; + } + case OBMAG_LIST: + { + struct basilyslist_st *src = (void *) p; + FORWARDED (src->first); + FORWARDED (src->last); + break; + } + case OBMAG_PAIR: + { + struct basilyspair_st *src = (void *) p; + FORWARDED (src->hd); + FORWARDED (src->tl); + break; + } + case OBMAG_TRIPLE: + { + struct basilystriple_st *src = (void *) p; + FORWARDED (src->hd); + FORWARDED (src->mi); + FORWARDED (src->tl); + break; + } + case ALL_OBMAG_SPECIAL_CASES: + { + struct basilysspecial_st *src = (void *) p; + src->mark = 1; + break; + } + case OBMAG_MAPOBJECTS: + { + struct basilysmapobjects_st *src = (void *) p; + int siz, ix; + if (!src->entab) + break; + siz = basilys_primtab[src->lenix]; + gcc_assert (siz > 0); + if (basilys_is_young (src->entab)) + { + struct entryobjectsbasilys_st *newtab = + ggc_alloc_cleared (siz * + sizeof (struct entryobjectsbasilys_st)); + memcpy (newtab, src->entab, + siz * sizeof (struct entryobjectsbasilys_st)); + src->entab = newtab; + } + for (ix = 0; ix < siz; ix++) + { + basilysobject_ptr_t at = src->entab[ix].e_at; + if (!at || at == (void *) 1) + { + src->entab[ix].e_va = NULL; + continue; + } + FORWARDED (at); + src->entab[ix].e_at = at; + FORWARDED (src->entab[ix].e_va); + } + break; + } + case OBMAG_MAPTREES: + { + struct basilysmaptrees_st *src = (void *) p; + int ix, siz; + if (!src->entab) + break; + siz = basilys_primtab[src->lenix]; + gcc_assert (siz > 0); + if (basilys_is_young (src->entab)) + { + struct entrytreesbasilys_st *newtab = + ggc_alloc_cleared (siz * sizeof (struct entrytreesbasilys_st)); + memcpy (newtab, src->entab, + siz * sizeof (struct entrytreesbasilys_st)); + src->entab = newtab; + } + for (ix = 0; ix < siz; ix++) + { + tree at = src->entab[ix].e_at; + if (!at || at == (void *) 1) + { + src->entab[ix].e_va = NULL; + continue; + } + FORWARDED (src->entab[ix].e_va); + } + break; + } + case OBMAG_MAPSTRINGS: + { + struct basilysmapstrings_st *src = (void *) p; + int ix, siz; + if (!src->entab) + break; + siz = basilys_primtab[src->lenix]; + gcc_assert (siz > 0); + if (basilys_is_young (src->entab)) + { + struct entrystringsbasilys_st *newtab + = + ggc_alloc_cleared (siz * + sizeof (struct entrystringsbasilys_st)); + memcpy (newtab, src->entab, + siz * sizeof (struct entrystringsbasilys_st)); + src->entab = newtab; + } + for (ix = 0; ix < siz; ix++) + { + char *at = src->entab[ix].e_at; + if (!at || at == (void *) 1) + { + src->entab[ix].e_va = NULL; + continue; + } + if (basilys_is_young (at)) + src->entab[ix].e_at = (char *) ggc_strdup (at); + FORWARDED (src->entab[ix].e_va); + } + break; + } + case OBMAG_MAPBASICBLOCKS: + { + struct basilysmapbasicblocks_st *src = (void *) p; + int ix, siz; + if (!src->entab) + break; + siz = basilys_primtab[src->lenix]; + gcc_assert (siz > 0); + if (basilys_is_young (src->entab)) + { + struct entrybasicblocksbasilys_st *newtab + = + ggc_alloc_cleared (siz * + sizeof (struct entrybasicblocksbasilys_st)); + memcpy (newtab, src->entab, + siz * sizeof (struct entrybasicblocksbasilys_st)); + src->entab = newtab; + } + for (ix = 0; ix < siz; ix++) + { + basic_block at = src->entab[ix].e_at; + if (!at || at == (void *) 1) + { + src->entab[ix].e_va = NULL; + continue; + } + FORWARDED (src->entab[ix].e_va); + } + break; + } + case OBMAG_MAPEDGES: + { + struct basilysmapedges_st *src = (void *) p; + int siz, ix; + if (!src->entab) + break; + siz = basilys_primtab[src->lenix]; + gcc_assert (siz > 0); + if (basilys_is_young (src->entab)) + { + struct entryedgesbasilys_st *newtab + = + ggc_alloc_cleared (siz * sizeof (struct entryedgesbasilys_st)); + memcpy (newtab, src->entab, + siz * sizeof (struct entryedgesbasilys_st)); + src->entab = newtab; + } + for (ix = 0; ix < siz; ix++) + { + edge at = src->entab[ix].e_at; + if (!at || at == (void *) 1) + { + src->entab[ix].e_va = NULL; + continue; + } + FORWARDED (src->entab[ix].e_va); + } + break; + } + case OBMAG_MIXINT: + { + struct basilysmixint_st *src = (void *) p; + FORWARDED (src->ptrval); + break; + } + case OBMAG_STRBUF: + { + struct basilysstrbuf_st *src = (void *) p; + char *oldbufzn = src->bufzn; + if (basilys_is_young (oldbufzn)) + { + int bsiz = basilys_primtab[src->buflenix]; + if (bsiz > 0) + { + char *newbufzn = ggc_alloc_cleared (bsiz + 1); + memcpy (newbufzn, oldbufzn, bsiz); + src->bufzn = newbufzn; + memset (oldbufzn, 0, bsiz); + } + else + src->bufzn = NULL; + } + break; + } + case OBMAG_INT: + case OBMAG_REAL: + case OBMAG_STRING: + case OBMAG_TREE: + case OBMAG_BASICBLOCK: + case OBMAG_EDGE: + break; + default: + gcc_unreachable (); + } +} + + + + + + +/** array of about 190 primes gotten by shell command + primes 3 2000000000 | awk '($1>p+p/8){print $1, ","; p=$1}' **/ +const long basilys_primtab[256] = { + 0, /* the first entry indexed #0 is 0 to never be used */ + 3, 5, 7, 11, 13, 17, 23, 29, 37, 43, 53, 61, 71, 83, 97, 113, + 131, 149, 173, 197, 223, 251, 283, 331, 373, 421, 479, 541, + 613, 691, 787, 887, 1009, 1151, 1297, 1471, 1657, 1867, 2111, + 2377, 2677, 3019, 3407, 3833, 4327, 4871, 5483, 6173, 6947, + 7817, 8803, 9907, 11149, 12547, 14143, 15913, 17903, 20143, + 22669, 25523, 28723, 32321, 36373, 40927, 46049, 51817, + 58309, 65599, 73819, 83047, 93463, 105167, 118343, 133153, + 149803, 168533, 189613, 213319, 239999, 270001, 303767, + 341743, 384469, 432539, 486617, 547453, 615887, 692893, + 779507, 876947, 986567, 1109891, 1248631, 1404721, 1580339, + 1777891, 2000143, 2250163, 2531443, 2847893, 3203909, + 3604417, 4054987, 4561877, 5132117, 5773679, 6495389, + 7307323, 8220743, 9248339, 10404403, 11704963, 13168091, + 14814103, 16665881, 18749123, 21092779, 23729411, 26695609, + 30032573, 33786659, 38010019, 42761287, 48106453, 54119761, + 60884741, 68495347, 77057297, 86689469, 97525661, 109716379, + 123430961, 138859837, 156217333, 175744531, 197712607, + 222426683, 250230023, 281508827, 316697431, 356284619, + 400820209, 450922753, 507288107, 570699121, 642036517, + 722291083, 812577517, 914149741, +#if HOST_BITS_PER_LONG >= 64 + 1028418463, 1156970821, 1301592203, + 1464291239, 1647327679, 1853243677, 2084899139, 2345511541, + 2638700497, 2968538081, 3339605383, 3757056091, 4226688133, + 4755024167, 5349402193, 6018077509, 6770337239, 7616629399, + 8568708139, 9639796667, 10844771263, 12200367671, + 13725413633, 15441090347, 17371226651, 19542629983, + 21985458749, 24733641113, 27825346259, 31303514549, + 35216453869, 39618510629, 44570824481, 50142177559, +#endif + 0, 0 +}; + +/* index of entry to get or add an attribute in an mapobject (or -1 on error) */ +static inline int +unsafe_index_mapobject (struct entryobjectsbasilys_st *tab, + basilysobject_ptr_t attr, int siz) +{ + int da = 0, ix = 0, frix = -1; + unsigned h = 0; + if (!tab) + return -1; + da = attr->obj_class->object_magic; + if (da == OBMAG_OBJECT) + h = ((struct basilysobject_st *) attr)->obj_hash; + else + return -1; + h = h % siz; + for (ix = h; ix < siz; ix++) + { + basilysobject_ptr_t curat = tab[ix].e_at; + if (curat == attr) + return ix; + else if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + } + for (ix = 0; ix < (int) h; ix++) + { + basilysobject_ptr_t curat = tab[ix].e_at; + if (curat == attr) + return ix; + else if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + } + return -1; /* entirely full, should not happen */ +} + + +basilys_ptr_t +basilysgc_new_int (basilysobject_ptr_t discr_p, long num) +{ + BASILYS_ENTERFRAME (2, NULL); +#define newint curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define int_newint ((struct basilysint_st*)(newint)) + newint = NULL; + discrv = (void *) discr_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_INT) + goto end; + newint = basilysgc_allocate (sizeof (struct basilysint_st), 0); + int_newint->discr = object_discrv; + int_newint->val = num; +end: + BASILYS_EXITFRAME (); + return newint; +#undef newint +#undef discrv +#undef int_newint +#undef object_discrv +} + + +basilys_ptr_t +basilysgc_new_mixint (basilysobject_ptr_t discr_p, + basilys_ptr_t val_p, long num) +{ + BASILYS_ENTERFRAME (3, NULL); +#define newmix curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define valv curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mix_newmix ((struct basilysmixint_st*)(newmix)) + newmix = NULL; + discrv = (void *) discr_p; + valv = val_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MIXINT) + goto end; + newmix = basilysgc_allocate (sizeof (struct basilysmixint_st), 0); + mix_newmix->discr = object_discrv; + mix_newmix->intval = num; + mix_newmix->ptrval = valv; +end: + BASILYS_EXITFRAME (); + return newmix; +#undef newmix +#undef valv +#undef discrv +#undef mix_newmix +#undef object_discrv +} + + +/* allocate a new routine object of given DISCR and of length LEN, + with a DESCR-iptive string a a PROC-edure */ +basilysroutine_ptr_t +basilysgc_new_routine (basilysobject_ptr_t discr_p, + unsigned len, const char *descr, + basilysroutfun_t * proc) +{ + union + { + long fad[1 + sizeof (basilysroutfun_t *) / sizeof (long)]; + basilysroutfun_t *fproc; + } un; + BASILYS_ENTERFRAME (2, NULL); +#define newroutv curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define obj_discrv ((basilysobject_ptr_t)(discrv)) +#define rou_newroutv ((basilysroutine_ptr_t)(newroutv)) + newroutv = NULL; + discrv = discr_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT + || obj_discrv->object_magic != OBMAG_ROUTINE || !descr || !descr[0] + || !proc || len > BASILYS_MAXLEN) + goto end; + newroutv = + basilysgc_allocate (sizeof (struct basilysroutine_st), + len * sizeof (void *)); + rou_newroutv->discr = discrv; + rou_newroutv->nbval = len; + memset (&un, 0, sizeof (un)); + un.fproc = proc; + memcpy (rou_newroutv->routaddr, un.fad, sizeof (rou_newroutv->routaddr)); + strncpy (rou_newroutv->routdescr, descr, BASILYS_ROUTDESCR_LEN - 1); + rou_newroutv->routdescr[BASILYS_ROUTDESCR_LEN - 1] = (char) 0; +end: + BASILYS_EXITFRAME (); + return newroutv; +#undef newroutv +#undef discrv +#undef obj_discrv +#undef rou_newroutv +} + +basilysclosure_ptr_t +basilysgc_new_closure (basilysobject_ptr_t discr_p, + basilysroutine_ptr_t rout_p, unsigned len) +{ + BASILYS_ENTERFRAME (3, NULL); +#define newclosv curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define routv curfram__.varptr[2] +#define clo_newclosv ((basilysclosure_ptr_t)(newclosv)) +#define obj_discrv ((basilysobject_ptr_t)(discrv)) +#define rou_routv ((basilysroutine_ptr_t)(routv)) + discrv = discr_p; + routv = rout_p; + newclosv = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT + || obj_discrv->object_magic != OBMAG_CLOSURE + || basilys_magic_discr (routv) != OBMAG_ROUTINE || len > BASILYS_MAXLEN) + goto end; + newclosv = + basilysgc_allocate (sizeof (struct basilysclosure_st), + sizeof (void *) * len); + clo_newclosv->discr = discrv; + clo_newclosv->rout = routv; + clo_newclosv->nbval = len; +end: + BASILYS_EXITFRAME (); + return newclosv; +#undef newclosv +#undef discrv +#undef routv +#undef clo_newclosv +#undef obj_discrv +#undef rou_routv +} + + + +struct basilysstrbuf_st * +basilysgc_new_strbuf (basilysobject_ptr_t discr_p, const char *str) +{ + int slen = 0, blen = 0, ix = 0; + BASILYS_ENTERFRAME (2, NULL); +#define newbufv curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define buf_newbufv ((struct basilysstrbuf_st*)(newbufv)) + discrv = discr_p; + newbufv = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (((basilysobject_ptr_t) (discrv))->object_magic != OBMAG_STRBUF) + goto end; + if (str) + slen = strlen (str); + gcc_assert (slen < BASILYS_MAXLEN); + slen += slen / 5 + 40; + for (ix = 2; (blen = basilys_primtab[ix]) != 0 && blen < slen; ix++); + gcc_assert (blen != 0); + newbufv = + basilysgc_allocate (offsetof + (struct basilysstrbuf_st, buf_space), blen + 1); + buf_newbufv->discr = discrv; + buf_newbufv->bufzn = buf_newbufv->buf_space; + buf_newbufv->buflenix = ix; + buf_newbufv->bufstart = 0; + if (str) + { + strcpy (buf_newbufv->bufzn, str); + buf_newbufv->bufend = strlen (str); + } + else + buf_newbufv->bufend = 0; +end: + BASILYS_EXITFRAME (); + return newbufv; +#undef newbufv +#undef discrv +#undef buf_newbufv +} + + +void +basilysgc_add_strbuf_raw (struct basilysstrbuf_st *strbuf_p, const char *str) +{ +#ifdef ENABLE_CHECKING + static long addcount; +#endif + int slen = 0, blen = 0; + BASILYS_ENTERFRAME (2, NULL); +#define strbufv curfram__.varptr[0] +#define buf_strbufv ((struct basilysstrbuf_st*)(strbufv)) + strbufv = strbuf_p; + if (!str) + goto end; + if (basilys_magic_discr (strbufv) != OBMAG_STRBUF) + goto end; + gcc_assert (!basilys_is_young ((void *) (char *) str)); + slen = strlen (str); + blen = basilys_primtab[buf_strbufv->buflenix]; + gcc_assert (blen > 0); +#ifdef ENABLE_CHECKING + addcount++; +#endif + gcc_assert (buf_strbufv->bufstart <= buf_strbufv->bufend + && buf_strbufv->bufend < (unsigned) blen); + if ((int) buf_strbufv->bufend + slen + 2 < blen) + { /* simple case, just copy at end */ + strcpy (buf_strbufv->bufzn + buf_strbufv->bufend, str); + buf_strbufv->bufend += slen; + buf_strbufv->bufzn[buf_strbufv->bufend] = 0; + } + else + if ((int) buf_strbufv->bufstart > (int) 0 + && (int) buf_strbufv->bufend - + (int) buf_strbufv->bufstart + (int) slen + 2 < (int) blen) + { /* should move the buffer to fit */ + int siz = buf_strbufv->bufend - buf_strbufv->bufstart; + gcc_assert (siz > 0); + memmove (buf_strbufv->bufzn, + buf_strbufv->bufzn + buf_strbufv->bufstart, siz); + buf_strbufv->bufstart = 0; + strcpy (buf_strbufv->bufzn + siz, str); + buf_strbufv->bufend = siz + slen; + buf_strbufv->bufzn[buf_strbufv->bufend] = 0; + } + else + { /* should grow the buffer to fit */ + int siz = buf_strbufv->bufend - buf_strbufv->bufstart; + int newsiz = (siz + slen + 50 + siz / 8) | 0x1f; + int newix = 0, newblen = 0; + char *newb = NULL; + int oldblen = basilys_primtab[buf_strbufv->buflenix]; + for (newix = buf_strbufv->buflenix + 1; + (newblen = basilys_primtab[newix]) != 0 + && newblen < newsiz; newix++); + gcc_assert (newblen >= newsiz); + gcc_assert (siz >= 0); + if (newblen > BASILYS_MAXLEN) + fatal_error ("strbuf overflow to %d bytes", newblen); + /* the newly grown buffer is allocated in young memory if the + previous was young, or in old memory if it was already old */ + if (basilys_is_young (buf_strbufv->bufzn)) + { + newb = basilysgc_allocate (newblen + 1, 0); + memcpy (newb, buf_strbufv->bufzn + buf_strbufv->bufstart, siz); + strcpy (newb + siz, str); + memset (buf_strbufv->bufzn, 0, oldblen); + buf_strbufv->bufzn = newb; + } + else + { + newb = ggc_alloc_cleared (newblen + 1); + memcpy (newb, buf_strbufv->bufzn + buf_strbufv->bufstart, siz); + strcpy (newb + siz, str); + memset (buf_strbufv->bufzn, 0, oldblen); + ggc_free (buf_strbufv->bufzn); + buf_strbufv->bufzn = newb; + } + buf_strbufv->buflenix = newix; + buf_strbufv->bufstart = 0; + buf_strbufv->bufend = siz + slen; + buf_strbufv->bufzn[buf_strbufv->bufend] = 0; + /* touch the buffer so that it will be scanned if not young */ + basilysgc_touch (strbufv); + } +end: + BASILYS_EXITFRAME (); +#undef strbufv +#undef buf_strbufv +} + +void +basilysgc_add_strbuf (struct basilysstrbuf_st *strbuf_p, const char *str) +{ + char sbuf[80]; + char *cstr = NULL; + int slen = 0; + if (str) + slen = strlen (str); + if (slen <= 0) + return; + if (slen < (int) sizeof (sbuf) - 1) + { + memset (sbuf, 0, sizeof (sbuf)); + strcpy (sbuf, str); + basilysgc_add_strbuf_raw (strbuf_p, sbuf); + } + else + { + cstr = xstrdup (str); + basilysgc_add_strbuf_raw (strbuf_p, cstr); + free (cstr); + } +} + +void +basilysgc_add_strbuf_cstr (struct basilysstrbuf_st *strbuf_p, const char *str) +{ + int slen = str ? strlen (str) : 0; + const char *ps = NULL; + char *pd = NULL; + char *cstr = NULL; + if (!str || !str[0]) + return; + cstr = xcalloc (slen + 5, 4); + pd = cstr; + for (ps = str; *ps; ps++) + { + switch (*ps) + { +#define ADDS(S) strcpy(pd, S); pd+=sizeof(S)-1; break + case '\n': + ADDS ("\\n"); + case '\r': + ADDS ("\\r"); + case '\t': + ADDS ("\\t"); + case '\v': + ADDS ("\\v"); + case '\f': + ADDS ("\\f"); + case '\'': + ADDS ("\\\'"); + case '\"': + ADDS ("\\\""); + case '\\': + ADDS ("\\\\"); +#undef ADDS + default: + if (ISPRINT (*ps)) + *(pd++) = *ps; + else + { + sprintf (pd, "\\%03o", (*ps) & 0xff); + pd += 4; + } + } + }; + basilysgc_add_strbuf_raw (strbuf_p, cstr); + free (cstr); +} + + +void +basilysgc_add_strbuf_ccomment (struct basilysstrbuf_st + *strbuf_p, const char *str) +{ + int slen = str ? strlen (str) : 0; + const char *ps = NULL; + char *pd = NULL; + char *cstr = NULL; + if (!str || !str[0]) + return; + cstr = xcalloc (slen + 4, 4); + pd = cstr; + for (ps = str; *ps; ps++) + { + if (ps[0] == '/' && ps[1] == '*') + { + pd[0] = '/'; + pd[1] = '+'; + pd += 2; + ps++; + } + else if (ps[0] == '*' && ps[1] == '/') + { + pd[0] = '+'; + pd[1] = '/'; + pd += 2; + ps++; + } + else + *(pd++) = *ps; + }; + basilysgc_add_strbuf_raw (strbuf_p, cstr); + free (cstr); +} + +void +basilysgc_add_strbuf_cident (struct basilysstrbuf_st + *strbuf_p, const char *str) +{ + int slen = str ? strlen (str) : 0; + char *dupstr = 0; + char *pc = 0; + char tinybuf[80]; + if (!str || !str[0]) + return; + if (slen < (int) sizeof (tinybuf) - 2) + { + memset (tinybuf, 0, sizeof (tinybuf)); + if (str) + strcpy (tinybuf, str); + dupstr = tinybuf; + } + else + { + dupstr = xcalloc (slen + 2, 1); + if (str) + strcpy (dupstr, str); + }; + for (pc = dupstr; *pc; pc++) + if (!ISALNUM (*pc)) + *pc = '_'; + basilysgc_add_strbuf_raw (strbuf_p, dupstr); + if (dupstr && dupstr != tinybuf) + free (dupstr); +} + +void +basilysgc_add_strbuf_cidentprefix (struct basilysstrbuf_st + *strbuf_p, const char *str, int preflen) +{ + char *dupstr = 0; + char *pc = 0; + char tinybuf[80]; + if (str) + { + int lenst = strlen (str); + if (lenst < preflen) + preflen = lenst; + } + else + return; + if (preflen >= (int) sizeof (tinybuf) - 1) + preflen = sizeof (tinybuf) - 2; + if (preflen <= 0) + return; + memset (tinybuf, 0, sizeof (tinybuf)); + if (str) + strncpy (tinybuf, str, preflen); + dupstr = tinybuf; + for (pc = dupstr; *pc; pc++) + if (!ISALNUM (*pc)) + *pc = '_'; + basilysgc_add_strbuf_raw (strbuf_p, dupstr); +} + + +void +basilysgc_add_strbuf_hex (struct basilysstrbuf_st *strbuf_p, unsigned long l) +{ + if (l == 0UL) + basilysgc_add_strbuf_raw (strbuf_p, "0"); + else + { + int ix = 0, j = 0; + char revbuf[80], thebuf[80]; + memset (revbuf, 0, sizeof (revbuf)); + memset (thebuf, 0, sizeof (thebuf)); + while (ix < (int) sizeof (revbuf) - 1 && l != 0UL) + { + unsigned h = l & 15; + l >>= 4; + revbuf[ix++] = "0123456789abcdef"[h]; + } + ix--; + for (j = 0; j < (int) sizeof (thebuf) - 1 && ix >= 0; j++, ix--) + thebuf[j] = revbuf[ix]; + basilysgc_add_strbuf_raw (strbuf_p, thebuf); + } +} + + +void +basilysgc_add_strbuf_dec (struct basilysstrbuf_st *strbuf_p, long l) +{ + if (l == 0UL) + basilysgc_add_strbuf_raw (strbuf_p, "0"); + else + { + int ix = 0, j = 0, neg = 0; + char revbuf[96], thebuf[96]; + memset (revbuf, 0, sizeof (revbuf)); + memset (thebuf, 0, sizeof (thebuf)); + if (l < 0) + { + l = -l; + neg = 1; + }; + while (ix < (int) sizeof (revbuf) - 1 && l != 0UL) + { + unsigned h = l % 10; + l = l / 10; + revbuf[ix++] = "0123456789"[h]; + } + ix--; + if (neg) + { + thebuf[0] = '-'; + j = 1; + }; + for (; j < (int) sizeof (thebuf) - 1 && ix >= 0; j++, ix--) + thebuf[j] = revbuf[ix]; + basilysgc_add_strbuf_raw (strbuf_p, thebuf); + } +} + + +void +basilysgc_strbuf_printf (struct basilysstrbuf_st *strbuf_p, + const char *fmt, ...) +{ + char *cstr = NULL; + va_list ap; + int l = 0; + static char tinybuf[80]; + memset (tinybuf, 0, sizeof (tinybuf)); + va_start (ap, fmt); + l = vsnprintf (tinybuf, sizeof (tinybuf) - 1, fmt, ap); + va_end (ap); + if (l < (int) sizeof (tinybuf) - 3) + { + basilysgc_add_strbuf_raw (strbuf_p, tinybuf); + return; + } + va_start (ap, fmt); + vasprintf (&cstr, fmt, ap); + va_end (ap); + basilysgc_add_strbuf_raw (strbuf_p, cstr); + free (cstr); +} + + +/* add safely into STRBUF either a space or an indented newline if the current line is bigger than the threshold */ +void +basilysgc_strbuf_add_indent (struct basilysstrbuf_st + *strbuf_p, int depth, int linethresh) +{ + int llln = 0; /* last line length */ + if (!strbuf_p || basilys_magic_discr ((void *) strbuf_p) != OBMAG_STRBUF) + return; + if (linethresh > 0 && linethresh < 40) + linethresh = 40; + /* compute the last line length llln */ + { + char *bs = 0, *be = 0, *nl = 0; + bs = strbuf_p->bufzn + strbuf_p->bufstart; + be = strbuf_p->bufzn + strbuf_p->bufend; + for (nl = be - 1; nl > bs && *nl && *nl != '\n'; nl--); + llln = be - nl; + gcc_assert (llln >= 0); + } + if (linethresh > 0 && llln < linethresh) + basilysgc_add_strbuf_raw (strbuf_p, " "); + else + { + int nbsp = depth; + static const char spaces32[] = " "; + basilysgc_add_strbuf_raw (strbuf_p, "\n"); + if (nbsp < 0) + nbsp = 0; + if (nbsp > 0 && nbsp % 32 != 0) + basilysgc_add_strbuf_raw (strbuf_p, spaces32 + (32 - nbsp % 32)); + } +} + + + + +/***************/ + +basilysobject_ptr_t +basilysgc_new_raw_object (basilysobject_ptr_t klass_p, unsigned len) +{ + unsigned h = 0; + BASILYS_ENTERFRAME (2, NULL); +#define newobjv curfram__.varptr[0] +#define klassv curfram__.varptr[1] +#define obj_newobjv ((basilysobject_ptr_t)(newobjv)) +#define obj_klassv ((basilysobject_ptr_t)(klassv)) + newobjv = NULL; + klassv = klass_p; + if (basilys_magic_discr (klassv) != OBMAG_OBJECT + || obj_klassv->object_magic != OBMAG_OBJECT || len >= SHRT_MAX) + goto end; + newobjv = + basilysgc_allocate (offsetof + (struct basilysobject_st, + obj__tabfields), len * sizeof (void *)); + obj_newobjv->obj_class = klassv; + do + { + h = basilys_lrand () & BASILYS_MAXHASH; + } + while (h == 0); + obj_newobjv->obj_hash = h; + obj_newobjv->obj_len = len; + if (len > 0) + obj_newobjv->obj_vartab = obj_newobjv->obj__tabfields; +end: + BASILYS_EXITFRAME (); + return newobjv; +#undef newobjv +#undef klassv +#undef obj_newobjv +#undef obj_klassv +} + + +/* allocate a new multiple of given DISCR & length LEN */ +basilys_ptr_t +basilysgc_new_multiple (basilysobject_ptr_t discr_p, unsigned len) +{ + BASILYS_ENTERFRAME (2, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + newmul = NULL; + gcc_assert (len < BASILYS_MAXLEN); + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * len); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = len; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discr +#undef mult_newmul +#undef object_discrv +} + + +void +basilysgc_multiple_put_nth (basilysmultiple_ptr_t mul_p, + int n, basilys_ptr_t val_p) +{ + int ln = 0; + BASILYS_ENTERFRAME (3, NULL); +#define mulv curfram__.varptr[0] +#define mult_mulv ((struct basilysmultiple_st*)(mulv)) +#define discrv curfram__.varptr[1] +#define valv curfram__.varptr[2] + mulv = mul_p; + valv = val_p; + if (!basilys_magic_discr (mulv) == OBMAG_MULTIPLE) + goto end; + ln = mult_mulv->nbval; + if (n < 0) + n += ln; + if (n >= 0 && n < ln) + { + mult_mulv->tabval[n] = valv; + basilysgc_touch_dest (mulv, valv); + } +end: + BASILYS_EXITFRAME (); +#undef mulv +#undef mult_mulv +#undef discrv +#undef valv +} + +/* allocate a new box of given DISCR & content VAL */ +basilys_ptr_t +basilysgc_new_box (basilysobject_ptr_t discr_p, basilys_ptr_t val_p) +{ + BASILYS_ENTERFRAME (3, NULL); +#define boxv curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define valv curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) + discrv = (void *) discr_p; + valv = (void *) val_p; + boxv = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_BOX) + goto end; + boxv = basilysgc_allocate (sizeof (struct basilysbox_st), 0); + ((struct basilysbox_st *) (boxv))->discr = discrv; + ((struct basilysbox_st *) (boxv))->val = valv; +end: + BASILYS_EXITFRAME (); + return boxv; +#undef boxv +#undef discr +#undef valv +#undef object_discrv +} + +/* put inside a box */ +void +basilysgc_box_put (basilys_ptr_t box_p, basilys_ptr_t val_p) +{ + BASILYS_ENTERFRAME (2, NULL); +#define boxv curfram__.varptr[0] +#define valv curfram__.varptr[1] + boxv = box_p; + valv = val_p; + if (basilys_magic_discr (boxv) != OBMAG_BOX) + goto end; + ((basilysbox_ptr_t) boxv)->val = valv; + basilysgc_touch_dest (boxv, valv); +end: + BASILYS_EXITFRAME (); +#undef boxv +#undef valv +} + + +/* allocate a multiple of arity 1 */ +basilys_ptr_t +basilysgc_new_mult1 (basilysobject_ptr_t discr_p, basilys_ptr_t v0_p) +{ + BASILYS_ENTERFRAME (3, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define v0 curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + v0 = v0_p; + newmul = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * 1); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = 1; + mult_newmul->tabval[0] = v0; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discr +#undef v0 +#undef mult_newmul +#undef object_discrv +} + +basilys_ptr_t +basilysgc_new_mult2 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p) +{ + BASILYS_ENTERFRAME (4, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define v0 curfram__.varptr[2] +#define v1 curfram__.varptr[3] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + v0 = v0_p; + v1 = v1_p; + newmul = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * 2); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = 2; + mult_newmul->tabval[0] = v0; + mult_newmul->tabval[1] = v1; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discr +#undef v0 +#undef v1 +#undef mult_newmul +#undef object_discrv +} + +basilys_ptr_t +basilysgc_new_mult3 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p) +{ + BASILYS_ENTERFRAME (5, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define v0 curfram__.varptr[2] +#define v1 curfram__.varptr[3] +#define v2 curfram__.varptr[4] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + v0 = v0_p; + v1 = v1_p; + v2 = v2_p; + newmul = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * 3); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = 3; + mult_newmul->tabval[0] = v0; + mult_newmul->tabval[1] = v1; + mult_newmul->tabval[2] = v2; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discrv +#undef v0 +#undef v1 +#undef v2 +#undef mult_newmul +#undef object_discrv +} + +basilys_ptr_t +basilysgc_new_mult4 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p, basilys_ptr_t v3_p) +{ + BASILYS_ENTERFRAME (6, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define v0 curfram__.varptr[2] +#define v1 curfram__.varptr[3] +#define v2 curfram__.varptr[4] +#define v3 curfram__.varptr[5] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + v0 = v0_p; + v1 = v1_p; + v2 = v2_p; + v3 = v3_p; + newmul = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * 4); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = 4; + mult_newmul->tabval[0] = v0; + mult_newmul->tabval[1] = v1; + mult_newmul->tabval[2] = v2; + mult_newmul->tabval[3] = v3; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discrv +#undef v0 +#undef v1 +#undef v2 +#undef v3 +#undef mult_newmul +#undef object_discrv +} + +basilys_ptr_t +basilysgc_new_mult5 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p, basilys_ptr_t v3_p, + basilys_ptr_t v4_p) +{ + BASILYS_ENTERFRAME (7, NULL); +#define newmul curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define v0 curfram__.varptr[2] +#define v1 curfram__.varptr[3] +#define v2 curfram__.varptr[4] +#define v3 curfram__.varptr[5] +#define v4 curfram__.varptr[6] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mult_newmul ((struct basilysmultiple_st*)(newmul)) + discrv = (void *) discr_p; + v0 = v0_p; + v1 = v1_p; + v2 = v2_p; + v3 = v3_p; + v4 = v4_p; + newmul = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MULTIPLE) + goto end; + newmul = + basilysgc_allocate (sizeof (struct basilysmultiple_st), + sizeof (void *) * 5); + mult_newmul->discr = object_discrv; + mult_newmul->nbval = 5; + mult_newmul->tabval[0] = v0; + mult_newmul->tabval[1] = v1; + mult_newmul->tabval[2] = v2; + mult_newmul->tabval[3] = v3; + mult_newmul->tabval[4] = v4; +end: + BASILYS_EXITFRAME (); + return newmul; +#undef newmul +#undef discrv +#undef v0 +#undef v1 +#undef v2 +#undef v3 +#undef v4 +#undef mult_newmul +#undef object_discrv +} + + +basilys_ptr_t +basilysgc_new_list (basilysobject_ptr_t discr_p) +{ + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define newlist curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define list_newlist ((struct basilyslist_st*)(newlist)) + discrv = (void *) discr_p; + newlist = NULL; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_LIST) + goto end; + newlist = basilysgc_allocate (sizeof (struct basilyslist_st), 0); + list_newlist->discr = object_discrv; + list_newlist->first = NULL; + list_newlist->last = NULL; +end: + BASILYS_EXITFRAME (); + return newlist; +#undef newlist +#undef discrv +#undef list_newlist +#undef object_discrv +} + +/* allocate a pair of given head and tail */ +basilys_ptr_t +basilysgc_new_pair (basilysobject_ptr_t discr_p, void *head_p, void *tail_p) +{ + BASILYS_ENTERFRAME (4, NULL); +#define pairv curfram__.varptr[0] +#define discrv curfram__.varptr[1] +#define headv curfram__.varptr[2] +#define tailv curfram__.varptr[3] + discrv = discr_p; + headv = head_p; + tailv = tail_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT + || ((basilysobject_ptr_t) (discrv))->object_magic != OBMAG_PAIR) + goto end; + if (basilys_magic_discr (tailv) != OBMAG_PAIR) + tailv = NULL; + pairv = basilysgc_allocate (sizeof (struct basilyspair_st), 0); + ((struct basilyspair_st *) (pairv))->discr = discrv; + ((struct basilyspair_st *) (pairv))->hd = headv; + ((struct basilyspair_st *) (pairv))->tl = tailv; +end: + BASILYS_EXITFRAME (); + return pairv; +#undef pairv +#undef headv +#undef tailv +#undef discrv +} + +/* change the head of a pair */ +void +basilysgc_pair_set_head (basilys_ptr_t pair_p, void *head_p) +{ + BASILYS_ENTERFRAME (2, NULL); +#define pairv curfram__.varptr[0] +#define headv curfram__.varptr[1] + pairv = pair_p; + headv = head_p; + if (basilys_magic_discr (pairv) != OBMAG_PAIR) + goto end; + ((struct basilyspair_st *) pairv)->hd = headv; + basilysgc_touch_dest (pairv, headv); +end: + BASILYS_EXITFRAME (); +#undef pairv +#undef headv +} + + +void +basilysgc_append_list (basilys_ptr_t list_p, basilys_ptr_t valu_p) +{ + BASILYS_ENTERFRAME (4, NULL); +#define list curfram__.varptr[0] +#define valu curfram__.varptr[1] +#define pairv curfram__.varptr[2] +#define lastv curfram__.varptr[3] +#define pai_pairv ((struct basilyspair_st*)(pairv)) +#define list_list ((struct basilyslist_st*)(list)) + list = list_p; + valu = valu_p; + if (basilys_magic_discr (list) != OBMAG_LIST || !BASILYSGOB (DISCR_PAIR)) + goto end; + pairv = basilysgc_allocate (sizeof (struct basilyspair_st), 0); + pai_pairv->discr = BASILYSGOB (DISCR_PAIR); + pai_pairv->hd = valu; + pai_pairv->tl = NULL; + gcc_assert (basilys_magic_discr (pairv) == OBMAG_PAIR); + lastv = list_list->last; + if (basilys_magic_discr ((basilys_ptr_t) lastv) == OBMAG_PAIR) + { + gcc_assert (((struct basilyspair_st *) lastv)->tl == NULL); + ((struct basilyspair_st *) lastv)->tl = pairv; + basilysgc_touch_dest (lastv, pairv); + } + else + list_list->first = pairv; + list_list->last = pairv; + basilysgc_touch_dest (list, pairv); +end: + BASILYS_EXITFRAME (); +#undef list +#undef valu +#undef list_list +#undef pairv +#undef pai_pairv +#undef lastv +} + +void +basilysgc_prepend_list (basilys_ptr_t list_p, basilys_ptr_t valu_p) +{ + BASILYS_ENTERFRAME (4, NULL); +#define list curfram__.varptr[0] +#define valu curfram__.varptr[1] +#define pairv curfram__.varptr[2] +#define firstv curfram__.varptr[3] +#define pai_pairv ((struct basilyspair_st*)(pairv)) +#define list_list ((struct basilyslist_st*)(list)) + list = list_p; + valu = valu_p; + if (basilys_magic_discr (list) != OBMAG_LIST || !BASILYSGOB (DISCR_PAIR)) + goto end; + pairv = basilysgc_allocate (sizeof (struct basilyspair_st), 0); + pai_pairv->discr = BASILYSGOB (DISCR_PAIR); + pai_pairv->hd = valu; + pai_pairv->tl = NULL; + gcc_assert (basilys_magic_discr (pairv) == OBMAG_PAIR); + firstv = (basilys_ptr_t) (list_list->first); + if (basilys_magic_discr (firstv) == OBMAG_PAIR) + { + pai_pairv->tl = firstv; + basilysgc_touch_dest (pairv, firstv); + } + else + list_list->last = pairv; + list_list->first = pairv; + basilysgc_touch_dest (list, pairv); +end: + BASILYS_EXITFRAME (); +#undef list +#undef valu +#undef list_list +#undef pairv +#undef pai_pairv +} + + +basilys_ptr_t +basilysgc_popfirst_list (basilys_ptr_t list_p) +{ + BASILYS_ENTERFRAME (3, NULL); +#define list curfram__.varptr[0] +#define valu curfram__.varptr[1] +#define pairv curfram__.varptr[2] +#define pai_pairv ((struct basilyspair_st*)(pairv)) +#define list_list ((struct basilyslist_st*)(list)) + list = list_p; + if (basilys_magic_discr (list) != OBMAG_LIST) + goto end; + pairv = list_list->first; + if (basilys_magic_discr ((basilys_ptr_t) pairv) != OBMAG_PAIR) + goto end; + if (list_list->last == pairv) + { + valu = pai_pairv->hd; + list_list->first = NULL; + list_list->last = NULL; + } + else + { + valu = pai_pairv->hd; + list_list->first = pai_pairv->tl; + } + basilysgc_touch (list); +end: + BASILYS_EXITFRAME (); + return valu; +#undef list +#undef value +#undef list_list +#undef pairv +#undef pai_pairv +} /* enf of popfirst */ + + +/* return the length of a list or -1 iff non list */ +int +basilys_list_length (basilys_ptr_t list_p) +{ + struct basilyspair_st *pair = NULL; + int ln = 0; + if (basilys_magic_discr (list_p) != OBMAG_LIST) + return -1; + for (pair = ((struct basilyslist_st *) list_p)->first; + basilys_magic_discr ((basilys_ptr_t) pair) == + OBMAG_PAIR; pair = (struct basilyspair_st *) (pair->tl)) + ln++; + return ln; +} + + +/* allocate a new empty mapobjects */ +basilys_ptr_t +basilysgc_new_mapobjects (basilysobject_ptr_t discr_p, unsigned len) +{ + int maplen = 0; + int lenix = 0, primlen = 0; + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define newmapv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mapobject_newmapv ((struct basilysmapobjects_st*)(newmapv)) + discrv = discr_p; + if (!discrv || object_discrv->obj_class->object_magic != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MAPOBJECTS) + goto end; + if (len > 0) + { + gcc_assert (len < (unsigned) BASILYS_MAXLEN); + for (lenix = 1; + (primlen = (int) basilys_primtab[lenix]) != 0 + && primlen <= (int) len; lenix++); + maplen = primlen; + }; + newmapv = + basilysgc_allocate (offsetof + (struct basilysmapobjects_st, map_space), + maplen * sizeof (struct entryobjectsbasilys_st)); + mapobject_newmapv->discr = object_discrv; + if (len > 0) + { + mapobject_newmapv->entab = mapobject_newmapv->map_space; + mapobject_newmapv->lenix = lenix; + }; +end: + BASILYS_EXITFRAME (); + return newmapv; +#undef discrv +#undef newmapv +#undef object_discrv +#undef mapobject_newmapv +} + +/* get from a mapobject */ +basilys_ptr_t +basilys_get_mapobjects (basilysmapobjects_ptr_t mapobject_p, + basilysobject_ptr_t attrobject_p) +{ + long ix, len; + basilys_ptr_t val = NULL; + if (!mapobject_p || !attrobject_p + || mapobject_p->discr->object_magic != OBMAG_MAPOBJECTS + || !mapobject_p->entab + || attrobject_p->obj_class->object_magic != OBMAG_OBJECT) + return NULL; + len = basilys_primtab[mapobject_p->lenix]; + if (len <= 0) + return NULL; + ix = unsafe_index_mapobject (mapobject_p->entab, attrobject_p, len); + if (ix < 0) + return NULL; + if (mapobject_p->entab[ix].e_at == attrobject_p) + val = mapobject_p->entab[ix].e_va; + return val; +} + +void +basilysgc_put_mapobjects (basilysmapobjects_ptr_t + mapobject_p, + basilysobject_ptr_t attrobject_p, + basilys_ptr_t valu_p) +{ + long ix = 0, len = 0, cnt = 0; + BASILYS_ENTERFRAME (4, NULL); +#define discrv curfram__.varptr[0] +#define mapobjectv curfram__.varptr[1] +#define attrobjectv curfram__.varptr[2] +#define valuv curfram__.varptr[3] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define object_attrobjectv ((basilysobject_ptr_t)(attrobjectv)) +#define map_mapobjectv ((basilysmapobjects_ptr_t)(mapobjectv)) + mapobjectv = mapobject_p; + attrobjectv = attrobject_p; + valuv = valu_p; + if (!mapobjectv || !attrobjectv || !valuv) + goto end; + discrv = map_mapobjectv->discr; + if (!discrv || object_discrv->object_magic != OBMAG_MAPOBJECTS) + goto end; + discrv = object_attrobjectv->obj_class; + if (!discrv || object_discrv->object_magic != OBMAG_OBJECT) + goto end; + if (!map_mapobjectv->entab) + { + len = basilys_primtab[1]; /* i.e. 3 */ + if (basilys_is_young (mapobjectv)) + map_mapobjectv->entab = + basilysgc_allocate (len * + sizeof (struct entryobjectsbasilys_st), 0); + else + map_mapobjectv->entab = + ggc_alloc_cleared (len * sizeof (struct entryobjectsbasilys_st)); + map_mapobjectv->lenix = 1; + basilysgc_touch (map_mapobjectv); + } + else + if ((len = basilys_primtab[map_mapobjectv->lenix]) <= + (5 * (cnt = map_mapobjectv->count)) / 4 + 1 + || (len <= 5 && cnt + 1 >= len)) + { + int ix, newcnt = 0; + int newlen = basilys_primtab[map_mapobjectv->lenix + 1]; + struct entryobjectsbasilys_st *newtab = NULL; + struct entryobjectsbasilys_st *oldtab = NULL; + if (basilys_is_young (map_mapobjectv->entab)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entryobjectsbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entryobjectsbasilys_st)); + oldtab = map_mapobjectv->entab; + for (ix = 0; ix < len; ix++) + { + basilysobject_ptr_t curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mapobject (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in old ggc space */ + ggc_free (oldtab); + map_mapobjectv->entab = newtab; + map_mapobjectv->count = newcnt; + map_mapobjectv->lenix++; + basilysgc_touch (map_mapobjectv); + len = newlen; + } + ix = + unsafe_index_mapobject (map_mapobjectv->entab, object_attrobjectv, len); + gcc_assert (ix >= 0); + if (map_mapobjectv->entab[ix].e_at != attrobjectv) + { + map_mapobjectv->entab[ix].e_at = attrobjectv; + map_mapobjectv->count++; + } + map_mapobjectv->entab[ix].e_va = valuv; + basilysgc_touch_dest (map_mapobjectv, attrobjectv); + basilysgc_touch_dest (map_mapobjectv, valuv); +end: + BASILYS_EXITFRAME (); +#undef discrv +#undef mapobjectv +#undef attrobjectv +#undef valuv +#undef object_discrv +#undef object_attrobjectv +#undef map_mapobjectv +} + + +basilys_ptr_t +basilysgc_remove_mapobjects (basilysmapobjects_ptr_t + mapobject_p, basilysobject_ptr_t attrobject_p) +{ + long ix = 0, len = 0, cnt = 0; + BASILYS_ENTERFRAME (4, NULL); +#define discrv curfram__.varptr[0] +#define mapobjectv curfram__.varptr[1] +#define attrobjectv curfram__.varptr[2] +#define valuv curfram__.varptr[3] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define object_attrobjectv ((basilysobject_ptr_t)(attrobjectv)) +#define map_mapobjectv ((basilysmapobjects_ptr_t)(mapobjectv)) + mapobjectv = mapobject_p; + attrobjectv = attrobject_p; + valuv = NULL; + if (!mapobjectv || !attrobjectv) + goto end; + discrv = map_mapobjectv->discr; + if (!discrv || object_discrv->object_magic != OBMAG_MAPOBJECTS) + goto end; + discrv = object_attrobjectv->obj_class; + if (!discrv || object_discrv->object_magic != OBMAG_OBJECT) + goto end; + if (!map_mapobjectv->entab) + goto end; + len = basilys_primtab[map_mapobjectv->lenix]; + if (len <= 0) + goto end; + ix = unsafe_index_mapobject (map_mapobjectv->entab, attrobject_p, len); + if (ix < 0 || map_mapobjectv->entab[ix].e_at != attrobjectv) + goto end; + map_mapobjectv->entab[ix].e_at = (void *) HTAB_DELETED_ENTRY; + valuv = map_mapobjectv->entab[ix].e_va; + map_mapobjectv->entab[ix].e_va = NULL; + map_mapobjectv->count--; + cnt = map_mapobjectv->count; + if (len >= 7 && cnt < len / 2 - 2) + { + int newcnt = 0, newlen = 0, newlenix; + struct entryobjectsbasilys_st *oldtab = NULL, *newtab = NULL; + for (newlenix = map_mapobjectv->lenix; + (newlen = basilys_primtab[newlenix]) > 2 * cnt + 3; newlenix--); + if (newlen >= len) + goto end; + if (basilys_is_young (map_mapobjectv->entab)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entryobjectsbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entryobjectsbasilys_st)); + oldtab = map_mapobjectv->entab; + for (ix = 0; ix < len; ix++) + { + basilysobject_ptr_t curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mapobject (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in old ggc space */ + ggc_free (oldtab); + map_mapobjectv->entab = newtab; + map_mapobjectv->count = newcnt; + map_mapobjectv->lenix = newlenix; + } + basilysgc_touch (map_mapobjectv); +end: + BASILYS_EXITFRAME (); + return valuv; +#undef discrv +#undef mapobjectv +#undef attrobjectv +#undef valuv +#undef object_discrv +#undef object_attrobjectv +#undef map_mapobjectv +} + + + +/* index of entry to get or add an attribute in an mapstring (or -1 on error) */ +static inline int +unsafe_index_mapstring (struct entrystringsbasilys_st *tab, + const char *attr, int siz) +{ + int ix = 0, frix = -1; + unsigned h = 0; + if (!tab || !attr || siz <= 0) + return -1; + h = (unsigned) htab_hash_string (attr) & BASILYS_MAXHASH; + h = h % siz; + for (ix = h; ix < siz; ix++) + { + const char *curat = tab[ix].e_at; + if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + else if (!strcmp (curat, attr)) + return ix; + } + for (ix = 0; ix < (int) h; ix++) + { + const char *curat = tab[ix].e_at; + if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + else if (!strcmp (curat, attr)) + return ix; + } + return -1; /* entirely full, should not happen */ +} + +/* allocate a new empty mapstrings */ +basilys_ptr_t +basilysgc_new_mapstrings (basilysobject_ptr_t discr_p, unsigned len) +{ + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define newmapv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define mapstring_newmapv ((struct basilysmapstrings_st*)(newmapv)) + discrv = discr_p; + if (!discrv || object_discrv->obj_class->object_magic != OBMAG_OBJECT) + goto end; + if (object_discrv->object_magic != OBMAG_MAPSTRINGS) + goto end; + newmapv = basilysgc_allocate (sizeof (struct basilysmapstrings_st), 0); + mapstring_newmapv->discr = object_discrv; + if (len > 0) + { + int lenix, primlen; + gcc_assert (len < (unsigned) BASILYS_MAXLEN); + for (lenix = 1; + (primlen = (int) basilys_primtab[lenix]) != 0 + && primlen <= (int) len; lenix++); + /* the newmapv is always young */ + mapstring_newmapv->entab = + basilysgc_allocate (primlen * + sizeof (struct entrystringsbasilys_st), 0); + mapstring_newmapv->lenix = lenix; + basilysgc_touch_dest (newmapv, mapstring_newmapv->entab); + } +end: + BASILYS_EXITFRAME (); + return newmapv; +#undef discrv +#undef newmapv +#undef object_discrv +#undef mapstring_newmapv +} + + +void +basilysgc_put_mapstrings (struct basilysmapstrings_st + *mapstring_p, const char *attr, + basilys_ptr_t valu_p) +{ + long ix = 0, len = 0, cnt = 0, atlen = 0; + char *attrdup = 0; + char tinybuf[130]; + BASILYS_ENTERFRAME (3, NULL); +#define discrv curfram__.varptr[0] +#define mapstringv curfram__.varptr[1] +#define valuv curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define map_mapstringv ((struct basilysmapstrings_st*)(mapstringv)) + mapstringv = mapstring_p; + valuv = valu_p; + if (!mapstringv || !attr || !attr[0] || !valuv) + goto end; + discrv = map_mapstringv->discr; + if (!discrv || object_discrv->object_magic != OBMAG_MAPSTRINGS) + goto end; + atlen = strlen (attr); + if (atlen < (int) sizeof (tinybuf) - 1) + { + memset (tinybuf, 0, sizeof (tinybuf)); + attrdup = strcpy (tinybuf, attr); + } + else + attrdup = strcpy (xcalloc (atlen + 1, 1), attr); + if (!map_mapstringv->entab) + { + len = basilys_primtab[1]; /* i.e. 3 */ + if (basilys_is_young (mapstringv)) + map_mapstringv->entab = + basilysgc_allocate (len * + sizeof (struct entrystringsbasilys_st), 0); + else + map_mapstringv->entab = + ggc_alloc_cleared (len * sizeof (struct entrystringsbasilys_st)); + map_mapstringv->lenix = 1; + basilysgc_touch (map_mapstringv); + } + else + if ((len = basilys_primtab[map_mapstringv->lenix]) <= + (5 * (cnt = map_mapstringv->count)) / 4 + 1 + || (len <= 5 && cnt + 1 >= len)) + { + int ix, newcnt = 0; + int newlen = basilys_primtab[map_mapstringv->lenix + 1]; + struct entrystringsbasilys_st *oldtab = NULL; + struct entrystringsbasilys_st *newtab = NULL; + if (basilys_is_young (mapstringv)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entrystringsbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entrystringsbasilys_st)); + oldtab = map_mapstringv->entab; + for (ix = 0; ix < len; ix++) + { + char *curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mapstring (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in old ggc space */ + ggc_free (oldtab); + map_mapstringv->entab = newtab; + map_mapstringv->count = newcnt; + map_mapstringv->lenix++; + basilysgc_touch (map_mapstringv); + len = newlen; + } + ix = unsafe_index_mapstring (map_mapstringv->entab, attrdup, len); + gcc_assert (ix >= 0); + if (!map_mapstringv->entab[ix].e_at + || map_mapstringv->entab[ix].e_at == HTAB_DELETED_ENTRY) + { + char *newat = basilysgc_allocate (atlen + 1, 0); + strcpy (newat, attrdup); + map_mapstringv->entab[ix].e_at = newat; + map_mapstringv->count++; + } + map_mapstringv->entab[ix].e_va = valuv; + basilysgc_touch_dest (map_mapstringv, valuv); +end: + if (attrdup && attrdup != tinybuf) + free (attrdup); + BASILYS_EXITFRAME (); +#undef discrv +#undef mapstringv +#undef attrobjectv +#undef valuv +#undef object_discrv +#undef object_attrobjectv +#undef map_mapstringv +} + +basilys_ptr_t +basilys_get_mapstrings (struct basilysmapstrings_st + *mapstring_p, const char *attr) +{ + long ix = 0, len = 0; + char *oldat = NULL; + if (!mapstring_p || !attr) + return NULL; + if (mapstring_p->discr->object_magic != OBMAG_MAPSTRINGS) + return NULL; + if (!mapstring_p->entab) + return NULL; + len = basilys_primtab[mapstring_p->lenix]; + if (len <= 0) + return NULL; + ix = unsafe_index_mapstring (mapstring_p->entab, attr, len); + if (ix < 0 || !(oldat = mapstring_p->entab[ix].e_at) + || oldat == HTAB_DELETED_ENTRY) + return NULL; + return mapstring_p->entab[ix].e_va; +} + +basilys_ptr_t +basilysgc_remove_mapstrings (struct basilysmapstrings_st * + mapstring_p, const char *attr) +{ + long ix = 0, len = 0, cnt = 0, atlen = 0; + const char *oldat = NULL; + char *attrdup = 0; + char tinybuf[130]; + BASILYS_ENTERFRAME (3, NULL); +#define discrv curfram__.varptr[0] +#define mapstringv curfram__.varptr[1] +#define valuv curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define map_mapstringv ((struct basilysmapstrings_st*)(mapstringv)) + mapstringv = mapstring_p; + valuv = NULL; + if (!mapstringv || !attr || !valuv || !attr[0]) + goto end; + atlen = strlen (attr); + discrv = map_mapstringv->discr; + if (!discrv || object_discrv->object_magic != OBMAG_MAPSTRINGS) + goto end; + if (!map_mapstringv->entab) + goto end; + len = basilys_primtab[map_mapstringv->lenix]; + if (len <= 0) + goto end; + if (atlen < (int) sizeof (tinybuf) - 1) + { + memset (tinybuf, 0, sizeof (tinybuf)); + attrdup = strcpy (tinybuf, attr); + } + else + attrdup = strcpy (xcalloc (atlen + 1, 1), attr); + ix = unsafe_index_mapstring (map_mapstringv->entab, attrdup, len); + if (ix < 0 || !(oldat = map_mapstringv->entab[ix].e_at) + || oldat == HTAB_DELETED_ENTRY) + goto end; + if (!basilys_is_young ((void *) (char *) oldat)) + ggc_free ((void *) oldat); + map_mapstringv->entab[ix].e_at = (void *) HTAB_DELETED_ENTRY; + valuv = map_mapstringv->entab[ix].e_va; + map_mapstringv->entab[ix].e_va = NULL; + map_mapstringv->count--; + cnt = map_mapstringv->count; + if (len > 7 && 2 * cnt + 2 < len) + { + int newcnt = 0, newlen = 0, newlenix; + struct entrystringsbasilys_st *oldtab = NULL, *newtab = NULL; + for (newlenix = map_mapstringv->lenix; + (newlen = basilys_primtab[newlenix]) > 2 * cnt + 3; newlenix--); + if (newlen >= len) + goto end; + if (basilys_is_young (mapstringv)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entrystringsbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entrystringsbasilys_st)); + oldtab = map_mapstringv->entab; + for (ix = 0; ix < len; ix++) + { + char *curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mapstring (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in ol<d ggc space */ + ggc_free (oldtab); + map_mapstringv->entab = newtab; + map_mapstringv->count = newcnt; + } + basilysgc_touch (map_mapstringv); +end: + if (attrdup && attrdup != tinybuf) + free (attrdup); + BASILYS_EXITFRAME (); + return valuv; +#undef discrv +#undef mapstringv +#undef valuv +#undef object_discrv +#undef map_mapstringv +} + + + +/* index of entry to get or add an attribute in an mappointer (or -1 on error) */ +struct entrypointerbasilys_st +{ + const void *e_at; + basilys_ptr_t e_va; +}; +static inline int +unsafe_index_mappointer (struct entrypointerbasilys_st *tab, + const void *attr, int siz) +{ + int ix = 0, frix = -1; + unsigned h = 0; + if (!tab || !attr || siz <= 0) + return -1; + h = ((unsigned) (((long) (attr)) >> 3)) & BASILYS_MAXHASH; + h = h % siz; + for (ix = h; ix < siz; ix++) + { + const void *curat = tab[ix].e_at; + if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + else if (curat == attr) + return ix; + } + for (ix = 0; ix < (int) h; ix++) + { + const void *curat = tab[ix].e_at; + if (curat == (void *) HTAB_DELETED_ENTRY) + { + if (frix < 0) + frix = ix; + } + else if (!curat) + { + if (frix < 0) + frix = ix; + return frix; + } + else if (curat == attr) + return ix; + } + return -1; /* entirely full, should not happen */ +} + + +/* this should be the same as basilysmaptrees_st, basilysmapedges_st, + basilysmapbasicblocks_st, .... */ +struct basilysmappointers_st +{ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entrypointerbasilys_st *entab; + /* the following field is usually the value of entab (for + objects in the young zone), to allocate the object and its fields + at once */ + struct entrypointerbasilys_st map_space[FLEXIBLE_DIM]; +}; +/* allocate a new empty mappointers without checks */ +void * +basilysgc_raw_new_mappointers (basilysobject_ptr_t discr_p, unsigned len) +{ + int lenix = 0, primlen = 0; + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define newmapv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define map_newmapv ((struct basilysmappointers_st*)(newmapv)) + discrv = discr_p; + if (len > 0) + { + gcc_assert (len < (unsigned) BASILYS_MAXLEN); + for (lenix = 1; + (primlen = (int) basilys_primtab[lenix]) != 0 + && primlen <= (int) len; lenix++); + }; + gcc_assert (sizeof (struct entrypointerbasilys_st) == + sizeof (struct entrytreesbasilys_st)); + gcc_assert (sizeof (struct entrypointerbasilys_st) == + sizeof (struct entryedgesbasilys_st)); + gcc_assert (sizeof (struct entrypointerbasilys_st) == + sizeof (struct entrybasicblocksbasilys_st)); + newmapv = + basilysgc_allocate (offsetof + (struct basilysmappointers_st, + map_space), + primlen * sizeof (struct entrypointerbasilys_st)); + map_newmapv->discr = object_discrv; + map_newmapv->count = 0; + map_newmapv->lenix = lenix; + if (len > 0) + map_newmapv->entab = map_newmapv->map_space; + else + map_newmapv->entab = NULL; + BASILYS_EXITFRAME (); + return newmapv; +#undef discrv +#undef newmapv +#undef object_discrv +#undef map_newmapv +} + + +void +basilysgc_raw_put_mappointers (void *mappointer_p, + const void *attr, basilys_ptr_t valu_p) +{ + long ix = 0, len = 0, cnt = 0; + BASILYS_ENTERFRAME (2, NULL); +#define mappointerv curfram__.varptr[0] +#define valuv curfram__.varptr[1] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define map_mappointerv ((struct basilysmappointers_st*)(mappointerv)) + mappointerv = mappointer_p; + valuv = valu_p; + if (!map_mappointerv->entab) + { + len = basilys_primtab[1]; /* i.e. 3 */ + if (basilys_is_young (mappointerv)) + map_mappointerv->entab = + basilysgc_allocate (len * + sizeof (struct entrypointerbasilys_st), 0); + else + map_mappointerv->entab = + ggc_alloc_cleared (len * sizeof (struct entrypointerbasilys_st)); + map_mappointerv->lenix = 1; + basilysgc_touch (map_mappointerv); + } + else + if ((len = basilys_primtab[map_mappointerv->lenix]) <= + (5 * (cnt = map_mappointerv->count)) / 4 + 1 + || (len <= 5 && cnt + 1 >= len)) + { + int ix, newcnt = 0; + int newlen = basilys_primtab[map_mappointerv->lenix + 1]; + struct entrypointerbasilys_st *oldtab = NULL; + struct entrypointerbasilys_st *newtab = NULL; + if (basilys_is_young (mappointerv)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entrypointerbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entrypointerbasilys_st)); + oldtab = map_mappointerv->entab; + for (ix = 0; ix < len; ix++) + { + const void *curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mappointer (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in old ggc space */ + ggc_free (oldtab); + map_mappointerv->entab = newtab; + map_mappointerv->count = newcnt; + map_mappointerv->lenix++; + basilysgc_touch (map_mappointerv); + len = newlen; + } + ix = unsafe_index_mappointer (map_mappointerv->entab, attr, len); + gcc_assert (ix >= 0); + if (!map_mappointerv->entab[ix].e_at + || map_mappointerv->entab[ix].e_at == HTAB_DELETED_ENTRY) + { + map_mappointerv->entab[ix].e_at = attr; + map_mappointerv->count++; + } + map_mappointerv->entab[ix].e_va = valuv; + basilysgc_touch_dest (map_mappointerv, valuv); + BASILYS_EXITFRAME (); +#undef discrv +#undef mappointerv +#undef valuv +#undef object_discrv +#undef map_mappointerv +} + +basilys_ptr_t +basilys_raw_get_mappointers (void *map, const void *attr) +{ + long ix = 0, len = 0; + const void *oldat = NULL; + struct basilysmappointers_st *mappointer_p = map; + if (!mappointer_p->entab) + return NULL; + len = basilys_primtab[mappointer_p->lenix]; + if (len <= 0) + return NULL; + ix = unsafe_index_mappointer (mappointer_p->entab, attr, len); + if (ix < 0 || !(oldat = mappointer_p->entab[ix].e_at) + || oldat == HTAB_DELETED_ENTRY) + return NULL; + return mappointer_p->entab[ix].e_va; +} + +basilys_ptr_t +basilysgc_raw_remove_mappointers (void *mappointer_p, const void *attr) +{ + long ix = 0, len = 0, cnt = 0; + const char *oldat = NULL; + BASILYS_ENTERFRAME (3, NULL); +#define discrv curfram__.varptr[0] +#define mappointerv curfram__.varptr[1] +#define valuv curfram__.varptr[2] +#define object_discrv ((basilysobject_ptr_t)(discrv)) +#define map_mappointerv ((struct basilysmappointers_st*)(mappointerv)) + mappointerv = mappointer_p; + valuv = NULL; + if (!map_mappointerv->entab) + goto end; + len = basilys_primtab[map_mappointerv->lenix]; + if (len <= 0) + goto end; + ix = unsafe_index_mappointer (map_mappointerv->entab, attr, len); + if (ix < 0 || !(oldat = map_mappointerv->entab[ix].e_at) + || oldat == HTAB_DELETED_ENTRY) + goto end; + map_mappointerv->entab[ix].e_at = (void *) HTAB_DELETED_ENTRY; + valuv = map_mappointerv->entab[ix].e_va; + map_mappointerv->entab[ix].e_va = NULL; + map_mappointerv->count--; + cnt = map_mappointerv->count; + if (len > 7 && 2 * cnt + 2 < len) + { + int newcnt = 0, newlen = 0, newlenix; + struct entrypointerbasilys_st *oldtab = NULL, *newtab = NULL; + for (newlenix = map_mappointerv->lenix; + (newlen = basilys_primtab[newlenix]) > 2 * cnt + 3; newlenix--); + if (newlen >= len) + goto end; + if (basilys_is_young (mappointerv)) + newtab = + basilysgc_allocate (newlen * + sizeof (struct entrypointerbasilys_st), 0); + else + newtab = + ggc_alloc_cleared (newlen * sizeof (struct entrypointerbasilys_st)); + oldtab = map_mappointerv->entab; + for (ix = 0; ix < len; ix++) + { + const void *curat = oldtab[ix].e_at; + int newix; + if (!curat || curat == (void *) HTAB_DELETED_ENTRY) + continue; + newix = unsafe_index_mappointer (newtab, curat, newlen); + gcc_assert (newix >= 0); + newtab[newix] = oldtab[ix]; + newcnt++; + } + if (!basilys_is_young (oldtab)) + /* free oldtab since it is in old ggc space */ + ggc_free (oldtab); + map_mappointerv->entab = newtab; + map_mappointerv->count = newcnt; + } + basilysgc_touch (map_mappointerv); +end: + BASILYS_EXITFRAME (); + return valuv; +#undef discrv +#undef mappointerv +#undef valuv +#undef object_discrv +#undef map_mappointerv +} + + +/***************** objvlisp test of strict subclassing */ +bool +basilys_is_subclass_of (basilysobject_ptr_t subclass_p, + basilysobject_ptr_t superclass_p) +{ + struct basilysmultiple_st *subanc = NULL; + struct basilysmultiple_st *superanc = NULL; + unsigned subdepth = 0, superdepth = 0; + if (basilys_magic_discr ((basilys_ptr_t) subclass_p) != + OBMAG_OBJECT || subclass_p->object_magic != OBMAG_OBJECT + || basilys_magic_discr ((basilys_ptr_t) superclass_p) != + OBMAG_OBJECT || superclass_p->object_magic != OBMAG_OBJECT) + { + gcc_unreachable (); + return FALSE; + } + if (subclass_p->obj_len < FCLASS__LAST + || !subclass_p->obj_vartab + || superclass_p->obj_len < FCLASS__LAST || !superclass_p->obj_vartab) + { + gcc_unreachable (); + return FALSE; + } + if (superclass_p == BASILYSGOB (CLASS_ROOT)) + return TRUE; + subanc = + (struct basilysmultiple_st *) subclass_p->obj_vartab[FCLASS_ANCESTORS]; + superanc = + (struct basilysmultiple_st *) superclass_p->obj_vartab[FCLASS_ANCESTORS]; + if (basilys_magic_discr ((basilys_ptr_t) subanc) != + OBMAG_MULTIPLE || subanc->discr != BASILYSGOB (DISCR_SEQCLASS)) + { + gcc_unreachable (); + return FALSE; + } + if (basilys_magic_discr ((basilys_ptr_t) superanc) != + OBMAG_MULTIPLE || superanc->discr != BASILYSGOB (DISCR_SEQCLASS)) + { + gcc_unreachable (); + return FALSE; + } + subdepth = subanc->nbval; + superdepth = superanc->nbval; + if (subdepth <= superdepth) + return FALSE; + if ((basilys_ptr_t) subanc->tabval[superdepth] == + (basilys_ptr_t) superclass_p) + return TRUE; + return FALSE; +} + + +basilys_ptr_t +basilysgc_new_string (basilysobject_ptr_t discr_p, const char *str) +{ + int slen = 0; + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define strv curfram__.varptr[1] +#define obj_discrv ((struct basilysobject_st*)(discrv)) +#define str_strv ((struct basilysstring_st*)(strv)) + strv = 0; + if (!str) + goto end; + slen = strlen (str); + discrv = discr_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (obj_discrv->object_magic != OBMAG_STRING) + goto end; + strv = basilysgc_allocate (sizeof (struct basilysstring_st), slen + 1); + str_strv->discr = obj_discrv; + strcpy (str_strv->val, str); +end: + BASILYS_EXITFRAME (); + return strv; +#undef discrv +#undef strv +#undef obj_discrv +#undef str_strv +} + +basilys_ptr_t +basilysgc_new_stringdup (basilysobject_ptr_t discr_p, const char *str) +{ + int slen = 0; + char tinybuf[80]; + char *strcop = 0; + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define strv curfram__.varptr[1] +#define obj_discrv ((struct basilysobject_st*)(discrv)) +#define str_strv ((struct basilysstring_st*)(strv)) + strv = 0; + if (!str) + goto end; + discrv = discr_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (obj_discrv->object_magic != OBMAG_STRING) + goto end; + slen = strlen (str); + if (slen < (int) sizeof (tinybuf) - 1) + { + memset (tinybuf, 0, sizeof (tinybuf)); + strcop = strcpy (tinybuf, str); + } + else + strcop = strcpy (xcalloc (1, slen + 1), str); + strv = basilysgc_allocate (sizeof (struct basilysstring_st), slen + 1); + str_strv->discr = obj_discrv; + strcpy (str_strv->val, strcop); +end: + if (strcop && strcop != tinybuf) + free (strcop); + memset (tinybuf, 0, sizeof (tinybuf)); + BASILYS_EXITFRAME (); + return strv; +#undef discrv +#undef strv +#undef obj_discrv +#undef str_strv +} + +basilys_ptr_t +basilysgc_new_string_nakedbasename (basilysobject_ptr_t + discr_p, const char *str) +{ + int slen = 0; + char tinybuf[120]; + char *strcop = 0; + char *basestr = 0; + char *dot = 0; + BASILYS_ENTERFRAME (2, NULL); +#define discrv curfram__.varptr[0] +#define strv curfram__.varptr[1] +#define obj_discrv ((struct basilysobject_st*)(discrv)) +#define str_strv ((struct basilysstring_st*)(strv)) + strv = 0; + if (!str) + goto end; + discrv = discr_p; + if (basilys_magic_discr (discrv) != OBMAG_OBJECT) + goto end; + if (obj_discrv->object_magic != OBMAG_STRING) + goto end; + slen = strlen (str); + if (slen < (int) sizeof (tinybuf) - 1) + { + memset (tinybuf, 0, sizeof (tinybuf)); + strcop = strcpy (tinybuf, str); + } + else + strcop = strcpy (xcalloc (1, slen + 1), str); + basestr = (char *) lbasename (strcop); + dot = strchr (basestr, '.'); + if (dot) + *dot = 0; + strv = + basilysgc_allocate (sizeof (struct basilysstring_st), + strlen (basestr) + 1); + str_strv->discr = obj_discrv; + strcpy (str_strv->val, basestr); +end: + if (strcop && strcop != tinybuf) + free (strcop); + memset (tinybuf, 0, sizeof (tinybuf)); + BASILYS_EXITFRAME (); + return strv; +#undef discrv +#undef strv +#undef obj_discrv +#undef str_strv +} + + +#if 0 && NOT_NEEDED +static const char * +copynamestring (const char *string) +{ + size_t len = strlen (string) + 1; + char *s = (char *) obstack_alloc (&bname_obstack, len); + strcpy (s, string); + return s; +} +#endif + + +#if ENABLE_CHECKING +static long applcount_basilys; +static int appldepth_basilys; +#define MAXDEPTH_APPLY_BASILYS 2000 +#endif +/*************** closure application ********************/ +basilys_ptr_t +basilysgc_apply (basilysclosure_ptr_t clos_p, + basilys_ptr_t arg1_p, + const char *xargdescr_, + union basilysparam_un *xargtab_, + const char *xresdescr_, union basilysparam_un *xrestab_) +{ + basilys_ptr_t res = NULL; + union + { + long funad[1 + sizeof (basilysroutfun_t *) / sizeof (long)]; + basilysroutfun_t *pfun; + } + ufun; +#if ENABLE_CHECKING + applcount_basilys++; + appldepth_basilys++; + if (appldepth_basilys > MAXDEPTH_APPLY_BASILYS) + fatal_error ("too deep (%d) basilys application", appldepth_basilys); +#endif + memset (&ufun, 0, sizeof (ufun)); + if (basilys_magic_discr ((void *) clos_p) != OBMAG_CLOSURE) + return NULL; + if (basilys_magic_discr ((void *) clos_p->rout) != + OBMAG_ROUTINE || !clos_p->rout->routaddr) + return NULL; + memcpy (&ufun.funad, clos_p->rout->routaddr, + sizeof (clos_p->rout->routaddr)); + gcc_assert (ufun.pfun); + /* only make sense on AMD64/Linux */ + gcc_assert (((unsigned long) ufun.pfun) > 4096UL + && ((unsigned long) ufun.pfun) < 0xffffffffff600000UL); + res = + (*ufun.pfun) (clos_p, arg1_p, xargdescr_, xargtab_, xresdescr_, xrestab_); +#if ENABLE_CHECKING + appldepth_basilys--; +#endif + return res; +} + + + +/************** method sending ***************/ +basilys_ptr_t +basilysgc_send (basilys_ptr_t recv_p, + basilys_ptr_t sel_p, + const char *xargdescr_, + union basilysparam_un * xargtab_, + const char *xresdescr_, union basilysparam_un * xrestab_) +{ +#ifdef ENABLE_CHECKING + static long sendcount; + long sendnum = ++sendcount; +#endif + BASILYS_ENTERFRAME (9, NULL); +#define recv curfram__.varptr[0] +#define selv curfram__.varptr[1] +#define argv curfram__.varptr[2] +#define closv curfram__.varptr[3] +#define discrv curfram__.varptr[4] +#define mapv curfram__.varptr[5] +#define superv curfram__.varptr[6] +#define resv curfram__.varptr[7] +#define ancv curfram__.varptr[8] +#define obj_discrv ((basilysobject_ptr_t)(discrv)) +#define obj_selv ((basilysobject_ptr_t)(selv)) +#define clo_closv ((basilysclosure_ptr_t)(closv)) +#define mul_ancv ((struct basilysmultiple_st*)(ancv)) + recv = recv_p; + selv = sel_p; + if (!recv) + goto end; +#ifdef ENABLE_CHECKING + (void) sendnum; /* to use it */ +#endif + if (basilys_magic_discr (selv) != OBMAG_OBJECT) + goto end; + if (!basilys_is_instance_of (selv, BASILYSG (CLASS_SELECTOR))) + goto end; +#if 0 && ENABLE_CHECKING + debugeprintf ("send #%ld recv %p", sendnum, (void *) recv); + debugeprintf ("send #%ld selv %p <%s>", sendnum, + (void *) obj_selv, + basilys_string_str (obj_selv->obj_vartab[FNAMED_NAME])); +#endif + discrv = + recv ? ((basilys_ptr_t) recv)->u_discr : BASILYSGOB (DISCR_NULLRECV); + while (discrv) + { + gcc_assert (basilys_magic_discr (discrv) == OBMAG_OBJECT); + gcc_assert (obj_discrv->obj_len >= FDISCR__LAST); +#if 0 && ENABLE_CHECKING + debugeprintf ("send #%ld discrv %p <%s>", + sendnum, discrv, + basilys_string_str (obj_discrv->obj_vartab[FNAMED_NAME])); +#endif + mapv = obj_discrv->obj_vartab[FDISCR_METHODICT]; + if (basilys_magic_discr (mapv) == OBMAG_MAPOBJECTS) + { + closv = basilys_get_mapobjects (mapv, selv); + } + else + { + closv = obj_discrv->obj_vartab[FDISCR_SENDCLOSURE]; + if (basilys_magic_discr (closv) == OBMAG_CLOSURE) + { + union basilysparam_un pararg[1]; + pararg[0].bp_aptr = (basilys_ptr_t *) & selv; + resv = basilysgc_apply (closv, recv, BPARSTR_PTR, pararg, + "", NULL); + closv = resv; + } + } + if (basilys_magic_discr (closv) == OBMAG_CLOSURE) + { +#if 0 && ENABLE_CHECKING + debugeprintf ("send #%ld applying closv %p", sendnum, closv); +#endif + resv = + basilysgc_apply (closv, recv, xargdescr_, xargtab_, + xresdescr_, xrestab_); + goto end; + } + discrv = obj_discrv->obj_vartab[FDISCR_SUPER]; + } /* end while discrv */ + resv = NULL; +end: +#if 0 && ENABLE_CHECKING + debugeprintf ("endsend #%ld recv %p resv %p selv %p <%s>", + sendnum, recv, resv, (void *) obj_selv, + basilys_string_str (obj_selv->obj_vartab[FNAMED_NAME])); +#endif + BASILYS_EXITFRAME (); + return resv; +#undef recv +#undef selv +#undef closv +#undef discrv +#undef argv +#undef mapv +#undef superv +#undef resv +#undef ancv +#undef obj_discrv +#undef obj_selv +#undef clo_closv +} + + +/* the srcfile is a generated .c file, the dlfile has no suffix, + because the suffix is expected to be added by the basilys-gcc + script */ +static void +compile_to_dyl (const char *srcfile, const char *dlfile) +{ + struct pex_obj *pex = 0; + int err = 0; + int cstatus = 0; + const char *errmsg = 0; + /* possible improvement for GlobalGcc partners : avoid recompiling + when not necessary; using timestamps a la make is not enough, + since the C source files are generated. + +The basilys-gcc script takes two arguments: the C source file path to +compile as a basilys plugin, and the naked dynamic library file to be +generated. A standard path for this script should be defined, and the +default should neither be getenv-ed not be built-in (as the +"basilys-gcc" string below) but somehow parametrized. + +The basilys-gcc script should be generated in the building process. +In addition of compiling the C source file, it should put into the +generated dynamic library the following two constant strings; + const char basilys_compiled_timestamp[]; + const char basilys_md5[]; + +the basilys_compiled_timestamp should contain a human readable +timestamp the basilys_md5 should contain the hexadecimal md5 digest, +followed by the source file name (i.e. the single line output by the +command: md5sum $Csourcefile; where $Csourcefile is replaced by the +source file path) + + */ + const char *basilysgcccmd = getenv ("BASILYS_GCC"); + struct pex_time ptime; + char *argv[4]; + memset (&ptime, 0, sizeof (ptime)); + if (!basilysgcccmd) + basilysgcccmd = "basilys-gcc"; + debugeprintf ("compile_to_dyl srcfile %s dlfile %s", srcfile, dlfile); + fflush (stdout); + fflush (stderr); + pex = pex_init (PEX_RECORD_TIMES, basilysgcccmd, NULL); + argv[0] = (char *) basilysgcccmd; + argv[1] = (char *) srcfile; + argv[2] = (char *) dlfile; + argv[3] = (char *) 0; + errmsg = + pex_run (pex, PEX_LAST | PEX_SEARCH, basilysgcccmd, argv, + NULL, NULL, &err); + if (errmsg) + fatal_error + ("failed to basilys compile to dyl: %s %s %s : %s", + basilysgcccmd, srcfile, dlfile, errmsg); + if (!pex_get_status (pex, 1, &cstatus)) + fatal_error + ("failed to get status of basilys dynamic compilation to dyl: %s %s %s - %m", + basilysgcccmd, srcfile, dlfile); + if (!pex_get_times (pex, 1, &ptime)) + fatal_error + ("failed to get time of basilys dynamic compilation to dyl: %s %s %s - %m", + basilysgcccmd, srcfile, dlfile); + pex_free (pex); + debugeprintf ("compile_to_dyl done srcfile %s dlfile %s", srcfile, dlfile); +} + + + + +/* compile (as a dynamically loadable module) some (usually generated) + C code and dynamically load it; the C code should contain a + function named start_module_basilys; that function is called with + the given modata and returns the module */ +basilys_ptr_t +basilysgc_compile_dyn (basilys_ptr_t modata_p, const char *srcfile) +{ + char *srcpath = 0, *shobjpath = 0; + lt_dlhandle dlh = 0; + lt_ptr dlsy = 0; + typedef basilys_ptr_t startroutine_t (basilys_ptr_t); + startroutine_t *starout = 0; + BASILYS_ENTERFRAME (3, NULL); +#define modulv curfram__.varptr[0] +#define mdatav curfram__.varptr[1] + mdatav = modata_p; + srcpath = xstrdup (srcfile); + shobjpath = 0; + debugeprintf ("basilysgc_compile srcfile=%s", srcfile); + if (access (srcpath, R_OK)) + fatal_error ("no source file %s to basilys compile : %m", srcpath); + /* @@@ this is too simplistic; the tldl library is able to deal with + shared objects which are not named .so but something else; some + GlobalGcc partner is expected to improve this, to take the + following into account: + + * looking in some well defined directory containing the basilys + dynamic libraries. This directory should be supported by the + build process + + * if a dynamic library of suitable name is found, check that its + basilys_md5 is the same as the md5 signature of the source file, + and change the shobjpath variable accordingly + + * if a dynamic library is not found, make a suitable temporary + file (whose suffix is not always .so, but could be .dylib on + MacOSX, etc... + + **/ + shobjpath = make_temp_file (".so"); + debugeprintf ("basilysgc_compile srcpath=%s shobjpath=%s", + srcpath, shobjpath); + compile_to_dyl (srcpath, shobjpath); + /** end of code to be improved by some GlobalGcc partner; everything + below is ok @@@ */ + dlh = lt_dlopenext (shobjpath); + if (!dlh) + fatal_error + ("basilysgc_compile failed to lt_dlopenext src=%s shobj=%s - %s", + srcpath, shobjpath, lt_dlerror ()); + dlsy = lt_dlsym (dlh, "start_module_basilys"); + if (!dlsy) + fatal_error + ("basilysgc_compile failed to lt_dlsym start_module_basilys in src=%s shobj=%ss - %s", + srcpath, shobjpath, lt_dlerror ()); + starout = (startroutine_t *) dlsy; + debugeprintvalue ("mdatav before calling start_module_basilys", mdatav); + debugeprintf + ("basilysgc_compile before calling start_module_basilys @%p", + (void *) dlsy); + modulv = (*starout) (mdatav); + debugeprintvalue ("modulv after calling start_module_basilys", modulv); + BASILYS_EXITFRAME (); + return modulv; +#undef mdatav +#undef modulv +} + +/*************** initial load machinery *******************/ + + +struct reading_st +{ + FILE *rfil; + const char *rpath; + char *rcurlin; /* current line mallocated buffer */ + int rlineno; /* current line number */ + int rcol; /* current column */ + basilys_ptr_t *rpfilnam; /* pointer to location of file name string */ + basilys_ptr_t *rpgenv; /* pointer to location of environment */ +}; +/* Obstack used for reading strings */ +static struct obstack bstring_obstack; +#define rdback() (rd->rcol--) +#define rdnext() (rd->rcol++) +#define rdcurc() rd->rcurlin[rd->rcol] +#define rdfollowc(Rk) rd->rcurlin[rd->rcol + (Rk)] +#define rdeof() (feof(rd->rfil) && rd->rcurlin[rd->rcol]==0) +#define READ_ERROR(Fmt,...) \ + fatal_error("%s:%d:%d: read error <%s:%d> - " Fmt, \ + rd->rpath, rd->rlineno, rd->rcol, \ + basename(__FILE__),__LINE__, ##__VA_ARGS__) +/* readval returns the read value and sets *PGOT to true if something + was read */ +static basilys_ptr_t readval (struct reading_st *rd, bool * pgot); +static int +skipspace_getc (struct reading_st *rd) +{ + int c = 0; + int incomm = 0; +readagain: + if (rdeof ()) + return EOF; + if (!rd->rcurlin) + goto readline; + c = rdcurc (); + if (c == '\n' || c == 0) + readline: + { + /* we expect most lines to fit into linbuf, so we don't handle + efficiently long lines */ + static char linbuf[400]; + char *mlin = 0; /* partial mallocated line buffer when + not fitting into linbuf */ + char *eol = 0; + if (rd->rcurlin) + free ((void *) rd->rcurlin); + rd->rcurlin = NULL; + /* we really want getline here .... */ + for (;;) + { + memset (linbuf, 0, sizeof (linbuf)); + eol = NULL; + if (!fgets (linbuf, sizeof (linbuf), rd->rfil)) + { + /* reached eof, so either give mlin or duplicate an empty + line */ + if (mlin) + rd->rcurlin = mlin; + else + rd->rcurlin = xstrdup (""); + break; + } + else + eol = strchr (linbuf, '\n'); + if (eol) + { + if (rd->rcurlin) + free ((void *) rd->rcurlin); + if (!mlin) + rd->rcurlin = xstrdup (linbuf); + else + { + rd->rcurlin = concat (mlin, linbuf, NULL); + free (mlin); + } + break; + } + else + { + /* read partly a long line without reaching the end of line */ + if (mlin) + { + char *newmlin = concat (mlin, linbuf, NULL); + free (mlin); + mlin = newmlin; + } + else + mlin = xstrdup (linbuf); + } + }; + rd->rlineno++; + rd->rcol = 0; + goto readagain; + } + else if (c == ';') + goto readline; + else if (c == '#' && rdfollowc (1) == '|') + { + incomm = 1; + rdnext (); + c = rdcurc (); + goto readagain; + } + else if (incomm && c == '|' && rdfollowc (1) == '#') + { + incomm = 0; + rdnext (); + rdnext (); + c = rdcurc (); + goto readagain; + } + else if (ISSPACE (c) || incomm) + { + rdnext (); + c = rdcurc (); + goto readagain; + } + else + return c; +} + + +#define EXTRANAMECHARS "_+-*/<>=!?:%~&@$" +/* read a simple name on the bname_obstack */ +static char * +readsimplename (struct reading_st *rd) +{ + int c = 0; + while (!rdeof () && (c = rdcurc ()) > 0 && + (ISALNUM (c) || strchr (EXTRANAMECHARS, c) != NULL)) + { + obstack_1grow (&bname_obstack, (char) c); + rdnext (); + } + obstack_1grow (&bname_obstack, (char) 0); + return XOBFINISH (&bname_obstack, char *); +} + + +/* read an integer, like +123, which may also be +%numbername or +|fieldname */ +static long +readsimplelong (struct reading_st *rd) +{ + int c = 0; + long r = 0; + char *endp = 0; + char *nam = 0; + bool neg = FALSE; + /* we do not need any GC locals ie BASILYS_ENTERFRAME because no + garbage collection occurs here */ + c = rdcurc (); + if (((c == '+' || c == '-') && ISDIGIT (rdfollowc (1))) || ISDIGIT (c)) + { + /* R5RS and R6RS require decimal notation -since the binary and + hex numbers are hash-prefixed but for convenience we accept + them thru strtol */ + r = strtol (&rdcurc (), &endp, 0); + if (r == 0 && endp <= &rdcurc ()) + READ_ERROR ("failed to read number %.20s", &rdcurc ()); + rd->rcol += endp - &rdcurc (); + return r; + } + else if ((c == '+' || c == '-') && rdfollowc (1) == '%') + { + neg = (c == '-'); + rdnext (); + rdnext (); + nam = readsimplename (rd); + r = -1; + /* the +%magicname notation is seldom used, we don't care to do + many needless strcmp-s in that case, to be able to define the + below simple macro */ + if (!nam) + READ_ERROR + ("magic number name expected after +%% or -%% for magic %s", nam); +#define NUMNAM(N) else if (!strcmp(nam,#N)) r = (N) + NUMNAM (OBMAG_OBJECT); + NUMNAM (OBMAG_MULTIPLE); + NUMNAM (OBMAG_BOX); + NUMNAM (OBMAG_CLOSURE); + NUMNAM (OBMAG_ROUTINE); + NUMNAM (OBMAG_LIST); + NUMNAM (OBMAG_PAIR); + NUMNAM (OBMAG_TRIPLE); + NUMNAM (OBMAG_INT); + NUMNAM (OBMAG_MIXINT); + NUMNAM (OBMAG_REAL); + NUMNAM (OBMAG_STRING); + NUMNAM (OBMAG_STRBUF); + NUMNAM (OBMAG_TREE); + NUMNAM (OBMAG_BASICBLOCK); + NUMNAM (OBMAG_EDGE); + NUMNAM (OBMAG_MAPOBJECTS); + NUMNAM (OBMAG_MAPSTRINGS); + NUMNAM (OBMAG_MAPTREES); + NUMNAM (OBMAG_MAPBASICBLOCKS); + NUMNAM (OBMAG_MAPEDGES); + NUMNAM (OBMAG_DECAY); + NUMNAM (OBMAG_SPEC_FILE); + NUMNAM (OBMAG_SPEC_MPFR); + NUMNAM (OBMAG_SPECPPL_COEFFICIENT); + NUMNAM (OBMAG_SPECPPL_LINEAR_EXPRESSION); + NUMNAM (OBMAG_SPECPPL_CONSTRAINT); + NUMNAM (OBMAG_SPECPPL_CONSTRAINT_SYSTEM); + NUMNAM (OBMAG_SPECPPL_GENERATOR); + NUMNAM (OBMAG_SPECPPL_GENERATOR_SYSTEM); + NUMNAM (FPROPED_PROP); + NUMNAM (FPROPED__LAST); + NUMNAM (FNAMED_NAME); + NUMNAM (FNAMED__LAST); + NUMNAM (FDISCR_METHODICT); + NUMNAM (FDISCR_SENDCLOSURE); + NUMNAM (FDISCR__LAST); + NUMNAM (FCLASS_ANCESTORS); + NUMNAM (FCLASS_FIELDS); + NUMNAM (FCLASS_OBJNUMDESCR); + NUMNAM (FCLASS_DATA); + NUMNAM (FCLASS__LAST); + NUMNAM (FSEXPR_LOCATION); + NUMNAM (FSEXPR_CONTENTS); + NUMNAM (FSEXPR__LAST); + /*** + not @NumNam (FFIELD_OWNCLASS); + not @NumNam (FFIELD_TYPINFO); + not @NumNam (FFIELD__LAST); + not @NumNam (FRENV_MACRODICT); + not @NumNam (FRENV_NAMEBIND); + not @NumNam (FRENV_PARENTENV); + not @NumNam (FRENV__LAST); + not @NumNam (FSYMB_DATA); + not @NumNam (FSYMB__LAST); + not @NumNam (FQUARK_SIGN); + not @NumNam (FQUARK_DATA); + not @NumNam (FQUARK__LAST); + not @NumNam (BPAR_PTR); + not @NumNam (BPAR_RESTPTR); + not @NumNam (BPAR_TREE); + not @NumNam (BPAR_LONG); + not @NumNam (BPAR_EDGE); + not @NumNam (BPAR_BB); + ***/ +#undef NUMNAM + if (r < 0) + READ_ERROR ("bad magic number name %s", nam); + obstack_free (&bname_obstack, nam); + return neg ? -r : r; + } + else + READ_ERROR ("invalid number %.20s", &rdcurc ()); + return 0; +} + + +static basilys_ptr_t +readseqlist (struct reading_st *rd, int endc) +{ + int c = 0; + int nbcomp = 0; + bool got = FALSE; + BASILYS_ENTERFRAME (2, NULL); +#define seqv curfram__.varptr[0] +#define compv curfram__.varptr[1] + seqv = basilysgc_new_list (BASILYSGOB (DISCR_LIST)); +readagain: + compv = NULL; + c = skipspace_getc (rd); + if (c == endc) + { + rdnext (); + goto end; + } + got = FALSE; + compv = readval (rd, &got); + if (!compv && !got) + READ_ERROR ("unexpected stuff in seq %.20s", &rdcurc ()); + basilysgc_append_list (seqv, compv); + nbcomp++; + goto readagain; +end: + BASILYS_EXITFRAME (); + return seqv; +#undef compv +#undef seqv +} + + + + +static basilys_ptr_t +makesexpr (struct reading_st *rd, int lineno, basilys_ptr_t contents_p) +{ + BASILYS_ENTERFRAME (4, NULL); +#define sexprv curfram__.varptr[0] +#define contsv curfram__.varptr[1] +#define locmixv curfram__.varptr[2] + contsv = contents_p; + gcc_assert (basilys_magic_discr (contsv) == OBMAG_LIST); + locmixv = basilysgc_new_mixint (BASILYSGOB (DISCR_MIXEDINT), + *rd->rpfilnam, (long) lineno); + sexprv = basilysgc_new_raw_object (BASILYSGOB (CLASS_SEXPR), FSEXPR__LAST); + ((basilysobject_ptr_t) (sexprv))->obj_vartab[FSEXPR_LOCATION] = locmixv; + ((basilysobject_ptr_t) (sexprv))->obj_vartab[FSEXPR_CONTENTS] = contsv; + basilysgc_touch (sexprv); + BASILYS_EXITFRAME (); + return sexprv; +#undef sexprv +#undef contsv +#undef locmixv +} + + +basilys_ptr_t +basilysgc_named_symbol (const char *nam, int create) +{ + int namlen = 0, ix = 0; + char *namdup = 0; + char tinybuf[130]; + BASILYS_ENTERFRAME (4, NULL); +#define symbv curfram__.varptr[0] +#define dictv curfram__.varptr[1] +#define closv curfram__.varptr[2] +#define nstrv curfram__.varptr[3] + symbv = NULL; + dictv = NULL; + closv = NULL; + if (!nam) + goto end; + namlen = strlen (nam); + memset (tinybuf, 0, sizeof (tinybuf)); + if (namlen < (int) sizeof (tinybuf) - 2) + namdup = strcpy (tinybuf, nam); + else + namdup = strcpy (xcalloc (namlen + 1, 1), nam); + gcc_assert (basilys_magic_discr (BASILYSG (CLASS_TOKENIZER)) + == OBMAG_OBJECT); + gcc_assert (basilys_magic_discr (BASILYSG (TOKENIZER)) == OBMAG_OBJECT); + for (ix = 0; ix < namlen; ix++) + if (ISALPHA (namdup[ix])) + namdup[ix] = TOUPPER (namdup[ix]); + if (basilys_is_instance_of + (BASILYSG (TOKENIZER), BASILYSG (CLASS_TOKENIZER)) + && BASILYSGOB (TOKENIZER)->obj_len >= FTOK__LAST) + { + dictv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_SYMBDICT]; + if (basilys_magic_discr (dictv) == OBMAG_MAPSTRINGS) + symbv = basilys_get_mapstrings (dictv, namdup); + if (symbv || !create) + goto end; + closv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_ADDSYMB]; + if (basilys_magic_discr (closv) == OBMAG_CLOSURE) + { + union basilysparam_un pararg[1]; + memset (¶rg, 0, sizeof (pararg)); + nstrv = basilysgc_new_string (BASILYSGOB (DISCR_STRING), namdup); + pararg[0].bp_aptr = (basilys_ptr_t *) & nstrv; + symbv = + basilysgc_apply (closv, BASILYSG (TOKENIZER), BPARSTR_PTR, + pararg, "", NULL); + goto end; + } + } +end:; + if (namdup && namdup != tinybuf) + free (namdup); + BASILYS_EXITFRAME (); + return symbv; +#undef symbv +#undef dictv +#undef closv +#undef nstrv +} + +basilys_ptr_t +basilysgc_intern_symbol (basilys_ptr_t symb_p) +{ + BASILYS_ENTERFRAME (5, NULL); +#define symbv curfram__.varptr[0] +#define dictv curfram__.varptr[1] +#define closv curfram__.varptr[2] +#define nstrv curfram__.varptr[3] +#define resv curfram__.varptr[4] +#define obj_symbv ((basilysobject_ptr_t)(symbv)) + symbv = symb_p; + if (basilys_magic_discr (symbv) != OBMAG_OBJECT + || obj_symbv->obj_len < FSYMB__LAST + || !basilys_is_instance_of (symbv, BASILYSG (CLASS_SYMBOL))) + goto fail; + nstrv = obj_symbv->obj_vartab[FNAMED_NAME]; + if (basilys_magic_discr (nstrv) != OBMAG_STRING) + goto fail; + if (basilys_magic_discr (BASILYSG (TOKENIZER)) != + OBMAG_OBJECT + || BASILYSGOB (TOKENIZER)->obj_len < FTOK__LAST + || !basilys_is_instance_of (BASILYSG (TOKENIZER), + BASILYSG (CLASS_TOKENIZER))) + goto fail; + closv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_INTERNSYMB]; + if (basilys_magic_discr (closv) != OBMAG_CLOSURE) + goto fail; + else + { + union basilysparam_un pararg[1]; + memset (¶rg, 0, sizeof (pararg)); + pararg[0].bp_aptr = (basilys_ptr_t *) & symbv; + resv = + basilysgc_apply (closv, BASILYSG (TOKENIZER), BPARSTR_PTR, + pararg, "", NULL); + goto end; + } +fail: + resv = NULL; +end:; + BASILYS_EXITFRAME (); + return resv; +#undef symbv +#undef dictv +#undef closv +#undef nstrv +#undef resv +#undef obj_symbv +} + + +basilys_ptr_t +basilysgc_intern_keyword (basilys_ptr_t keyw_p) +{ + BASILYS_ENTERFRAME (5, NULL); +#define keywv curfram__.varptr[0] +#define dictv curfram__.varptr[1] +#define closv curfram__.varptr[2] +#define nstrv curfram__.varptr[3] +#define resv curfram__.varptr[4] +#define obj_keywv ((basilysobject_ptr_t)(keywv)) + keywv = keyw_p; + if (basilys_magic_discr (keywv) != OBMAG_OBJECT + || obj_keywv->obj_len < FSYMB__LAST + || !basilys_is_instance_of (keywv, BASILYSG (CLASS_KEYWORD))) + goto fail; + nstrv = obj_keywv->obj_vartab[FNAMED_NAME]; + if (basilys_magic_discr (nstrv) != OBMAG_STRING) + goto fail; + if (basilys_magic_discr (BASILYSG (TOKENIZER)) != + OBMAG_OBJECT + || BASILYSGOB (TOKENIZER)->obj_len < FTOK__LAST + || !basilys_is_instance_of (BASILYSG (TOKENIZER), + BASILYSG (CLASS_TOKENIZER))) + goto fail; + closv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_INTERNKEYW]; + if (basilys_magic_discr (closv) != OBMAG_CLOSURE) + goto fail; + else + { + union basilysparam_un pararg[1]; + memset (¶rg, 0, sizeof (pararg)); + pararg[0].bp_aptr = (basilys_ptr_t *) & keywv; + resv = + basilysgc_apply (closv, BASILYSG (TOKENIZER), BPARSTR_PTR, + pararg, "", NULL); + goto end; + } +fail: + resv = NULL; +end:; + BASILYS_EXITFRAME (); + return resv; +#undef symbv +#undef dictv +#undef closv +#undef nstrv +#undef resv +#undef obj_symbv +} + + + + + + +basilys_ptr_t +basilysgc_named_keyword (const char *nam, int create) +{ + int namlen = 0, ix = 0; + char *namdup = 0; + char tinybuf[130]; + BASILYS_ENTERFRAME (4, NULL); +#define keywv curfram__.varptr[0] +#define dictv curfram__.varptr[1] +#define closv curfram__.varptr[2] +#define nstrv curfram__.varptr[3] + keywv = NULL; + dictv = NULL; + closv = NULL; + if (!nam) + goto end; + if (nam[0] == ':') + nam++; + namlen = strlen (nam); + memset (tinybuf, 0, sizeof (tinybuf)); + if (namlen < (int) sizeof (tinybuf) - 2) + namdup = strcpy (tinybuf, nam); + else + namdup = strcpy (xcalloc (namlen + 1, 1), nam); + for (ix = 0; ix < namlen; ix++) + if (ISALPHA (namdup[ix])) + namdup[ix] = TOUPPER (namdup[ix]); + gcc_assert (basilys_magic_discr (BASILYSG (CLASS_TOKENIZER)) + == OBMAG_OBJECT); + gcc_assert (basilys_magic_discr (BASILYSG (TOKENIZER)) == OBMAG_OBJECT); + if (basilys_is_instance_of + (BASILYSG (TOKENIZER), BASILYSG (CLASS_TOKENIZER)) + && BASILYSGOB (TOKENIZER)->obj_len >= FTOK__LAST) + { + dictv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_KEYWDICT]; + if (basilys_magic_discr (dictv) == OBMAG_MAPSTRINGS) + keywv = basilys_get_mapstrings (dictv, namdup); + if (keywv || !create) + goto end; + closv = BASILYSGOB (TOKENIZER)->obj_vartab[FTOK_ADDKEYW]; + if (basilys_magic_discr (closv) == OBMAG_CLOSURE) + { + union basilysparam_un pararg[1]; + memset (¶rg, 0, sizeof (pararg)); + nstrv = basilysgc_new_string (BASILYSGOB (DISCR_STRING), namdup); + pararg[0].bp_aptr = (basilys_ptr_t *) & nstrv; + keywv = + basilysgc_apply (closv, BASILYSG (TOKENIZER), BPARSTR_PTR, + pararg, "", NULL); + goto end; + } + } +end:; + if (namdup && namdup != tinybuf) + free (namdup); + BASILYS_EXITFRAME (); + return keywv; +#undef keywv +#undef dictv +#undef closv +#undef nstrv +} + + + +static basilys_ptr_t +readsexpr (struct reading_st *rd, int endc) +{ + int c = 0, lineno = rd->rlineno; + BASILYS_ENTERFRAME (3, NULL); +#define sexprv curfram__.varptr[0] +#define contv curfram__.varptr[1] +#define locmixv curfram__.varptr[2] + if (!endc || rdeof ()) + READ_ERROR ("eof in s-expr (lin%d)", lineno); + c = skipspace_getc (rd); + contv = readseqlist (rd, endc); + sexprv = makesexpr (rd, lineno, contv); + BASILYS_EXITFRAME (); + return sexprv; +#undef sexprv +#undef contv +#undef locmixv +} + + +static basilys_ptr_t +readassoc (struct reading_st *rd) +{ + int sz = 0, c = 0, ln = 0, pos = 0; + BASILYS_ENTERFRAME (3, NULL); +#define mapv curfram__.varptr[0] +#define attrv curfram__.varptr[1] +#define valv curfram__.varptr[2] + /* maybe read the size */ + if (rdcurc () == '/') + { + sscanf (&rdcurc (), "/%d%n", &sz, &pos); + if (pos > 0) + rd->rcol += pos; + }; + if (sz > BASILYS_MAXLEN) + sz = BASILYS_MAXLEN; + else if (sz < 0) + sz = 2; + mapv = basilysgc_new_mapobjects (BASILYSGOB (DISCR_MAPOBJECTS), sz); + c = skipspace_getc (rd); + while (c != '}' && !rdeof ()) + { + bool gotat = FALSE, gotva = FALSE; + ln = rd->rlineno; + attrv = readval (rd, &gotat); + if (!gotat || !attrv || basilys_magic_discr (attrv) != OBMAG_OBJECT) + READ_ERROR ("bad attribute in mapoobject line %d", ln); + c = skipspace_getc (rd); + if (c != '=') + READ_ERROR ("expected equal = after attribute but got %c", + ISPRINT (c) ? c : ' '); + rdnext (); + ln = rd->rlineno; + valv = readval (rd, &gotva); + if (!valv) + READ_ERROR ("null or missing value in mapobject line %d", ln); + c = skipspace_getc (rd); + if (c == '.') + c = skipspace_getc (rd); + } + if (c == '}') + rdnext (); + BASILYS_EXITFRAME (); + return mapv; +#undef mapv +#undef attrv +#undef valv +} + + + +static basilys_ptr_t +readstring (struct reading_st *rd) +{ + int c = 0; + int nbesc = 0; + char *cstr = 0, *endc = 0; + BASILYS_ENTERFRAME (1, NULL); +#define strv curfram__.varptr[0] +#define str_strv ((struct basilysstring_st*)(strv)) + while ((c = rdcurc ()) != '"' && !rdeof ()) + { + if (c != '\\') + { + obstack_1grow (&bstring_obstack, (char) c); + rdnext (); + } + else + { + rdnext (); + c = rdcurc (); + nbesc++; + switch (c) + { + case 'a': + c = '\a'; + rdnext (); + break; + case 'b': + c = '\b'; + rdnext (); + break; + case 't': + c = '\t'; + rdnext (); + break; + case 'n': + c = '\n'; + rdnext (); + break; + case 'v': + c = '\v'; + rdnext (); + break; + case 'f': + c = '\f'; + rdnext (); + break; + case 'r': + c = '\r'; + rdnext (); + break; + case '"': + c = '\"'; + rdnext (); + break; + case '\n': + case '\r': + rdnext (); + continue; + case ' ': + c = ' '; + rdnext (); + break; + case 'x': + rdnext (); + c = (char) strtol (&rdcurc (), &endc, 16); + if (c == 0 && endc <= &rdcurc ()) + READ_ERROR ("illegal hex \\x escape in string %.20s", + &rdcurc ()); + if (*endc == ';') + endc++; + rd->rcol += endc - &rdcurc (); + break; + default: + READ_ERROR ("illegal escape sequence %.3s in string", + &rdcurc () - 1); + } + obstack_1grow (&bstring_obstack, (char) c); + } + } + if (c == '"') + rdnext (); + else + READ_ERROR ("unterminated string %.20s", &rdcurc ()); + obstack_1grow (&bstring_obstack, (char) 0); + cstr = XOBFINISH (&bstring_obstack, char *); + strv = basilysgc_new_string (BASILYSGOB (DISCR_STRING), cstr); + if (nbesc > 0) + debugeprintf ("read at line %d escaped string '%s'", rd->rlineno, cstr); + obstack_free (&bstring_obstack, cstr); + BASILYS_EXITFRAME (); + return strv; +#undef strv +#undef str_strv +} + + +static basilys_ptr_t +readhashescape (struct reading_st *rd) +{ + int c = 0; + BASILYS_ENTERFRAME (4, NULL); +#define readv curfram__.varptr[0] +#define compv curfram__.varptr[1] +#define listv curfram__.varptr[2] +#define pairv curfram__.varptr[3] + readv = NULL; + c = rdcurc (); + if (!c || rdeof ()) + READ_ERROR ("eof in hashescape %.20s", &rdcurc ()); + if (c == '\\') + { + rdnext (); + if (ISALPHA (rdcurc ()) && rdcurc () != 'x' && ISALPHA (rdfollowc (1))) + { + char *nam = readsimplename (rd); + c = 0; + if (!strcmp (nam, "nul")) + c = 0; + else if (!strcmp (nam, "alarm")) + c = '\a'; + else if (!strcmp (nam, "backspace")) + c = '\b'; + else if (!strcmp (nam, "tab")) + c = '\t'; + else if (!strcmp (nam, "linefeed")) + c = '\n'; + else if (!strcmp (nam, "vtab")) + c = '\v'; + else if (!strcmp (nam, "page")) + c = '\f'; + else if (!strcmp (nam, "return")) + c = '\r'; + else if (!strcmp (nam, "space")) + c = ' '; + /* won't work on non ASCII or ISO or Unicode host, but we don't care */ + else if (!strcmp (nam, "delete")) + c = 0xff; + else if (!strcmp (nam, "esc")) + c = 0x1b; + else + READ_ERROR ("invalid char escape %s", nam); + obstack_free (&bname_obstack, nam); + char_escape: + readv = basilysgc_new_int (BASILYSGOB (DISCR_CHARINTEGER), c); + } + else if (rdcurc () == 'x' && ISXDIGIT (rdfollowc (1))) + { + char *endc = 0; + rdnext (); + c = strtol (&rdcurc (), &endc, 16); + if (c == 0 && endc <= &rdcurc ()) + READ_ERROR ("illigal hex #\\x escape in char %.20s", &rdcurc ()); + rd->rcol += endc - &rdcurc (); + goto char_escape; + } + else if (ISPRINT (rdcurc ())) + { + c = rdcurc (); + rdnext (); + goto char_escape; + } + else + READ_ERROR ("unrecognized char escape #\\%s", &rdcurc ()); + } + else if (c == '(') + { + int ln = 0, ix = 0; + listv = readseqlist (rd, ')'); + ln = basilys_list_length (listv); + gcc_assert (ln >= 0); + readv = basilysgc_new_multiple (BASILYSGOB (DISCR_MULTIPLE), ln); + for ((ix = 0), (pairv = + ((struct basilyslist_st *) (listv))->first); + ix < ln && basilys_magic_discr (pairv) == OBMAG_PAIR; + pairv = ((struct basilyspair_st *) (pairv))->tl) + ((struct basilysmultiple_st *) (readv))-> + tabval[ix++] = ((struct basilyspair_st *) (pairv))->hd; + basilysgc_touch (readv); + } + else if (c == '[') + { + /* a basilys extension #[ .... ] for lists */ + readv = readseqlist (rd, ']'); + } + else if ((c == 'b' || c == 'B') && ISDIGIT (rdfollowc (1))) + { + /* binary number */ + char *endc = 0; + long n = 0; + rdnext (); + n = strtol (&rdcurc (), &endc, 2); + if (n == 0 && endc <= &rdcurc ()) + READ_ERROR ("bad binary number %s", endc); + readv = basilysgc_new_int (BASILYSGOB (DISCR_INTEGER), n); + } + else if ((c == 'o' || c == 'O') && ISDIGIT (rdfollowc (1))) + { + /* octal number */ + char *endc = 0; + long n = 0; + rdnext (); + n = strtol (&rdcurc (), &endc, 8); + if (n == 0 && endc <= &rdcurc ()) + READ_ERROR ("bad octal number %s", endc); + readv = basilysgc_new_int (BASILYSGOB (DISCR_INTEGER), n); + } + else if ((c == 'd' || c == 'D') && ISDIGIT (rdfollowc (1))) + { + /* decimal number */ + char *endc = 0; + long n = 0; + rdnext (); + n = strtol (&rdcurc (), &endc, 10); + if (n == 0 && endc <= &rdcurc ()) + READ_ERROR ("bad decimal number %s", endc); + readv = basilysgc_new_int (BASILYSGOB (DISCR_INTEGER), n); + } + else if ((c == 'x' || c == 'x') && ISDIGIT (rdfollowc (1))) + { + /* hex number */ + char *endc = 0; + long n = 0; + rdnext (); + n = strtol (&rdcurc (), &endc, 16); + if (n == 0 && endc <= &rdcurc ()) + READ_ERROR ("bad octal number %s", endc); + readv = basilysgc_new_int (BASILYSGOB (DISCR_INTEGER), n); + } + else if (c == '+' && ISALPHA (rdfollowc (1))) + { + bool gotcomp = FALSE; + char *nam = 0; + nam = readsimplename (rd); + compv = readval (rd, &gotcomp); + if (!strcmp (nam, "BASILYS")) + readv = compv; + else + readv = readval (rd, &gotcomp); + } + else + READ_ERROR ("invalid escape %.20s", &rdcurc ()); + BASILYS_EXITFRAME (); + return readv; +#undef readv +#undef listv +#undef compv +#undef pairv +} + + + +static basilys_ptr_t +readval (struct reading_st *rd, bool * pgot) +{ + int c = 0; + char *nam = 0; + BASILYS_ENTERFRAME (4, NULL); +#define readv curfram__.varptr[0] +#define compv curfram__.varptr[1] +#define seqv curfram__.varptr[2] +#define altv curfram__.varptr[3] + readv = NULL; + c = skipspace_getc (rd); + /* debugeprintf ("start readval line %d col %d char %c", rd->rlineno, rd->rcol, + ISPRINT (c) ? c : ' '); */ + if (ISDIGIT (c) + || ((c == '-' || c == '+') + && (ISDIGIT (rdfollowc (1)) || rdfollowc (1) == '%' + || rdfollowc (1) == '|'))) + { + long num = 0; + num = readsimplelong (rd); + readv = + basilysgc_new_int ((basilysobject_ptr_t) BASILYSGOB (DISCR_INTEGER), + num); + *pgot = TRUE; + goto end; + } /* end if ISDIGIT or '-' or '+' */ + else if (c == '"') + { + rdnext (); + readv = readstring (rd); + *pgot = TRUE; + goto end; + } /* end if '"' */ + else if (c == '(') + { + rdnext (); + if (rdcurc () == ')') + { + rdnext (); + readv = NULL; + *pgot = TRUE; + goto end; + } + readv = readsexpr (rd, ')'); + *pgot = TRUE; + goto end; + } /* end if '(' */ + else if (c == '[') + { + rdnext (); + readv = readsexpr (rd, ']'); + *pgot = TRUE; + goto end; + } /* end if '(' */ + else if (c == '{') + { + rdnext (); + readv = readassoc (rd); + *pgot = TRUE; + goto end; + } + else if (c == '#') + { + rdnext (); + c = rdcurc (); + readv = readhashescape (rd); + *pgot = TRUE; + goto end; + } + else if (c == '\'') + { + int lineno = rd->rlineno; + bool got = false; + rdnext (); + compv = readval (rd, &got); + if (!got) + READ_ERROR ("expecting value after quote %.20s", &rdcurc ()); + seqv = basilysgc_new_list (BASILYSGOB (DISCR_LIST)); + altv = basilysgc_named_symbol ("quote", BASILYS_CREATE); + basilysgc_append_list (seqv, altv); + basilysgc_append_list (seqv, compv); + readv = makesexpr (rd, lineno, seqv); + *pgot = TRUE; + goto end; + } + else if (c == '`') + { + int lineno = rd->rlineno; + bool got = false; + rdnext (); + compv = readval (rd, &got); + if (!got) + READ_ERROR ("expecting value after backquote %.20s", &rdcurc ()); + seqv = basilysgc_new_list (BASILYSGOB (DISCR_LIST)); + altv = basilysgc_named_symbol ("backquote", BASILYS_CREATE); + basilysgc_append_list (seqv, altv); + basilysgc_append_list (seqv, compv); + readv = makesexpr (rd, lineno, seqv); + *pgot = TRUE; + goto end; + } + else if (c == ',') + { + int lineno = rd->rlineno; + bool got = false; + rdnext (); + compv = readval (rd, &got); + if (!got) + READ_ERROR ("expecting value after comma %.20s", &rdcurc ()); + seqv = basilysgc_new_list (BASILYSGOB (DISCR_LIST)); + altv = basilysgc_named_symbol ("comma", BASILYS_CREATE); + basilysgc_append_list (seqv, altv); + basilysgc_append_list (seqv, compv); + readv = makesexpr (rd, lineno, seqv); + *pgot = TRUE; + goto end; + } + else if (c == ':') + { + nam = readsimplename (rd); + readv = basilysgc_named_keyword (nam, BASILYS_CREATE); + if (!readv) + READ_ERROR ("unknown named keyword %s", nam); + *pgot = TRUE; + goto end; + } + else if (ISALPHA (c) || strchr (EXTRANAMECHARS, c) != NULL) + { + nam = readsimplename (rd); + readv = basilysgc_named_symbol (nam, BASILYS_CREATE); + *pgot = TRUE; + goto end; + } + else + { + if (c >= 0) + rdback (); + readv = NULL; + } +end: + BASILYS_EXITFRAME (); + if (nam) + { + *nam = 0; + obstack_free (&bname_obstack, nam); + }; + return readv; +#undef readv +#undef compv +#undef seqv +#undef altv +} + + + +basilys_ptr_t +basilysgc_read_file (const char *filnam) +{ + struct reading_st rds; + FILE *fil = 0; + char *filpath = 0, *filnamdup = 0; + int filnamlen = 0; + char tinybuf[140]; + struct reading_st *rd = 0; + BASILYS_ENTERFRAME (4, NULL); +#define genv curfram__.varptr[0] +#define valv curfram__.varptr[1] +#define filnamv curfram__.varptr[2] +#define seqv curfram__.varptr[3] + memset (&rds, 0, sizeof (rds)); + memset (tinybuf, 0, sizeof (tinybuf)); + if (!filnam) + goto end; + debugeprintf ("basilysgc_read_file filnam %s", filnam); + filnamlen = strlen (filnam); + if (filnamlen < (int) sizeof (tinybuf) - 1) + filnamdup = strcpy (tinybuf, filnam); + else + filnamdup = strcpy (xcalloc (filnamlen + 1, 1), filnam); + fil = fopen (filnamdup, "rt"); + if (!fil) + { + filpath = update_path (filnamdup, "GCC"); + fil = fopen (filpath, "rt"); + } + if (!fil) + fatal_error ("cannot open basilys file %s - %m", filnamdup); + /* debugeprintf ("starting loading file %s", filnamdup); */ + rds.rfil = fil; + rds.rpath = filnamdup; + rds.rlineno = 0; + rd = &rds; + filnamv = basilysgc_new_string (BASILYSGOB (DISCR_STRING), filnamdup); + rds.rpfilnam = (basilys_ptr_t *) & filnamv; + rds.rpgenv = (basilys_ptr_t *) & genv; + seqv = basilysgc_new_list (BASILYSGOB (DISCR_LIST)); + while (!rdeof ()) + { + bool got = FALSE; + skipspace_getc (rd); + if (rdeof ()) + break; + valv = readval (rd, &got); + if (!got) + READ_ERROR ("no value read %.20s", &rdcurc ()); + basilysgc_append_list (seqv, valv); + }; + rd = 0; +end: + BASILYS_EXITFRAME (); + if (filpath) + free (filpath); + if (filnamdup && filnamdup != tinybuf) + free (filnamdup); + return seqv; +#undef vecshv +#undef genv +#undef filnamv +#undef seqv +} + + +static void +do_initial_command (void) +{ + BASILYS_ENTERFRAME (4, NULL); +#define dictv curfram__.varptr[0] +#define closv curfram__.varptr[1] +#define cstrv curfram__.varptr[2] + debugeprintf ("do_initial_command command_string %s", + basilys_command_string); + if (basilys_magic_discr + ((BASILYSG (INITIAL_COMMAND_DISPATCHER))) != OBMAG_OBJECT + || BASILYSGOB (INITIAL_COMMAND_DISPATCHER)->obj_len < + FCMDIS__LAST + || !BASILYSGOB (INITIAL_COMMAND_DISPATCHER)->obj_vartab + || !basilys_command_string || !basilys_command_string[0]) + goto end; + dictv = BASILYSGOB (INITIAL_COMMAND_DISPATCHER)->obj_vartab[FCMDIS_FUNDICT]; + debugeprintf ("do_initial_command dictv=%p", dictv); + if (basilys_magic_discr (dictv) != OBMAG_MAPSTRINGS) + goto end; + closv = basilys_get_mapstrings (dictv, basilys_command_string); + debugeprintf ("do_initial_command closv=%p", closv); + if (basilys_magic_discr (closv) != OBMAG_CLOSURE) + goto end; + debugeprintf ("do_initial_command argument_string %s", + basilys_argument_string); + { + union basilysparam_un pararg[1]; + memset (pararg, 0, sizeof (pararg)); + cstrv = + basilysgc_new_string (BASILYSGOB (DISCR_STRING), + basilys_argument_string); + pararg[0].bp_aptr = (basilys_ptr_t *) & cstrv; + debugeprintf ("do_initial_command before apply closv %p", closv); + (void) basilysgc_apply (closv, + BASILYSG + (INITIAL_COMMAND_DISPATCHER), + BPARSTR_PTR, pararg, "", NULL); + debugeprintf ("do_initial_command after apply closv %p", closv); + } +end:; + debugeprintf ("do_initial_command end %s", basilys_argument_string); + BASILYS_EXITFRAME (); +#undef dictv +#undef closv +#undef cstrv +} + + + +/**** + * Initialize basilys. Called from toplevel.c before pass management. + ****/ +void +basilys_initialize (void) +{ + static int inited; + long seed; + const char *pc; + const char *randomseed = 0; + if (inited) + return; +#if ENABLE_CHECKING +#warning basile debogue temporaire + { + char nom_debogue[200]; + snprintf (nom_debogue, sizeof (nom_debogue), + "%s/tmp/debughack_basilys", getenv ("HOME")); + debughack_file = fopen (nom_debogue, "w"); + if (debughack_file) + { + time_t maintenant = 0; + time (&maintenant); + fprintf (debughack_file, + "# fichier %s pid %d du %s\n compilé %s @ %s", + nom_debogue, (int) getpid (), ctime (&maintenant), + __DATE__, __TIME__); + fflush (debughack_file); + } + } +#endif + seed = 0; + randomseed = get_random_seed (false); + gcc_assert (randomseed != (char *) 0); + gcc_assert (BASILYS_ALIGN == sizeof (void *) + || BASILYS_ALIGN == 2 * sizeof (void *) + || BASILYS_ALIGN == 4 * sizeof (void *)); + inited = 1; + ggc_collect (); + obstack_init (&bstring_obstack); + obstack_init (&bname_obstack); + for (pc = randomseed; *pc; pc++) + seed ^= (seed << 6) + (*pc); + srand48_r ((long) seed, &randata); + gcc_assert (!basilys_curalz); + { + size_t wantedwords = MINOR_SIZE_KILOWORD * 4096; + if (wantedwords < (1 << 20)) + wantedwords = (1 << 20); + gcc_assert (basilys_startalz == NULL && basilys_endalz == NULL); + gcc_assert (wantedwords * sizeof (void *) > + 300 * BGLOB__LASTGLOB * sizeof (struct basilysobject_st)); + basilys_curalz = basilys_startalz = + xcalloc (sizeof (void *), wantedwords); + basilys_endalz = (char *) basilys_curalz + wantedwords * sizeof (void *); + basilys_storalz = ((void **) basilys_endalz) - 2; + basilys_newspeclist = NULL; + basilys_oldspeclist = NULL; + } + if (!basilys_init_string) + fatal_error ("no initial basilys file specified thru -fbasilys-init"); + debugeprintf + ("basilys_initialize before compile_dyn init_string=%s", + basilys_init_string); + basilysgc_compile_dyn ((basilys_ptr_t) 0, basilys_init_string); + debugeprintf + ("basilys_initialize before initial_command command_string=%s", + basilys_command_string); +#if ENABLE_CHECKING +#warning basile debogue temporaire ici + if (debughack_file) + { + fprintf (debughack_file, + "%s:%d apres initial_command command_string=%s\n", + basename (__FILE__), __LINE__, basilys_command_string); + fflush (debughack_file); + } +#endif + if (basilys_magic_discr + ((BASILYSG (INITIAL_COMMAND_DISPATCHER))) == OBMAG_OBJECT + && BASILYSGOB (INITIAL_COMMAND_DISPATCHER)->obj_len >= + FCMDIS__LAST && basilys_command_string) + { + gcc_assert (dump_file == (FILE *) 0); + if (flag_basilys_debug) + { + fflush (stderr); + dump_file = stderr; + fflush (stderr); + } + do_initial_command (); + exit_after_options = 1; + debugeprintf + ("basilys_initialize after do_initial_command (will exit after options) command_string %s", + basilys_command_string); + if (dump_file) + { + debugeprintf ("basilys_initialize dump_file cleared was %p", + (void *) dump_file); + fflush (dump_file); + dump_file = 0; + } + } + debugeprintf ("basilys_initialize ended with %ld GarbColl, %ld fullGc", + basilys_nb_garbcoll, basilys_nb_full_garbcoll); +#if ENABLE_CHECKING +#warning basile debogue temporaire final + if (debughack_file) + { + fprintf (debughack_file, "%s:%d fini compilé %s @ %s\n", + basename (__FILE__), __LINE__, __DATE__, __TIME__); + fclose (debughack_file); + debughack_file = NULL; + } +#endif +} + + + + + + +static void +discr_out (struct debugprint_basilys_st *dp, basilysobject_ptr_t odiscr) +{ + int dmag = basilys_magic_discr ((void *) odiscr); + struct basilysstring_st *str = NULL; + if (dmag != OBMAG_OBJECT) + { + fprintf (dp->dfil, "?discr@%p?", (void *) odiscr); + return; + } + if (odiscr->obj_len >= FNAMED__LAST && odiscr->obj_vartab) + { + str = (void *) odiscr->obj_vartab[FNAMED_NAME]; + if (basilys_magic_discr ((void *) str) != OBMAG_STRING) + str = NULL; + } + if (!str) + { + fprintf (dp->dfil, "?odiscr/%d?", odiscr->obj_hash); + return; + } + fprintf (dp->dfil, "#%s", str->val); +} + + +static void +nl_debug_out (struct debugprint_basilys_st *dp, int depth) +{ + int i; + putc ('\n', dp->dfil); + for (i = 0; i < depth; i++) + putc (' ', dp->dfil); +} + +static void +skip_debug_out (struct debugprint_basilys_st *dp, int depth) +{ + if (dp->dcount % 4 == 0) + nl_debug_out (dp, depth); + else + putc (' ', dp->dfil); +} + + +static bool +is_named_obj (basilysobject_ptr_t ob) +{ + struct basilysstring_st *str = 0; + if (basilys_magic_discr ((void *) ob) != OBMAG_OBJECT) + return FALSE; + if (ob->obj_len < FNAMED__LAST || !ob->obj_vartab) + return FALSE; + str = (void *) ob->obj_vartab[FNAMED_NAME]; + if (basilys_magic_discr ((void *) str) != OBMAG_STRING) + return FALSE; + if (basilys_is_instance_of ((basilys_ptr_t) ob, BASILYSG (CLASS_NAMED))) + return TRUE; + return FALSE; +} + +static void +debug_outstr (struct debugprint_basilys_st *dp, const char *str) +{ + int nbclin = 0; + const char *pc; + for (pc = str; *pc; pc++) + { + nbclin++; + if (nbclin > 60 && strlen (pc) > 5) + { + if (ISSPACE (*pc) || ISPUNCT (*pc) || nbclin > 72) + { + fputs ("\\\n", dp->dfil); + nbclin = 0; + } + } + switch (*pc) + { + case '\n': + fputs ("\\n", dp->dfil); + break; + case '\r': + fputs ("\\r", dp->dfil); + break; + case '\t': + fputs ("\\t", dp->dfil); + break; + case '\v': + fputs ("\\v", dp->dfil); + break; + case '\f': + fputs ("\\f", dp->dfil); + break; + case '\"': + fputs ("\\q", dp->dfil); + break; + case '\'': + fputs ("\\a", dp->dfil); + break; + default: + if (ISPRINT (*pc)) + putc (*pc, dp->dfil); + else + fprintf (dp->dfil, "\\x%02x", (*pc) & 0xff); + break; + } + } +} + + +void +basilys_debug_out (struct debugprint_basilys_st *dp, + basilys_ptr_t ptr, int depth) +{ + int mag = basilys_magic_discr (ptr); + int ix; + if (!dp->dfil) + return; + dp->dcount++; + switch (mag) + { + case 0: + { + if (ptr) + fprintf (dp->dfil, "??@%p??", (void *) ptr); + else + fputs ("@@", dp->dfil); + break; + } + case OBMAG_OBJECT: + { + struct basilysobject_st *p = (void *) ptr; + bool named = is_named_obj (p); + fputs ("%", dp->dfil); + discr_out (dp, p->obj_class); + fprintf (dp->dfil, "/L%dH%d", p->obj_len, p->obj_hash); + if (p->obj_num) + fprintf (dp->dfil, "N%d", p->obj_num); + if (named) + fprintf (dp->dfil, "<#%s>", + ((struct basilysstring_st *) (p-> + obj_vartab + [FNAMED_NAME]))->val); + if ((!named || depth == 0) && depth < dp->dmaxdepth) + { + fputs ("[", dp->dfil); + if (p->obj_vartab) + for (ix = 0; ix < p->obj_len; ix++) + { + if (ix > 0) + skip_debug_out (dp, depth); + basilys_debug_out (dp, p->obj_vartab[ix], depth + 1); + } + fputs ("]", dp->dfil); + } + else if (!named) + fputs ("..", dp->dfil); + break; + } + case OBMAG_MULTIPLE: + { + struct basilysmultiple_st *p = (void *) ptr; + fputs ("*", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fputs ("(", dp->dfil); + for (ix = 0; ix < (int) p->nbval; ix++) + { + if (ix > 0) + skip_debug_out (dp, depth); + basilys_debug_out (dp, p->tabval[ix], depth + 1); + } + fputs (")", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_STRING: + { + struct basilysstring_st *p = (void *) ptr; + fputs ("!", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fputs ("\"", dp->dfil); + debug_outstr (dp, p->val); + fputs ("\"", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_INT: + { + struct basilysint_st *p = (void *) ptr; + fputs ("!", dp->dfil); + discr_out (dp, p->discr); + fprintf (dp->dfil, "#%ld", p->val); + break; + } + case OBMAG_MIXINT: + { + struct basilysmixint_st *p = (void *) ptr; + fputs ("!", dp->dfil); + discr_out (dp, p->discr); + fprintf (dp->dfil, "[#%ld&", p->intval); + basilys_debug_out (dp, p->ptrval, depth + 1); + fputs ("]", dp->dfil); + break; + } + case OBMAG_LIST: + { + struct basilyslist_st *p = (void *) ptr; + fputs ("!", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + int ln = basilys_list_length ((void *) p); + struct basilyspair_st *pr; + if (ln > 2) + fprintf (dp->dfil, "[/%d ", ln); + else + fputs ("[", dp->dfil); + for (pr = p->first; + pr && basilys_magic_discr ((void *) pr) == OBMAG_PAIR; + pr = pr->tl) + { + basilys_debug_out (dp, pr->hd, depth + 1); + if (pr->tl) + skip_debug_out (dp, depth); + } + fputs ("]", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_MAPSTRINGS: + { + struct basilysmapstrings_st *p = (void *) ptr; + fputs ("|", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + int ln = basilys_primtab[p->lenix]; + fprintf (dp->dfil, "{~%d/", p->count); + if (p->entab) + for (ix = 0; ix < ln; ix++) + { + const char *ats = p->entab[ix].e_at; + if (!ats || ats == HTAB_DELETED_ENTRY) + continue; + nl_debug_out (dp, depth); + fputs ("'", dp->dfil); + debug_outstr (dp, ats); + fputs ("' = ", dp->dfil); + basilys_debug_out (dp, p->entab[ix].e_va, depth + 1); + fputs (";", dp->dfil); + } + fputs (" ~}", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_MAPOBJECTS: + { + struct basilysmapobjects_st *p = (void *) ptr; + fputs ("|", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + int ln = basilys_primtab[p->lenix]; + fprintf (dp->dfil, "{%d/", p->count); + if (p->entab) + for (ix = 0; ix < ln; ix++) + { + basilysobject_ptr_t atp = p->entab[ix].e_at; + if (!atp || atp == HTAB_DELETED_ENTRY) + continue; + nl_debug_out (dp, depth); + basilys_debug_out (dp, (void *) atp, dp->dmaxdepth); + fputs ("' = ", dp->dfil); + basilys_debug_out (dp, p->entab[ix].e_va, depth + 1); + fputs (";", dp->dfil); + } + fputs (" }", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_CLOSURE: + { + struct basilysclosure_st *p = (void *) ptr; + fputs ("!.", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fprintf (dp->dfil, "[. rout="); + basilys_debug_out (dp, (void *) p->rout, depth + 1); + skip_debug_out (dp, depth); + fprintf (dp->dfil, " /%d: ", p->nbval); + for (ix = 0; ix < (int) p->nbval; ix++) + { + if (ix > 0) + skip_debug_out (dp, depth); + basilys_debug_out (dp, p->tabval[ix], depth + 1); + } + fputs (".]", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_ROUTINE: + { + struct basilysroutine_st *p = (void *) ptr; + fputs ("!:", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fprintf (dp->dfil, ".%s[:/%d ", p->routdescr, p->nbval); + for (ix = 0; ix < (int) p->nbval; ix++) + { + if (ix > 0) + skip_debug_out (dp, depth); + basilys_debug_out (dp, p->tabval[ix], depth + 1); + } + fputs (":]", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_STRBUF: + { + struct basilysstrbuf_st *p = (void *) ptr; + fputs ("!`", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fprintf (dp->dfil, "[`buflen=%ld ", basilys_primtab[p->buflenix]); + gcc_assert (p->bufstart <= p->bufend + && p->bufend < basilys_primtab[p->buflenix]); + fprintf (dp->dfil, "bufstart=%u bufend=%u buf='", + p->bufstart, p->bufend); + if (p->bufzn) + debug_outstr (dp, p->bufzn + p->bufstart); + fputs ("' `]", dp->dfil); + } + else + fputs ("..", dp->dfil); + break; + } + case OBMAG_PAIR: + { + struct basilyspair_st *p = (void *) ptr; + fputs ("[pair:", dp->dfil); + discr_out (dp, p->discr); + if (depth < dp->dmaxdepth) + { + fputs ("hd:", dp->dfil); + basilys_debug_out (dp, p->hd, depth + 1); + fputs ("; ti:", dp->dfil); + basilys_debug_out (dp, (basilys_ptr_t) p->tl, depth + 1); + } + else + fputs ("..", dp->dfil); + fputs ("]", dp->dfil); + break; + } + case OBMAG_TRIPLE: + case OBMAG_TREE: + case OBMAG_BASICBLOCK: + case OBMAG_EDGE: + case OBMAG_MAPTREES: + case OBMAG_MAPBASICBLOCKS: + case OBMAG_MAPEDGES: + case OBMAG_DECAY: + fatal_error ("debug_out unimplemented magic %d", mag); + default: + gcc_unreachable (); + } +} + + +/************************************************************************* + * GATE & PASS should be moved in another file + *************************************************************************/ + + +/* just dump the cgraph node to understand what is it about */ +static void +dump_cgraph_basilys (int passcount) +{ + struct cgraph_node *cgr_fun = 0; + tree tr_body = 0; + dbgprintf ("start dump_cgraph_basilys passcount=%d", passcount); + for (cgr_fun = cgraph_nodes; cgr_fun; cgr_fun = cgr_fun->next) + { + dbgprintf ("current cgraph cgr_fun %p ", (void *) cgr_fun); + if (dump_file) + dump_cgraph_node (dump_file, cgr_fun); + tr_body = DECL_SAVED_TREE (cgr_fun->decl); + dbgprintf ("current cgraph tr_body %p ", (void *) tr_body); + if (dump_file) + print_generic_stmt (dump_file, tr_body, + TDF_LINENO | TDF_BLOCKS | TDF_DETAILS | TDF_IPA); + } +} + +void +basilys_dbgeprint (void *p) +{ + struct debugprint_basilys_st dps = { + 0, 4, 0 + }; + dps.dfil = stderr; + basilys_debug_out (&dps, p, 0); + putc ('\n', stderr); + fflush (stderr); +} + +void +basilys_dbgbacktrace (int depth) +{ + int curdepth = 1, totdepth = 0; + struct callframe_basilys_st *fr = 0; + fprintf (stderr, " <{\n"); + for (fr = basilys_topframe; fr != NULL && curdepth < depth; + (fr = fr->prev), (curdepth++)) + { + fprintf (stderr, "frame#%d closure: ", curdepth); + basilys_dbgeprint (fr->clos); + } + for (totdepth = curdepth; fr != NULL; fr = fr->prev); + fprintf (stderr, "}> backtraced %d frames of %d\n", curdepth, totdepth); + fflush (stderr); +} + + +void +basilys_dbgshortbacktrace(const char* msg, int maxdepth) { + int curdepth = 1; + struct callframe_basilys_st *fr = 0; + if (maxdepth<2) maxdepth=2; + fprintf (stderr, "\nSHORT BACKTRACE %s;", msg?msg:"/"); + for (fr = basilys_topframe; fr != NULL && curdepth < maxdepth; + (fr = fr->prev), (curdepth++)) + { + if ((curdepth-1) % 3 == 0) + putc('\n', stderr); + fprintf(stderr, "#%d:", curdepth); + if (basilys_magic_discr((void*)fr->clos) == OBMAG_CLOSURE) { + basilysroutine_ptr_t curout = fr->clos->rout; + if (basilys_magic_discr((void*)curout) == OBMAG_ROUTINE) + fprintf(stderr, "<%s> ", curout->routdescr); + else + fputs("?norout? ", stderr); + } else + fprintf(stderr, "_ "); + }; + if (fr) + fprintf(stderr, "...&%d", maxdepth-curdepth); + else + fputs(".", stderr); + putc('\n', stderr); + putc('\n', stderr); + fflush(stderr); +} + +/*********************************************************** + * generate C code for a basilys unit name + ***********************************************************/ +void +basilys_output_cfile_decl_impl (basilys_ptr_t unitnam, + basilys_ptr_t declbuf, basilys_ptr_t implbuf) +{ + int unamlen = 0; + char *dotcnam = NULL; + char *dotcpercentnam = NULL; + FILE *cfil = NULL; + gcc_assert (basilys_magic_discr (unitnam) == OBMAG_STRING); + gcc_assert (basilys_magic_discr (declbuf) == OBMAG_STRBUF); + gcc_assert (basilys_magic_discr (implbuf) == OBMAG_STRBUF); + /** FIXME : should implement some policy about the location of the + generated C file; currently using the pwd */ + unamlen = strlen (basilys_string_str (unitnam)); + dotcnam = xcalloc (unamlen + 3, 1); + dotcpercentnam = xcalloc (unamlen + 4, 1); + strcpy (dotcnam, basilys_string_str (unitnam)); + strcpy (dotcpercentnam, basilys_string_str (unitnam)); + strcat (dotcnam, ".c"); + strcat (dotcpercentnam, ".c%"); + (void) rename (dotcnam, dotcpercentnam); + cfil = fopen (dotcnam, "w"); + if (!cfil) + fatal_error ("failed to open basilys generated file %s - %m", dotcnam); + fprintf (cfil, + "/* GCC BASILYS GENERATED FILE %s - DO NOT EDIT */\n", dotcnam); + fprintf (cfil, "#include \"run-basilys.h\"\n"); + fprintf (cfil, "\n/**** %s declarations ****/\n", + basilys_string_str (unitnam)); + basilys_putstrbuf (cfil, declbuf); + putc ('\n', cfil); + fflush (cfil); + fprintf (cfil, "\n/**** %s implementations ****/\n", + basilys_string_str (unitnam)); + basilys_putstrbuf (cfil, implbuf); + putc ('\n', cfil); + fflush (cfil); + fprintf (cfil, "\n/**** end of %s ****/\n", basilys_string_str (unitnam)); + fclose (cfil); + free (dotcnam); + free (dotcpercentnam); +} + +/* this function decides if Basile's analysis is done. Currently we + check for -fbasilys flag; but we should also check for + -fwhole-program flag */ +static bool +gate_basilys (void) +{ +#if HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL + /*@@@ we need to check the whole program flag @@@ */ + if (!flag_basilys) + return 0; + if (!flag_whole_program && flag_basilys) + { + static int warnedonce; + if (!warnedonce) + { + warnedonce = 1; + warning (OPT_Wall, "-fbasilys flag passed without -fwhole-program"); + }; + } + return flag_basilys; +#else /* no HAVE_PARMAPOLY or no HAVE_LIBTOOLDYNL */ +#warning no HAVE_PARMAPOLY or no HAVE_LIBTOOLDYNL + if (flag_basilys) + fatal_error ("-fbasilys flag specified, \ +but GCC configured without Parma Polyhedra Library or LibTool Dynamic Loader"); + return 0; +#endif +} + +void +basilys_assert_failed (const char *msg, const char *filnam, + int lineno, const char *fun) +{ + static char msgbuf[500]; + if (basilys_dbgcounter>0) + snprintf(msgbuf, sizeof(msgbuf)-1, "%s:%d: BASILYS ASSERT #!%ld: %s {%s}", + basename (filnam), lineno, basilys_dbgcounter, fun, msg); + else + snprintf(msgbuf, sizeof(msgbuf)-1, "%s:%d: BASILYS ASSERT: %s {%s}", + basename (filnam), lineno, fun, msg); + basilys_dbgshortbacktrace(msgbuf, 100); + fatal_error ("%s:%d: BASILYS ASSERT FAILED <%s> : %s\n", + basename (filnam), lineno, fun, msg); +} + + +/* this function does the bulk of the work; return additional TODOs to + the pass machinery */ +static unsigned int +execute_basilys (void) +{ + static int passcount; + passcount++; + fprintf (stderr, "\nbasilys.c:%d: start pass %d\n", __LINE__, passcount); + dbgprintf ("start of execute_basilys pass %d", passcount); + dump_cgraph_basilys (passcount); + dbgprintf ("end of execute_basilys pass %d\n", passcount); + fprintf (stderr, "basilys.c:%d: end pass %d\n\n", __LINE__, passcount); + return 0; +} + +struct tree_opt_pass pass_basilys = { + "basilys", /* name */ + gate_basilys, /* gate */ + execute_basilys, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_BASILE_ANALYSIS, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +#include "gt-basilys.h" +/* eof basilys.c */ diff --git a/gcc/basilys.h b/gcc/basilys.h new file mode 100644 index 00000000000..90d098dad91 --- /dev/null +++ b/gcc/basilys.h @@ -0,0 +1,2096 @@ +/* Basile's static analysis (should have a better name) header basilys.h + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef BASILYS_INCLUDED_ +#define BASILYS_INCLUDED_ + +/* use -fdump-ipa-basilys */ + +#define dbgprintf_raw(Fmt,...) do{if (dump_file) \ + {fprintf(dump_file, Fmt, ##__VA_ARGS__); fflush(dump_file);}}while(0) +#define dbgprintf(Fmt,...) dbgprintf_raw("@%s:%d: " Fmt "\n", \ + basename(__FILE__), __LINE__, ##__VA_ARGS__) + +extern long basilys_dbgcounter; + +#define debugeprintf_raw(Fmt,...) do{if (flag_basilys_debug) \ + {fprintf(stderr, Fmt, ##__VA_ARGS__); fflush(stderr);}}while(0) +#define debugeprintf(Fmt,...) debugeprintf_raw("!@%s:%d: " Fmt "\n", \ + basename(__FILE__), __LINE__, ##__VA_ARGS__) +#define debugeprintvalue(Msg,Val) do{if (flag_basilys_debug){ \ + void* __val = (Val); \ + fprintf(stderr,"!@%s:%d: %s @%p= ", \ + basename(__FILE__), __LINE__, (Msg), __val); \ + basilys_dbgeprint(__val); }} while(0) +#define debugebacktrace(Msg,Depth) do{if (flag_basilys_debug){ \ + void* __val = (Val); \ + fprintf(stderr,"!@%s:%d: %s **backtrace** ", \ + basename(__FILE__), __LINE__, (Msg)); \ + basilys_dbgbacktrace((Depth)); }} while(0) +/* the maximal debug depth - should be a parameter */ +#define BASILYSDBG_MAXDEPTH 7 + +/* unspecified flexible dimension in structure */ +#if defined(__STDC__) && __STDC__VERSION >= 199901L +#define FLEXIBLE_DIM /*flexible */ +#define HAVE_FLEXIBLE_DIM 1 +#else +#define FLEXIBLE_DIM /*flexibly*/1 +#define HAVE_FLEXIBLE_DIM 0 +#endif + +/* array of (at least 100, increasing order but non consecutive) + primes, zero terminated. Each prime is at least 1/8-th bigger than + previous */ +extern const long basilys_primtab[256]; + + +/* naming convention: all struct basilys*_st are inside the + basilys_un */ + +typedef union basilys_un *basilys_ptr_t; +typedef struct basilysobject_st *basilysobject_ptr_t; +typedef struct basilysmapobjects_st *basilysmapobjects_ptr_t; +typedef struct basilysclosure_st *basilysclosure_ptr_t; +typedef struct basilysroutine_st *basilysroutine_ptr_t; +typedef struct basilysmultiple_st *basilysmultiple_ptr_t; +typedef struct basilysbox_st *basilysbox_ptr_t; +typedef struct basilyspair_st *basilyspair_ptr_t; + +struct debugprint_basilys_st +{ + FILE *dfil; + int dmaxdepth; + int dcount; +}; + +void basilys_debug_out (struct debugprint_basilys_st *dp, basilys_ptr_t ptr, + int depth); +void basilys_dbgeprint (void *p); +void basilys_dbgbacktrace (int depth); + +/******************* closures, routines ************************/ + +union basilysparam_un +{ + /* for basilys value pointers, we pass the address of a local, to be + compatible with our copying garbage collector */ + basilys_ptr_t *bp_aptr; /* letter P */ +#define BPAR_PTR 'P' +#define BPARSTR_PTR "P" + + /* for passing a pair-list of rest arguments, we pass likewise the + address of a local */ +#define BPAR_RESTPTR 'R' +#define BPARSTR_RESTPTR "R" + basilys_ptr_t *bp_rptr; /* letter R */ + + + tree bp_tree; /* letter t */ + tree *bp_treeptr; /* for extra results */ +#define BPAR_TREE 't' +#define BPARSTR_TREE "t" + + long bp_long; /* letter l */ + long *bp_longptr; /* for results */ +#define BPAR_LONG 'l' +#define BPARSTR_LONG "l" + + edge bp_edge; /* letter e */ + edge *bp_edgeptr; /* for results */ +#define BPAR_EDGE 'e' +#define BPARSTR_EDGE "e" + + basic_block bp_bb; /* letter b */ + basic_block *bp_bbptr; /* for results */ +#define BPAR_BB 'b' +#define BPARSTR_BB "b" +}; + +/*** the closures contain routines which are called by applying + closures; each routine is called with: + + + the called closure + + this first pointer argument + + a (non null, can be empty) constant string describing the extra arguments + (eg "ppt" for two value pointers and one tree) + + the array of union basilysparam_un for extra arguments + + a (non null, can be empty) constant string describing the extra results + + the array of union basilysparam_un for extra results + + and the result of the call is a pointer (the main result) + +BTW, on AMD64 or x86_64 processors [a very common host at time of +writing], http://www.x86-64.org/documentation/abi.pdf the first six +arguments are passed thru registers; on POWERPC eight arguments are +passed thru registers +*/ + + +typedef basilys_ptr_t basilysroutfun_t (basilysclosure_ptr_t closp_, + basilys_ptr_t firstargp_, + const char xargdescr_[], + union basilysparam_un *xargtab_, + const char xresdescr_[], + union basilysparam_un *xrestab_); + +basilys_ptr_t basilysgc_apply (basilysclosure_ptr_t clos_p, + basilys_ptr_t firstarg, + const char xargdescr_[], + union basilysparam_un *xargtab_, + const char xresdescr_[], + union basilysparam_un *xrestab_); + +/* gnu indent has some trouble with GTY hence */ +/* *INDENT-OFF* */ + +DEF_VEC_P (basilys_ptr_t); +DEF_VEC_ALLOC_P (basilys_ptr_t, gc); + + + +DEF_VEC_P (basilysobject_ptr_t); +DEF_VEC_ALLOC_P (basilysobject_ptr_t, gc); + + +/* sadly we cannot use these types in GTY-ed structure because + gengtype don't follow typedefs but these typedef-s are still + useful */ + +typedef +VEC (basilysobject_ptr_t, gc) + basilys_objectvec_t; + +typedef VEC (basilys_ptr_t, gc) basilys_valvec_t; + +enum obmag_en { + OBMAG__NONE = 0, + OBMAG_OBJECT = 30000, + OBMAG_BOX, + OBMAG_MULTIPLE, + OBMAG_CLOSURE, + OBMAG_ROUTINE, + OBMAG_LIST, + OBMAG_PAIR, + OBMAG_TRIPLE, + OBMAG_INT, + OBMAG_MIXINT, + OBMAG_REAL, + OBMAG_STRING, + OBMAG_STRBUF, + OBMAG_TREE, + OBMAG_BASICBLOCK, + OBMAG_EDGE, + OBMAG_MAPOBJECTS, + OBMAG_MAPSTRINGS, + OBMAG_MAPTREES, + OBMAG_MAPBASICBLOCKS, + OBMAG_MAPEDGES, + OBMAG_DECAY, + OBMAG__SPARE1, + OBMAG__SPARE2, + OBMAG__SPARE3, + OBMAG__SPARE4, + OBMAG__SPARE5, + OBMAG__SPARE6, + OBMAG__SPARE7, + OBMAG__SPARE8, + OBMAG__SPARE9, + OBMAG__SPARE10, + OBMAG__SPARE11, + OBMAG__SPARE12, + OBMAG__SPARE13, + OBMAG__SPARE14, + OBMAG__SPARE15, + OBMAG__SPARE16, + OBMAG__SPARE17, + OBMAG__SPARE18, + OBMAG__SPARE19, + OBMAG__SPARE20, + OBMAG__SPARE21, + OBMAG__SPARE22, + OBMAG__SPARE23, + OBMAG__SPARE24, + OBMAG__SPARE25, + OBMAG__SPARE26, + OBMAG__SPARE27, + OBMAG__SPARE28, + OBMAG__SPARE29, + OBMAG__SPARE30, + OBMAG__SPARE31, + OBMAG__SPARE32, + OBMAG__SPARE33, + OBMAG__SPARE34, + OBMAG__SPARE35, + OBMAG__SPARE36, + OBMAG__SPARE37, + OBMAG__SPARE38, + OBMAG__SPARE39, + OBMAG_SPEC_FILE, + OBMAG_SPEC_MPFR, + OBMAG_SPECPPL_COEFFICIENT, + OBMAG_SPECPPL_LINEAR_EXPRESSION, + OBMAG_SPECPPL_CONSTRAINT, + OBMAG_SPECPPL_CONSTRAINT_SYSTEM, + OBMAG_SPECPPL_GENERATOR, + OBMAG_SPECPPL_GENERATOR_SYSTEM, + OBMAG__LAST +}; + + +/* maxhash can also be used as a bit mask */ +#define BASILYS_MAXHASH 0x3fffffff + +/* maxlen can also be used as a bit mask */ +#define BASILYS_MAXLEN 0x1fffffff + + +/*** + objects are à la ObjVlisp, single-inheritance with a root class, + the discr of an object is its class + each object has its hashcode, its magic (used to discriminate non-object values), + its number of slots or instance variables object_arity, and an array of slots called vartab[] + + objects should be allocated in young region, hence discr should be + forwarded in the garbage collector + + + +*/ + +/* *INDENT-ON* */ + +/* when OBMAG_OBJECT -- */ +struct basilysobject_st +GTY (()) +{ + /* for objects, the discriminant is their class */ + basilysobject_ptr_t obj_class; + unsigned obj_hash; /* hash code of the object */ + unsigned short obj_num; +/* discriminate the basilys_un containing it as discr */ +#define object_magic obj_num + unsigned short obj_len; + basilys_ptr_t *GTY ((length ("%h.obj_len"))) obj_vartab; + /* the following field is usually the value of obj_vartab (for + objects in the young zone), to allocate the object and its fields + at once; hence its GTY-ed length is zero */ + basilys_ptr_t GTY ((length ("0"))) obj__tabfields[FLEXIBLE_DIM]; +}; + +#define BASILYS_OBJECT_STRUCT(N) { \ + basilysobject_ptr_t obj_class; \ + unsigned obj_hash; \ + unsigned short obj_num; \ + unsigned short obj_len; \ + basilys_ptr_t* obj_vartab; \ + basilys_ptr_t obj__tabfields[N]; \ + long _gap; } + + +/* some types, including objects, strbuf, stringmaps, objectmaps, all + the other *maps, contain a pointer to a non value; this pointer + should be carefully updated in the forwarding step (and checked if + young) */ + +/* forwarded pointers; nobody see them except the basilys copying + garbage collector */ +struct basilysforward_st +GTY (()) +{ + basilysobject_ptr_t discr; /* actually always (void*)1 for forwarded */ + basilys_ptr_t forward; +}; + +/* when OBMAG_DECAY */ +struct basilysdecay_st +GTY ((mark_hook ("basilys_mark_decay"))) +{ + basilysobject_ptr_t discr; + basilys_ptr_t val; + unsigned remain; /* remaining number of marking */ +}; + + +/* when OBMAG_BOX */ +struct basilysbox_st +GTY (()) +{ + basilysobject_ptr_t discr; + basilys_ptr_t val; +}; + +/* when OBMAG_MULTIPLE */ +struct basilysmultiple_st +GTY (()) +{ + basilysobject_ptr_t discr; + unsigned nbval; + basilys_ptr_t GTY ((length ("%h.nbval"))) tabval[FLEXIBLE_DIM]; +}; + +#define BASILYS_MULTIPLE_STRUCT(N) { \ + basilysobject_ptr_t discr; \ + unsigned nbval; \ + basilys_ptr_t tabval[N]; \ + long _gap; } + +/* when OBMAG_CLOSURE */ +struct basilysclosure_st +GTY (()) +{ + basilysobject_ptr_t discr; + basilysroutine_ptr_t rout; + unsigned nbval; + basilys_ptr_t GTY ((length ("%h.nbval"))) tabval[FLEXIBLE_DIM]; +}; + +#define BASILYS_CLOSURE_STRUCT(N) { \ + basilysobject_ptr_t discr; \ + basilysroutine_ptr_t rout; \ + unsigned nbval; \ + basilys_ptr_t tabval[N]; \ + long _gap; } + +/* when OBMAG_ROUTINE */ +#define BASILYS_ROUTDESCR_LEN 80 +struct basilysroutine_st +GTY (()) +{ + basilysobject_ptr_t discr; + char routdescr[BASILYS_ROUTDESCR_LEN]; + long GTY ((skip)) routaddr[1 + sizeof (basilysroutfun_t *) / sizeof (long)]; + unsigned nbval; + basilys_ptr_t GTY ((length ("%h.nbval"))) tabval[FLEXIBLE_DIM]; +}; + +#define BASILYS_ROUTINE_STRUCT(N) { \ + basilysobject_ptr_t discr; \ + char routdescr[BASILYS_ROUTDESCR_LEN]; \ + long routaddr[1+sizeof(basilysroutfun_t *)/sizeof(long)]; \ + unsigned nbval; \ + basilys_ptr_t tabval[N]; \ + long _gap; } + + +/* when OBMAG_PAIR */ +struct basilyspair_st +GTY ((chain_next ("%h.tl"))) +{ + basilysobject_ptr_t discr; + basilys_ptr_t hd; + struct basilyspair_st *tl; +}; + +/* when OBMAG_TRIPLE */ +struct basilystriple_st +GTY ((chain_next ("%h.tl"))) +{ + basilysobject_ptr_t discr; + basilys_ptr_t hd; + basilys_ptr_t mi; + struct basilystriple_st *tl; +}; + +/* when OBMAG_LIST */ +struct basilyslist_st +GTY (()) +{ + basilysobject_ptr_t discr; + struct basilyspair_st *first; + struct basilyspair_st *last; +}; + + + + + +/* when OBMAG_INT - */ +struct basilysint_st +GTY (()) +{ + basilysobject_ptr_t discr; + long val; +}; + +/* when OBMAG_MIXINT - */ +struct basilysmixint_st +GTY (()) +{ + basilysobject_ptr_t discr; + basilys_ptr_t ptrval; + long intval; +}; + + + +/* when OBMAG_REAL */ +struct basilysreal_st +GTY (()) +{ + basilysobject_ptr_t discr; + REAL_VALUE_TYPE val; +}; + + +/* a union of special pointers which have to be explicitly deleted */ +union special_basilys_un +{ + /* all the pointers here have to be pointers to struct or to void, + because the generated gtype-desc.c don't include all the files + which define mpfr_ptr ppl_Coefficient_t etc... */ + /* generic pointer */ void *sp_pointer; + /* stdio file */ FILE *sp_file; + /*mpfr_ptr= */ void *sp_mpfr; + /* malloced pointer to mpfr_t */ + /*ppl_Coefficient_t= */ struct ppl_Coefficient_tag *sp_coefficient; + /*ppl_Linear_Expression_t= */ struct ppl_Linear_Expression_tag + *sp_linear_expression; + /*ppl_Constraint_t= */ struct ppl_Constraint_tag *sp_constraint; + /*ppl_Constraint_System_t= */ struct ppl_Constraint_System_tag + *sp_constraint_system; + /*ppl_Generator_t= */ struct ppl_Generator_tag *sp_generator; + /*ppl_Generator_System_t= */ struct ppl_Generator_System_tag + *sp_generator_system; +}; + +/* PPL special have to be explicitly deleted; hence we need a hook + to mark them, an inside mark, and to maintain lists of existing + such PPL special boxes -which we scan to delete the unmarked + ones */ +/* when OBMAG_SPEC* eg OBMAG_SPEC_MPFR, OBMAG_SPECPPL_COEFFICIENT; etc. + */ +struct basilysspecial_st +GTY ((mark_hook ("basilys_mark_special"))) +{ + basilysobject_ptr_t discr; + int mark; + struct basilysspecial_st *GTY ((skip)) nextspec; + union special_basilys_un GTY ((skip)) val; +}; + +static inline void +basilys_mark_special (struct basilysspecial_st *p) +{ + p->mark = 1; +} + +static inline void +basilys_mark_decay (struct basilysdecay_st *p) +{ + /* this is tricky since it actually changes the marked data; however, + changing pointers to NULL is ok! */ + if (p->remain <= 0) + p->val = NULL; + else + p->remain--; +} + +/* when OBMAG_STRING - */ +struct basilysstring_st +GTY (()) +{ + basilysobject_ptr_t discr; + char val[FLEXIBLE_DIM]; /* null terminated */ +}; + +#define BASILYS_STRING_STRUCT(N) { \ + basilysobject_ptr_t discr; \ + char val[(N)+1]; /* null terminated */ \ + long _gap; } + +/* when OBMAG_STRBUF - */ +struct basilysstrbuf_st +GTY (()) +{ + basilysobject_ptr_t discr; + char *GTY ((length ("1+basilys_primtab[%h.buflenix]"))) bufzn; + unsigned char buflenix; /* allocated length index of + buffer */ + unsigned bufstart; + unsigned bufend; /* start & end useful positions */ + /* the following field is usually the value of buf (for + objects in the young zone), to allocate the object and its fields + at once; hence its GTY-ed length is zero */ + char GTY ((length ("0"))) buf_space[FLEXIBLE_DIM]; +}; + +/* when OBMAG_TREE */ +struct basilystree_st +GTY (()) +{ + basilysobject_ptr_t discr; + tree val; +}; + +/* when OBMAG_BASICBLOCK */ +struct basilysbasicblock_st +GTY (()) +{ + basilysobject_ptr_t discr; + basic_block val; +}; + +/* when OBMAG_EDGE */ +struct basilysedge_st +GTY (()) +{ + basilysobject_ptr_t discr; + edge val; +}; + + + + +/*** hashed maps of objects to basilys ***/ +struct entryobjectsbasilys_st +GTY (()) +{ + basilysobject_ptr_t e_at; + basilys_ptr_t e_va; +}; + +/* when OBMAG_MAPOBJECTS */ +struct basilysmapobjects_st +GTY (()) +{ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entryobjectsbasilys_st *GTY ((length ("basilys_primtab[%h.lenix]"))) + entab; + /* the following field is usually the value of entab (for + objects in the young zone), to allocate the object and its fields + at once; hence its GTY-ed length is zero */ + struct entryobjectsbasilys_st GTY ((length ("0"))) map_space[FLEXIBLE_DIM]; +}; + +/*** hashed maps of trees to basilys ***/ +struct entrytreesbasilys_st +GTY (()) +{ + tree e_at; + basilys_ptr_t e_va; +}; + +/* when OBMAG_MAPTREES */ +struct basilysmaptrees_st +GTY (()) +{ + /* change basilysmappointers_st when changing this structure */ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entrytreesbasilys_st *GTY ((length ("basilys_primtab[%h.lenix]"))) + entab; +}; + +/*** hashed maps of strings to basilys ***/ +struct entrystringsbasilys_st +GTY (()) +{ + char *GTY (()) e_at; + basilys_ptr_t e_va; +}; + +/* when OBMAG_MAPSTRINGS */ +struct basilysmapstrings_st +GTY (()) +{ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entrystringsbasilys_st *GTY ((length ("basilys_primtab[%h.lenix]"))) + entab; +}; + + +/*** hashed maps of basicblocks to basilys ***/ + +struct entrybasicblocksbasilys_st +GTY (()) +{ + basic_block e_at; + basilys_ptr_t e_va; +}; + +/* when OBMAG_MAPBASICBLOCKS */ +struct basilysmapbasicblocks_st +GTY (()) +{ + /* change basilysmappointers_st when changing this structure */ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entrybasicblocksbasilys_st + *GTY ((length ("basilys_primtab[%h.lenix]"))) entab; +}; + +/*** hashed maps of edges to basilys ***/ +struct entryedgesbasilys_st +GTY (()) +{ + edge e_at; + basilys_ptr_t e_va; +}; + +/* when OBMAG_MAPEDGES */ +struct basilysmapedges_st +GTY (()) +{ + /* change basilysmappointers_st when changing this structure */ + basilysobject_ptr_t discr; + unsigned count; + unsigned char lenix; + struct entryedgesbasilys_st *GTY ((length ("basilys_primtab[%h.lenix]"))) + entab; +}; + + +/**** our union for everything ***/ +/* never use an array of basilys_un, only array of pointers basilys_ptr_t */ +typedef union basilys_un +GTY ((desc ("%0.u_discr->object_magic"))) +{ + basilysobject_ptr_t GTY ((skip)) u_discr; + struct basilysforward_st GTY ((skip)) u_forward; + struct basilysobject_st GTY ((tag ("OBMAG_OBJECT"))) u_object; + struct basilysbox_st GTY ((tag ("OBMAG_BOX"))) u_box; + struct basilysdecay_st GTY ((tag ("OBMAG_DECAY"))) u_decay; + struct basilysmultiple_st GTY ((tag ("OBMAG_MULTIPLE"))) u_multiple; + struct basilysclosure_st GTY ((tag ("OBMAG_CLOSURE"))) u_closure; + struct basilysroutine_st GTY ((tag ("OBMAG_ROUTINE"))) u_routine; + struct basilyslist_st GTY ((tag ("OBMAG_LIST"))) u_list; + struct basilysint_st GTY ((tag ("OBMAG_INT"))) u_int; + struct basilysmixint_st GTY ((tag ("OBMAG_MIXINT"))) u_mixint; + struct basilysreal_st GTY ((tag ("OBMAG_REAL"))) u_real; + struct basilyspair_st GTY ((tag ("OBMAG_PAIR"))) u_pair; + struct basilystriple_st GTY ((tag ("OBMAG_TRIPLE"))) u_triple; + struct basilysspecial_st + GTY ((tag ("OBMAG_SPEC_FILE"), + tag ("OBMAG_SPEC_MPFR"), + tag ("OBMAG_SPECPPL_COEFFICIENT"), + tag ("OBMAG_SPECPPL_LINEAR_EXPRESSION"), + tag ("OBMAG_SPECPPL_CONSTRAINT"), + tag ("OBMAG_SPECPPL_CONSTRAINT_SYSTEM"), + tag ("OBMAG_SPECPPL_GENERATOR"), + tag ("OBMAG_SPECPPL_GENERATOR_SYSTEM"))) u_special; + struct basilysstring_st GTY ((tag ("OBMAG_STRING"))) u_string; + struct basilysstrbuf_st GTY ((tag ("OBMAG_STRBUF"))) u_strbuf; + struct basilystree_st GTY ((tag ("OBMAG_TREE"))) u_tree; + struct basilysbasicblock_st GTY ((tag ("OBMAG_BASICBLOCK"))) u_basicblock; + struct basilysedge_st GTY ((tag ("OBMAG_EDGE"))) u_edge; + struct basilysmapobjects_st GTY ((tag ("OBMAG_MAPOBJECTS"))) u_mapobjects; + struct basilysmapstrings_st GTY ((tag ("OBMAG_MAPSTRINGS"))) u_mapstrings; + struct basilysmaptrees_st GTY ((tag ("OBMAG_MAPTREES"))) u_maptrees; + struct basilysmapbasicblocks_st GTY ((tag ("OBMAG_MAPBASICBLOCKS"))) + u_mapbasicblocks; + struct basilysmapedges_st GTY ((tag ("OBMAG_MAPEDGES"))) u_mapedges; +} basilys_un_t; + +/* return the magic of the discriminant or 0 */ +static inline int +basilys_magic_discr (basilys_ptr_t p) +{ + if (!p || !p->u_discr) + return 0; + return p->u_discr->object_magic; +} + +/* return the discriminant or class itself */ +static inline basilysobject_ptr_t +basilys_discr (basilys_ptr_t p) +{ + if (!p) + return NULL; + return p->u_discr; +} + +/* return the nth of a multiple (starting from 0) */ +static inline basilys_ptr_t +basilys_multiple_nth (basilysmultiple_ptr_t mul, int n) +{ + if (!mul || mul->discr->object_magic != OBMAG_MULTIPLE) + return NULL; + if (n >= 0 && n < (int) mul->nbval) + return mul->tabval[n]; + else if (n < 0 && n + (int) mul->nbval >= 0) + return mul->tabval[n + mul->nbval]; + return NULL; +} + +/* set the nth of a multiple (but beware of circularities!) */ +void basilysgc_multiple_put_nth (basilysmultiple_ptr_t mul, int n, + basilys_ptr_t val); + +/* return the length of a multiple */ +static inline int +basilys_multiple_length (basilysmultiple_ptr_t mul) +{ + if (!mul || mul->discr->object_magic != OBMAG_MULTIPLE) + return 0; + return mul->nbval; +} + +/* allocate a new box of given DISCR & content VAL */ +basilys_ptr_t basilysgc_new_box (basilysobject_ptr_t discr_p, + basilys_ptr_t val_p); + +/* return the content of a box */ +static inline basilys_ptr_t +basilys_box_content (basilysbox_ptr_t box) +{ + if (!box || box->discr->object_magic != OBMAG_BOX) + return NULL; + return box->val; +} + +void basilysgc_box_put (basilys_ptr_t box, basilys_ptr_t val); + + +void *basilysgc_raw_new_mappointers (basilysobject_ptr_t discr_p, + unsigned len); + +static inline basilys_ptr_t +basilysgc_new_maptrees (basilysobject_ptr_t discr, unsigned len) +{ + if (basilys_magic_discr ((void *) discr) != OBMAG_OBJECT) + return NULL; + if (discr->object_magic != OBMAG_MAPTREES) + return NULL; + return basilysgc_raw_new_mappointers (discr, len); +} + +static inline basilys_ptr_t +basilysgc_new_mapedges (basilysobject_ptr_t discr, unsigned len) +{ + if (basilys_magic_discr ((void *) discr) != OBMAG_OBJECT) + return NULL; + if (discr->object_magic != OBMAG_MAPEDGES) + return NULL; + return basilysgc_raw_new_mappointers (discr, len); +} + +static inline basilys_ptr_t +basilysgc_new_mapbasicblocks (basilysobject_ptr_t discr, unsigned len) +{ + if (basilys_magic_discr ((void *) discr) != OBMAG_OBJECT) + return NULL; + if (discr->object_magic != OBMAG_MAPBASICBLOCKS) + return NULL; + return basilysgc_raw_new_mappointers (discr, len); +} +void +basilysgc_raw_put_mappointers (void *mappointer_p, + const void *attr, basilys_ptr_t valu_p); + +static inline void +basilysgc_put_maptrees (struct basilysmaptrees_st *map_p, + tree attr, basilys_ptr_t valu_p) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPTREES + || !attr || !valu_p) + return; + basilysgc_raw_put_mappointers (map_p, attr, valu_p); +} + +static inline void +basilysgc_put_mapedges (struct basilysmapedges_st *map_p, + edge attr, basilys_ptr_t valu_p) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPEDGES + || !attr || !valu_p) + return; + basilysgc_raw_put_mappointers (map_p, attr, valu_p); +} + +static inline void +basilysgc_put_mapbasicblocks (struct basilysmapbasicblocks_st *map_p, + basic_block attr, basilys_ptr_t valu_p) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPBASICBLOCKS + || !attr || !valu_p) + return; + basilysgc_raw_put_mappointers (map_p, attr, valu_p); +} + + +basilys_ptr_t +basilys_raw_get_mappointers (void *mappointer_p, const void *attr); + +static inline basilys_ptr_t +basilys_get_maptrees (basilys_ptr_t map_p, tree attr) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPTREES || !attr) + return NULL; + return basilys_raw_get_mappointers (map_p, attr); +} + +static inline basilys_ptr_t +basilys_get_mapedges (basilys_ptr_t map_p, edge attr) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPEDGES || !attr) + return NULL; + return basilys_raw_get_mappointers (map_p, attr); +} + +static inline basilys_ptr_t +basilys_get_mapbasicblocks (basilys_ptr_t map_p, basic_block attr) +{ + if (basilys_magic_discr ((void *) map_p) != OBMAG_MAPBASICBLOCKS || !attr) + return NULL; + return basilys_raw_get_mappointers (map_p, attr); +} + +basilys_ptr_t +basilysgc_raw_remove_mappointers (void *mappointer_p, const void *attr); + +static inline basilys_ptr_t +basilysgc_remove_maptrees (struct basilysmaptrees_st *map, tree attr) +{ + if (basilys_magic_discr ((void *) map) != OBMAG_MAPTREES || !attr) + return NULL; + return basilysgc_raw_remove_mappointers (map, attr); +} + +static inline basilys_ptr_t +basilysgc_remove_mapedges (struct basilysmaptrees_st *map, edge attr) +{ + if (basilys_magic_discr ((void *) map) != OBMAG_MAPEDGES || !attr) + return NULL; + return basilysgc_raw_remove_mappointers (map, attr); +} + +static inline basilys_ptr_t +basilysgc_remove_mapbasicblocks (struct basilysmapbasicblocks_st *map, + basic_block attr) +{ + if (basilys_magic_discr ((void *) map) != OBMAG_MAPBASICBLOCKS || !attr) + return NULL; + return basilysgc_raw_remove_mappointers (map, attr); +} + +/************************************************************* + * young generation copying garbage collector + * + * the young generation is managed specifically by an additional + * copying garbage collector, which copies basilys_ptr_t data into the + * GGC heap from a young region. This requires that every local + * variable is known to our copying basilys GC. For that purpose, + * locals are copied (or used) inside a chain of callframe_basilys_st + * structures. Since our copying GC change pointers, every allocation + * or call may change all the frames. Also stores inside data should + * be explicitly managed in a store list + * + * the young allocation zone is typically of a few megabytes when it + * is full, a minor garbage collection occur (and possibly a full GGC + * collection afterwards) which changes all the locals + *************************************************************/ + +/* start and end of young allocation zone */ +extern void *basilys_startalz; +extern void *basilys_endalz; +/* current allocation pointer aligned */ +extern char *basilys_curalz; +/* the store vector grows downward */ +extern void **basilys_storalz; +/* list of specials in the allocation zone */ +extern struct basilysspecial_st *basilys_newspeclist; +/* list of specials in the heap */ +extern struct basilysspecial_st *basilys_oldspeclist; +/* kilowords allocated since last full collection */ +extern unsigned long basilys_kilowords_sincefull; +/* number of full & any basilys garbage collections */ +extern unsigned long basilys_nb_full_garbcoll; +extern unsigned long basilys_nb_garbcoll; + +extern bool basilys_prohibit_garbcoll; + +/* extra scanning routine pointer - only for GC experts, and mostly + useful to possibly scan bison or yacc semantic value stack */ +extern void (*basilys_extra_scanrout_p) (void); + +/* the basilys copying garbage collector routine - moves all locals on the stack! */ +enum +{ BASILYS_MINOR_OR_FULL = 0, BASILYS_NEED_FULL = 1 }; +void basilys_garbcoll (size_t wanted, bool needfull); + +/* the alignment */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define BASILYS_ALIGN (__alignof__(union basilys_un)) +#define BASILYS_LIKELY(P) __builtin_expect((P),1) +#define BASILYS_UNLIKELY(P) __builtin_expect((P),0) +#else +#define BASILYS_ALIGN (2*sizeof(void*)) +#define BASILYS_LIKELY(P) (P) +#define BASILYS_UNLIKELY(P) (P) +#endif + +static inline bool +basilys_is_young (const void *p) +{ + return (char *) p >= (char *) basilys_startalz + && (char *) p < (char *) basilys_endalz; +} + + +#if ENABLE_CHECKING +/* to ease debugging we sometimes want to know when some pointer is + allocated: set these variables in the debugger */ +static void* tracedptr1; +static void* tracedptr2; +#endif + +/* the allocator routine allocates a zone of BASESZ with extra GAP */ +static inline void * +basilysgc_allocate (size_t basesz, size_t gap) +{ + size_t wanted; + void *ptr; + if (basesz < sizeof (struct basilysforward_st)) + basesz = sizeof (struct basilysforward_st); + if ((basesz % BASILYS_ALIGN) != 0) + basesz += (BASILYS_ALIGN - (basesz % BASILYS_ALIGN)); + if ((gap % BASILYS_ALIGN) != 0) + gap += (BASILYS_ALIGN - (gap % BASILYS_ALIGN)); + wanted = basesz + gap; + gcc_assert (wanted >= sizeof (struct basilysforward_st)); + if (BASILYS_UNLIKELY (basilys_curalz + wanted + 2 * BASILYS_ALIGN + >= (char *) basilys_storalz)) + basilys_garbcoll (wanted, BASILYS_MINOR_OR_FULL); + ptr = basilys_curalz; +#if ENABLE_CHECKING + if (ptr == tracedptr1) + debugeprintf("allocated tracedptr1 %p", ptr); + else if (ptr == tracedptr2) + debugeprintf("allocated tracedptr2 %p", ptr); +#endif + basilys_curalz += wanted; + return ptr; +} + + +/* we maintain a small cache hasharray of touched values - the touched + cache size should be a small prime */ +#define BASILYS_TOUCHED_CACHE_SIZE 17 +extern void *basilys_touched_cache[BASILYS_TOUCHED_CACHE_SIZE]; +/* the touching routine should be called on every basilys value which + has been touched (by mutating one of its internal pointers) - it + may add the touched value to the store "array" and may trigger our + basilys copying garbage collector */ +static inline void +basilysgc_touch (void *touchedptr) +{ + /* we know that this may loose -eg on some 64bits hosts- some + highend bits of the pointer but we don't care, since the 32 + lowest bits are enough (as hash); we need a double cast to avoid + a warning */ + unsigned pad = (unsigned) (HOST_WIDE_INT) touchedptr; + if ((char *) touchedptr >= (char *) basilys_startalz + && (char *) touchedptr <= (char *) basilys_endalz) + return; + pad = pad % (unsigned) BASILYS_TOUCHED_CACHE_SIZE; + if (basilys_touched_cache[pad] == touchedptr) + return; + *basilys_storalz = touchedptr; + basilys_storalz--; + basilys_touched_cache[pad] = touchedptr; + if (BASILYS_UNLIKELY + ((char *) ((void **) basilys_storalz - 3) <= (char *) basilys_curalz)) + basilys_garbcoll (1024 * sizeof (void *) + + ((char *) basilys_endalz - (char *) basilys_storalz), + BASILYS_MINOR_OR_FULL); +} + +/* we can avoid the hassle of adding a touched pointer to the store + list if we know that the newly added pointer inside does not point + into the new allocation zone; TOUCHEDPTR is the mutated value and + DSTPTR is the newly added pointer insided */ +static inline void +basilysgc_touch_dest (void *touchedptr, void *destptr) +{ + /* if we add an old pointer we don't care */ + if (!basilys_is_young(destptr)) + return; + basilysgc_touch (touchedptr); +} + + + + + + +/* low level map routines */ + + +/*** + * allocation routines that may trigger a garbage collection + * (their name starts with basilysgc) + ***/ + +/* allocate a boxed long integer (or null if bad DISCR) fillen with NUM */ +basilys_ptr_t basilysgc_new_int (basilysobject_ptr_t discr, long num); + +static inline long +basilys_get_int (basilys_ptr_t v) +{ + switch (basilys_magic_discr (v)) + { + case OBMAG_INT: + return ((struct basilysint_st *) (v))->val; + case OBMAG_MIXINT: + return ((struct basilysmixint_st *) (v))->intval; + case OBMAG_OBJECT: + return ((basilysobject_ptr_t) (v))->obj_num; + default: + return 0; + } +} + +static inline bool +basilys_put_int (basilys_ptr_t v, long x) +{ + switch (basilys_magic_discr (v)) + { + case OBMAG_INT: + ((struct basilysint_st *) (v))->val = x; + return TRUE; + case OBMAG_MIXINT: + ((struct basilysmixint_st *) (v))->intval = x; + return TRUE; + case OBMAG_OBJECT: + if (((basilysobject_ptr_t) (v))->obj_num != 0) + return FALSE; + ((basilysobject_ptr_t) (v))->obj_num = (unsigned short) x; + return TRUE; + default: + return FALSE; + } +} + + +static inline long +basilys_obj_hash (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_OBJECT) + return ((basilysobject_ptr_t) (v))->obj_hash; + return 0; +} + + +static inline long +basilys_obj_len (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_OBJECT) + return ((basilysobject_ptr_t) (v))->obj_len; + return 0; +} + +static inline long +basilys_obj_num (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_OBJECT) + return ((basilysobject_ptr_t) (v))->obj_num; + return 0; +} + +/* safe integer div & mod */ +static inline long +basilys_idiv (long i, long j) +{ + return (j != 0) ? (i / j) : 0; +} +static inline long +basilys_imod (long i, long j) +{ + return (j != 0) ? (i % j) : 0; +} + + + +/* allocate a boxed mixed integer & value) */ +basilys_ptr_t +basilysgc_new_mixint (basilysobject_ptr_t discr_p, basilys_ptr_t val_p, + long num); + +static inline basilys_ptr_t +basilys_val_mixint (basilys_ptr_t mix) +{ + struct basilysmixint_st *smix = (void *) mix; + if (basilys_magic_discr (mix) == OBMAG_MIXINT) + return smix->ptrval; + return NULL; +} + +static inline long +basilys_num_mixint (basilys_ptr_t mix) +{ + struct basilysmixint_st *smix = (void *) mix; + if (basilys_magic_discr (mix) == OBMAG_MIXINT) + return smix->intval; + return 0; +} + + +/* get (safely) the nth (counting from 0) field of an object */ +static inline basilys_ptr_t +basilys_field_object (basilys_ptr_t ob, unsigned off) +{ + if (basilys_magic_discr (ob) == OBMAG_OBJECT) + { + basilysobject_ptr_t pob = (void *) ob; + if (off < pob->obj_len) + return pob->obj_vartab[off]; + }; + return NULL; +} + +/* get (safely) the length of an object */ +static inline int +basilys_object_length (basilys_ptr_t ob) +{ + if (basilys_magic_discr (ob) == OBMAG_OBJECT) + { + basilysobject_ptr_t pob = (void *) ob; + return pob->obj_len; + } + return 0; +} + +/* allocate a new string (or null if bad DISCR or null STR) initialized from + _static_ (non gc-ed) memory STR */ +basilys_ptr_t basilysgc_new_string (basilysobject_ptr_t discr, + const char *str); + +/* allocate a new string (or null if bad DISCR or null STR) initialized from + a memory STR which is temporarily duplicated (so can be in gc-ed) */ +basilys_ptr_t basilysgc_new_stringdup (basilysobject_ptr_t discr, + const char *str); + +/* get the naked nasename of a path, ie from "/foo/bar.gyz" return "bar"; argument is duplicated */ +basilys_ptr_t basilysgc_new_string_nakedbasename (basilysobject_ptr_t discr, + const char *str); + +static inline const char * +basilys_string_str (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_STRING) + return ((struct basilysstring_st *) v)->val; + return 0; +} + +static inline int +basilys_string_length (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_STRING) + return strlen(((struct basilysstring_st *) v)->val); + return 0; +} + +static inline bool +basilys_string_same (basilys_ptr_t v1, basilys_ptr_t v2) +{ + if (basilys_magic_discr (v1) == OBMAG_STRING + && basilys_magic_discr (v2) == OBMAG_STRING) + { + return 0 == strcmp (((struct basilysstring_st *) v1)->val, + ((struct basilysstring_st *) v2)->val); + } + return 0; +} + +static inline const char * +basilys_strbuf_str (basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_STRBUF) + { + struct basilysstrbuf_st *sb = (void *) v; + if (sb->bufend >= sb->bufstart) + return sb->bufzn + sb->bufstart; + } + return 0; +} + +static inline int +basilys_strbuf_usedlength(basilys_ptr_t v) +{ + if (basilys_magic_discr (v) == OBMAG_STRBUF) + { + struct basilysstrbuf_st *sb = (void *) v; + if (sb->bufend >= sb->bufstart) + return sb->bufend - sb->bufstart; + } + return 0; +} + + +/* allocate a pair of given head and tail */ +basilys_ptr_t basilysgc_new_pair (basilysobject_ptr_t discr, + void *head, void *tail); + +/* change the head of a pair */ +void basilysgc_pair_set_head(basilys_ptr_t pair, void* head); + +/* allocate a new multiple of given DISCR & length LEN */ +basilys_ptr_t basilysgc_new_multiple (basilysobject_ptr_t discr_p, + unsigned len); + +/* allocate a multiple of arity 1 */ +basilys_ptr_t basilysgc_new_mult1 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p); +/* allocate a multiple of arity 2 */ +basilys_ptr_t basilysgc_new_mult2 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p); +/* allocate a multiple of arity 3 */ +basilys_ptr_t basilysgc_new_mult3 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p); +/* allocate a multiple of arity 4 */ +basilys_ptr_t basilysgc_new_mult4 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p, basilys_ptr_t v3_p); +/* allocate a multiple of arity 5 */ +basilys_ptr_t basilysgc_new_mult5 (basilysobject_ptr_t discr_p, + basilys_ptr_t v0_p, basilys_ptr_t v1_p, + basilys_ptr_t v2_p, basilys_ptr_t v3_p, + basilys_ptr_t v4_p); + +/* allocate a new (empty) list */ +basilys_ptr_t basilysgc_new_list (basilysobject_ptr_t discr_p); +/* append to the tail of a list */ +void basilysgc_append_list (basilys_ptr_t list_p, basilys_ptr_t val_p); +/* prepend to the head of a list */ +void basilysgc_prepend_list (basilys_ptr_t list_p, basilys_ptr_t val_p); +/* pop from head of list (and remove) */ +basilys_ptr_t basilysgc_popfirst_list (basilys_ptr_t list_p); + +/* return the length of a list or -1 iff non list */ +int basilys_list_length (basilys_ptr_t list_p); + +/* allocate e new empty mapobjects */ +basilys_ptr_t basilysgc_new_mapobjects (basilysobject_ptr_t discr_p, + unsigned len); + +/* put into a mapobjects */ +void basilysgc_put_mapobjects (basilysmapobjects_ptr_t mapobject_p, + basilysobject_ptr_t attrobject_p, + basilys_ptr_t valu_p); + +/* get from a mapobject */ +basilys_ptr_t basilys_get_mapobjects (basilysmapobjects_ptr_t mapobject_p, + basilysobject_ptr_t attrobject_p); + +/* remove from a mapobject (return the removed value) */ +basilys_ptr_t basilysgc_remove_mapobjects (basilysmapobjects_ptr_t + mapobject_p, + basilysobject_ptr_t attrobject_p); + +static inline int +basilys_size_mapobjects (basilysmapobjects_ptr_t mapobject_p) +{ + if (!mapobject_p || mapobject_p->discr->obj_num != OBMAG_MAPOBJECTS) + return 0; + return basilys_primtab[mapobject_p->lenix]; +} + +static inline unsigned +basilys_count_mapobjects (basilysmapobjects_ptr_t mapobject_p) +{ + if (!mapobject_p || mapobject_p->discr->obj_num != OBMAG_MAPOBJECTS) + return 0; + return mapobject_p->count; +} + +static inline basilysobject_ptr_t +basilys_nthattr_mapobjects (basilysmapobjects_ptr_t mapobject_p, int ix) +{ + basilysobject_ptr_t at = 0; + if (!mapobject_p || mapobject_p->discr->obj_num != OBMAG_MAPOBJECTS) + return 0; + if (ix < 0 || ix >= basilys_primtab[mapobject_p->lenix]) + return 0; + at = mapobject_p->entab[ix].e_at; + if ((void *) at == (void *) HTAB_DELETED_ENTRY) + return 0; + return at; +} + +static inline basilys_ptr_t +basilys_nthval_mapobjects (basilysmapobjects_ptr_t mapobject_p, int ix) +{ + basilysobject_ptr_t at = 0; + if (!mapobject_p || mapobject_p->discr->obj_num != OBMAG_MAPOBJECTS) + return 0; + if (ix < 0 || ix >= basilys_primtab[mapobject_p->lenix]) + return 0; + at = mapobject_p->entab[ix].e_at; + if ((void *) at == (void *) HTAB_DELETED_ENTRY) + return 0; + return mapobject_p->entab[ix].e_va; +} + +/* allocate a new empty mapstrings */ +basilys_ptr_t basilysgc_new_mapstrings (basilysobject_ptr_t discr_p, + unsigned len); + +/* put into a mapstrings, the string is copied so can be in the gc-ed heap */ +void basilysgc_put_mapstrings (struct basilysmapstrings_st *mapstring_p, + const char *str, basilys_ptr_t valu_p); + +/* get from a mapstring */ +basilys_ptr_t basilys_get_mapstrings (struct basilysmapstrings_st + *mapstring_p, const char *attr); + + +/* remove from a mapstring (return the removed value) */ +basilys_ptr_t basilysgc_remove_mapstrings (struct basilysmapstrings_st + *mapstring_p, const char *str); + +static inline int +basilys_size_mapstrings (struct basilysmapstrings_st *mapstring_p) +{ + if (!mapstring_p || mapstring_p->discr->obj_num != OBMAG_MAPSTRINGS) + return 0; + return basilys_primtab[mapstring_p->lenix]; +} + +static inline unsigned +basilys_count_mapstrings (struct basilysmapstrings_st *mapstring_p) +{ + if (!mapstring_p || mapstring_p->discr->obj_num != OBMAG_MAPSTRINGS) + return 0; + return mapstring_p->count; +} + +static inline const char * +basilys_nthattrraw_mapstrings (struct basilysmapstrings_st *mapstring_p, + int ix) +{ + const char *at = 0; + if (!mapstring_p || mapstring_p->discr->obj_num != OBMAG_MAPSTRINGS) + return 0; + if (ix < 0 || ix >= basilys_primtab[mapstring_p->lenix]) + return 0; + at = mapstring_p->entab[ix].e_at; + if ((void *) at == (void *) HTAB_DELETED_ENTRY) + return 0; + return at; +} + +static inline basilys_ptr_t +basilys_nthval_mapstrings (struct basilysmapstrings_st *mapstring_p, int ix) +{ + const char *at = 0; + if (!mapstring_p || mapstring_p->discr->obj_num != OBMAG_MAPSTRINGS) + return 0; + if (ix < 0 || ix >= basilys_primtab[mapstring_p->lenix]) + return 0; + at = mapstring_p->entab[ix].e_at; + if ((void *) at == (void *) HTAB_DELETED_ENTRY) + return 0; + return mapstring_p->entab[ix].e_va; +} + +/* allocate a new routine object of given DISCR and of length LEN, + with a DESCR-iptive string a a PROC-edure */ +basilysroutine_ptr_t basilysgc_new_routine (basilysobject_ptr_t discr_p, + unsigned len, const char *descr, + basilysroutfun_t * proc); + + +static inline char * +basilys_routine_descrstr (basilys_ptr_t rout) +{ + if (rout && ((basilysroutine_ptr_t) rout)->discr->obj_num == OBMAG_ROUTINE) + return ((basilysroutine_ptr_t) rout)->routdescr; + return (char *) 0; +} + +static inline int +basilys_routine_size (basilys_ptr_t rout) +{ + if (rout && ((basilysroutine_ptr_t) rout)->discr->obj_num == OBMAG_ROUTINE) + return ((basilysroutine_ptr_t) rout)->nbval; + return 0; +} + +static inline basilys_ptr_t +basilys_routine_nth (basilys_ptr_t rout, int ix) +{ + if (rout && ((basilysroutine_ptr_t) rout)->discr->obj_num == OBMAG_ROUTINE) + if (ix >= 0 && ix < (int) ((basilysroutine_ptr_t) rout)->nbval) + return ((basilysroutine_ptr_t) rout)->tabval[ix]; + return 0; +} + +/*********/ +/* allocate a new closure of given DISCR with a given ROUT, and of length LEN + */ +basilysclosure_ptr_t basilysgc_new_closure (basilysobject_ptr_t discr_p, + basilysroutine_ptr_t rout_p, + unsigned len); + +static inline int +basilys_closure_size (basilys_ptr_t clo) +{ + if (clo && ((basilysclosure_ptr_t) clo)->discr->obj_num == OBMAG_CLOSURE) + return ((basilysclosure_ptr_t) clo)->nbval; + return 0; +} + +static inline basilys_ptr_t +basilys_closure_routine (basilys_ptr_t clo) +{ + if (clo && ((basilysclosure_ptr_t) clo)->discr->obj_num == OBMAG_CLOSURE) + return (basilys_ptr_t) (((basilysclosure_ptr_t) clo)->rout); + return 0; +} + +static inline basilys_ptr_t +basilys_closure_nth (basilys_ptr_t clo, int ix) +{ + if (clo && ((basilysclosure_ptr_t) clo)->discr->obj_num == OBMAG_CLOSURE + && ix >= 0 && ix < (int) (((basilysclosure_ptr_t) clo)->nbval)) + return (basilys_ptr_t) (((basilysclosure_ptr_t) clo)->tabval[ix]); + return 0; +} + + +/***** list and pairs accessors ****/ +/* safe pair head & tail accessors */ +static inline basilys_ptr_t +basilys_pair_head (basilys_ptr_t pair) +{ + if (pair && ((struct basilyspair_st *) pair)->discr->obj_num == OBMAG_PAIR) + return ((struct basilyspair_st *) pair)->hd; + return 0; +} + +static inline basilys_ptr_t +basilys_pair_tail (basilys_ptr_t pair) +{ + if (pair && ((struct basilyspair_st *) pair)->discr->obj_num == OBMAG_PAIR) + return (basilys_ptr_t) (((struct basilyspair_st *) pair)->tl); + return 0; +} + +/* compute the length of a pairlist */ +static inline long +basilys_pair_listlength (basilys_ptr_t pair) +{ + long l = 0; + while (pair + && ((struct basilyspair_st *) pair)->discr->obj_num == OBMAG_PAIR) + { + l++; + pair = (basilys_ptr_t) (((struct basilyspair_st *) pair)->tl); + }; + return l; +} + +static inline basilys_ptr_t +basilys_list_first (basilys_ptr_t lis) +{ + if (lis && ((struct basilyslist_st *) lis)->discr->obj_num == OBMAG_LIST) + return (basilys_ptr_t) (((struct basilyslist_st *) lis)->first); + return NULL; +} + +static inline basilys_ptr_t +basilys_list_last (basilys_ptr_t lis) +{ + if (lis && ((struct basilyslist_st *) lis)->discr->obj_num == OBMAG_LIST) + return (basilys_ptr_t) (((struct basilyslist_st *) lis)->last); + return NULL; +} + +/* allocate a new raw object of given KLASS (unchecked) with LEN slots */ +basilysobject_ptr_t basilysgc_new_raw_object (basilysobject_ptr_t klass_p, + unsigned len); + + +/***** STRBUF ie string buffers *****/ + +/* allocate a new strbuf of given DISCR with initial content STR */ +struct basilysstrbuf_st *basilysgc_new_strbuf (basilysobject_ptr_t discr_p, + const char *str); + +/* add into STRBUF the static string STR (which is not in the basilys heap) */ +void basilysgc_add_strbuf_raw (struct basilysstrbuf_st *strbuf_p, + const char *str); + +/* add safely into STRBUF the string STR (which is first copied, so + can be in the basilys heap) */ +void basilysgc_add_strbuf (struct basilysstrbuf_st *strbuf_p, + const char *str); +/* add safely into STRBUF the string STR encoded as a C string with + backslash escapes */ +void basilysgc_add_strbuf_cstr (struct basilysstrbuf_st *strbuf_p, + const char *str); +/* add safely into STRBUF the string STR encoded as the interior of a + C comment with slash star and star slash replaced by slash plus and + plus slash */ +void basilysgc_add_strbuf_ccomment (struct basilysstrbuf_st *strbuf_p, + const char *str); + +/* add safely into STRBUF the string STR (which is copied at first) + encoded as a C identifier; ie non-alphanum begine encoded as an + underscore */ +void basilysgc_add_strbuf_cident (struct basilysstrbuf_st *strbuf_p, + const char *str); + +/* add safely into STRBUF the initial prefix of string STR (which is + copied at first), with a length of at most PREFLEN encoded as a C + identifier; ie non-alphanum begine encoded as an underscore */ +void +basilysgc_add_strbuf_cidentprefix (struct basilysstrbuf_st + *strbuf_p, const char *str, int preflen); + +/* add safely into STRBUF the hex encoded number L */ +void basilysgc_add_strbuf_hex (struct basilysstrbuf_st *strbuf_p, + unsigned long l); +/* add safely into STRBUF the decimal encoded number L */ +void basilysgc_add_strbuf_dec (struct basilysstrbuf_st *strbuf_p, long l); + +/* add safely into STRBUF a printf like stuff with FMT */ +void +basilysgc_strbuf_printf (struct basilysstrbuf_st *strbuf_p, const char *fmt, + ...) ATTRIBUTE_PRINTF (2, 3); + +/* add safely into STRBUF either a space or an indented newline if the current line is bigger than the threshold */ +void basilysgc_strbuf_add_indent (struct basilysstrbuf_st *strbuf_p, + int indeptn, int linethresh); + +/**************************** misc *****************************/ +/* a random generator */ +long basilys_lrand (void); + +static inline unsigned basilys_nonzerohash (void) +{ + unsigned h; + do + { + h = basilys_lrand () & BASILYS_MAXHASH; + } + while (h == 0); + return h; +} + +/* initialize all - don't do anything when called more than once */ +void basilys_initialize (void); + +/* compile (as a dynamically loadable module) some (usually generated) + C code and dynamically load it; the C code should contain a + function named start_module_basilys; that function is called with + the given modata and returns the module */ +basilys_ptr_t +basilysgc_compile_dyn (basilys_ptr_t modata_p, const char *srcfile); + +/* first_module_basilys is the function start_module_basilys in first-basilys.c */ +basilys_ptr_t first_module_basilys (basilys_ptr_t); + + +/* get (or create) the symbol of a given name, using the TOKENIZER + global; the NAM string can be in the GC-allocated heap since it is + copied */ +enum +{ /* a meningful enum for the create flag below */ + BASILYS_GET = 0, + BASILYS_CREATE +}; + +basilys_ptr_t basilysgc_named_symbol (const char *nam, int create); + +/* get (or create) the keyword of a given name (without the colon), + using the TOKENIZER global; the NAM string can be in the + GC-allocated heap since it is copied */ +basilys_ptr_t basilysgc_named_keyword (const char *nam, int create); + +/* intern a symbol, ie add it into the global name map; if the symbol + is new, return it otherwise return the older homonymous symnol */ +basilys_ptr_t basilysgc_intern_symbol (basilys_ptr_t symb); + +/* intern a keyword, ie add it into the global name map; if the symbol + is new, return it otherwise return the older homonymous symnol */ +basilys_ptr_t basilysgc_intern_keyword (basilys_ptr_t symb); + +/* read a list of sexpressions from a file */ +basilys_ptr_t basilysgc_read_file (const char *filnam); + +/* Use basilys_assert(MESSAGE,EXPR) to test invariants. The MESSAGE + should be a constant string displayed when asserted EXPR is + false */ +#if ENABLE_ASSERT_CHECKING +void +basilys_assert_failed (const char *msg, const char *filnam, int lineno, + const char *fun) + ATTRIBUTE_NORETURN; +enum { BASILYS_ANYWHERE=0, BASILYS_NOYOUNG }; +void basilys_check_call_frames_at(int youngflag, const char*msg, const char*filenam, int lineno); +#define basilys_assertmsg(MSG,EXPR) \ + (!(EXPR)?(basilys_assert_failed((MSG),__FILE__,__LINE__,__FUNCTION__), 0):0) +#define basilys_check_call_frames(YNG,MSG) \ + ((void)(basilys_check_call_frames_at((YNG),(MSG),__FILE__,__LINE__))) +#else +/* Include EXPR, so that unused variable warnings do not occur. */ +#define basilys_assertmsg(MSG,EXPR) ((void)(0 && (MSG) && (EXPR))) +#define basilys_check_call_frames(YNG,MSG) (void)(0) +#endif + +/******************* method sending ************************/ +basilys_ptr_t basilysgc_send (basilys_ptr_t recv, + basilys_ptr_t sel, + const char *xargdescr_, + union basilysparam_un *xargtab_, + const char *xresdescr_, + union basilysparam_un *xrestab_); + +/**************************** globals **************************/ + +/* enumeration of predefined global object indexes inside + basilys_globvec; the firsts are wired predefined, in the sense that + they are automagically allocated and partly filled before loading + the basilys file. The others are named, and are expected to be + created by loading the basilysfile */ +enum basilys_globalix_en +{ + BGLOB__NONE, + /************************** wired predefined */ + /*** + * don't forget to fill these objects in basilys-init.bysl file + ***/ + /* the pseudo discriminant using for sending to null pointers */ + BGLOB_DISCR_NULLRECV, + /* the initial discriminant of string */ + BGLOB_DISCR_STRING, + /* the initial discriminant of integer */ + BGLOB_DISCR_INTEGER, + /* the initial discriminant of lists */ + BGLOB_DISCR_LIST, + /* the initial discriminant of multiples */ + BGLOB_DISCR_MULTIPLE, + /* the initial discriminant of boxes */ + BGLOB_DISCR_BOX, + /* the initial discriminant of mapobjects */ + BGLOB_DISCR_MAPOBJECTS, + /* the initial discriminant of mapstrings */ + BGLOB_DISCR_MAPSTRINGS, + /* the initial discriminant of charcode integer */ + BGLOB_DISCR_CHARINTEGER, + /* the initial discriminant of mixedint */ + BGLOB_DISCR_MIXEDINT, + /* the discriminant of ancestors or other class sequences */ + BGLOB_DISCR_SEQCLASS, + /* the discriminant of closures */ + BGLOB_DISCR_CLOSURE, + /* the discriminant of routine */ + BGLOB_DISCR_ROUTINE, + /* the discriminant of pairs */ + BGLOB_DISCR_PAIR, + /* the discriminant of short name strings */ + BGLOB_DISCR_NAMESTRING, + /* the discriminant of verbatim strings (in primitive expansions) */ + BGLOB_DISCR_VERBATIMSTRING, + /* discriminant for sequence of fields */ + BGLOB_DISCR_SEQFIELD, + /* discriminant for dictionnaries (mapobjects) of methods */ + BGLOB_DISCR_METHODMAP, + /* the class of classes */ + BGLOB_CLASS_CLASS, + /* the root class */ + BGLOB_CLASS_ROOT, + /* the proped class */ + BGLOB_CLASS_PROPED, + /* the named class */ + BGLOB_CLASS_NAMED, + /* the located class */ + BGLOB_CLASS_LOCATED, + /* the symbol class */ + BGLOB_CLASS_SYMBOL, + /* the keyword class */ + BGLOB_CLASS_KEYWORD, + /* the sexpr class */ + BGLOB_CLASS_SEXPR, + /* class of fields */ + BGLOB_CLASS_FIELD, + /* class of message selectors */ + BGLOB_CLASS_SELECTOR, + /* class of primitives */ + BGLOB_CLASS_PRIMITIVE, + /* class of formal bindings */ + BGLOB_CLASS_FORMAL_BINDING, + /* the discr class */ + BGLOB_CLASS_DISCR, + /* the class of tokenizers */ + BGLOB_CLASS_TOKENIZER, + /* the class of command dispatchers */ + BGLOB_CLASS_COMMAND_DISPATCHER, + /* atom for returning true */ + BGLOB_ATOM_TRUE, + /**** every ctype should be predefined ****/ + /* ctype of longs */ + BGLOB_CTYPE_LONG, + /* ctype of values */ + BGLOB_CTYPE_VALUE, + /* ctype of trees */ + BGLOB_CTYPE_TREE, + /* ctype for void */ + BGLOB_CTYPE_VOID, + /* ctype of constant cstrings */ + BGLOB_CTYPE_CSTRING, + /* the global tokenizer */ + BGLOB_TOKENIZER, + /* the initial command dispatcher */ + BGLOB_INITIAL_COMMAND_DISPATCHER, + /**************************** placeholder for last wired */ + BGLOB__LASTWIRED, + /*****/ + BGLOB__LASTGLOB +}; + + +/* *INDENT-OFF* */ + +/* the array of global values */ +extern GTY (()) basilys_ptr_t basilys_globarr[BGLOB__LASTGLOB]; + +/* *INDENT-ON* */ + +/* fields inside every proped object */ +enum +{ + FPROPED_PROP = 0, + FPROPED__LAST +}; +/* fields inside every named object */ +enum +{ + FNAMED_NAME = FPROPED__LAST, + FNAMED__LAST +}; + +/* fields inside every discriminant */ +enum +{ + FDISCR_METHODICT = FNAMED__LAST, /* a mapobjects for method mapping + selectors to closures */ + FDISCR_SENDCLOSURE, /* the closure doing the send if a + selector is not in the method + dict */ + FDISCR_SUPER, /* the "superclass" or "parent discrim" */ + FDISCR__LAST +}; + +/* fields inside every class */ +enum +{ + FCLASS_ANCESTORS = FDISCR__LAST, /* a multiple for the class ancestors + (first being the CLASS:ROOT last + being the immediate superclass) */ + FCLASS_FIELDS, /* a multiple for the class fields */ + FCLASS_OBJNUMDESCR, /* a description of the objnum */ + FCLASS_DATA, /* class variables */ + FCLASS__LAST +}; + + +/* fields inside each symbol */ +enum +{ + FSYMB_DATA = FNAMED__LAST, + FSYMB__LAST +}; + +/* fields inside a source expression (sexpr) */ +enum +{ + FSEXPR_LOCATION = FPROPED__LAST, + FSEXPR_CONTENTS, /* the contents of the sexpression (as a list) */ + FSEXPR__LAST +}; + +/* fields inside a tokenizer */ +enum +{ + FTOK_SYMBDICT = FNAMED__LAST, /* the stringdict of symbols */ + FTOK_KEYWDICT, /* the stringdict of keywords */ + FTOK_ADDSYMB, /* closure to add a new symbol (given its name string) */ + FTOK_ADDKEYW, /* closure to add a new keyword */ + FTOK_INTERNSYMB, /* closure to intern a (freshly build) symbol */ + FTOK_INTERNKEYW, /* closure to intern a keyword */ + FTOK__LAST +}; + +/* fields inside the command dispatcher */ +enum +{ + FCMDIS_FUNDICT = FNAMED__LAST, /* the stringdict of commands */ + FCMDIS__LAST +}; + +/* BASILYSG(Foo) is the global of index BGLOB_Foo */ +#define BASILYSG(Glob) basilys_globarr[BGLOB_##Glob] +#define BASILYSGOB(Glob) ((basilysobject_ptr_t)(BASILYSG(Glob))) + + +bool basilys_is_subclass_of (basilysobject_ptr_t subclass_p, + basilysobject_ptr_t superclass_p); + +static inline bool +basilys_is_instance_of (basilys_ptr_t inst_p, basilys_ptr_t class_p) +{ + unsigned mag_class = 0; + unsigned mag_inst = 0; + if (!inst_p) + return FALSE; + if (!class_p) + return FALSE; + gcc_assert(class_p->u_discr != NULL); + gcc_assert(inst_p->u_discr != NULL); + mag_class = class_p->u_discr->obj_num; + mag_inst = inst_p->u_discr->obj_num; + if (mag_class != OBMAG_OBJECT || !mag_inst) + return FALSE; + if (((basilysobject_ptr_t) inst_p)->obj_class == + (basilysobject_ptr_t) class_p) + return TRUE; + if (mag_inst != ((basilysobject_ptr_t) class_p)->object_magic) + return FALSE; + if (mag_inst == OBMAG_OBJECT) + return basilys_is_subclass_of (((basilysobject_ptr_t) inst_p)->obj_class, + ((basilysobject_ptr_t) class_p)); + /* the instance is not an object but something else and it has the + good magic */ + return TRUE; +} + +/*** + * CALL FRAMES + ***/ + +/* call frames for our copying garbage collector cannot be GTY-ed + because they are inside the C call stack */ +struct callframe_basilys_st +{ + unsigned nbvar; + struct basilysclosure_st *clos; + struct excepth_basilys_st *exh; /* for our exceptions - not implemented yet */ + struct callframe_basilys_st *prev; + basilys_ptr_t varptr[FLEXIBLE_DIM]; +}; + +/* maximal number of local variables per frame */ +#define BASILYS_MAXNBLOCALVAR 4096 + +/* the topmost call frame */ +extern struct callframe_basilys_st *basilys_topframe; + +#if 0 +/* the jmpbuf for our catch & throw */ +extern jmp_buf *basilys_jmpbuf; +extern basilys_ptr_t basilys_jmpval; +#endif + +/* declare the current callframe */ +#define BASILYS_DECLFRAME(NBVAR) struct { \ + unsigned nbvar; \ + struct basilysclosure_st* clos; \ + struct excepth_basilys_st* exh; \ + struct callframe_basilys_st* prev; \ + void* /* a basilys_ptr_t */ varptr[NBVAR]; \ +} curfram__ + +/* initialize the current callframe and link it at top */ +#define BASILYS_INITFRAME(NBVAR,CLOS) do { \ + memset(&curfram__, 0, sizeof(curfram__)); \ + curfram__.nbvar = (NBVAR); \ + curfram__.prev = basilys_topframe; \ + curfram__.clos = (CLOS); \ + basilys_topframe = ((void*)&curfram__); \ +} while(0) + +/* declare and initialize the current callframe */ +#define BASILYS_ENTERFRAME(NBVAR,CLOS) \ + BASILYS_DECLFRAME(NBVAR); BASILYS_INITFRAME(NBVAR,CLOS) + +/* exit the current frame and return */ +#define BASILYS_EXITFRAME() do { \ + basilys_topframe = curfram__.prev; \ +} while(0) + +/**** +#define BASILYS_CATCH(Vcod,Vptr) do { + jmp_buf __jbuf; + int __jcod; + jmp_buf* __prevj = basilys_jmpbuf; + memset(&__jbuf, 0, sizeof(jmp_buf)); + basilys_jmpbuf = &__jbuf; + __jcod = setjmp(&__jbuf); + Vcod = __jcod; + if (__jcod) { + basilys_topframe = ((void*)&curfram__); + Vptr = basilys_jmpval; + }; +} while(0) + +#define BASILYS_THROW(Cod,Ptr) do { +} while(0) +***/ + + +/* ====== safer output routines ===== */ + +/* output a string */ +static inline void +basilys_puts (FILE * f, const char *str) +{ + if (f && str) + fputs (str, f); +} + +/* output a number with a prefix & suffix message */ +static inline void +basilys_putnum(FILE* f, const char*pref, long l, const char*suff) { + if (f) + fprintf(f, "%s%ld%s", pref?pref:"", l, suff?suff:""); +} + +/* safe flush */ +static inline void +basilys_flush (FILE * f) +{ + if (f) + fflush (f); +} + +/* safe newline and flush */ +static inline void +basilys_newlineflush (FILE * f) +{ + if (f) + { + putc ('\n', f); + fflush (f); + } +} + +/* output a string value */ +static inline void +basilys_putstr (FILE * f, basilys_ptr_t sv) +{ + if (f && sv && basilys_magic_discr (sv) == OBMAG_STRING) + fputs (((struct basilysstring_st *) sv)->val, f); +} + +/* output a string buffer */ +static inline void +basilys_putstrbuf (FILE * f, basilys_ptr_t sb) +{ + struct basilysstrbuf_st *sbuf = (struct basilysstrbuf_st *) sb; + if (f && sbuf && basilys_magic_discr ((void *) sbuf) == OBMAG_STRBUF) + { + gcc_assert (sbuf->bufzn); + if (!sbuf->bufzn || sbuf->bufend <= sbuf->bufstart) + return; + fwrite (sbuf->bufzn + sbuf->bufstart, sbuf->bufend - sbuf->bufstart, 1, + f); + } +} + + +/* output the declaration and implementation buffers of a generated file */ +void +basilys_output_cfile_decl_impl(basilys_ptr_t cfilnam, basilys_ptr_t declbuf, basilys_ptr_t implbuf); + +static inline void +debugeputs_at (const char *fil, int lin, const char *msg) +{ + debugeprintf_raw ("!@%s:%d: %s\n", basename (fil), lin, msg); +} + +#define debugeputs(Msg) debugeputs_at(__FILE__,__LINE__,(Msg)) + +static inline void +debugvalue_at (const char *fil, int lin, const char *msg, void *val) +{ + if (flag_basilys_debug) + { + fprintf (stderr, "!@%s:%d: %s @%p/%d= ", + basename (fil), lin, (msg), val, basilys_magic_discr (val)); + basilys_dbgeprint (val); + fflush (stderr); + } +} + +#define debugvalue(Msg,Val) debugvalue_at(__FILE__, __LINE__, (Msg), (Val)) + +static inline void +debugbacktrace_at (const char *fil, int lin, const char *msg, int depth) +{ + if (flag_basilys_debug) + { + fprintf (stderr, "\n!@%s:%d: %s ** BACKTRACE** ", + basename (fil), lin, msg); + basilys_dbgbacktrace (depth); + fflush (stderr); + } +} + +#define debugbacktrace(Msg,Depth) debugbacktrace_at(__FILE__, __LINE__, (Msg), (Depth)) + +static inline void +debugnum_at (const char *fil, int lin, const char *msg, long val) +{ + debugeprintf_raw ("!@%s:%d: %s =#= %ld\n", basename (fil), lin, msg, val); +} + +#define debugnum(Msg,Val) debugnum_at(__FILE__, __LINE__, (Msg), (Val)) + +static inline void * +basilys_globpredef (int rank) +{ + if (rank > 0 && rank < BGLOB__LASTGLOB) + return basilys_globarr[rank]; + return NULL; +} + +void basilys_dbgshortbacktrace(const char* msg, int maxdepth); + +#if ENABLE_CHECKING +extern void* basilys_checkedp_ptr1; +extern void* basilys_checkedp_ptr2; +void basilys_caught_assign_at(void*ptr, const char*fil, int lin); +#define basilys_checked_assign_at(Assign,Fil,Lin) ({ \ + void* p_##Lin = (Assign); \ + if (p_##Lin && !basilys_discr(p_##Lin)) \ + basilys_assert_failed("bad assign",Fil,Lin,__FUNCTION__); \ + if ( (p_##Lin == basilys_checkedp_ptr1 && p_##Lin) \ + || (p_##Lin == basilys_checkedp_ptr2 && p_##Lin)) \ + basilys_caught_assign_at(p_##Lin,Fil,Lin); p_##Lin; }) +#define basilys_checked_assign(Assign) basilys_checked_assign_at((Assign),__FILE__,__LINE__) +void basilys_cbreak_at(const char*msg, const char*fil, int lin); +#define basilys_cbreak(Msg) basilys_cbreak_at((Msg),__FILE__,__LINE__) +#else +#define basilys_checked_assign(Assign) Assign +#define basilys_cbreak(Msg) ((void)(Msg)) +#endif /*ENABLE_CHECKING*/ + +#endif /*BASILYS_INCLUDED_ */ +/* eof basilys.h */ diff --git a/gcc/common.opt b/gcc/common.opt index 810f879fe48..15b0aa3c415 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -319,6 +319,37 @@ fauto-inc-dec Common Report Var(flag_auto_inc_dec) Init(1) Generate auto-inc/dec instructions +;;;;;; basilys stuff +; global GCC analysis by Basile (source file gcc/basilys.c) +fbasilys +Common Report Var(flag_basilys) Condition(HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL) +Perform whole program static analysis by Basile; require -fwhole-program + +; debug flag for above analysis +fbasilys-debug +Common Report Var(flag_basilys_debug) Condition(HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL) +Gives lots of debugging stuff for -fbasilys analysis + +; initial C file for above analysis +fbasilys-init= +Common Report Var(basilys_init_string) RejectNegative Joined Condition(HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL) +Initial file for -fbasilys analysis (dynamic C mode) + +; command for basilys +fbasilys-command= +Common Report Var(basilys_command_string) RejectNegative Joined Condition(HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL) +Initial command for basilys analysis + +; argument string for basilys +fbasilys-arg= +Common Report Var(basilys_argument_string) RejectNegative Joined Condition(HAVE_PARMAPOLY && HAVE_LIBTOOLDYNL) +Initial argument for basilys analysis + + + + +;;;;;;;;;; end of basilys stuff + ; -fcheck-bounds causes gcc to generate array bounds checks. ; For C, C++ and ObjC: defaults off. ; For Java: defaults to on. @@ -370,6 +401,14 @@ fcommon Common Report Var(flag_no_common,0) Optimization Do not put uninitialized globals in the common section +fcompiler-probe= +Common Report Var(compiler_probe_string) RejectNegative Joined Condition(ENABLE_COMPILER_PROBE) +Probe the compiler (using the comprobe protocol) with the given companion probing program + +fcompiler-probe-debug +Common Report Var(flag_compiler_probe_debug) RejectNegative Condition(ENABLE_COMPILER_PROBE) +Gives on stderr lot of debugging output for the compiler probe if enabled + fcprop-registers Common Report Var(flag_cprop_registers) Optimization Perform a register copy-propagation optimization pass diff --git a/gcc/compiler-probe.c b/gcc/compiler-probe.c new file mode 100644 index 00000000000..6a7a5e0c922 --- /dev/null +++ b/gcc/compiler-probe.c @@ -0,0 +1,2078 @@ +/* Compiler probe + Copyright (C) 2007 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "regs.h" +#include "timevar.h" +#include "intl.h" +#include "diagnostic.h" +#include "hashtab.h" +#include "tree.h" +#include "tree-pass.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "tree-inline.h" +#include "tree-iterator.h" +#include "diagnostic.h" +#include "toplev.h" +#include "ggc.h" +#include "vec.h" +#include "cgraph.h" +#include "flags.h" +#include "options.h" +#include "safe-ctype.h" +#include "basic-block.h" +#include "rtl.h" +#include "version.h" + +#include "compiler-probe.h" + +#if !defined(ENABLE_COMPILER_PROBE) || ENABLE_COMPILER_PROBE==0 +/* this file is linked in only if the compiler probe is enabled at + configure time */ +#error messy configuration: compiler-probe.c compiled but not enabled +#endif + +const char *tree_code_names[] = { +#define DEFTREECODE(SYM, STRING, TYPE, NARGS) STRING, +#include "tree.def" +#undef DEFTREECODE + (char *) 0 +}; + + +#define debugeprintf_raw(Fmt,...) do{if (flag_compiler_probe_debug) \ + {fprintf(stderr, Fmt, ##__VA_ARGS__); fflush(stderr);}}while(0) +#define debugeprintf(Fmt,...) debugeprintf_raw("@!%s:%d: " Fmt "\n", \ + basename(__FILE__), __LINE__, ##__VA_ARGS__) +/* some debugeprintf give warnings so I disable them */ +#define nodebugeprintf(Fmt,...) do {}while(0) + +/* #define nodebugprintf debugprintf */ + +#if ! defined( SIGCHLD ) && defined( SIGCLD ) +# define SIGCHLD SIGCLD +#endif + +/* set this flag on SIGIO */ +volatile sig_atomic_t comprobe_interrupted; + +int comprobe_bb_ok_rtl; /* declared in basic-block.h */ + +/* the probe command process */ +pid_t comprobe_pid; +/* the command stream piped into the compiler probe process */ +FILE *comprobe_replf; +/* the file descriptor for requests from the probe process; it is never 0 */ +int comprobe_reqfd; + + + +/* grace delay in milliseconds for the compiler probe */ +#define PROBE_GRACE_DELAY_MS 250 + + +struct proberequest_buffer_st +{ + unsigned len; + unsigned used; + char str[1]; /* actual size is len, zero-terminated */ +}; +/* the buffer above is allocate in multiple of (should be a power of 2) : */ +#define PROBUF_GRAN 0x1000 +static struct proberequest_buffer_st *proberequest_buf; + + +/* hash table for requests (from probe to compiler) handlers contain entries like */ +struct proberequesthentry_st +{ + const char *verb; /* strdup-ed */ + void *data; /* explicitly allocated & freed by caller */ + comprobe_requestfun_t *rout; +}; + +static htab_t proberequest_htable; + + +/* filename are e.g. unix paths */ +typedef char *filename_t; +/* hash table for filenames contain entries like */ +struct filenamehentry_st +{ + filename_t file; /* strdup-ed filename */ + int rank; /* strictly positive rank in filename vector */ +}; + +static htab_t filename_htable; + +/* *INDENT-OFF* */ +static GTY(()) VEC(tree,gc) *unique_tree_vector; +static GTY(()) VEC(basic_block,gc) *unique_bb_vector; +/* each tree of unique_tree_vector or basic_block of unique_bb_vector is + unique; we manage an hash table of indexes (>2) there. the index 0 + is HTAB_EMPTY_ENTRY, the index 1 is HTAB_DELETED_ENTRY, the index 2 + is for the seeked entry */ +static GTY (()) tree unique_seeked_tree; +static GTY (()) basic_block unique_seeked_bb; +/* *INDENT-ON* */ +/* hashtables of integer indexes into the unique_tree_vector & unique_bb_vector */ +static htab_t unique_tree_htable; +static htab_t unique_bb_htable; +#define HTAB_SEEKED_ENTRY ((PTR) 2) + +/*** +we would like to use vectors of filenames, but I cannot make them work + with GTY: + // see thread http://gcc.gnu.org/ml/gcc/2007-01/msg00172.html + DEF_VEC_P (filename_t); + DEF_VEC_ALLOC_P (filename_t,heap); // don't work + VEC(filename_t,heap) *file_vector; + the gengtype parser choke on this with an error: unidentified type +`filename_t' +****/ + +/* variable array of filenames */ +static struct +{ + int size; /* allocated size */ + int last; /* last used index */ + char **tab; +} files_varr; + +struct displaychoice_st +{ + long di_magic; +#define DI_MAGIC 2491573L + HOST_WIDE_INT di_data; + comprobe_infodisplay_fun_t *di_fun; + char di_msg[1]; /* duplicated display message + - longer than 1 */ +}; +typedef struct displaychoice_st *displaychoice_ptr_t; +/* *INDENT-OFF* */ +DEF_VEC_P (displaychoice_ptr_t); +DEF_VEC_ALLOC_P (displaychoice_ptr_t, heap); + +struct comprobe_infodisplay_st { + int idis_num; /* unique infodisplay number */ + int idis_choice; /* current display choice*/ + struct infopointhentry_st* idis_infp; /* the information point */ + VEC(displaychoice_ptr_t,heap) *idis_navig; /* the navigation vector */ + void*idis_data; /* client data */ + void (*idis_destroy)(struct comprobe_infodisplay_st*idi); /* destructor */ +}; + +typedef struct comprobe_infodisplay_st* infodisplay_ptr_t; +DEF_VEC_P(infodisplay_ptr_t); +DEF_VEC_ALLOC_P(infodisplay_ptr_t,heap); +static VEC(infodisplay_ptr_t,heap) *infodisplay_vector; + +/* the info point hashtable contains entries like : */ +struct infopointhentry_st +{ + int infp_filerank; /* file rank */ + int infp_lineno; /* line number */ + int infp_num; /* unique infopoint number */ + VEC(displaychoice_ptr_t,heap) *infp_dischvec; +}; +typedef struct infopointhentry_st *infopoint_ptr_t; +static htab_t infopoint_htable; +DEF_VEC_P (infopoint_ptr_t); +DEF_VEC_ALLOC_P (infopoint_ptr_t, heap); +VEC (infopoint_ptr_t, heap) * infopoint_vector; +/* *INDENT-ON* */ + +/* random data for multiline replies */ +static struct drand48_data randata; + + +/**** + * supporting functions for probe reply hashtable + *****/ +static hashval_t +hash_proberequest (const void *d) +{ + const struct proberequesthentry_st *p = d; + return htab_hash_string (p->verb); +} + +static int +eq_proberequest (const void *dx, const void *dy) +{ + const struct proberequesthentry_st *px = dx; + const struct proberequesthentry_st *py = dy; + return !strcmp (px->verb, py->verb); +} + +static void +del_proberequest (void *d) +{ + struct proberequesthentry_st *p = d; + gcc_assert (p && p->verb); + free ((void *) p->verb); + p->verb = NULL; +} + + + +/**** + * supporting functions for filename hashtable + *****/ +static hashval_t +hash_filename (const void *d) +{ + const struct filenamehentry_st *p = d; + return htab_hash_string (p->file); +} + +static int +eq_filename (const void *dx, const void *dy) +{ + const struct filenamehentry_st *px = dx; + const struct filenamehentry_st *py = dy; + return !strcmp (px->file, py->file); +} + +static void +del_filename (void *d) +{ + struct filenamehentry_st *p = d; + gcc_assert (p && p->file && p->rank > 0); + free ((void *) p->file); + p->file = NULL; +} + +/**** + * supporting functions for infopoint hashtable + *****/ +static hashval_t +hash_infopoint (const void *d) +{ + const struct infopointhentry_st *ifp = d; + return (hashval_t) + (((long) (ifp->infp_filerank << 12)) ^ ((long) ifp->infp_lineno)); +} + +static int +eq_infopoint (const void *dx, const void *dy) +{ + const struct infopointhentry_st *ifx = dx; + const struct infopointhentry_st *ify = dy; + return ifx->infp_lineno == ify->infp_lineno + && ifx->infp_filerank == ify->infp_filerank; +} + +/*** + * supporting functions for unique_tree_htable + ***/ +static hashval_t +hash_info_tree (const void *d) +{ + comprobe_ix_t lg = (comprobe_ix_t) d; + switch (lg) + { + case (comprobe_ix_t) HTAB_EMPTY_ENTRY: + case (comprobe_ix_t) HTAB_DELETED_ENTRY: + return (hashval_t) 0; + case (comprobe_ix_t) HTAB_SEEKED_ENTRY: + lg = (comprobe_ix_t) unique_seeked_tree; + return (hashval_t) (lg ^ (lg >> 10)); + default: + if (lg > 2 && unique_tree_vector + && lg < VEC_length (tree, unique_tree_vector)) + { + lg = (comprobe_ix_t) VEC_index (tree, unique_tree_vector, lg); + return (hashval_t) (lg ^ (lg >> 10)); + }; + return 0; + } +} + + +static int +eq_info_tree (const void *dx, const void *dy) +{ + comprobe_ix_t lx = (comprobe_ix_t) dx; + comprobe_ix_t ly = (comprobe_ix_t) dy; + comprobe_ix_t nbtree = 0; + tree tx = NULL_TREE, ty = NULL_TREE; + if (lx == ly) + return 1; + if (unique_tree_vector) + nbtree = VEC_length (tree, unique_tree_vector); + else + return 0; + if (lx == (comprobe_ix_t) HTAB_SEEKED_ENTRY) + tx = unique_seeked_tree; + else if (lx > 2 && lx < nbtree) + tx = VEC_index (tree, unique_tree_vector, lx); + if (ly == (comprobe_ix_t) HTAB_SEEKED_ENTRY) + ty = unique_seeked_tree; + else if (ly > 2 && ly < nbtree) + ty = VEC_index (tree, unique_tree_vector, ly); + return tx == ty && tx != NULL_TREE; +} + + +comprobe_ix_t +comprobe_unique_index_of_tree (tree tr) +{ + comprobe_ix_t trix = 0; + comprobe_ix_t l = 0, nbtree = 0; + void **sp = NULL; + if (tr == NULL_TREE) + return 0; + gcc_assert (unique_tree_vector + && VEC_length (tree, unique_tree_vector) > 2); + l = (comprobe_ix_t) HTAB_SEEKED_ENTRY; + nbtree = VEC_length (tree, unique_tree_vector); + unique_seeked_tree = tr; + sp = htab_find_slot (unique_tree_htable, &l, INSERT); + if (sp) + { + if (*sp != HTAB_EMPTY_ENTRY && *sp != HTAB_DELETED_ENTRY + && *sp != HTAB_SEEKED_ENTRY) + l = *(comprobe_ix_t *) (*sp); + else + l = 0; + if (l > 2) + { + gcc_assert (l < nbtree + && VEC_index (tree, unique_tree_vector, l) == tr); + trix = l; + } + else + { + VEC_safe_push (tree, gc, unique_tree_vector, tr); + trix = nbtree; + *(comprobe_ix_t *) (sp) = trix; + } + } + else /* failed to insert into unique_tree_htable */ + gcc_unreachable (); + return trix; +} + +tree +comprobe_tree_of_unique_index (comprobe_ix_t ix) +{ + unsigned nbtree = 0; + if (ix < 2 || !unique_tree_vector) + return 0; + nbtree = VEC_length (tree, unique_tree_vector); + if ((int) ix < (int) nbtree) + return VEC_index (tree, unique_tree_vector, ix); + return 0; +} + + + +/*** + * supporting functions for unique_bb_htable + ***/ +static hashval_t +hash_info_bb (const void *d) +{ + comprobe_ix_t lg = (comprobe_ix_t) d; + switch (lg) + { + case (comprobe_ix_t) HTAB_EMPTY_ENTRY: + case (comprobe_ix_t) HTAB_DELETED_ENTRY: + return (hashval_t) 0; + case (comprobe_ix_t) HTAB_SEEKED_ENTRY: + lg = (comprobe_ix_t) unique_seeked_bb; + return (hashval_t) (lg ^ (lg >> 10)); + default: + if (lg > 2 && unique_bb_vector + && lg < VEC_length (basic_block, unique_bb_vector)) + { + lg = (comprobe_ix_t) VEC_index (basic_block, unique_bb_vector, lg); + return (hashval_t) (lg ^ (lg >> 10)); + }; + return 0; + } +} + + +static int +eq_info_bb (const void *dx, const void *dy) +{ + comprobe_ix_t lx = (comprobe_ix_t) dx; + comprobe_ix_t ly = (comprobe_ix_t) dy; + long nbbb = 0; + basic_block bx = NULL, by = NULL; + if (lx == ly) + return 1; + if (unique_bb_vector) + nbbb = VEC_length (basic_block, unique_bb_vector); + else + return 0; + if (lx == (comprobe_ix_t) HTAB_SEEKED_ENTRY) + bx = unique_seeked_bb; + else if (lx > 2 && lx < nbbb) + bx = VEC_index (basic_block, unique_bb_vector, lx); + if (ly == (comprobe_ix_t) HTAB_SEEKED_ENTRY) + by = unique_seeked_bb; + else if (ly > 2 && ly < nbbb) + by = VEC_index (basic_block, unique_bb_vector, ly); + return bx == by && bx != NULL; +} + +/**** + * register a reply verb + ****/ +static void +comprobe_register_unchecked (const char *verb, + comprobe_requestfun_t * handler, void *data) +{ + struct proberequesthentry_st slot; + struct proberequesthentry_st **slotptr; + hashval_t h; + memset (&slot, 0, sizeof (slot)); + slot.verb = verb; + h = hash_proberequest (&slot); + slotptr = (struct proberequesthentry_st **) + htab_find_slot_with_hash (proberequest_htable, &slot, h, INSERT); + if (!slotptr) + fatal_error + ("compiler probe failed to register request verb %s (memory full): %m", + verb); + if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY) + { + struct proberequesthentry_st *newslot; + newslot = xcalloc (sizeof (struct proberequesthentry_st), 1); + newslot->verb = xstrdup (verb); + newslot->rout = handler; + newslot->data = data; + *slotptr = newslot; + } + else + { + struct proberequesthentry_st *oldslot = *slotptr; + gcc_assert (!strcmp (oldslot->verb, verb)); + oldslot->rout = handler; + oldslot->data = data; + } +} + + +/**** + * register a verb (and check that it is alphanumerical) + ****/ +void +comprobe_register (const char *verb, comprobe_requestfun_t * handler, + void *data) +{ + const char *pc; + if (!verb) + return; + if (!ISALPHA (verb[0])) + fatal_error ("compiler probe: invalid verb %s to register", verb); + for (pc = verb + 1; *pc; pc++) + if (!ISALNUM (*pc) && *pc != '_') + fatal_error ("compiler probe: invalid verb %s to register", verb); + comprobe_register_unchecked (verb, handler, data); +} + + +/**** + * remove a registered verb @@@@@@ HAS TO BE CODED + ****/ +void +comprobe_unregister (const char *verb) +{ + gcc_assert (verb && *verb); + /* #warning to be written comprobe_unregister */ + gcc_unreachable (); +} + + +void +comprobe_infopoint_add_display (int infoptrank, + comprobe_infodisplay_fun_t * dispfun, + const char *msg, HOST_WIDE_INT data) +{ + infopoint_ptr_t infp = NULL; + displaychoice_ptr_t dch = NULL; + size_t msgl = 0; + if (!comprobe_replf) + return; + debugeprintf ("infopoint_add_display infoptrank %d msg %s", infoptrank, + msg); + if (infoptrank < 0 || !infopoint_vector + || infoptrank >= (int) VEC_length (infopoint_ptr_t, infopoint_vector)) + return; + infp = VEC_index (infopoint_ptr_t, infopoint_vector, infoptrank); + nodebugeprintf ("infopoint_add_display infp %p msg %s dispfun %p", + infp, msg, (void *) dispfun); + if (!infp || !msg || !dispfun) + return; + msgl = strlen (msg); + gcc_assert (infp->infp_num == infoptrank); + dch = xcalloc (sizeof (*dch) + msgl, 1); + dch->di_data = data; + dch->di_magic = DI_MAGIC; + dch->di_fun = dispfun; + memcpy (dch->di_msg, msg, msgl); + debugeprintf ("infopoint_add_display dch %p", (void*)dch); + VEC_safe_push (displaychoice_ptr_t, heap, infp->infp_dischvec, dch); +} + +void +comprobe_display_add_navigator (struct comprobe_infodisplay_st *idi, + comprobe_infodisplay_fun_t * navfun, + const char *msg, HOST_WIDE_INT data) +{ + displaychoice_ptr_t dch = NULL; + size_t msgl = 0; + gcc_assert (idi); + gcc_assert (msg); + if (!comprobe_replf) + return; + msgl = strlen (msg); + if (!idi->idis_navig) + idi->idis_navig = VEC_alloc (displaychoice_ptr_t, heap, 3); + dch = xcalloc (sizeof (*dch) + msgl, 1); + dch->di_data = data; + dch->di_fun = navfun; + dch->di_magic = DI_MAGIC; + memcpy (dch->di_msg, msg, msgl); + nodebugeprintf ("add_navigator display %d navfun %p msg '%s'", + idi->idis_num, (void *) navfun, msg); + VEC_safe_push (displaychoice_ptr_t, heap, idi->idis_navig, dch); +} + + + +/**** + * the SIGIO and SIGCHLD signal handler just sets a flag + ****/ +static void +sig_interrupted (int sig) +{ + gcc_assert (sig != 0); + comprobe_interrupted = 1; +} + + +/**** + * Create the probing process and set up the pipes to it. + * Do not exchange anything yet + ****/ +static void +create_probe_process (void) +{ + /* the probe process */ + pid_t probpid; + /* the pipes from probe to gcc, and from gcc to probe */ + int pip2gcc[2], pip2probe[2]; + const char *progarg[5]; + if (comprobe_pid > 0 && comprobe_replf && comprobe_reqfd >= 0) + return; + /* we do not use the pex_* routines from liberty.h because the + compiler probe is quite specific to Linux and similar Unix + operating systems with SIGIO, select, .... (probably Solaris, + and recent *BSD should be ok) */ + pip2gcc[0] = pip2gcc[1] = -1; + pip2probe[0] = pip2probe[1] = -1; + if (pipe (pip2gcc) || pipe (pip2probe)) + fatal_error ("failed to create pipes for compiler probe: %m"); + probpid = fork (); + if (probpid == (pid_t) 0) + { + /* child process */ + int ifd; + signal (SIGIO, SIG_DFL); +#ifdef SIGSEGV + signal (SIGSEGV, SIG_DFL); +#endif +#ifdef SIGINT + signal (SIGINT, SIG_DFL); +#endif +#ifdef SIGTERM + signal (SIGTERM, SIG_DFL); +#endif +#ifdef SIGQUIT + signal (SIGQUIT, SIG_DFL); +#endif +#define perror_exit(Msg) do{perror(Msg); exit(1);}while(0) + /* write-pipe from probe to gcc is our stdout */ + if (pip2gcc[1] != STDOUT_FILENO) + { + if (dup2 (pip2gcc[1], STDOUT_FILENO) < 0) + perror_exit + ("comprobe child process failed to dup2 pipe to stdout to gcc"); + (void) close (pip2gcc[1]); + } + /* read-pipe from gcc to probe is our stdin */ + if (pip2probe[0] != STDIN_FILENO) + { + if (dup2 (pip2probe[0], STDIN_FILENO) < 0) + perror_exit + ("comprobe child process failed to dup2 pipe to stdin from gcc"); + (void) close (pip2probe[0]); + } + /* close useless fds in the child before exec */ + for (ifd = STDERR_FILENO + 1; ifd < 64; ifd++) + (void) close (ifd); + /* use sh -c for the compiler probe command */ + memset (progarg, 0, sizeof (progarg)); + progarg[0] = "sh"; + progarg[1] = "-c"; + progarg[2] = compiler_probe_string; + progarg[3] = (char *) 0; + execv ("/bin/sh", (char *const *) progarg); + perror_exit ("comprobe child process failed to exec /bin/sh"); + } +#undef perror_exit + else if (probpid < (pid_t) 0) + { + /* error fork failed */ + fatal_error ("failed to fork for compiler probe: %m"); + } + else + { /* parent */ + (void) close (pip2gcc[1]); + (void) close (pip2probe[0]); + comprobe_pid = probpid; + comprobe_replf = fdopen (pip2probe[1], "a"); + comprobe_reqfd = pip2gcc[0]; + if (!comprobe_replf) + fatal_error ("failed to open pipe stream to compiler probe: %m"); + if (comprobe_reqfd <= 0) + { + /* this should almost never happen; I could think it might + happen if gcc is run without any open file descriptor - not + even stdin; but I expect the request file descriptor to be + positive */ + fatal_error ("failed to get pipe fd %d from compiler probe: %m", + comprobe_reqfd); + }; + if (fcntl (comprobe_reqfd, F_SETFL, (long) O_NONBLOCK) < 0) + fatal_error + ("failed to make non-blocking the pipe fd %d from compiler probe: %m", + comprobe_reqfd); + if (fcntl (comprobe_reqfd, F_SETOWN, (long) getpid ()) < 0) + fatal_error ("failed to SETOWN pipe fd %d from compiler probe: %m", + comprobe_reqfd); + setlinebuf (comprobe_replf); + fprintf (stderr, "created compiler probe '%s' process %ld\n", + compiler_probe_string, (long) comprobe_pid); + } +} + + + +/**** + * wait for the compiler probe process, returns 0 when waited successfully; + * if BLOCKING is set, wait indefinitely, otherwise just test without + * blocking + ****/ +static int +wait_for_probe (int blocking, int *pstatus) +{ + int probstatus = 0; + gcc_assert (comprobe_pid > 0); +#if HAVE_WAITPID || HAVE_SYS_WAIT_H + if (waitpid (comprobe_pid, &probstatus, blocking ? WNOHANG : 0) == + comprobe_pid) + { + if (pstatus) + *pstatus = probstatus; + return 0; + } +#elif HAVE_WAIT4 + if (wait4 + (comprobe_pid, &probstatus, blocking ? WNOHANG : 0, + (struct rusage *) 0) == comprobepid) + { + if (pstatus) + *pstatus = probstatus; + return 0; + }; +#else +#error should have waitpid or wait4 +#endif + return 1; +} + +/**** + * output a string URL encoded wtih STR89' prefix for a string of 89 + * chars and a ' suffix + ****/ +void +comprobe_outenc_string (const char *s) +{ + int c, l; + if (!comprobe_replf || !s) + return; + l = strlen (s); + comprobe_printf ("STR%d'", l); + for (; (c = (*s)) != 0; s++) + { + if ((c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) + putc (c, comprobe_replf); + else + switch (c) + { + case ' ': + putc ('+', comprobe_replf); + break; + case '*': + case '/': + case '_': + case '@': + case '-': + case '(': + case ')': + case '!': + case '[': + case ']': + case '.': + case ',': + case ';': + putc (c, comprobe_replf); + break; + default: + fprintf (comprobe_replf, "%%%02x", c & 0xff); + break; + } + } + putc ('\'', comprobe_replf); +} + +/**** + * process a single line of request (from probe to compiler) + ****/ +static void +process_request_line (struct comprobe_whatpos_st *wp, char *line) +{ + struct proberequesthentry_st *ptrslot; + struct proberequesthentry_st slot; + char *pc; + char *argreq; + if (line[0] == '#' || line[0] == 0) + return; + debugeprintf ("req.lin: %s", line); + memset (&slot, 0, sizeof (slot)); + for (pc = line; ISALNUM (*pc) || *pc == '_'; pc++); + argreq = 0; + if (*pc) + argreq = pc + 1; + *pc = 0; + slot.verb = line; + ptrslot = + (struct proberequesthentry_st *) htab_find (proberequest_htable, &slot); + if (ptrslot && ptrslot->rout) + (*ptrslot->rout) (wp, argreq, ptrslot->data); + else + fprintf (stderr, "gcc compiler-probe don't understand request: %s\n", + line); + debugeprintf ("req.lin done: %s", line); +} + +/**** + * stop the compiler probe + ****/ +void +comprobe_stop (void) +{ + int status = 0; + if (!compiler_probe_string || !compiler_probe_string[0] || !comprobe_pid) + return; + /* kill the probing process and wait for it nicely, first by closing the pipe to it */ + fclose (comprobe_replf); + close (comprobe_reqfd); + /* give a little time to the probe */ + usleep ((unsigned long) PROBE_GRACE_DELAY_MS * 1000); + if (wait_for_probe (0, &status)) + { + (void) kill (comprobe_pid, SIGTERM); + while (!wait_for_probe (1, &status)) + { + usleep ((unsigned long) PROBE_GRACE_DELAY_MS * 1000); + (void) kill (comprobe_pid, SIGQUIT); + }; + }; + fprintf (stderr, "ended compiler probe process %ld [status %d]:", + (long) comprobe_pid, status); + if (WIFEXITED (status)) + fprintf (stderr, "probe exited %d\n", WEXITSTATUS (status)); + else if (WIFSIGNALED (status)) + psignal (WTERMSIG (status), + WCOREDUMP (status) + ? "probe coredumped on signal" : "probe terminated with signal"); + putc ('\n', stderr); + fflush (stderr); + comprobe_reqfd = -1; + comprobe_replf = (FILE *) 0; + comprobe_pid = 0; + compiler_probe_string = 0; + signal (SIGIO, SIG_DFL); + signal (SIGCHLD, SIG_DFL); +} + +/* forced kill of probe - called only on unrecoverable errors */ +void +comprobe_forced_kill (void) +{ + if (!compiler_probe_string || !compiler_probe_string[0] + || !comprobe_pid || !comprobe_replf) + return; + fflush (comprobe_replf); + (void) kill (comprobe_pid, SIGTERM); + comprobe_stop (); +} + +/**** + * read all probe requests, waiting for them for a delay in milliseconds + * and process every newline terminated reply line + ****/ +static void +read_probe_requests (struct comprobe_whatpos_st *wp, unsigned millisec) +{ + fd_set rdset; + struct timeval tv; + int maxfd = 0; + int selnb = 0; + if (comprobe_reqfd <= 0) + return; + /* flush the reply stream to send any pending stuff */ + if (comprobe_replf) + fflush (comprobe_replf); + FD_ZERO (&rdset); + if (comprobe_reqfd >= 0) + FD_SET (comprobe_reqfd, &rdset); + maxfd = MAX (maxfd, comprobe_reqfd); + if (millisec >= 1000) + millisec = 999; + tv.tv_sec = 0; + tv.tv_usec = millisec * 1000; + selnb = select (maxfd + 1, &rdset, (fd_set *) 0, (fd_set *) 0, &tv); + if (selnb > 0 && FD_ISSET (comprobe_reqfd, &rdset)) + { + int again = 0; + do + { + int newsiz; + int readcnt, readlen; + if (comprobe_reqfd < 0) + break; + newsiz = 0; + if (!proberequest_buf) + newsiz = 2 * PIPE_BUF; + else if (proberequest_buf->used + PIPE_BUF <= proberequest_buf->len) + newsiz = + (((5 * proberequest_buf->len / 4 + 2 * PIPE_BUF)) + | (PROBUF_GRAN - 1)) + 1; + if (newsiz > 0) + { + struct proberequest_buffer_st *newbuf; + newbuf = xcalloc (1, + sizeof (struct + proberequest_buffer_st) + newsiz - 1); + newbuf->len = newsiz; + if (proberequest_buf) + { + gcc_assert (proberequest_buf->used <= + proberequest_buf->len); + memcpy (newbuf->str, proberequest_buf->str, + proberequest_buf->used); + newbuf->used = proberequest_buf->used; + free (proberequest_buf); + }; + proberequest_buf = newbuf; + }; + gcc_assert (proberequest_buf->used + PIPE_BUF < + proberequest_buf->len); + readlen = proberequest_buf->len - proberequest_buf->used - 1; + readcnt = read (comprobe_reqfd, + proberequest_buf->str + proberequest_buf->used, + readlen); + again = 0; + if (readcnt == 0) + { /* got end of file on the probe reply pipe */ + again = 0; + comprobe_stop (); + } + else if (readcnt < 0) + { + if (errno == EINTR) + again = 1; + else if (errno == EAGAIN) + again = 0; + else + fatal_error ("unexpected read error from compiler probe: %m"); + } + else /*readcnt>0 */ + { + char *eol = 0; + char *pc = 0; + off_t off, rlen; + proberequest_buf->used += readcnt; + proberequest_buf->str[proberequest_buf->used] = 0; + for (pc = proberequest_buf->str; (eol = strchr (pc, '\n')) != 0; + pc = eol + 1) + { + *eol = 0; + process_request_line (wp, pc); + if (comprobe_replf) + fflush (comprobe_replf); + }; + off = pc - proberequest_buf->str; + if (off > 0) + { + rlen = proberequest_buf->str + proberequest_buf->used - pc; + memmove (proberequest_buf->str, pc, rlen); + proberequest_buf->str[rlen] = 0; + proberequest_buf->used = rlen; + if (proberequest_buf->len - rlen > 3 * PIPE_BUF) + { + unsigned newsiz = + ((rlen + 2 * PIPE_BUF) | (PROBUF_GRAN - 1)) + 1; + if (newsiz < proberequest_buf->len && newsiz > rlen) + { + proberequest_buf = + xrealloc (proberequest_buf, newsiz); + proberequest_buf->len = newsiz; + } + } + }; + again = 1; + } + } + while (again); + } +} + +/**** + * handle a request (called by comprobe_check macro) + ****/ +void +comprobe_handle_probe (const char *what, const char *file, int lineno) +{ + struct comprobe_whatpos_st wp; + if (!compiler_probe_string || !compiler_probe_string[0] + || comprobe_pid <= 0) + return; + memset (&wp, 0, sizeof (wp)); + wp.wp_what = what; + wp.wp_file = file; + wp.wp_line = lineno; + read_probe_requests (&wp, 0); +} + +/**** + * handle all requests until a given variable is cleared, or the probe ended + ****/ +void +comprobe_while_probe (const char *what, const char *file, int lineno, + int *pvar) +{ + struct comprobe_whatpos_st wp; + if (comprobe_pid <= 0 || !pvar) + return; + memset (&wp, 0, sizeof (wp)); + wp.wp_what = what; + wp.wp_file = file; + wp.wp_line = lineno; + while (comprobe_pid > 0 && *pvar) + { + read_probe_requests (&wp, PROBE_GRACE_DELAY_MS); + }; +} + +/*** + * big commands are uniquely bracketed + ***/ +static long leftcode, rightcode; +void +comprobe_begin_big (void) +{ + gcc_assert (leftcode == 0 && rightcode == 0); + if (!comprobe_replf) + return; + do + { + lrand48_r (&randata, &leftcode); + } + while (leftcode == 0); + do + { + lrand48_r (&randata, &rightcode); + } + while (rightcode == 0); + fprintf (comprobe_replf, "\n!#%x/%X[\n", + (int) (leftcode & 0xfffffff), (int) (rightcode & 0xfffffff)); +} + +void +comprobe_end_big (void) +{ + gcc_assert (leftcode != 0 && rightcode != 0); + if (comprobe_replf) + { + fprintf (comprobe_replf, "\n!#%x/%X]\n", + (int) (leftcode & 0xfffffff), (int) (rightcode & 0xfffffff)); + fflush (comprobe_replf); + } + leftcode = rightcode = 0; +} + + +static int nonstopped; + +/* the STOP request from probe stops properly the probe */ +static void +stop_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED, + char *reqlin ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) +{ + if (comprobe_replf) + fflush (comprobe_replf); + nonstopped = 0; + comprobe_stop (); +} + +static int +cmp_displaychoice_ptr (const void *x, const void *y) +{ + displaychoice_ptr_t dx = *(displaychoice_ptr_t *) x; + displaychoice_ptr_t dy = *(displaychoice_ptr_t *) y; + return strcmp (dx->di_msg, dy->di_msg); +} + +/* the NEWINFODIALOG request from probe make a new dialog for an infopoint */ +static void +newinfodialog_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED, + char *reqlin, void *data ATTRIBUTE_UNUSED) +{ + int infork = -1, dialrk = -1, nbdisp = 0, chix = 0; + infopoint_ptr_t ip = NULL; + infodisplay_ptr_t idisp = NULL; + if (!comprobe_replf) + return; + debugeprintf ("newinfodialog_reqfun reqlin: %s", reqlin); + if (sscanf (reqlin, " pt: %d dia: %d", &infork, &dialrk) < 2 + || infork < 0 || dialrk < 0) + return; + debugeprintf ("newinfodialog_reqfun infork=%d dialrk=%d", infork, dialrk); + if (infork >= (int) VEC_length (infopoint_ptr_t, infopoint_vector)) + return; + ip = VEC_index (infopoint_ptr_t, infopoint_vector, infork); + if (!ip) + return; + if ((int) VEC_length (infodisplay_ptr_t, infodisplay_vector) <= dialrk) + VEC_safe_grow_cleared (infodisplay_ptr_t, heap, infodisplay_vector, + 5 * dialrk / 4 + 16); + idisp = xcalloc (sizeof (*idisp), 1); + idisp->idis_num = dialrk; + idisp->idis_infp = ip; + VEC_replace (infodisplay_ptr_t, infodisplay_vector, dialrk, idisp); + /* sort the display choices in alphanumerical order */ + if (ip->infp_dischvec) + nbdisp = VEC_length (displaychoice_ptr_t, ip->infp_dischvec); + debugeprintf ("newinfodialog_reqfun nbdisp=%d", nbdisp); + if (nbdisp > 0) + qsort ((VEC_address (displaychoice_ptr_t, ip->infp_dischvec)), + (size_t) nbdisp, sizeof (displaychoice_ptr_t), + cmp_displaychoice_ptr); + for (chix = 0; chix < nbdisp; chix++) + { + displaychoice_ptr_t dch = + VEC_index (displaychoice_ptr_t, ip->infp_dischvec, chix); + gcc_assert (dch && dch->di_fun); + gcc_assert (dch->di_magic == DI_MAGIC); + comprobe_printf ("PROB_dialogchoice dia:%d msg:", dialrk); + comprobe_outenc_string (dch->di_msg); + comprobe_printf (" ch:%d\n", chix); + }; + comprobe_printf ("PROB_showdialog dia:%d\n", dialrk); + comprobe_flush (); +} + +static void bb_starting_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig); + +static void tree_starting_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig); + +static void tree_ending_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig); + +static void +display_tree (tree tr, struct comprobe_infodisplay_st *di) +{ + gcc_assert (di != 0); + if (!tr) + comprobe_printf ("*** NULL TREE %p ***\n", (void*)tr); + else if (GIMPLE_STMT_P (tr)) + { + comprobe_printf ("*** GIMPLE STMT %p ***\n", (void*)tr); + print_generic_stmt_indented (comprobe_replf, tr, + TDF_LINENO | TDF_VOPS | TDF_MEMSYMS | + TDF_UID, 1); + } + else if (EXPR_P (tr)) + { + comprobe_printf ("*** EXPR %p ***\n", (void*)tr); + print_generic_expr (comprobe_replf, tr, + TDF_LINENO | TDF_VOPS | TDF_MEMSYMS); + } + else if (TREE_CODE (tr) == STATEMENT_LIST) + { + tree_stmt_iterator tsi; + int rk = 0; + comprobe_printf ("*** STATEMENT LIST %p ***\n", (void*)tr); + print_generic_expr (comprobe_replf, tr, + TDF_LINENO | TDF_VOPS | TDF_MEMSYMS); + for (tsi = tsi_start (tr); !tsi_end_p (tsi); tsi_next (&tsi)) + { + tree stmt = tsi_stmt (tsi); + rk++; + if (stmt) + { + static char titbuf[64]; + memset (titbuf, 0, sizeof (titbuf)); + snprintf (titbuf, sizeof (titbuf) - 1, "%d-th substmt", rk); + comprobe_display_add_navigator (di, tree_starting_displayer, + titbuf, + comprobe_unique_index_of_tree + (stmt)); + } + + } + } + else + comprobe_printf ("*** tree of code %d <%s>***\n", + TREE_CODE (tr), tree_code_names[TREE_CODE (tr)]); + if (TREE_CODE (tr) == PHI_NODE) + { + basic_block bb = PHI_BB (tr); + if (bb) + { + comprobe_ix_t bbix = comprobe_unique_index_of_basic_block (bb); + comprobe_display_add_navigator (di, bb_starting_displayer, + "phi node basic block", bbix); + } + } +} + +static void +tree_starting_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, + HOST_WIDE_INT navig ATTRIBUTE_UNUSED) +{ + tree tr = NULL_TREE; + comprobe_ix_t ix = (comprobe_ix_t) data; + unsigned nbtree = VEC_length (tree, unique_tree_vector); + debugeprintf ("tree_starting_displayer ix %d nbtree %d", (int) ix, + (int) nbtree); + if (ix > 0 && ix < (long) nbtree) + { + tr = VEC_index (tree, unique_tree_vector, ix); + comprobe_printf + ("// starting tree_%ld #%d shown when '%s' \n// from gcc file %s line %d\n", + ix, di->idis_infp->infp_num, wp->wp_what, basename (wp->wp_file), + wp->wp_line); + display_tree (tr, di); + } + else + comprobe_printf + (" ?? invalid starting tree index %ld nbtree %d info #%d??", (long) ix, + (int) nbtree, di->idis_infp->infp_num); +} + +static void +tree_ending_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, + HOST_WIDE_INT navig ATTRIBUTE_UNUSED) +{ + tree tr = NULL_TREE; + comprobe_ix_t ix = (comprobe_ix_t) data; + unsigned nbtree = VEC_length (tree, unique_tree_vector); + debugeprintf ("tree_ending_displayer ix %d nbtree %d", (int) ix, + (int) nbtree); + if (ix > 0 && ix < (long) nbtree) + { + tr = VEC_index (tree, unique_tree_vector, ix); + comprobe_printf + ("// ending tree_%ld #%d shown when '%s'\n// from gcc file %s line %d\n", + (long) ix, di->idis_infp->infp_num, wp->wp_what, + basename (wp->wp_file), wp->wp_line); + display_tree (tr, di); + } + else + comprobe_printf (" ?? invalid ending tree index %ld nbtree %d info #%d??", + (long) ix, (int) nbtree, di->idis_infp->infp_num); +} + + +static void +bb_starting_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, + HOST_WIDE_INT navig ATTRIBUTE_UNUSED) +{ + comprobe_ix_t ix = (comprobe_ix_t) data; + char pfx[24]; + basic_block bb = NULL; + debugeprintf ("bb_starting_displayer ix %d", (int) ix); + comprobe_bb_ok_rtl = 1; + if (ix > 0 && ix < VEC_length (basic_block, unique_bb_vector)) + { + bb = VEC_index (basic_block, unique_bb_vector, ix); + comprobe_printf + ("// starting basic block _%ld #%d shown when '%s' \n// from gcc file %s line %d\n", + (long) ix, di->idis_infp->infp_num, wp->wp_what, + basename (wp->wp_file), wp->wp_line); + snprintf (pfx, sizeof (pfx), "[+bb#%d] ", di->idis_infp->infp_num); + comprobe_printf ("\n// basic block info _%ld #%d is\n", + (long) ix, di->idis_infp->infp_num); + dump_bb_info (bb, true, true, + TDF_DETAILS | TDF_LINENO | TDF_VOPS | TDF_MEMSYMS, + pfx, comprobe_replf); + if (phi_nodes(bb)) + { + comprobe_printf ("\n// basic block phi_nodes _%ld #%d is\n", + ix, di->idis_infp->infp_num); + display_tree (phi_nodes(bb), di); + comprobe_display_add_navigator + (di, tree_starting_displayer, + "phi nodes", comprobe_unique_index_of_tree (phi_nodes(bb))); + }; + if (bb_stmt_list(bb)) + { + comprobe_printf ("\n// basic block stmt_list _%ld #%d is\n", ix, + di->idis_infp->infp_num); + display_tree (bb_stmt_list(bb), di); + comprobe_display_add_navigator + (di, tree_starting_displayer, + "stmt list", comprobe_unique_index_of_tree (bb_stmt_list(bb))); + }; + } + else + comprobe_printf ("?? invalid starting basic block index %ld info #%d??", + ix, di->idis_infp->infp_num); + comprobe_bb_ok_rtl = 0; +} + +static void +bb_ending_displayer (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig ATTRIBUTE_UNUSED) +{ + comprobe_ix_t ix = (comprobe_ix_t) data; + char pfx[24]; + basic_block bb = NULL; + int infoptrk = di->idis_infp->infp_num; + debugeprintf ("bb_ending_displayer ix %d", (int) ix); + comprobe_bb_ok_rtl = 1; + if (ix > 0 && ix < VEC_length (basic_block, unique_bb_vector)) + { + bb = VEC_index (basic_block, unique_bb_vector, ix); + comprobe_printf + ("// ending basic block _%ld #%d shown when '%s'\n// from gcc file %s line %d\n", + ix, infoptrk, wp->wp_what, basename (wp->wp_file), wp->wp_line); + snprintf (pfx, sizeof (pfx), "[-bb#%d] ", infoptrk); + dump_bb_info (bb, true, true, + TDF_DETAILS | TDF_LINENO | TDF_VOPS | TDF_MEMSYMS, + pfx, comprobe_replf); + } + else + comprobe_printf ("?? invalid ending basic block index %ld info #%d??", ix, + infoptrk); + comprobe_bb_ok_rtl = 0; +} + +/* clear the navigation vector inside a display */ +static void +infodialog_clear_navig (infodisplay_ptr_t disp) +{ + int navix = 0; + displaychoice_ptr_t navch = NULL; + debugeprintf ("infodialog_clear_navig disp %p num %d", (void*)disp, + disp->idis_num); + if (disp->idis_navig) + { + for (navix = 0; + VEC_iterate (displaychoice_ptr_t, disp->idis_navig, navix, + navch); navix++) + { + if (!navch) + continue; + gcc_assert (navch->di_magic == DI_MAGIC); + VEC_replace (displaychoice_ptr_t, disp->idis_navig, navix, NULL); + memset (navch, 0, sizeof (navch)); + free (navch); + } + VEC_free (displaychoice_ptr_t, heap, disp->idis_navig); + disp->idis_navig = NULL; + } +} + + +static void +fill_infodialog (struct comprobe_whatpos_st *wp, infodisplay_ptr_t disp, + displaychoice_ptr_t ch, comprobe_ix_t chix) +{ + debugeprintf("fill_infodialog ch %p chix %d", (void*)ch, (int)chix); + gcc_assert (ch && ch->di_magic == DI_MAGIC); + infodialog_clear_navig (disp); + if (ch->di_fun) + { + comprobe_begin_big_printf ("PROB_dialogcontent dia:%d\n", + disp->idis_num); + (*ch->di_fun) (wp, disp, ch->di_data, chix); + comprobe_end_big (); + if (disp->idis_navig + && VEC_length (displaychoice_ptr_t, disp->idis_navig) > 0) + { + int navix = 0; + displaychoice_ptr_t navch = NULL; + for (navix = 0; + VEC_iterate (displaychoice_ptr_t, disp->idis_navig, navix, + navch); navix++) + { + gcc_assert (navch->di_magic == DI_MAGIC); + debugeprintf ("fill_infodialog %d navix %d navch msg '%s'", + disp->idis_num, navix, navch->di_msg); + comprobe_printf ("PROB_dialognavig dia:%d msg:", + disp->idis_num); + comprobe_outenc_string (navch->di_msg); + comprobe_printf (" nav:%d\n", navix); + } + } + comprobe_printf ("PROB_showdialog dia:%d\n", disp->idis_num); + comprobe_flush (); + } + else debugeprintf("fill_infodialog no function in ch %p", (void*)ch); +} + + +/* the SHOWINFODIALOG request from probe ask for the dialog to be shown */ +static void +showinfodialog_reqfun (struct comprobe_whatpos_st *wp, + char *reqlin, void *data ATTRIBUTE_UNUSED) +{ + int dialrk = -1, chrk = -1; + infodisplay_ptr_t disp = NULL; + infopoint_ptr_t ip = NULL; + displaychoice_ptr_t ch = NULL; + if (!comprobe_replf) + return; + debugeprintf ("showinfodialog_reqfun reqlin: %s", reqlin); + if (sscanf (reqlin, " dia: %d ch: %d", &dialrk, &chrk) < 2 + || chrk < 0 || dialrk < 0) + return; + if (!infodisplay_vector + || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector)) + return; + disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk); + if (!disp) + return; + gcc_assert (disp->idis_num == dialrk); + ip = disp->idis_infp; + gcc_assert (ip); + if (chrk >= (int) VEC_length (displaychoice_ptr_t, ip->infp_dischvec)) + return; + ch = VEC_index (displaychoice_ptr_t, ip->infp_dischvec, chrk); + if (!ch) + return; + gcc_assert (ch->di_magic == DI_MAGIC); + disp->idis_choice = chrk; + debugeprintf ("showinfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg); + fill_infodialog (wp, disp, ch, -1); + debugeprintf ("showinfodialog_reqfun end reqlin: %s", reqlin); +} + + +static void +updateinfodialog_reqfun (struct comprobe_whatpos_st *wp, + char *reqlin, void *data ATTRIBUTE_UNUSED) +{ + int dialrk = -1; + infodisplay_ptr_t disp = NULL; + infopoint_ptr_t ip = NULL; + displaychoice_ptr_t ch = NULL; + if (!comprobe_replf) + return; + debugeprintf ("updateinfodialog_reqfun reqlin: %s", reqlin); + if (sscanf (reqlin, " dia: %d", &dialrk) <= 0 || dialrk < 0) + return; + if (!infodisplay_vector + || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector)) + return; + disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk); + if (!disp) + return; + gcc_assert (disp->idis_num == dialrk); + ip = disp->idis_infp; + if (disp->idis_choice >= 0 + && disp->idis_choice < + (int) VEC_length (displaychoice_ptr_t, ip->infp_dischvec)) + ch = + VEC_index (displaychoice_ptr_t, ip->infp_dischvec, disp->idis_choice); + if (!ch) { + debugeprintf("updateinfodialog_reqfun no ch %p", (void*)ch); + return; + }; + gcc_assert (ch->di_magic == DI_MAGIC); + debugeprintf ("updateinfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg); + fill_infodialog (wp, disp, ch, -1); + debugeprintf ("updateinfodialog_reqfun end reqlin: %s", reqlin); +} + +static void +naviginfodialog_reqfun (struct comprobe_whatpos_st *wp, + char *reqlin, void *data ATTRIBUTE_UNUSED) +{ + int dialrk = -1, navrk = -1; + infodisplay_ptr_t disp = NULL; + infopoint_ptr_t ip = NULL; + displaychoice_ptr_t ch = NULL; + if (!comprobe_replf) + return; + debugeprintf ("naviginfodialog_reqfun reqlin: %s", reqlin); + if (sscanf (reqlin, " dia: %d nav: %d", &dialrk, &navrk) <= 0 + || dialrk < 0 || navrk < 0) + return; + if (!infodisplay_vector + || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector)) + return; + disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk); + debugeprintf ("naviginfodialog_reqfun disp %p", (void*)disp); + if (!disp) + return; + gcc_assert (disp->idis_num == dialrk); + ip = disp->idis_infp; + if (navrk < (int) VEC_length (displaychoice_ptr_t, disp->idis_navig)) + ch = VEC_index (displaychoice_ptr_t, disp->idis_navig, navrk); + if (!ch) + return; + debugeprintf ("naviginfodialog_reqfun ch %p navrk %d", (void*)ch, navrk); + gcc_assert (ch->di_magic == DI_MAGIC); + debugeprintf ("naviginfodialog_reqfun ch %p str= %s", (void*)ch, ch->di_msg); + fill_infodialog (wp, disp, ch, navrk); + debugeprintf ("naviginfodialog_reqfun end reqlin: %s\n", reqlin); +} + +static void +removeinfodialog_reqfun (struct comprobe_whatpos_st *wp ATTRIBUTE_UNUSED, + char *reqlin, void *data ATTRIBUTE_UNUSED) +{ + int dialrk = -1; + infodisplay_ptr_t disp = NULL; + if (!comprobe_replf) + return; + debugeprintf ("removeinfodialog_reqfun reqlin: %s", reqlin); + if (sscanf (reqlin, " dia: %d", &dialrk) <= 0 || dialrk < 0) + return; + if (!infodisplay_vector + || dialrk >= (int) VEC_length (infodisplay_ptr_t, infodisplay_vector)) + return; + disp = VEC_index (infodisplay_ptr_t, infodisplay_vector, dialrk); + if (!disp) + return; + gcc_assert (disp->idis_num == dialrk); + infodialog_clear_navig (disp); + free (disp); + VEC_replace (infodisplay_ptr_t, infodisplay_vector, dialrk, 0); + comprobe_printf ("PROB_destroydialog dia:%d\n", dialrk); + comprobe_flush (); + debugeprintf ("removeinfodialog_reqfun end reqlin: %s", reqlin); +} + +/**** + * send a message to be shown + ****/ +void +comprobe_show_message (const char *msg) +{ + if (!msg || !comprobe_replf) + return; + comprobe_puts ("PROB_message msg:"); + comprobe_outenc_string (msg); + comprobe_puts ("\n"); + comprobe_flush (); +} + + +/**** + * Initialize the probe. Called from toplev.c + ****/ +void +comprobe_initialize (void) +{ + static int inited; + long seed = 0; + const char *pc; + const char* randomseed = get_random_seed(false); + gcc_assert (!inited); + gcc_assert (randomseed != (char *) 0); + inited = 1; + if (!compiler_probe_string || !compiler_probe_string[0]) + return; + for (pc = randomseed; *pc; pc++) + seed ^= (seed << 5) + (*pc); + srand48_r ((long) seed, &randata); + signal (SIGIO, sig_interrupted); + signal (SIGCHLD, sig_interrupted); + proberequest_htable = + htab_create (113, hash_proberequest, eq_proberequest, del_proberequest); + filename_htable = + htab_create (229, hash_filename, eq_filename, del_filename); + infopoint_htable = htab_create (2081, hash_infopoint, eq_infopoint, NULL); + infopoint_vector = VEC_alloc (infopoint_ptr_t, heap, 2048); + unique_tree_vector = VEC_alloc (tree, gc, 1024); + unique_bb_vector = VEC_alloc (basic_block, gc, 512); + /* reserve but don't use the first 4 entries hence HTAB_SEEKED_ENTRY unused */ + VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0); + VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0); + VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0); + VEC_safe_push (tree, gc, unique_tree_vector, (tree) 0); + VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0); + VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0); + VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0); + VEC_safe_push (basic_block, gc, unique_bb_vector, (basic_block) 0); + unique_tree_htable = htab_create (4007, hash_info_tree, eq_info_tree, NULL); + unique_bb_htable = htab_create (3001, hash_info_bb, eq_info_bb, NULL); + files_varr.tab = XNEWVEC (char *, 100); + files_varr.size = 100; + files_varr.last = 0; + memset (files_varr.tab, 0, sizeof (char **) * files_varr.size); + comprobe_register ("prob_NAVIGINFODIALOG", naviginfodialog_reqfun, (void *) 0); + comprobe_register ("prob_NEWINFODIALOG", newinfodialog_reqfun, (void *) 0); + comprobe_register ("prob_REMOVEINFODIALOG", removeinfodialog_reqfun, (void *) 0); + comprobe_register ("prob_SHOWINFODIALOG", showinfodialog_reqfun, (void *) 0); + comprobe_register ("prob_STOP", stop_reqfun, (void *) 0); + comprobe_register ("prob_UPDATEINFODIALOG", updateinfodialog_reqfun, (void *) 0); + create_probe_process (); + comprobe_printf ("PROB_version proto:%d msg:", COMPROBE_PROTOCOL_NUMBER); + comprobe_outenc_string (version_string); + comprobe_puts ("\n"); + comprobe_flush (); + atexit (comprobe_forced_kill); +} + +/**** + * Finish the probe. Called from toplev.c + ****/ +void +comprobe_finish (void) +{ + nonstopped = 1; + comprobe_puts ("PROB_message msg:"); + comprobe_outenc_string ("probe finished"); + comprobe_puts ("\n"); + comprobe_flush (); + comprobe_while ("finishing", &nonstopped); + comprobe_stop (); + if (proberequest_htable) + { + htab_empty (proberequest_htable); + htab_delete (proberequest_htable); + proberequest_htable = 0; + }; + if (filename_htable) + { + htab_empty (filename_htable); + htab_delete (filename_htable); + filename_htable = 0; + }; +} + + + +int +comprobe_file_rank (const char *filename) +{ + struct filenamehentry_st slot; + struct filenamehentry_st **slotptr = 0; + int filerank = 0; + + if (!filename || !comprobe_replf) + return 0; + memset (&slot, 0, sizeof (slot)); + slot.file = (char *) filename; + slotptr = (struct filenamehentry_st **) + htab_find_slot (filename_htable, &slot, INSERT); + if (!slotptr) + fatal_error + ("compiler probe failed to register file %s (memory full): %m", + filename); + if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY) + { + struct filenamehentry_st *newslot = 0; + const char *dupfilename = xstrdup (filename); + newslot = xcalloc (sizeof (*newslot), 1); + if (files_varr.last + 1 >= files_varr.size) + { + int newsiz = ((5 * files_varr.last) / 4 + 50) | 0x1f; + int ix; + char **newarr = XNEWVEC (char *, newsiz); + newarr[0] = 0; + for (ix = files_varr.last; ix > 0; ix--) + newarr[ix] = files_varr.tab[ix]; + for (ix = files_varr.last + 1; ix < newsiz; ix++) + newarr[ix] = (char *) 0; + memset (files_varr.tab, 0, sizeof (char *) * files_varr.size); + XDELETEVEC (files_varr.tab); + files_varr.tab = newarr; + } + /* dont use index 0 */ + filerank = ++files_varr.last; + files_varr.tab[filerank] = (char *) dupfilename; + gcc_assert (filerank > 0); + newslot->file = (char *) dupfilename; + newslot->rank = filerank; + *slotptr = newslot; + debugeprintf ("new file rank filerank%d file %s newslot %p", filerank, + dupfilename, (void*)newslot); + comprobe_printf ("PROB_file rank:%d fpath:", filerank); + comprobe_outenc_string(dupfilename); + comprobe_puts("\n"); + comprobe_flush(); + } + else + { + struct filenamehentry_st *oldslot = *slotptr; + filerank = oldslot->rank; + gcc_assert (!strcmp (files_varr.tab[filerank], filename)); + debugeprintf ("old file rank filerank%d file %s oldslot %p", filerank, + filename, (void*)oldslot); + } + return filerank; +} + + +int +comprobe_infopoint_rank (int filerank, int lineno) +{ + int inforank = 0; + struct infopointhentry_st slot; + struct infopointhentry_st **slotptr = 0; + gcc_assert (filerank > 0 && filerank <= files_varr.last); + gcc_assert (lineno > 0); + gcc_assert (infopoint_vector != NULL); + memset (&slot, 0, sizeof (slot)); + slot.infp_filerank = filerank; + slot.infp_lineno = lineno; + slotptr = (struct infopointhentry_st **) + htab_find_slot (infopoint_htable, &slot, INSERT); + if (!slotptr) + fatal_error + ("compiler probe failed to register infopoint filerank=%d,lineno=%d (memory full): %m", + filerank, lineno); + if (*slotptr == HTAB_EMPTY_ENTRY || (*slotptr) == HTAB_DELETED_ENTRY) + { + struct infopointhentry_st *newslot = 0; + newslot = xcalloc (sizeof (*newslot), 1); + /* dont use index 0 */ + if (VEC_length (infopoint_ptr_t, infopoint_vector) == 0) + VEC_safe_push (infopoint_ptr_t, heap, infopoint_vector, + (struct infopointhentry_st *) 0); + VEC_safe_push (infopoint_ptr_t, heap, infopoint_vector, newslot); + inforank = VEC_length (infopoint_ptr_t, infopoint_vector) - 1; + comprobe_printf ("PROB_infopoint fil:%d lin:%d rk:%d\n", filerank, + lineno, inforank); + comprobe_flush (); + newslot->infp_filerank = filerank; + newslot->infp_lineno = lineno; + newslot->infp_num = inforank; + newslot->infp_dischvec = VEC_alloc (displaychoice_ptr_t, heap, 3); + debugeprintf + ("new infopoint slot filerank%d lineno%d inforank%d slot%p", filerank, + lineno, inforank, (void*) newslot); + *slotptr = newslot; + } + else + { + struct infopointhentry_st *oldslot = (*slotptr); + gcc_assert (oldslot->infp_filerank == filerank + && oldslot->infp_lineno == lineno); + inforank = oldslot->infp_num; + gcc_assert (inforank >= 0 + && inforank < (int) VEC_length (infopoint_ptr_t, + infopoint_vector)); + gcc_assert (VEC_index (infopoint_ptr_t, infopoint_vector, inforank) + == oldslot); + debugeprintf + ("old infopoint slot filerank%d lineno%d inforank%d oldslot%p", + filerank, lineno, inforank, (void*)oldslot); + } + return inforank; +} + + + +/*** + * return true if a (GIMPLE/SSA) tree TR has a position + * and in that case fill the PFILENAME and PLINENO + * if the END flag is set, return the last position + ***/ +bool +comprobe_get_position (tree tr, char **pfilename, int *plineno, int end) +{ + if (CAN_HAVE_LOCATION_P (tr) && EXPR_HAS_LOCATION (tr)) + { + char *pfile = (char *) EXPR_FILENAME (tr); + if (pfile) + { + *pfilename = pfile; + *plineno = EXPR_LINENO (tr); + return TRUE; + } + } + else if (TREE_CODE (tr) == STATEMENT_LIST) + { + tree_stmt_iterator iter; + tree tr_stmt; + if (end) + { + for (iter = tsi_last (tr); !tsi_end_p (iter); tsi_prev (&iter)) + { + tr_stmt = tsi_stmt (iter); + if (comprobe_get_position + (tr_stmt, pfilename, plineno, POS_END)) + return TRUE; + } + } + else + for (iter = tsi_start (tr); !tsi_end_p (iter); tsi_next (&iter)) + { + tr_stmt = tsi_stmt (iter); + if (comprobe_get_position + (tr_stmt, pfilename, plineno, POS_START)) + return TRUE; + } + } + else if (GIMPLE_STMT_P (tr)) + { + char *pfile = (char *) EXPR_FILENAME (tr); + if (pfile) + { + *pfilename = pfile; + *plineno = EXPR_LINENO (tr); + return TRUE; + } + } + else if (GIMPLE_TUPLE_P (tr) && GIMPLE_TUPLE_HAS_LOCUS_P (tr)) + { + /* @@@@ dont know yet how to get location of a tuple */ + gcc_unreachable (); + } + return FALSE; +} + +int +comprobe_file_rank_of_tree (tree tr, int *plineno) +{ + char *filename = 0; + int lineno = 0, filerank = 0; + if (!tr) + return 0; + if (!comprobe_get_position (tr, &filename, &lineno, POS_START)) + return 0; + filerank = comprobe_file_rank (filename); + if (filerank > 0 && plineno) + *plineno = lineno; + return filerank; +} + + +/* run the compiler probe pass only if we have a real probe */ +static bool +gate_comprobe (void) +{ + return comprobe_replf != (FILE *) 0 && comprobe_pid != (pid_t) 0; +} + + +/* add information point and display start of a given tree TR with + string DMESG - return the infopoint rank */ +static int +added_infopoint_display_tree (tree tr, const char *dmesg) +{ + int frk = 0, lin = 0, infrk = 0; + comprobe_ix_t trix = 0; + debugeprintf ("added_infopoint_display_tree tr+ %p dmesg %s", (void*)tr, dmesg); + if (!tr) + return 0; + frk = comprobe_file_rank_of_tree (tr, &lin); + if (frk > 0 && lin > 0) + { + trix = comprobe_unique_index_of_tree (tr); + gcc_assert (trix > 2); + infrk = comprobe_infopoint_rank (frk, lin); + debugeprintf + ("added_infopoint_display_tree infrk%d frk%d lin%d tree %p dmesg %s", + infrk, frk, lin, (void*)tr, dmesg); + comprobe_infopoint_add_display (infrk, tree_starting_displayer, dmesg, + (HOST_WIDE_INT) trix); + return infrk; + }; + return 0; +} + + +/* add information point for a given function body */ +static void +add_infopoint_funbody (tree tr_body) +{ + int frk_body = 0, lin_body = 0; + debugeprintf ("add_infopoint_funbody tr_body %p start", (void*)tr_body); + frk_body = comprobe_file_rank_of_tree (tr_body, &lin_body); + if (frk_body >= 0 && lin_body > 0) + { + int esnumins = 0; + char *endfile = 0; + /* @@@ should probably dynamically allocate the message buffer */ + static char msgbuf[200]; + int endline = -1, endfrk = -1, infendnum = -1; + comprobe_ix_t trix = 0; + int infstartnum = -1; + infstartnum = comprobe_infopoint_rank (frk_body, lin_body); + if (comprobe_get_position (tr_body, &endfile, &endline, POS_END) + && (endfrk = comprobe_file_rank (endfile)) >= 0) + infendnum = comprobe_infopoint_rank (endfrk, endline); + trix = comprobe_unique_index_of_tree (tr_body); + esnumins = estimate_num_insns (tr_body, &eni_inlining_weights); + debugeprintf + ("add_infopoint_funbody tr%p infstartnum%d lin_body%d infendnum%d endline%d", + (void*)tr_body, infstartnum, lin_body, infendnum, endline); + if (infstartnum > 0 && lin_body > 0) + { + memset (msgbuf, 0, sizeof (msgbuf)); + if (frk_body == endfrk && endline > lin_body) + snprintf (msgbuf, sizeof (msgbuf) - 1, + _("starting body of %d lines & %d instrs"), + endline - lin_body, esnumins); + else + snprintf (msgbuf, sizeof (msgbuf) - 1, + _("starting body of %d instrs"), esnumins); + if (added_infopoint_display_tree (tr_body, msgbuf) != infstartnum) + gcc_unreachable (); + } + if (infendnum > 0 && endline > 0) + { + memset (msgbuf, 0, sizeof (msgbuf)); + if (frk_body == endfrk && endline > lin_body && lin_body > 0) + snprintf (msgbuf, + sizeof (msgbuf) - 1, + _("ending body of %d lines & %d instrs"), + endline - lin_body, esnumins); + else + snprintf (msgbuf, + sizeof (msgbuf) - 1, + _("ending body of %d instrs"), esnumins); + comprobe_infopoint_add_display + (infendnum, tree_ending_displayer, msgbuf, (HOST_WIDE_INT) trix); + } + } + debugeprintf ("add_infopoint_funbody tr_body %p end", (void*)tr_body); +} + + +comprobe_ix_t +comprobe_unique_index_of_basic_block (basic_block bb) +{ + comprobe_ix_t bbix = 0; + comprobe_ix_t l = 0, nbbb = 0; + void **sp = 0; + if (bb == NULL || !unique_bb_vector) + return 0; + gcc_assert (unique_bb_vector + && VEC_length (basic_block, unique_bb_vector) > 2); + l = (comprobe_ix_t) HTAB_SEEKED_ENTRY; + nbbb = VEC_length (basic_block, unique_bb_vector); + unique_seeked_bb = bb; + sp = htab_find_slot (unique_bb_htable, &l, INSERT); + if (sp) + { + if (*sp != HTAB_EMPTY_ENTRY && *sp != HTAB_DELETED_ENTRY + && *sp != HTAB_SEEKED_ENTRY) + l = *(comprobe_ix_t *) (*sp); + else + l = 0; + if (l > 2) + { + gcc_assert (l < nbbb + && VEC_index (basic_block, unique_bb_vector, l) == bb); + bbix = l; + } + else + { + VEC_safe_push (basic_block, gc, unique_bb_vector, bb); + bbix = nbbb; + *(comprobe_ix_t *) (sp) = bbix; + } + } + else /* failed to insert into unique_bb_htable */ + gcc_unreachable (); + return bbix; +} + + +basic_block +comprobe_basic_block_of_unique_index (comprobe_ix_t ix) +{ + int nbbb = 0; + if (ix < 2 || !unique_bb_vector) + return NULL; + nbbb = VEC_length (basic_block, unique_bb_vector); + if ((long) ix < (long) nbbb) + return VEC_index (basic_block, unique_bb_vector, ix); + return NULL; +} + +/* add information point for a given basic block */ +static void +add_infopoint_basic_block (basic_block bb) +{ + block_stmt_iterator bsi; + int stmtcnt = 0; + comprobe_ix_t bbix = 0; + bool bbgotpos = 0; + debugeprintf ("add_infopoint_basic_block bb %p start", (void*)bb); + if (bb == NULL) + return; + bbix = comprobe_unique_index_of_basic_block (bb); + gcc_assert (bbix > 2); + bbgotpos = FALSE; + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + char *filename = 0; + int lineno = 0; + int filrk = 0, infrk = 0; + static char msgbuf[64]; + if (stmt) + stmtcnt++; + else + continue; + if (comprobe_get_position (stmt, &filename, &lineno, POS_START)) + { + filrk = comprobe_file_rank (filename); + infrk = comprobe_infopoint_rank (filrk, lineno); + if (!bbgotpos) + { + bbgotpos = TRUE; + memset (msgbuf, 0, sizeof (msgbuf)); + snprintf (msgbuf, + sizeof (msgbuf) - 1, "start bb#%d", bb->index); + comprobe_infopoint_add_display + (infrk, bb_starting_displayer, msgbuf, (HOST_WIDE_INT) bbix); + }; + memset (msgbuf, 0, sizeof (msgbuf)); + snprintf (msgbuf, + sizeof (msgbuf) - 1, "stmt#%d bb#%d", stmtcnt, bb->index); + (void) added_infopoint_display_tree (stmt, msgbuf); + } + } + for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) + { + tree stmt = bsi_stmt (bsi); + char *filename = 0; + int lineno = 0; + int filrk = 0, infrk = 0; + static char msgbuf[64]; + if (comprobe_get_position (stmt, &filename, &lineno, POS_END)) + { + filrk = comprobe_file_rank (filename); + infrk = comprobe_infopoint_rank (filrk, lineno); + memset (msgbuf, 0, sizeof (msgbuf)); + snprintf (msgbuf, sizeof (msgbuf) - 1, "end bb#%d", bb->index); + comprobe_infopoint_add_display + (infrk, bb_ending_displayer, msgbuf, (HOST_WIDE_INT) bbix); + break; + } + }; + debugeprintf ("add_infopoint_basic_block bb %p end", (void*)bb); +} + + +/* this function does the bulk of the work of the pass and returns + additional TODOs to the pass machinery */ +static unsigned int +execute_comprobe (void) +{ + struct cgraph_node *cgr_fun = 0; + basic_block bb = 0; + for (cgr_fun = cgraph_nodes; cgr_fun; cgr_fun = cgr_fun->next) + { + tree tr_decl, tr_body; + int frk_decl = 0, lin_decl = 0; + if (!comprobe_replf) + break; + debugeprintf ("execute_comprobe cgr_fun=%p", (void*)cgr_fun); + if (flag_compiler_probe_debug) + dump_cgraph_node (stderr, cgr_fun); + tr_decl = cgr_fun->decl; + frk_decl = comprobe_file_rank_of_tree (tr_decl, &lin_decl); + tr_body = DECL_SAVED_TREE (tr_decl); + if (!tr_body) + continue; + comprobe_check ("comprobe cgraph loop"); + add_infopoint_funbody (tr_body); + comprobe_flush (); + } + FOR_EACH_BB (bb) + { + if (!comprobe_replf) + break; + debugeprintf ("execute_comprobe bb %p", (void*)bb); + if (!bb_stmt_list(bb)) + continue; + comprobe_check ("comprobe bb loop"); + add_infopoint_basic_block (bb); + comprobe_flush (); + } + comprobe_flush (); + return 0; /* no additional todos */ +} + +struct tree_opt_pass pass_compiler_probe = { + "comprobe", /* name */ + gate_comprobe, /* gate */ + execute_comprobe, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0 /*PROP_cfg | PROP_ssa */ , /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +#include "gt-compiler-probe.h" +/* eof compiler-probe.c */ diff --git a/gcc/compiler-probe.h b/gcc/compiler-probe.h new file mode 100644 index 00000000000..1f5aa0b34b8 --- /dev/null +++ b/gcc/compiler-probe.h @@ -0,0 +1,482 @@ +/* Compiler probe. + Copyright (C) 2007 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef GCC_COMPILER_PROBE_H +#define GCC_COMPILER_PROBE_H + +#define COMPROBE_PROTOCOL_NUMBER 200701 + +/* the compiler probe */ +#if defined(ENABLE_COMPILER_PROBE) && ENABLE_COMPILER_PROBE +/* <unistd.h> and <fcntl.h> and <string.h> have already been included + and the following includes have been checked by autoconf */ +#include <sys/select.h> +#include <signal.h> + +/* compiler-probe.c uses the comprobe_ prefix */ + +struct comprobe_whatpos_st +{ + const char *wp_what; + const char *wp_file; + int wp_line; +}; + +/* handling routine for a request (from probe to compiler) */ +typedef void comprobe_requestfun_t (struct comprobe_whatpos_st *wp, + char *reqlin, void *data); + +/**** + * the interrupt flag, its handler, and the macro to check it + ****/ +extern volatile sig_atomic_t comprobe_interrupted; + +void comprobe_handle_probe (const char *what, const char *file, int lineno); + +/* this macro should be put at all the points where we want to permit + compiler probe interaction; in the common case where + comprobe_interrupted is cleared, this macro runs quite quickly */ +#define comprobe_check(WHAT) do{ if (comprobe_interrupted) { \ + comprobe_handle_probe((WHAT),__FILE__,__LINE__); }} while(0) + +/*** + * stop the compiler probe (can be called from action handler) + ***/ +void comprobe_stop (void); + +/*** + * forced kill of the compiler probe + ***/ +void comprobe_forced_kill (void); + +/* force probing till an integer variable is cleared or the probe ended */ +void comprobe_while_probe (const char *what, const char *file, int lineno, + int *pvar); +#define comprobe_while(WHAT,PVAR) do{ \ + comprobe_while_probe((WHAT),__FILE__,__LINE__,(PVAR));}while(0) +/*** + * the stream for replying to the probe ; may be NULL so should be tested! + ***/ +extern FILE *comprobe_replf; +#define comprobe_printf(Fmt, ...) do{if(comprobe_replf) { \ + fprintf(comprobe_replf, (Fmt), ##__VA_ARGS__); \ + fflush(comprobe_replf);}}while(0) +#define comprobe_puts(S) do{if(comprobe_replf) { \ + fputs((S), comprobe_replf); \ + fflush(comprobe_replf);}}while(0) +#define comprobe_flush() do{if(comprobe_replf) \ + fflush(comprobe_replf); } while(0) +void comprobe_begin_big (void); +void comprobe_end_big (void); +void comprobe_outenc_string (const char *s); +#define comprobe_begin_big_printf(Fmt, ...) do{if(comprobe_replf) { \ + comprobe_begin_big(); fprintf(comprobe_replf, (Fmt), \ + ##__VA_ARGS__);}}while(0) +/*** + * initialize and finish. called in toplev.c + ****/ +void comprobe_initialize (void); +void comprobe_finish (void); + + +/**** + * send a message to be shown + ****/ +void comprobe_show_message (const char *msg); + + +extern struct tree_opt_pass pass_compiler_probe; + +/*** + * return a unique positive file rank for a file path; or 0 for NULL name + * may send a PROB_file request to the probe + ***/ +int comprobe_file_rank (const char *filename); + +/*** + * return a unique positive infopoint rank for a file rank and a line + * number; may send a PROB_file request and a PROB_infopoint request + * to the probe + **/ +int comprobe_infopoint_rank (int filrank, int lineno); + +/*** + * return the linenumber, filerank, and filename of a given infopoint + * or O|NULL if invalid infopoint rank + ***/ +int comprobe_line_of_infopoint (int infoptrank); +int comprobe_filerank_of_infopoint (int infoptrank); +const char *comprobe_filename_of_infopoint (int infoptrank); + +/*** + * infopoint displayer routines + ***/ + +/* info displayers are opaque structures managed by the compiler probe */ +struct comprobe_infodisplay_st; + +typedef void comprobe_infodisplay_fun_t + (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig); + +void comprobe_infopoint_add_display (int infoptrank, + comprobe_infodisplay_fun_t * dispfun, + const char *msg, HOST_WIDE_INT data); + +/* displayer routines can add navigators */ +void comprobe_display_add_navigator (struct comprobe_infodisplay_st *idi, + comprobe_infodisplay_fun_t * navfun, + const char *msg, HOST_WIDE_INT data); + + +/*** + * verb handler registration (the verb and data should be constant or + * global data, or explicitly allocated at registration and freed + * after unregistration). + ***/ +void comprobe_register (const char *verb, comprobe_requestfun_t * handler, + void *data); +/* unregistration is not yet imlemented */ +void comprobe_unregister (const char *verb); + +typedef HOST_WIDE_INT comprobe_ix_t; + +/*************************************************************************** + * additional tree specific routines are declared only if we know + * about trees because this file has been included after tree.h + *******/ +#ifdef TREE_CODE /*TREE_CODE is an important macro from tree.h */ + +/*** + * return true if a (GIMPLE/SSA) tree TR has a position + * and in that case fill the PFILENAME and PLINENO + * if the END flag is set, return the last position + ***/ +enum { POS_START = 0, POS_END }; +bool comprobe_get_position (tree tr, char **pfilename, int *plineno, int end); + +/*** + * return a unique positive file rank for the location of a tree, if + * any (else 0); may send a PROB_file request to the probe and set the + * *plineno to the line number + **/ +int comprobe_file_rank_of_tree (tree tr, int *plineno); + +/**** + * we manage a unique mapping between trees and indexes thru our hash + * table; to get the index of a tree and vice versa the tree of an + * index + ***/ +comprobe_ix_t comprobe_unique_index_of_tree (tree tr); +tree comprobe_tree_of_unique_index (comprobe_ix_t ix); + +#endif /*TREE_CODE */ + + + + +/************************************************************************ + * additional basic block specific routines are declared only if + * we know about basic blocks because "basic-block.h" have been included + ************************************************************************/ +#ifdef BASIC_BLOCK /* an important macro of basic-block */ +/**** + * we manage a unique mapping between basic blocks and indexes thru + * our hash table; to get the index of a basic block and vice versa + * the basic block of an index + ***/ +comprobe_ix_t comprobe_unique_index_of_basic_block (basic_block bb); +basic_block comprobe_basic_block_of_unique_index (comprobe_ix_t ix); +#endif + +#else /* compiler probe disabled */ + +/***************** fake stubs when probe disabled *******************/ +#define comprobe_check(WHAT) do{}while(0) +#define comprobe_while(WHAT,PVAR) do{}while(0) +#define comprobe_stop() do{}while(0) +#define comprobe_forced_kill() do{}while(0) +#define comprobe_flush() do{}while(0) +#define comprobe_replf ((FILE*)0) +#define comprobe_show_message(M) do{if(0) puts(M);}while(0) +#define comprobe_puts(S) do[}while(0) +#define comprobe_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_big_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_register(Verb,Hdlr,Data) do{}while(0) +#define comprobe_unregister(Verb,Hdlr,Data) do{}while(0) +#define comprobe_begin_big() +#define comprobe_begin_big_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_end_big() +#define comprobe_outenc_string(S) do{if (0 && ((S) == (char*)0));}while(0) +#define comprobe_filerank_of_tree(T,P) (0 && (T) == (tree)0 && (P) == (int*)0) +#define comprobe_unique_index_of_tree(T) (0 && (T) == (tree)0) +#define comprobe_tree_of_unique_index(I) NULL_TREE +#define comprobe_filerank(P) (0 && (P) == (const char*)0) +#define comprobe_get_position(T,PF,PL,E) (FALSE \ + && (T)!=(tree)0 \ + && (PF)!=(char**0) \ + && (PL) != (int*)0 && (E)) +#define comprobe_infopoint_add_displayer(IRK,DMESG,DROUT,DATA) while(0 && \ + (IRK) != (int)0 && (DMESG) != (char*)0 && \ + (DROUT) != (comprobe_infoptdisplayroutine_t*)0 && (DATA) != (void*)0) {} +#endif /*ENABLE_COMPILER_PROBE */ + +#endif /*GCC_COMPILER_PROBE_H */ +/* Compiler probe. + Copyright (C) 2007 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef GCC_COMPILER_PROBE_H +#define GCC_COMPILER_PROBE_H + +#define COMPROBE_PROTOCOL_NUMBER 200701 + +/* the compiler probe */ +#if defined(ENABLE_COMPILER_PROBE) && ENABLE_COMPILER_PROBE +/* <unistd.h> and <fcntl.h> and <string.h> have already been included + and the following includes have been checked by autoconf */ +#include <sys/select.h> +#include <signal.h> + +/* compiler-probe.c uses the comprobe_ prefix */ + +struct comprobe_whatpos_st +{ + const char *wp_what; + const char *wp_file; + int wp_line; +}; + +/* handling routine for a request (from probe to compiler) */ +typedef void comprobe_requestfun_t (struct comprobe_whatpos_st *wp, + char *reqlin, void *data); + +/**** + * the interrupt flag, its handler, and the macro to check it + ****/ +extern volatile sig_atomic_t comprobe_interrupted; + +void comprobe_handle_probe (const char *what, const char *file, int lineno); + +/* this macro should be put at all the points where we want to permit + compiler probe interaction; in the common case where + comprobe_interrupted is cleared, this macro runs quite quickly */ +#define comprobe_check(WHAT) do{ if (comprobe_interrupted) { \ + comprobe_handle_probe((WHAT),__FILE__,__LINE__); }} while(0) + +/*** + * stop the compiler probe (can be called from action handler) + ***/ +void comprobe_stop (void); + +/*** + * forced kill of the compiler probe + ***/ +void comprobe_forced_kill (void); + +/* force probing till an integer variable is cleared or the probe ended */ +void comprobe_while_probe (const char *what, const char *file, int lineno, + int *pvar); +#define comprobe_while(WHAT,PVAR) do{ \ + comprobe_while_probe((WHAT),__FILE__,__LINE__,(PVAR));}while(0) +/*** + * the stream for replying to the probe ; may be NULL so should be tested! + ***/ +extern FILE *comprobe_replf; +#define comprobe_printf(Fmt, ...) do{if(comprobe_replf) { \ + fprintf(comprobe_replf, (Fmt), ##__VA_ARGS__); \ + fflush(comprobe_replf);}}while(0) +#define comprobe_flush() do{if(comprobe_replf) \ + fflush(comprobe_replf); } while(0) +void comprobe_begin_big (void); +void comprobe_end_big (void); +void comprobe_outenc_string (const char *s); +#define comprobe_begin_big_printf(Fmt, ...) do{if(comprobe_replf) { \ + comprobe_begin_big(); fprintf(comprobe_replf, (Fmt), \ + ##__VA_ARGS__);}}while(0) +/*** + * initialize and finish. called in toplev.c + ****/ +void comprobe_initialize (void); +void comprobe_finish (void); + + +/**** + * send a message to be shown + ****/ +void comprobe_show_message (const char *msg); + + +extern struct tree_opt_pass pass_compiler_probe; + +/*** + * return a unique positive file rank for a file path; or 0 for NULL name + * may send a PROB_file request to the probe + ***/ +int comprobe_file_rank (const char *filename); + +/*** + * return a unique positive infopoint rank for a file rank and a line + * number; may send a PROB_file request and a PROB_infopoint request + * to the probe + **/ +int comprobe_infopoint_rank (int filrank, int lineno); + +/*** + * return the linenumber, filerank, and filename of a given infopoint + * or O|NULL if invalid infopoint rank + ***/ +int comprobe_line_of_infopoint (int infoptrank); +int comprobe_filerank_of_infopoint (int infoptrank); +const char *comprobe_filename_of_infopoint (int infoptrank); + +/*** + * infopoint displayer routines + ***/ + +/* info displayers are opaque structures managed by the compiler probe */ +struct comprobe_infodisplay_st; + +typedef void comprobe_infodisplay_fun_t + (struct comprobe_whatpos_st *wp, + struct comprobe_infodisplay_st *di, + HOST_WIDE_INT data, HOST_WIDE_INT navig); + +void comprobe_infopoint_add_display (int infoptrank, + comprobe_infodisplay_fun_t * dispfun, + const char *msg, HOST_WIDE_INT data); + +/* displayer routines can add navigators */ +void comprobe_display_add_navigator (struct comprobe_infodisplay_st *idi, + comprobe_infodisplay_fun_t * navfun, + const char *msg, HOST_WIDE_INT data); + + +/*** + * verb handler registration (the verb and data should be constant or + * global data, or explicitly allocated at registration and freed + * after unregistration). + ***/ +void comprobe_register (const char *verb, comprobe_requestfun_t * handler, + void *data); +/* unregistration is not yet imlemented */ +void comprobe_unregister (const char *verb); + +typedef HOST_WIDE_INT comprobe_ix_t; + +/*************************************************************************** + * additional tree specific routines are declared only if we know + * about trees because this file has been included after tree.h + *******/ +#ifdef TREE_CODE /*TREE_CODE is an important macro from tree.h */ + +/*** + * return true if a (GIMPLE/SSA) tree TR has a position + * and in that case fill the PFILENAME and PLINENO + * if the END flag is set, return the last position + ***/ +enum { POS_START = 0, POS_END }; +bool comprobe_get_position (tree tr, char **pfilename, int *plineno, int end); + +/*** + * return a unique positive file rank for the location of a tree, if + * any (else 0); may send a PROB_file request to the probe and set the + * *plineno to the line number + **/ +int comprobe_file_rank_of_tree (tree tr, int *plineno); + +/**** + * we manage a unique mapping between trees and indexes thru our hash + * table; to get the index of a tree and vice versa the tree of an + * index + ***/ +comprobe_ix_t comprobe_unique_index_of_tree (tree tr); +tree comprobe_tree_of_unique_index (comprobe_ix_t ix); + +#endif /*TREE_CODE */ + + + + +/************************************************************************ + * additional basic block specific routines are declared only if + * we know about basic blocks because "basic-block.h" have been included + ************************************************************************/ +#ifdef BASIC_BLOCK /* an important macro of basic-block */ +/**** + * we manage a unique mapping between basic blocks and indexes thru + * our hash table; to get the index of a basic block and vice versa + * the basic block of an index + ***/ +comprobe_ix_t comprobe_unique_index_of_basic_block (basic_block bb); +basic_block comprobe_basic_block_of_unique_index (comprobe_ix_t ix); +#endif + +#else /* compiler probe disabled */ + +/***************** fake stubs when probe disabled *******************/ +#define comprobe_check(WHAT) do{}while(0) +#define comprobe_while(WHAT,PVAR) do{}while(0) +#define comprobe_stop() do{}while(0) +#define comprobe_forced_kill() do{}while(0) +#define comprobe_flush() do{}while(0) +#define comprobe_replf ((FILE*)0) +#define comprobe_show_message(M) do{if(0) puts(M);}while(0) +#define comprobe_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_big_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_register(Verb,Hdlr,Data) do{}while(0) +#define comprobe_unregister(Verb,Hdlr,Data) do{}while(0) +#define comprobe_begin_big() +#define comprobe_begin_big_printf(Fmt, ...) do{if(0) printf((Fmt),##__VA_ARGS__);}while(0) +#define comprobe_end_big() +#define comprobe_outenc_string(S) do{if (0 && ((S) == (char*)0));}while(0) +#define comprobe_filerank_of_tree(T,P) (0 && (T) == (tree)0 && (P) == (int*)0) +#define comprobe_unique_index_of_tree(T) (0 && (T) == (tree)0) +#define comprobe_tree_of_unique_index(I) NULL_TREE +#define comprobe_filerank(P) (0 && (P) == (const char*)0) +#define comprobe_get_position(T,PF,PL,E) (FALSE \ + && (T)!=(tree)0 \ + && (PF)!=(char**0) \ + && (PL) != (int*)0 && (E)) +#define comprobe_infopoint_add_displayer(IRK,DMESG,DROUT,DATA) while(0 && \ + (IRK) != (int)0 && (DMESG) != (char*)0 && \ + (DROUT) != (comprobe_infoptdisplayroutine_t*)0 && (DATA) != (void*)0) {} +#endif /*ENABLE_COMPILER_PROBE */ + +#endif /*GCC_COMPILER_PROBE_H */ diff --git a/gcc/config.in b/gcc/config.in index 723b88fc8e7..49007bd346a 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -46,6 +46,12 @@ #endif +/* Define if compiler probe is enabled. */ +#ifndef USED_FOR_TARGET +#undef ENABLE_COMPILER_PROBE +#endif + + /* Define to 1 to specify that we are using the BID decimal floating point format instead of DPD */ #ifndef USED_FOR_TARGET @@ -1026,6 +1032,12 @@ #endif +/* Define if Libtool dynamic linker is in use. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LIBTOOLDYNL +#endif + + /* Define to 1 if you have the <limits.h> header file. */ #ifndef USED_FOR_TARGET #undef HAVE_LIMITS_H @@ -1104,6 +1116,12 @@ #endif +/* Define if Parma Polyhedra Library is in use. */ +#ifndef USED_FOR_TARGET +#undef HAVE_PARMAPOLY +#endif + + /* Define to 1 if you have the `putchar_unlocked' function. */ #ifndef USED_FOR_TARGET #undef HAVE_PUTCHAR_UNLOCKED diff --git a/gcc/configure.ac b/gcc/configure.ac index f3bc7b352c5..d230bcb59a7 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -308,6 +308,212 @@ AC_CHECK_SIZEOF(long) AC_CHECK_TYPES([long long], [AC_CHECK_SIZEOF(long long)]) AC_CHECK_TYPES([__int64], [AC_CHECK_SIZEOF(__int64)]) +################################################ +##### Basilys specific stuff + +################ +# Check for PPL (Parma Polyhedral Library) +ppllibs= +pplinc= +have_ppl=yes + +AC_ARG_WITH(ppl, [ --with-ppl=PATH Specify prefix directory for installed Parma Polyedra Library (PPL) + Equivalent to --with-ppl-include=PATH/include + plus --with-ppl-lib=PATH/lib]) +AC_ARG_WITH(ppl_include, [ --with-ppl-include=PATH Specify directory for installed PPL include files]) +AC_ARG_WITH(ppl_lib, [ --with-ppl-lib=PATH Specify the directory for the installed PPL library]) + + +if test "x$with_ppl" != x; then + ppllibs="-L$with_ppl/lib -lppl_c -lppl $ppllibs" + pplinc="-I$with_ppl/include" +fi + +if test "x$ppl_include" != x; then + pplinc="-I$ppl_include $pplinc" +fi + +if test "x$ppl_lib" != x; then + ppllibs="-L$ppl_lib -lppl_c -lppl $ppllibs" +fi + +## check for Parma Polyedra Lib +saved_CFLAGS="$CFLAGS" +saved_LIBS="$LIBS" +CFLAGS="$CFLAGS $pplinc $gmpinc $ppllibs $gmplibs" +AC_MSG_CHECKING([for correct version of ppl_c.h]) +AC_TRY_LINK([#include <ppl_c.h>],[ +ppl_version_major(); ], [AC_MSG_RESULT([yes]); have_ppl=yes], [AC_MSG_RESULT([no]); have_ppl=no]) + +# one some systems, PPL requires an additional C++ wrapping library for GMP +# namely -lgmpxx ahead of -lgmp +if test x"$have_ppl" != xyes; then + saved_LIBS="$LIBS" + ppllibs="-lgmpxx $ppllibs" + #maybe we should do:: gmplibs=`echo "$gmplibs" | sed -e 's/-lgmp/-lgmpxx -lgmp/'` + CFLAGS="$CFLAGS $pplinc $gmpinc $ppllibs $gmplibs" + AC_MSG_CHECKING([for libgmpxx needed by ppl]) + AC_TRY_LINK([#include <ppl_c.h>],[ + ppl_version_major(); ], [AC_MSG_RESULT([yes]); have_ppl=yes], [AC_MSG_RESULT([no]); have_ppl=no]) +fi +if test x"$have_ppl" = xyes; then + AC_DEFINE(HAVE_PARMAPOLY, 1, [Define if Parma Polyhedra Library is in use.]) +fi +LIBS="$saved_LIBS" +CFLAGS="$saved_CFLAGS" + +if test -d ${srcdir}/gcc && test x$have_ppl != xyes; then + AC_MSG_WARN([Some passes of GCC require PPL 0.9+. +Try the --with-ppl option to specify the installed PPL location, +or specify separately --with-ppl-include=DIRINCL --with-ppl-lib=DIRLIB. +Copies of this library source code can be found at its respective +hosting site as well as at ftp://gcc.gnu.org/pub/gcc/infrastructure/. +See also http://gcc.gnu.org/install/prerequisites.html for additional info.]) +fi + +# Flags needed for PPL +AC_SUBST(ppllibs) +AC_SUBST(pplinc) + + + +################ +# Check for LTDL (Libtool dynamic loader) +ltdllibs="-lltdl" +ltdlinc= +have_ltdl=yes + +AC_ARG_WITH(ltdl, [ --with-ltdl=PATH Specify prefix directory for installed LibTool Dynamic Loader library + Equivalent to --with-ltdl-include=PATH/include + plus --with-ltdl-lib=PATH/lib]) + +AC_ARG_WITH(ltdl_include, [ --with-ltdl-include=PATH Specify directory for installed LTDL include files]) +AC_ARG_WITH(ltdl_lib, [ --with-ltdl-lib=PATH Specify the directory for the installed LTDL library]) + + +if test "x$with_ltdl" != x; then + ltdllibs="-L$with_ltdl/lib -lltdl" + ltdlinc="-I$with_ltdl/include" +fi + +if test "x$ltdl_include" != x; then + ltdlinc="-I$ltdl_include $ltdlinc" +fi + +if test "x$ltdl_lib" != x; then + ltdllibs="-L$ltdl_lib -lltdl $ltdllibs" +fi + +ltdl_ldflags="" + +saved_CFLAGS="$CFLAGS" +saved_LIBS="$LIBS" +saved_LDFLAGS="$LD_FLAGS" +CFLAGS="$CFLAGS $ltdlinc" +LIBS="$LIBS $ltdllibs" +LDFLAGS="$LDFLAGS -rdynamic" +AC_MSG_CHECKING([for LibTool Dynamic Loader]) +AC_TRY_LINK([#include <ltdl.h>],[ + lt_dlhandle h; + lt_dlinit (); + h = lt_dlopen ((const char *)0); +], [AC_MSG_RESULT([yes]); have_ltdl=yes], [AC_MSG_RESULT([no]); have_ltdl=no]) + +if test "x$have_ltdl" != xyes; then + AC_MSG_WARN([Some passes of GCC require LibTool Dynamic Loader. +Try the --with-ltdl option to specify the installed LTDL location. +Copies of this library source code can be found at its respective +hosting site as well as at ftp://gcc.gnu.org/pub/gcc/infrastructure/. +See also http://gcc.gnu.org/install/prerequisites.html for additional info.]) +else + AC_DEFINE(HAVE_LIBTOOLDYNL, 1, + [Define if Libtool dynamic linker is in use.]) + ltdl_ldflags="-rdynamic" +fi + +CFLAGS="$saved_CFLAGS" +LIBS="$saved_LIBS" +LDFLAGS="$saved_LDFLAGS" + +# Flags needed for LTDL +AC_SUBST(ltdllibs) +AC_SUBST(ltdlinc) +AC_SUBST(ltdl_ldflags) + + +# for debugging only +echo '%!%' after LTDL LIBS= $LIBS CFLAGS= $CFLAGS + +# ------------------------ +# Compiler probing support +# ------------------------ +enabled_compiler_probe=no + +AC_ARG_ENABLE(compiler-probe, +[ --enable-compiler-probe Enable instrumenting probe of compiler + only useful for compiler hackers or + users expecting huge compilation times; + this could slow down the compiler + [hence is disabled by default]. +], +enabled_compiler_probe=$enableval, +enabled_compiler_probe=no) + +if test "$enabled_compiler_probe" = "yes" ; then + AC_MSG_CHECKING([for features required for compiler probe]) +## we check specifically for the Posix/SuS (Single Unix Spec) select, +## for the SIGPOLL SuS signal handled by SuS sigaction +## and for fcntl F_SETOWN available in Linux, *BSD, Solaris +AC_TRY_COMPILE([ +/* testing features for compiler probe */ +#include <unistd.h> +#include <fcntl.h> +#include <sys/select.h> +#include <signal.h> +#include <string.h> + +volatile sig_atomic_t my_flag; +static void my_signal_handler(int sig) +{if (sig == SIGPOLL) my_flag=1;} +], +[ + fd_set rfs; + int fd = 1; + struct timeval tv; + struct sigaction sa; + FD_ZERO (&rfs); + FD_SET (0, &rfs); + tv.tv_sec = 0; + tv.tv_usec = 500000; + /* Posix/Single Unix Spec select */ + if (select (1, &rfs, (fd_set *) 0, (fd_set *) 0, &tv)) + return 0; + /* Posix/SuS signal */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = my_signal_handler; + if (sigaction (SIGPOLL, &sa, (struct sigaction *) 0)) + return 0; + /* Linux, Solaris, and most BSD have F_SETOWN */ + if (fcntl (fd, F_SETOWN, (long) getpid ())) + return 0; + return 0; +], +[AC_MSG_RESULT([yes]); + enabled_compiler_probe=yes; + AC_DEFINE(ENABLE_COMPILER_PROBE, 1, [Define if compiler probe is enabled.]) + COMPILER_PROBE=compiler-probe.o +], +[AC_MSG_RESULT([no]); + AC_MSG_WARN([Your system lacks the required features for compiler probing. + Hence compiler probe is disabled.]); + enabled_compiler_probe=no] +); +fi + +AC_SUBST(COMPILER_PROBE) +###################### end of basilys specific stuff + + # --------------------- # Warnings and checking # --------------------- diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 6bbfe9a36e7..c05a8ccc415 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -41,6 +41,8 @@ along with GCC; see the file COPYING3. If not see #include "langhooks-def.h" #include "opts.h" +#include "compiler-probe.h" +/* we just need to kill the compiler probe on internal|fatal errors */ /* Prototypes. */ static char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; @@ -588,6 +590,8 @@ fatal_error (const char *gmsgid, ...) report_diagnostic (&diagnostic); va_end (ap); + comprobe_forced_kill(); + gcc_unreachable (); } @@ -606,6 +610,8 @@ internal_error (const char *gmsgid, ...) report_diagnostic (&diagnostic); va_end (ap); + comprobe_forced_kill(); + gcc_unreachable (); } diff --git a/gcc/gdbinit.in b/gcc/gdbinit.in index e8d10e236c4..b90287d4168 100644 --- a/gcc/gdbinit.in +++ b/gcc/gdbinit.in @@ -129,6 +129,17 @@ document pbm Dump the bitmap that is in $ as a comma-separated list of numbers. end +## for basilys +set breakpoint pending on +define pby +set basilys_dbgeprint ($) +end + +document pby +Print the basilys_ptr_t that is $. +Works only when an inferior is executing. +end + # Put breakpoints at exit and fancy_abort in case abort is mapped # to either fprintf/exit or fancy_abort. b fancy_abort diff --git a/gcc/gengtype.c b/gcc/gengtype.c index ca7d5b411cd..7261e71f61f 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1535,7 +1535,9 @@ open_base_files (void) "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h", "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h", - "cfglayout.h", "except.h", "output.h", "cfgloop.h", NULL + "cfglayout.h", "except.h", "output.h", "cfgloop.h", + "basilys.h", + NULL }; const char *const *ifp; outf_p gtype_desc_c; diff --git a/gcc/params.def b/gcc/params.def index 0428c3120af..c7a0513e136 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -708,6 +708,22 @@ DEFPARAM (PARAM_USE_CANONICAL_TYPES, "Whether to use canonical types", 1, 0, 1) +/**** stuff for Basilys runtime */ + +/* the Basilys minor zone size for its own copying garbage collector */ +DEFPARAM (PARAM_BASILYS_MINOR_ZONE, + "basilys-minor-zone", + "size in kilowords (one word = one pointer) of the minor zone for the specialized copying basilys collector", + 256, 128, 32768) + +/* paramater tuning the frequency of full garbage collection in Basilys */ +DEFPARAM (PARAM_BASILYS_FULL_FREQ, + "basilys-full-freq", + "tuning the frequency of full garbage collection in the specialized basilys collector", + 16, 8, 128) +/**** end of Basilys stuff */ + + DEFPARAM (PARAM_MAX_PARTIAL_ANTIC_LENGTH, "max-partial-antic-length", "Maximum length of partial antic set when performing tree pre optimization", diff --git a/gcc/passes.c b/gcc/passes.c index 2614c90b3ca..af499a80ed2 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -102,6 +102,9 @@ along with GCC; see the file COPYING3. If not see declarations for e.g. AIX 4.x. */ #endif + +#include "compiler-probe.h" + /* This is used for debugging. It allows the current pass to printed from anywhere in compilation. */ struct tree_opt_pass *current_pass; @@ -546,7 +549,8 @@ init_optimization_passes (void) NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_type_escape); NEXT_PASS (pass_ipa_pta); - NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_basilys); *p = NULL; /* These passes are run after IPA passes on every function that is being @@ -677,6 +681,11 @@ init_optimization_passes (void) NEXT_PASS (pass_mark_used_blocks); NEXT_PASS (pass_cleanup_cfg_post_optimizing); } + +#if ENABLE_COMPILER_PROBE + NEXT_PASS(pass_compiler_probe); +#endif + NEXT_PASS (pass_warn_function_noreturn); NEXT_PASS (pass_free_datastructures); NEXT_PASS (pass_mudflap_2); @@ -1065,6 +1074,10 @@ execute_one_pass (struct tree_opt_pass *pass) { bool initializing_dump; unsigned int todo_after = 0; +#if ENABLE_COMPILER_PROBE + static char cprobuf[80]; + memset(cprobuf, 0, sizeof(cprobuf)); +#endif current_pass = pass; /* See if we're supposed to run this pass. */ @@ -1089,6 +1102,13 @@ execute_one_pass (struct tree_opt_pass *pass) (void *)(size_t)pass->properties_required); #endif + if (pass->name && comprobe_replf) { + static char buf[80]; + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf)-1, "pass %s", pass->name); + comprobe_show_message(buf); + } + /* If a dump file name is present, open it if enabled. */ if (pass->static_pass_number != -1) { @@ -1119,7 +1139,15 @@ execute_one_pass (struct tree_opt_pass *pass) /* Do it! */ if (pass->execute) { + comprobe_check((snprintf(cprobuf, sizeof(cprobuf)-1, + "pass %s before execute", + pass->name?pass->name:"_"), + cprobuf)); todo_after = pass->execute (); + comprobe_check((snprintf(cprobuf, sizeof(cprobuf)-1, + "pass %s executed", + pass->name?pass->name:"_"), + cprobuf)); do_per_function (clear_last_verified, NULL); } diff --git a/gcc/run-basilys.h b/gcc/run-basilys.h new file mode 100644 index 00000000000..80c728f93f1 --- /dev/null +++ b/gcc/run-basilys.h @@ -0,0 +1,63 @@ +/* Basile's static analysis (should have a better name) run-basilys.h + all include files for generated code + + Copyright 2008 Free Software Foundation, Inc. + Contributed by Basile Starynkevitch <basile@starynkevitch.net> + Indented with GNU indent + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "obstack.h" +#include "tm.h" +#include "tree.h" +#include "tree-pass.h" +#include "tree-dump.h" +#include "basic-block.h" +#include "timevar.h" +#include "errors.h" +#include "ggc.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "flags.h" +#include "toplev.h" +#include "options.h" +#include "params.h" +#include "real.h" +#include "prefix.h" + +#include "compiler-probe.h" + + +#if HAVE_PARMAPOLY +#include <ppl_c.h> +#else +#error required parma polyedral library PPL +#endif /*HAVE_PARMAPOLY */ + +#if HAVE_LIBTOOLDYNL +#include <ltdl.h> +#else +#error required libtool dynamic loader library LTDL +#endif /*HAVE_LIBTOOLDYNL */ + +#include "basilys.h" diff --git a/gcc/system.h b/gcc/system.h index 568bd751a4c..8131d28aebd 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -349,6 +349,15 @@ extern int errno; #define WCOREFLG 0200 #endif + +/* the compiler probe */ +#if defined(ENABLE_COMPILER_PROBE) && ENABLE_COMPILER_PROBE +/* <unistd.h> and <fcntl.h> and <string.h> have already been included + and the following includes have been checked by autoconf */ +#include <sys/select.h> +#include <signal.h> +#endif + /* The HAVE_DECL_* macros are three-state, undefined, 0 or 1. If they are defined to 0 then we must provide the relevant declaration here. These checks will be in the undefined state while configure diff --git a/gcc/timevar.def b/gcc/timevar.def index e503894677b..6d9888b2425 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -192,5 +192,8 @@ DEFTIMEVAR (TV_SYMOUT , "symout") DEFTIMEVAR (TV_VAR_TRACKING , "variable tracking") DEFTIMEVAR (TV_TREE_IFCOMBINE , "tree if-combine") +/* Basilys needs */ +DEFTIMEVAR (TV_BASILE_ANALYSIS , "Basile's analysis") + /* Everything else in rest_of_compilation not included above. */ DEFTIMEVAR (TV_REST_OF_COMPILATION , "rest of compilation") diff --git a/gcc/toplev.c b/gcc/toplev.c index 512e0fb8708..7064c7e2876 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -32,6 +32,15 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include <signal.h> +/* Basilys needs the Parma Polyhedral Library & the Libtool dynamic loader */ +#if HAVE_PARMAPOLY +#include <ppl_c.h> +#endif + +#if HAVE_LIBTOOLDYNL +#include <ltdl.h> +#endif + #ifdef HAVE_SYS_RESOURCE_H # include <sys/resource.h> #endif @@ -81,6 +90,7 @@ along with GCC; see the file COPYING3. If not see #include "value-prof.h" #include "alloc-pool.h" #include "tree-mudflap.h" +#include "compiler-probe.h" #include "tree-pass.h" #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) @@ -100,6 +110,11 @@ along with GCC; see the file COPYING3. If not see declarations for e.g. AIX 4.x. */ #endif +/* we don't include basilys.h but declare its initializer here */ +#if HAVE_LIBTOOLDYNL && HAVE_PARMAPOLY +extern void basilys_initialize(void); /* in basilys.c */ +#endif + static void general_init (const char *); static void do_compile (void); static void process_options (void); @@ -1669,6 +1684,19 @@ general_init (const char *argv0) line_table->reallocator = realloc_for_line_map; init_ttree (); + /* Basilys needs PARMAPOLY & LIBTOOLDYNL */ +#if HAVE_PARMAPOLY + /* Initialize the Parma Polyhedra Library. */ + if (ppl_initialize () <0) + fatal_error ("failed to initialize Parma Polyedra Library"); +#endif + +#if HAVE_LIBTOOLDYNL + /* Initialize the Libtool Dynamic Loader */ + if (lt_dlinit() > 0) + fatal_error ("failed to initialize Libtool Dynamic Loader"); +#endif + /* Initialize register usage now so switches may override. */ init_reg_sets (); @@ -2242,6 +2270,12 @@ do_compile (void) if (!no_backend) backend_init (); +#if ENABLE_COMPILER_PROBE + /* just to be sure the probe loads the input file */ + (void) comprobe_file_rank(main_input_filename); +#endif + + /* Language-dependent initialization. Returns true on success. */ if (lang_dependent_init (main_input_filename)) compile_file (); @@ -2274,10 +2308,27 @@ toplev_main (unsigned int argc, const char **argv) init_local_tick (); +#if ENABLE_COMPILER_PROBE + /* Initialize the compiler probe (may install a SIGIO handler and + uses the random seed) */ + comprobe_initialize(); +#endif + +#if HAVE_LIBTOOLDYNL && HAVE_PARMAPOLY + /* initialize basilys if needed */ + if (flag_basilys) + basilys_initialize(); +#endif + /* Exit early if we can (e.g. -help). */ if (!exit_after_options) do_compile (); +#if ENABLE_COMPILER_PROBE + /* Finish the compiler probe (may wait) */ + comprobe_finish(); +#endif + if (errorcount || sorrycount) return (FATAL_EXIT_CODE); diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 1afbd1a8fc7..75288e991cb 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -609,7 +609,7 @@ addresses_taken (tree stmt) static inline tree phi_nodes (const_basic_block bb) { - gcc_assert (!(bb->flags & BB_RTL)); + gcc_assert (comprobe_bb_ok_rtl || !(bb->flags & BB_RTL)); if (!bb->il.tree) return NULL; return bb->il.tree->phi_nodes; @@ -620,7 +620,7 @@ phi_nodes (const_basic_block bb) static inline tree * phi_nodes_ptr (basic_block bb) { - gcc_assert (!(bb->flags & BB_RTL)); + gcc_assert (comprobe_bb_ok_rtl || !(bb->flags & BB_RTL)); return &bb->il.tree->phi_nodes; } @@ -631,7 +631,7 @@ set_phi_nodes (basic_block bb, tree l) { tree phi; - gcc_assert (!(bb->flags & BB_RTL)); + gcc_assert (comprobe_bb_ok_rtl || !(bb->flags & BB_RTL)); bb->il.tree->phi_nodes = l; for (phi = l; phi; phi = PHI_CHAIN (phi)) set_bb_for_stmt (phi, bb); @@ -711,7 +711,7 @@ phi_ssa_name_p (const_tree t) static inline tree bb_stmt_list (const_basic_block bb) { - gcc_assert (!(bb->flags & BB_RTL)); + gcc_assert (comprobe_bb_ok_rtl || !(bb->flags & BB_RTL)); return bb->il.tree->stmt_list; } @@ -720,7 +720,7 @@ bb_stmt_list (const_basic_block bb) static inline void set_bb_stmt_list (basic_block bb, tree list) { - gcc_assert (!(bb->flags & BB_RTL)); + gcc_assert (comprobe_bb_ok_rtl || !(bb->flags & BB_RTL)); bb->il.tree->stmt_list = list; } diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 01056827c07..06b38929b5c 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -343,6 +343,10 @@ extern struct tree_opt_pass pass_early_local_passes; extern struct tree_opt_pass pass_ipa_increase_alignment; extern struct tree_opt_pass pass_ipa_function_and_variable_visibility; +/* Basilys passes */ +extern struct tree_opt_pass pass_basilys; + + extern struct tree_opt_pass pass_all_optimizations; extern struct tree_opt_pass pass_cleanup_cfg_post_optimizing; extern struct tree_opt_pass pass_free_cfg_annotations; |