summaryrefslogtreecommitdiffstats
path: root/gc.c
Commit message (Collapse)AuthorAgeFilesLines
* New data type: tnode.Kaz Kylheku2019-09-221-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Binary search tree nodes are being added as a basic heap data type. The C type tag is TNOD, and the Lisp type is tnode. Binary search tree nodes have three elements: a key, a left child and a right child. The printed notation is #N(key left right). Quasiquoting is supported: ^#N(,foo ,bar) but not splicing. Because tnodes have three elements, they they fit into TXR's four-word heap cell, not requiring any additional memory allocation. These nodes are going to be the basis for a binary search tree container, which will use the scapegoat tree algorithm for maintaining balance. * tree.c, tree.h: New files. * Makefile (OBJS): Adding tree.o. * eval.c (expand_qquote_rec): Recurse through tnode cells, so unquotes work inside #N syntax. * gc.c (finalize): Add TNOD to no-op case in switch; tnodes don't require finalization. (mark_obj): Traverse tnode cell. * hash.c (equal_hash): Add TNOD case. * lib.c (tnode_s): New symbol variable. (seq_kind_tab): New entry for TNOD, mapping to SEQ_NOTSEQ. (code2type, equal): Handle TNOD. (obj_init): Initialize tnode_s variable. (obj_print_impl, populate_obj_hash): Handle TNOD. (init): Call tree_init function in tree.c. * lib.h (enum type, type_t): New enumeration TNOD. (struct tnod): New struct type. (union obj, obj_t): New union member tn of type struct tnod. (tnode_s): Declard. * parserc.c (circ_backpatch): Handle TNOD, so circular notation works through tnode cells. * parser.l (grammar): Recognize #N prefix, mapping to HASH_N token. * parser.y (HASH_N): New grammar terminal symbol. (tnode): New nonterminal symbol. (i_expr, n_expr): Add tnode cases to productions. (yybadtoken): Map HASH_N to "#N" string.
* gc: align objects more strictly.Kaz Kylheku2019-09-121-3/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In this commit, we ensure that objects in the heap are aligned to at east eight byte boundaries (the minimum alignment from most malloc implementations on 32 and 64 bit systems). If possible, we align objects to a multiple of their size, sizeof (obj_t), which is 16 bytes on 32 bit platforms and 32 bytes on 64 bit platforms. We do this by making the object array the first field of the heap structure, and by allocating it with an aligned allocator function, if possible. * configure: detect memory alignment function: either memalign (preferred) or else posix_memalign (ugly duckling). We conditionally add either HAVE_MEMALIGN or HAVE_POSIX_MEMALIGN into config.h. * gc.c (OBJ_ALIGN): New macro. (struct heap, heap_t): Put the block member first, so objects are aligned with the containing heap. (in_heap): If the pointer is not aligned to a multiple of OBJ_ALIGN, it can't be a heap object; return zero. If allocations of the heap are aligned, then we don't need the additional alignment check in the loop body; if the pointer lands in the array, then the earlier OBJ_ALIGN check assures us it must be aligned. If we have only malloc alignment, we must do the check; the pointer could be to an address divisible by 8 which is in the middle of an obj_t. * lib.c: If HAVE_MEMALIGN is true, then include <malloc.h> so we have it declared. (memalign): If HAVE_POSIX_MEMALIGN is true, this static function is defined; it's compatible with the Glibc memalign. If HAVE_MEMALIGN and HAVE_POSIX_MEMALIGN are false, then memalign is defined as a malloc wrapper which doesn't align. (chk_malloc_gc_more): Use memalign instead of malloc. If aligned allocation is available, this will cause the heap to be aligned to a multiple of the object size.
* gc: bug in determining tight heap bounding box.Kaz Kylheku2019-09-121-2/+2
| | | | | | | | * gc.c (more): The heap_max_bound and heap_min_bound variables are initialized to null. We must update them unconditionally if they are in that state. What's happening otherwise is that heap_min_bound stays null and so we unnecessarily process false positives in the in_heap function.
* gc: remove #if 0 and #if 1.Kaz Kylheku2019-08-121-8/+0
| | | | | * gc.c (mark_obj): Remove material excluded by #if 1. (gc): Eliminate #if 0 block.
* sha256: recycle I/O buffer used in stream hash.Kaz Kylheku2019-07-041-0/+1
| | | | | | | | | | | | | * chksum.c (sha256_stream): Use iobuf_get and iobuf_put. * gc.c (gc): Do not mark the list of recycled buffers; just consider them to be garbage and clear the list, like we do with recycled conses via rcyc_empty. * stream.c (iobuf_free_list): New static variable. (iobuf_get, iobuf_put, iobuf_list_empty): New functions. * stream.h (iobuf_get, iobuf_put, iobuf_list_empty): Declared.
* internal debug support: reduce noise from sweep_one.Kaz Kylheku2019-06-191-1/+1
| | | | | | | | * gc.c (sweep_one): If the swept object matches the break_obj, only log it if the object isn't free. Otherwise if break_obj is sitting on the free list, we will uselessly report on it on every sweep operation, which is very often under --gc-debug torture operation.
* gc: bug: finalized objects not reclaimed.Kaz Kylheku2019-02-181-1/+11
| | | | | | | | | | | | | | | | | The problem: in an incremental GC run, when an generation 0 object is determined to be unreachable and has a registered finalizer, it ends up hanging around until a full GC. This is because it is marked as if it were reachable (just in case the finalizer re-introduces it into the object graph) and left to be processed at the next GC. However, what's missing is that the object is not in the freshobj array any more, and so it is not reclaimed by the sweep function. Effectively, it's as if the object had been promoted to gen 1. * gc.c (call_finalizers_impl): After invoking a finalizer, if the object is still in gen 0, add it to the freshobj array as if it had just been allocated. If there is no room in the freshobj array, set the full_gc flag, as usual.
* Copyright year bump 2019.Kaz Kylheku2019-01-161-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, buf.c, buf.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, ffi.c, ffi.h, filter.c, filter.h, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, protsym.c, rand.c, rand.h, regex.c, regex.h, share/txr/stdlib/asm.tl, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/compiler.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/doloop.tl, share/txr/stdlib/error.tl, share/txr/stdlib/except.tl, share/txr/stdlib/ffi.tl, share/txr/stdlib/getopts.tl, share/txr/stdlib/getput.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/keyparams.tl, share/txr/stdlib/op.tl, share/txr/stdlib/package.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/pmac.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/stream-wrap.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/tagbody.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/trace.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/vm-param.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl, signal.c, signal.h, socket.c, socket.h, stream.c, stream.h, struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h, vmop.h, win/cleansvg.txr: Extended Copyright line to 2018.
* Drastically reduce inclusion of <dirent.h>.Kaz Kylheku2018-12-111-1/+0
| | | | | | | | | | | | | | | | | | | The <dirent.h> header is included all over the place because it is needed by a single declaration in stream.h. That declaration is for a function that is only called within stream.c, so we make it internal. Now only stream.c has to include <dirent.h>. * buf.c, debug.c, eval.c, ffi.c, filter.c, gc.c, gencadr.txr, hash.c, lib.c, lisplib.c, match.c, parser.c, regex.c, socket.c, struct.c, strudel.c, sysif.c, syslog.c, termios.c, txr.c, unwind.c, vm.c: Remove #include <dirent.h>. * cadr.c: Regenerated. * stream.c (make_dir_stream): Make external function static. * stream.h (make_dir_stream): Declaration updated.
* type_check: take function name arg.Kaz Kylheku2018-11-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * arith.c (flo_int): Pass down name to type_check. * eval.c (copy_env, env_fbind, env_vbind, env_vb_to_fb, func_get_name, lexical_var_p, lexical_fun_p, lexical_lisp1_binding, squash_menv_deleting_range, op_upenv): Pass relevant Lisp function name to type_check. (lookup_global_var, lookup_sym_lisp1, lookup_fun, lookup_mac, lookup_symac, lookup_symac_lisp1): For these widely used functions, pass situational prefix in place of function name. They may get a funtion name argument in the future. * gc.c (gc_finalize): Pass function name to type_check. * lib.c (throw_mismatch): Take function nme argument, incorporate into mesage. (lcons_fun, c_flo, string_extend, symbol_name, symbol_package, get_package, package_name, func_get_form, func_get_env, func_set_env, vec_set_length, length_vec, size_vec, list_vec, lay_str_force, lay_str_force_upto, lazy_str_get_trailing_list, from, too, set_from, set_to): Pass relevant Lisp function name to type_check. (symbol_setname, symbol_visible): Pass indication of internal error into type_check, since this doesn't pertain to any Lisp function being wrong. * lib.h (throw_mismatch): Declaration updated. (type_check): Take new parameter and pass down to throw_mismatch. * signal.c (set_sig_handler): Pass name down to type_check.
* gc: eliminate most uses of gc_mutated.Kaz Kylheku2018-11-061-9/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The code is using gc_mutated in situations that resemble assignment: a value is stored into a slot in some object. These situations should be handled using the same logic as embodied in the gc_set function. This is because gc_set will consider both objects, and in many cases will not have to do anything special. E.g. if an immature object is stored into another immature object, or mature into immature, or mature into mature. Whereas gc_mutated is a "just in case" function which forces the garbage collector to traverse the indicated object, if that object is mature. In this patch we refactor gc_set to expose its underlying logic with a somewhat more flexible function called gc_assign_check. We put that behind a conditionally defined macro called setcheck, and then use that to replace invocations of the mut macro in various places. The only uses of gc_mutated that remain are in the bulk vector assignment and copy_struct: operations in which potentially many element values are migrated from one aggregate object to another, making it potentially expensive to do individual assignment checks. * gc.c (gc_assign_check): New function, formed from guts of gc_set. (gc_set): Now a trivial function, implemented via call to gc_assign_check. * gc.h (gc_assign_check): Declared. * lib.c (cons): Use setcheck instead of gc_mutated, since we are storing only two values into the existing cons: the car and the cdr. * struct.c (clear_struct): Use setcheck instead of gc_mutated, since we are just storing one value into the structure, the clear_val. The fact that we are storing it into multiple slots is irrelevant. * vm.c (vm_make_closure): Use setcheck instead of mut, using the new heap_vector as the child object with regard to the closure. Rationale: the only threat here is that when we allocate the heap vector, a GC is triggered which pushes the closure into the mature generation. Then the store of the heap vector into the closure is a wrong-way reference, with regard to generational GC. The elements in the vector are immaterial; they are older than both the closure and the vector, therefore their relationship to either object is a right-way reference. (vm_set, vm_sm_set): Replace mut by a setcheck between the vector from the display and the new value being stored in it. (vm_stab): Replace the gc_mutated check, which should have been a mut macro call, with a setcheck between the vm, and the binding being stored into the table. The gc_mutated should have been wrapped with an #if CONFIG_GEN_GC so we are fixing a build bug here: the code would have prevented TXR from being built with the generational GC disabled.
* gc: tail recurse on env rather than code.Kaz Kylheku2018-03-201-4/+5
| | | | | | | * gc.c (mark_obj): When marking functions, tail recurse on the environment. That's the pointer more likely to be a gateway to serious depth, rather than the vm description or interpreted function's source.
* vm: handle FVM function type thorughout run-time.Kaz Kylheku2018-03-161-1/+5
| | | | | | | | | | | | | | | | * gc.c (mark_obj): Recognize FVM functions and mark their vm_desc. * lib.c (equal): Handle equality for FVM. If the environment pointers are equal, consider the functions equal. (funcall, funcall1, funcall2, funcall3, funcall4): Recognize and call FVM functions. However, there is a lack of robustness here that needs to be addressed: vm_execute_closure doesn't check whether there are too many or not enough arguments. Interpreted functions have a run-time check inside bind_args. (obj_print_impl): Don't print VM functions as #<intrinsic fun...> but rather #<vm fun>.
* Copyright year bump 2018.Kaz Kylheku2018-02-151-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, buf.c, buf.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, ffi.c, ffi.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, protsym.c, rand.c, rand.h, regex.c, regex.h, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/doloop.tl, share/txr/stdlib/error.tl, share/txr/stdlib/except.tl, share/txr/stdlib/ffi.tl, share/txr/stdlib/getopts.tl, share/txr/stdlib/getput.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/keyparams.tl, share/txr/stdlib/op.tl, share/txr/stdlib/package.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/pmac.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/stream-wrap.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/tagbody.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl, signal.c, signal.h, socket.c, socket.h, stream.c, stream.h, struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, win/cleansvg.txr: Extended Copyright line to 2018.
* Port to aarch64 (ARM 8).Kaz Kylheku2017-08-161-1/+7
| | | | | | | | | | | | Continuations don't work yet. * gc.c (STACK_TOP_EXTRA_WORDS): New macro. (mark): On aarch64, we must include four words above the stack top. Some live root pointers sometimes hide there which are not in any of the callee-saved register that end up in the machine context via jmp_save. * jmp.S (jmp_save, jmp_restore): Implement for aarch64.
* gc: remove assertion from make_obj.Kaz Kylheku2017-07-191-1/+0
| | | | | | | * gc.c (make_obj): remove assertion that the object pulled from the free list is marked FREE. This hasn't proved to be valuable and adds a nonzero cost to a frequently executed path.
* ffi: sanity check on object in ffi_val_get.Kaz Kylheku2017-05-241-0/+14
| | | | | | | | | | | | | | | | | * ffi.c (ffi_val_get): Throw an exception if the object doesn't appear valid. * gc.c (valid_object_p): New function. Invalid objects are those that are pointers, but either not into a heap, or else to a freed object or to an object that is marked by the garbage collector (should only be seen while GC is running). All others are valid. There can be false positives here: a value with the LIT tag is in fact a pointer, but we don't check whether that is valid. * gc.c (valid_object_p): Declared. * txr.1: Remarks added to documentation of FFI val type.
* Splitting cptr object into separate CPTR tag.Kaz Kylheku2017-05-151-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | CPTR shares representation and a lot of implementation with COBJ. The COBJ class symbol is the CPTR type tag. There is no hierarchy among CPTR tags. The nil tag is used for a modicum of type looseness, so that we don't straitjacket ourselves too much into this tag-based typing scheme. All existing cptr objects are becoming CPTR, and all get a nil tag, except for dlopen library handles, and dlsym symbols, which are tagged as dlhandle and dlsym. The FFI framework will support tag-declared cptr's. This will help with safety. For instance, suppose an API has half a dozen different kinds of opaque handles. If they are all just cptr on the TXR Lisp side, it's easy to mix them up, passing the wrong one to the wrong C function. * lib.h (enum type): New enum member, CPTR. (cptr_print_op, cptr_typed, cptrp, cptr_type, cptr_handle): Declared. (cptr_addr_of): Parameters added. * lib.c (code2type): Map CPTR type code to cptr_s. (equal): Handle CPTR objects. They are only equal to other CPTR objects which have the same operations, and are equal under the equal function of those operations. (cptr_print_op): New function. (cptr_ops): Use cptr_print_op rather than cobj_print_op. (cptr_typed): New function. (cptr): Use cptr_typed to make a cptr with tag nil, rather than using cobj. (cptrp, cptr_handle, cptr_type): New functions. (cptr_get): Go through cptr_handle rather than cobj_handle. (cptr_addr_of, cptr_zap, cptr_free): Use call to cptr_handle rather than cobj_handle for the type checking side effect. New parameters for type and parent function name. (obj_print_impl): Handle CPTR with same case as COBJ. * gc.c (finalize, mark_obj): Handle CPTR cases using common code with COBJ. * hash.c (equal_hash): Handle CPTR just like COBJ. * eval.c (eval_init): Register cptrp and cptr-type intrinsic functions. * ffi.c (ffi_cptr_put, ffi_cptr_get, ffi_cptr_alloc): Use the potentially type-safe cptr_handle, instead of cptr_get. However, for an untagged cptr, there is no type safety because tft->mtypes is nil. The argument can be any kind of cptr. * sysif.c (dlhandle_s, dlsym_s): New symbol variables. (cptr_dl_ops): Use cptr_print_op. (dlopen_wrap, dlclose_wrap): Use typed cptr with dlhandle as the type. (dlsym_wrap, dlsym_checked, dlvsym_wrap, dlvsym_checked): Recognize only a cptr of type dlhandle for the library. Construct a typed cptr of type dlsym. (sysif_init): Initialize dlhandle_s and dlsym_s. Register dlsym function using dlsym_s.
* gc: bug in --free-all --vg-debug combination.Kaz Kylheku2017-05-131-1/+1
| | | | | | | | * gc.c (gc_free_all): Mark defined the current block being iterated, not the next one. Otherwise Valgrind generates numerous false errors from accesses to free objects in the first block. Not to mention that next is a null pointer in the last iteration.
* gc: use symbolic constants for special vec slots.Kaz Kylheku2017-05-121-4/+4
| | | | | | | * gc.c (mark_obj): The vector alloc size and length which lie at negative indices should be accessed using the index constants vec_alloc and vec_length, rather than -2 and -1.
* New buffer data type.Kaz Kylheku2017-04-161-1/+10
| | | | | | | | | | | | | | | | | | | | | | | Work in progress. * gc.c (finalize): Add cast to switch expression so gcc flags when we are missing one of the enumerations. Handle new BUF enum to free dynamic buffers. (mark_obj): Mark len and size fields of buf, in case they aren't just nil or integers. * hash.c (hash_buf): New static function. (equal_hash): Route BUF type to hash_buf. * lib.c (buf_s): New symbol variable. (code2type): Handle BUF. (equal): Handle BUF using memcmp on the data. (obj_init): Intern buf symbol and initialize buf_s. * lib.h (type_t): New enum member BUF. (struct buf): New type. (union obj): New member b, of struct buf type. (buf_s): Declared.
* call-finalizers: allow recursion.Kaz Kylheku2017-03-231-40/+41
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Code to invoke finalizers and remove them from the list is consolidated: both the gc and call-finalizers now use the same lower-level function. Finalizers may now themselves call-finalizers; it is no longer "unspecified behavior". This greatly improves the the TXR Lisp support for RAII, since :fini handlers of objects can call finalization on related objects. For instance a container being finalized can call the finalizers of contained objects. * gc.c (call_finalizers_impl): New function. Gathers all eligible finalizer registrations into a local list, first, removing them from the global list. Then does the calls in a second pass. Also, relative to the original functions which it replaces, this fixes an incorrect case: when the list is of length 1 and contains an eligible entry, in which case the global final_tail pointer is left aiming at a local variable! (is_reachable_final): New static function. (call_finalizers): Use call_finalizers_impl, specifying is_reachable_final as the predicate. (is_matching_final): New static function. (gc_call_finalizers): Use call_finalizers_impl, specifying is_matching_final as the predicate. * txr.1: Update documentation about call-finalizers.
* Rename badly named default_bool_argKaz Kylheku2017-03-171-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * lib.h (default_bool_arg): Inline function renamed to default_null_arg. * eval.c (if_fun, pad, ginterate, giterate, range_star, range, constantp, macroexpand_1, macro_form_p, expand_with_free_refs, do_expand, eval_intrinsic, func_get_name, make_env_intrinsic): Follow rename. * arith.c (lognot): Likewise. * gc.c (gc_finalize): Likewise. * glob.c (glob_wrap): Likewise. * hash.c (group_reduce, gethash_n): Likewise. * lib.c (print, multi_sort, lazy_str, vector, iff, tok_str, split_str_keep, search_str, remove_if, val): Likewise. * match.c (match_fun): Likewise. * parser.c (lisp_parse_impl, regex_parse): Likewise. * rand.c (make_random_state): Likewise. * regex.c (read_until_match, search_regex, regex_compile): Likewise. * socket.c (sock_accept, sock_connect): Likewise. * stream.c (open_files_star, open_files, run, open_process, open_tail, get_string, record_adapter): Likewise. * struct.c (static_slot_ensure, static_slot_ens_rec, clear_struct, make_struct_type): Likewise. * sysif.c (exec_wrap, errno_wrap, cobj_ops_init): Likewise. * unwind.c (uw_capture_cont, uw_find_frames_impl): Likewise.
* Bump copyright year to 2017.Kaz Kylheku2017-01-231-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, rand.c, rand.h, regex.c, regex.h, signal.c, signal.h, stream.c, stream.h, struct.c, struct.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/except.tl, share/txr/stdlib/getopts.tl, share/txr/stdlib/getput.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/package.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/tagbody.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl: Add 2017 to all copyright headers and strings.
* Cancel in-progress gc if handling async signal.Kaz Kylheku2016-12-121-1/+24
| | | | | | | | | | | | | | | | | | | | If a signal goes off in the middle of gc that is routed to an async lambda handler, we should cancel gc, so the handler finds the heap in a good state. Of course, the handler must not return in this case, or else the interrupted gc will try to resume. * gc.c (inprogress): New static flag. (gc): Increment and decrement inprogress variable. Abort if re-entered. (gc_inprogress): New function. (unmark): Do not clear FREE flags, only REACHABLE. (gc_cancel): New function. * gc.h (gc_inprogress, gc_cancel): Declared. * signal.c (sig_handler): In the async lambda case, check for an in-progress gc and cancel it.
* Adjust some gen-gc array sizes.Kaz Kylheku2016-11-151-2/+2
| | | | | | | | | | | | | | Tuning some parameters by experimenting with timings. * gc.c (CHECKOBJ_VEC_SIZE): Reduce to 2*HEAP_SIZE; this doesn't have to be equal in size to FRESHOBJ_VEC_SIZE; entries into the checkobj array are not expected to be as frequent as in the freshobj array. (MUTOBJ_VEC_SIZE): On the other hand, at HEAP_SIZE/4, this may be too small. Increasing to 2*HEAP_SIZE. Overall, the storage for these arrays is reduced by over 25%, with seemingly better performance.
* Implementing package foreign symbol concept.Kaz Kylheku2016-11-101-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): Register new intrinsics: package-local-symbols, package-foreign-symbols, use-sym, unuse-sym, use-package, unuse-package, unintern. * gc.c (mark_obj): Mark new hidhash member of struct package. * lib.c (make_package): Initialize new hidhash member of struct package. (lookup_package): New static function. (find_package): Allow string or symbol argument. (get_package): New static function. (delete_package, package_symbols): Use get_package for flexible package argument; delete_package removes symbols from other packages via unuse_package. (package_local_symbols, package_foreign_symbols): New functions. (use_sym, unuse_sym): New functions. (resolve_package_designators): New static function. (use_package, unuse_package): New functions. (symbol_present): New static function. (intern): Revised with get_package for flexible package argument. (unintern): New function. (rehome_sym): Use get_package. Semantics revised. (obj_print_impl): Use symbol_present function to determine whether object is visible in *package* and can be printed without a prefix, rather than naive home package test. * lib.h (struct package): New member, hidhash. (package_local_symbols, package_foreign_symbols, use_sym, unuse_sym, use_package, unuse_package, unintern): Declared. * txr.1: Documentation updated. Extended section introducing the design of packages, and argument conventions. New functions described. Existing function descriptions revised, particularly rehome-sym. Missing description of delete-package added.
* Synchronize license comments with LICENSE.Kaz Kylheku2016-10-011-16/+17
| | | | | | | | | | | | | | | | | | | | * Makefile, args.c, args.h, arith.c, arith.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, rand.c, rand.h, regex.c, regex.h, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/except.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl, signal.c, signal.h, socket.c, socket.h, stream.c, stream.h, struct.c, struct.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h: Revert to verbatim 2-Clause BSD.
* Rename EXTRA_DEBUGGING to CONFIG_EXTRA_DEBUGGING.Kaz Kylheku2016-06-171-5/+5
| | | | | | | | * configure: Generate #define CONFIG_EXTRA_DEBUGGING 1 in config.h header, rather than EXTRA_DEBUGGING. * gc.c, gc.h, hash.c: Change references to EXTRA_DEBUGGING preprocessor symbol to CONFIG_EXTRA_DEBUGGING.
* Print valgrind backtraces for break_obj.Kaz Kylheku2016-06-171-2/+28
| | | | | | | | | | | | * gc.c (more): Under EXTRA_DEBUGGING, call breakpt() here also, when it is detected that break_obj is added to the free list for the firts time. Print a message and backtrace using VALGRIND_PRINTF_BACKTRACE. (make_obj): Likewise, for an object that is pulled out of the free list and returned. (mark_obj, sweep_one): Print backtrace with Valgrind for break_obj, in addition to calling breakpt().
* Useful assertion in make_obj.Kaz Kylheku2016-06-171-0/+1
| | | | | * gc.c (make_obj): Assert that the object we are pulling from the free list is marked FREE.
* gc bugfix: maintain free_tail properly.Kaz Kylheku2016-06-161-5/+6
| | | | | | | | | | | | | * gc.c (more): Only set the free_tail if the new memory is being added to an empty free_list. Otherwise free_tail is valid. (make_obj): If we empty the free_list, then reset the free_tail pointer, so it doesn't continue pointing into the object we are returning. (sweep): Remove defensive code which tries to reset the free_tail in the empty free_list case, but assumes that free_tail is correct in the non-empty case.
* Remove more vestiges of the mark_makefresh hack.Kaz Kylheku2016-06-161-16/+3
| | | | | | | | | | * gc.c (sweep_one): Don't check for gen == -1; no reachable object can have that at this stage, since mark flips -1 objects to gen 0. (sweep): Do not clear freshobj_idx here; completely revert the mark_markfresh code. (gc): Clear freshobj_idx here., as before the mark_makefresh hack.
* New --free-all option for freeing memory on exit.Kaz Kylheku2016-06-071-0/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Although we are garbage-collected, being able to clean up on shutdown is nevertheless useful for uncovering leaks. Leaks can occur, for instance, due to neglect to free out-of-heap satellite data from objects that are reclaimed by gc. This feature is long overdue. * arith.c, arith.h (arith_free_all): New function. * gc.c, gc.h (gc_free_all): New function. * lib.c (init): Remove program name parameter and redundant initialization of progname globl variable. * lib.h (progname): Superfluous declaration removed. This is already declared in txr.h. (init): Declaration updated. * regex.c (char_set_destroy): Do not check the static allocation flag here; just destroy the object. Do check for a null pointer, though. (char_set_cobj_destroy): This cobj destructor now checks the static flag of the char set object and avoids freeing it. Thus our char set singletons are left alone by gc, but our global freeing function takes care of them. (wide_cs): New static variable moved out of wide_display_char_p to static scope. (regex_free_all): New function. * regex.h (regex_free_all): Declared. * txr.c (progname): const qualifier and initializer removed. (main): Ensure progname is always dynamically allocated, even in the argv[0] == 0 case. Do not pass progname to init; it doesn't take that argument any more. (free_all): New static function. (txr_main): Implement --free-all option. * txr.h (progname): Declaration updated.
* Fix incorrect comment.Kaz Kylheku2016-05-151-1/+1
| | | | | * gc.c (gc_set): Should say "promote obj to gen 1", not "to gen 0".
* Mechanism for recycling conses outside of GC.Kaz Kylheku2016-04-201-0/+1
| | | | | | | | | | | | * lib.c (recycled_conses): New static variable. (rcyc_pop, rcyc_cons, rcyc_list, rcyc_empty): New functions. (cons): Take a recycled cons, if available. * lib.h (rcyc_pop, rcyc_cons, rcyc_list, rcyc_empty): Declared. * gc.c (gc): Call rcyc_empty to make recycle_list unreachable.
* Replace all stray C style casts with macros.Kaz Kylheku2016-03-291-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * gc.c (gc_report_copies): C style casts found in this function. * linenoise.c (strip_qual, convert, coerce): Copy and paste the macros here. (record_undo, compare_completions, lino_add_completion, history_search, ab_append, sync_data_to_buf, refresh_singleline, screen_rows, refresh_multiline, find_nearest_paren, paren_jump, yank_sel, edit_move_matching_paren, edit, lino_make, lino_copy, lino_hist_add, lino_hist_set_max_len): C style casts replaced. * mpi/mpi-types.h (MP_DIGIT_BIT, MP_DIGIT_MAX, MP_WORD_BIT, MP_WORD_MAX, RADIX): C style casts replaced. * mpi/mpi.c (convert, coerce): Copy and paste the macros here. (mp_init_size, mp_init_copy, mp_copy, mp_set_int, mp_div_d, mp_bit, mp_to_double, mp_to_signed_bin, mp_to_unsigned_bin, mp_to_unsigned_buf, mp_toradix_case, mp_grow, s_mp_set_bit, s_mp_mod_2d, s_mp_mul_2d, s_mp_div_2d, s_mp_mul_d, s_mp_mul, s_mp_sqr, s_mp_div, s_mp_2expt, s_mp_todigit): C style casts replaced. * mpi/mplogic (convert): Macro copy and pasted here. (mpl_num_set, mpl_num_clear): C style casts replaced. * parser.c (provide_completions): Likewise. * signal.c (small_sigfillset): Likewise. * stream.c (stdio_truncate, test_set_indent_mode, set_indent_mode): Likewise.
* Use struct instead of cons for lazy string fields.Kaz Kylheku2016-01-091-2/+6
| | | | | | | | | | | | | | | | * gc.c (finalize): Must free the dynamic structure attached to the LSTR type now. (mark_obj): Must mark interior of LSTR type's props structure. * lib.c (lazy_sub_str, copy_lazy_str): Copy props structure. (lazy_str): Allocate and initialize props structure. (lazy_str_force, lazy_str_put, lazy_str_force_upto, lazy_str_get_trailing_list, out_lazy_str): Follow representation change. * lib.h (struct lazy_string_props): New struct type. (strut lazy_string): Member opts replaced with props pointer to struct lazy_string_props.
* Copyright year bump.Kaz Kylheku2015-12-311-1/+1
| | | | | | | | | | | | | | | | | | | | | | | * LICENSE, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, filter.c, filter.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, jmp.S, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, rand.c, rand.h, regex.c, regex.h, share/txr/stdlib/cadr.tl, share/txr/stdlib/except.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl, signal.c, signal.h, stream.c, stream.h, struct.c, struct.h, sysif.c, sysif.h, syslog.c, syslog.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h: Add 2016 copyright. * linenoise/LICENSE, linenoise/linenoise.c, linenoise/linenoise.h: Bump one principal author's copyright from 2014 to 2015. The code is based on a snapshot of 2015 upstream work.
* Useful debugging function for spurious retention.Kaz Kylheku2015-11-201-0/+12
| | | | | | * gc.c (gc_report_copies): New function * gc.h (gc_report_copies): Declared.
* Remove unused rel1 function.Kaz Kylheku2015-11-061-7/+0
| | | | | | * gc.c (rel1): Removed. * gc.h (rel1): Declaration removed.
* New range type, distinct from cons cell.Kaz Kylheku2015-11-011-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): Register intrinsic functions rcons, rangep from and to. (eval_init): Register rangep intrinsic. * gc.c (mark_obj): Traverse RNG objects. (finalize): Handle RNG in switch. * hash.c (equal_hash, eql_hash): Hashing for for RNG objects. * lib.c (range_s, rcons_s): New symbol variables. (code2type): Handle RNG type. (eql, equal): Equality for ranges. (less_tab_init): Table extended to cover RNG. (less): Semantics defined for ranges. (rcons, rangep, from, to): New functions. (obj_init): range_s and rcons_s variables initialized. (obj_print_impl): Produce #R notation for ranges. (generic_funcall, dwim_set): Recognize range objects for indexing * lib.h (enum type): New enum member, RNG. MAXTYPE redefined to RNG value. (TYPE_SHIFT): Increased to 5 since there are now 16 type codes. (struct range): New struct type. (union obj): New member rn, of type struct range. (range_s, rcons_s, rcons, rangep, from, to): Declared. (range_bind): New macro. * parser.l (grammar): New rule for recognizing the #R sequence as HASH_R token. * parser.y (HASH_R): New terminal symbol. (range): New nonterminal symbol. (n_expr): Derives the new range symbol. The n_expr DOTDOT n_expr rule produces rcons expression rather than const. * match.c (format_field): Recognize rcons syntax in fields which is now what ranges translate to. Also recognize range object. * tests/013/maze.tl (neigh): Fix code which destructures range as a cons. That can't be done any more. * txr.1: Document ranges.
* Expose memory region marking function.Kaz Kylheku2015-10-251-0/+5
| | | | | | * gc.c (gc_mark_mem): New function. * gc.h (gc_mark_mem): Declared.
* Stop using C library setjmp/longjmp.Kaz Kylheku2015-10-251-3/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | TXR is moving to custom assembly-language routines. This is mainly motivated by a very dubious thing done in the GNU C Library setjmp and longjmp in the name of security. Evidently, glibc's setjmp "mangles" certain pointer values which are stored into the jmp_buf buffer. It's been that way since 2005, evidently. This means that, firstly, all along, the use of setjmp in gc.c to get registers into a buffer so they can be scanned has not actually worked properly. More importantly, this pointer mangling in setjmp and longjmp is very hostile to a stack copying implementation of delimited continuations. The reason is that continuations contain jmp_buf buffers, which get relocated in the process of capturing and reviving a continuation. Any pointers in a jmp_buf which point into the captured stack segment have to be fixed up to point into the relocated location. Mangled pointers make this difficult, requiring hacks which are specific to glibc and the machine architecture. We might as well implement a clean, well-behaved setjmp and longjmp. * Makefile (jmp.o): New object file. (dbg/%.o, opt/%.o): New rules for .S prerequisites. * args.c, arith.c, cadr.c, combi.c, cadr.c, combi.c, debug.c, eval.c, filter.c, glob.c, hash.c, lib.c, match.c, parser.c, rand.c, regex.c, signal.c, stream.c, struct.c, sysif.c, syslog.c, txr.c, unwind.c, utf8.c: Removed <setjmp.h> include. * gc.c: Switch to struct jmp and jmp_save, instead of jmp_buf and setjmp. * jmp.S: New source file. * signal.h (struct jmp): New struct type. (jmp_save, jmp_restore): New function declarations denoting assembly language routines in jmp.S. (extended_jmp_buf): Uses struct jmp instead of setjmp. (extended_setjmp): Use jmp_save instead of setjmp. (extended_longjmp): Use jmp_restore instead of longjmp.
* New function: call-finalizers.Kaz Kylheku2015-10-061-0/+33
| | | | | | | | | * gc.c (gc_call_finalizers): New function. (gc_late_init): Register call-finalizers intrinsic. * gc.h (gc_call_finalizers): Declared. * txr.1: documented call-finalizers.
* Support for reverse order in finalization.Kaz Kylheku2015-10-011-5/+15
| | | | | | | | | | | | | | | | | | | | | | A new optional argument on finalize allows it to be expressed that multiple finalizers on the same object are to be called in reverse order, which is potentially for objects with inheritance. * gc.c (gc_finalize): New optional argument, rev_order_p. Insert at the head of the list if this argument is specified and true. (gc_late_init): Register finalize as three-argument function with optional argument. * gc.h (gc_finalize): Declaration updated. * share/txr/stdlib/struct.tl (defstruct): Register :fini functions in reverse, so that derived finalizers are called before supertype finalizers. * txr.1: Documented new finalize argument, and behavior of :fini.
* Full gc should be done if driven by malloc.Kaz Kylheku2015-09-271-0/+5
| | | | | | | | | * gc.c (gc): If the number of bytes malloced since the last gc exceeds the gc delta, we must do do a full garbage collection. The mature generation is almost certainly holding on to a lot of that memory. A test case for this is (lazy-str-force (lazy-str (get-lines (open-file "file")))). The file doesn't even have to be very large.
* Small optimization in finalization.Kaz Kylheku2015-09-091-1/+6
| | | | | | | | | | | | | * gc.c (prepare_finals): In the second pass, only mark objects that were identified in the first pass as unreachable. Reachable ones don't require a redundant call to mark_obj. Also, objects identified as unreachable can be moved to gen 0. This is something like what the mark_makefresh hack was trying to do. It only does anything in a full GC pass, because in an incremental pass, anything identified as unreachable is necessarily gen 0. It can help prevent some objects that are revived by finalization from sliding back to gen 1 and hanging around.
* Remove useless mark_makefresh hack.Kaz Kylheku2015-09-091-12/+1
| | | | | | | | | This contraption doesn't actually do anything. * gc.c (mark_makefresh): Static variable removed. (mark_obj): Remove logic conditional no mark_makefresh. (prepare_finals): Remove setting of mark_makefresh. (call_finals): Remove clearing of mark_makefresh.
* Finalization fix: incorrect for generational gc.Kaz Kylheku2015-09-091-17/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | Another bug found in the finalization hooks. The reachability test being applied is not correct for generational GC, relying only on the REACHABLE flag. This bug means that we call finalization hooks on mature objects, while they remain reachable. It must use the gc_is_reachable logic, just like weak hash table processing does, because under an incremental garbage collection pass, all gen 1 objects are considered reachable (though they don't have the REACHABLE flag set). * gc.c (struct fin_reg): Remving obj_type member, replacing with reachable flag. (is_reachable): New static function based on gc_is_reachable, minus the is_ptr test. (GC code which knows it is dealing with a pointer doesn't need the test). (prepare_finals): In the first pass, instead of memorizing the prior object type, simply calculate the reachable flag, correctly taking into account generational GC. (call_finals): Rely on the new reachable flag rather than the REACHABLE flag in the saved obj_type. (gc_is_reachable): Becomes a public wrapper for is_reachable which adds the pointer test. (gc_finalize): Initialize the reachable member of fin_reg. Remove initialization for obj_type.