| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* LICENSE, LICENSE-CYG, METALICENSE, Makefile, alloca.h,
args.c, args.h, arith.c, arith.h, autoload.c, autoload.h,
buf.c, buf.h, cadr.c, cadr.h, chksum.c, chksum.h,
chksums/crc32.c, chksums/crc32.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, gzio.c,
gzio.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S,
lex.yy.c.shipped, lib.c, lib.h, linenoise/linenoise.c,
linenoise/linenoise.h, match.c, match.h, parser.c, parser.h,
parser.l, parser.y, protsym.c, psquare.h, rand.c, rand.h,
regex.c, regex.h, signal.c, signal.h, socket.c, socket.h,
stdlib/arith-each.tl, stdlib/asm.tl, stdlib/awk.tl,
stdlib/build.tl, stdlib/cadr.tl, stdlib/comp-opts.tl,
stdlib/compiler.tl, stdlib/constfun.tl, stdlib/conv.tl,
stdlib/copy-file.tl, stdlib/csort.tl, stdlib/debugger.tl,
stdlib/defset.tl, stdlib/doloop.tl, stdlib/each-prod.tl,
stdlib/error.tl, stdlib/except.tl, stdlib/expander-let.tl,
stdlib/ffi.tl, stdlib/getopts.tl, stdlib/getput.tl,
stdlib/glob.tl, stdlib/hash.tl, stdlib/ifa.tl,
stdlib/keyparams.tl, stdlib/load-args.tl, stdlib/match.tl,
stdlib/op.tl, stdlib/optimize.tl, stdlib/package.tl,
stdlib/param.tl, stdlib/path-test.tl, stdlib/pic.tl,
stdlib/place.tl, stdlib/pmac.tl, stdlib/quips.tl,
stdlib/save-exe.tl, stdlib/socket.tl, stdlib/stream-wrap.tl,
stdlib/struct.tl, stdlib/tagbody.tl, stdlib/termios.tl,
stdlib/trace.tl, stdlib/txr-case.tl, stdlib/type.tl,
stdlib/vm-param.tl, stdlib/with-resources.tl,
stdlib/with-stream.tl, stdlib/yield.tl, stream.c, stream.h,
struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h,
syslog.c, syslog.h, termios.c, termios.h, time.c, time.h,
tree.c, tree.h, txr.1, txr.c, txr.h, unwind.c, unwind.h,
utf8.c, utf8.h, vm.c, vm.h, vmop.h, win/cleansvg.txr,
y.tab.c.shipped: Copyright bumped to 2025.
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct): We must calculate the size
of a flexible structure the way GCC does it. We cannot simply
truncate it at the offset of the member. Rather, the size
is calculated in the usual way. The alignment of the array is
taken into account for the purpose of determining what is the
most aligned member of the structure, and then padding is
added, if required. Thus, the size may exceed the offset of
that member.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* lib.h (struct cobj_ops): New function pointer, clone.
(cobj_ops_init, cobj_ops_init_ex): Add clone argument to macros.
* lib.c (seq_iter_cobj_ops): Use copy_iter as the clone operation.
(cptr_ops): Use copy_cptr as clone operation.
(copy): Replace if statements by check whether COBJ has a clone
operation. If so, we use it to copy the object.
* struct.h (enum special_slot): New member, copy_m.
* struct.c (copy_s): New symbol variable.
(special_sym): Associate copy_m enum value with copy symbol.
(struct_init): Initialize copy_s with interned symbol.
(struct_inst_clone): New static function.
(struct_type_ops): Specify no clone operation via null pointer.
(struct_inst_ops): Specify struct_inst_clone as clone
operation.
* arith.c (psq_ops): Indicate no clone operation via null pointer.
* buf.c (buf_strm_ops): Likewise.
* chksum.c (sha1_ops, sha256_ops, md5_ops): Likewise.
* ffi.c (ffi_type_builtin_ops, ffi_type_struct_ops,
ffi_type_ptr_ops, ffi_type_enum_ops, ffi_closure_ops,
union_ops): Likewise.
(carray_borrowed_ops, carry_owned_ops, carray_mmap_ops):
Specify copy_carray as clone operation.
* gc.c (prot_array_ops): Indicate no clone operation via
null pointer.
* gzip.c (gzio_ops_rd, gzip_ops_wr): Likewise.
* hash.c (hash_iter_ops): Likewise.
(hash_ops): Specify copy_hash as clone operation.
* parser.c (parser_ops): Indicate no clone operation via
null pointer.
* rand.c (random_state_clone): New static function.
(random_state_ops): Use random_state_clone as clone function.
* regex.c (char_set_obj_ops, regex_obj_ops): Indicate no clone
operation via null pointer.
* socket.c (dgram_strm_ops): Likewise.
* stream.c (null-ops, stdio_ops, tail_ops, pipe_ops,
dir_ops, string_in_ops, byte_in_ops, strlist_in_ops,
string_out_ops, strlist_out_ops, cat_stream_ops,
record_adapter_ops): Likewise.
* strudel.c (strudel_ops): Likewise.
* sysif.c (cptr_dl_ops, opendir_ops): Likewise.
* syslog.c (syslog_strm_ops): Likewise.
* unwind.c (cont_ops): Likewise.
* vm.c (vm_desc_ops, vm_closure_ops): Likewise.
* tree.c (tree_ops): Use copy_search_tree for clone
operation.
(tree_iter_ops): Use copy_tree_iter for clone operation.
* genchksum.txr: Changes in chksum.c specified in one
place here.
* tests/012/oop.tl: Couple of new tests.
* txr.1: Documented.
|
|
|
|
|
|
|
| |
* ffi.c (mmap_wrap): Make the diagnostic depend on the actual
condition that it's wording is about. If the element type is
nonzero, but the length is too low for the array to have any
elements, that is not strictly an error; we can let that pass.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* LICENSE, LICENSE-CYG, METALICENSE, Makefile, alloca.h,
args.c, args.h, arith.c, arith.h, autoload.c, autoload.h,
buf.c, buf.h, cadr.c, cadr.h, chksum.c, chksum.h,
chksums/crc32.c, chksums/crc32.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, gzio.c,
gzio.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lib.c,
lib.h, linenoise/linenoise.c, linenoise/linenoise.h, match.c,
match.h, parser.c, parser.h, parser.l, parser.y, psquare.h,
rand.c, rand.h, regex.c, regex.h, signal.c, signal.h, socket.c,
socket.h, stdlib/arith-each.tl, stdlib/asm.tl, stdlib/awk.tl,
stdlib/build.tl, stdlib/cadr.tl, stdlib/compiler.tl,
stdlib/constfun.tl, stdlib/conv.tl, stdlib/copy-file.tl,
stdlib/csort.tl, stdlib/debugger.tl, stdlib/defset.tl,
stdlib/doloop.tl, stdlib/each-prod.tl, stdlib/error.tl,
stdlib/except.tl, stdlib/expander-let.tl, stdlib/ffi.tl,
stdlib/getopts.tl, stdlib/getput.tl, stdlib/glob.tl,
stdlib/hash.tl, stdlib/ifa.tl, stdlib/keyparams.tl,
stdlib/load-args.tl, stdlib/match.tl, stdlib/op.tl,
stdlib/optimize.tl, stdlib/package.tl, stdlib/param.tl,
stdlib/path-test.tl, stdlib/pic.tl, stdlib/place.tl,
stdlib/pmac.tl, stdlib/quips.tl, stdlib/save-exe.tl,
stdlib/socket.tl, stdlib/stream-wrap.tl, stdlib/struct.tl,
stdlib/tagbody.tl, stdlib/termios.tl, stdlib/trace.tl,
stdlib/txr-case.tl, stdlib/type.tl, stdlib/vm-param.tl,
stdlib/with-resources.tl, stdlib/with-stream.tl,
stdlib/yield.tl, stream.c, stream.h, struct.c, struct.h,
strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h,
termios.c, termios.h, time.c, time.h, tree.c, tree.h, txr.1,
txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h,
vmop.h, win/cleansvg.txr, y.tab.c.shipped:
Copyright year bumped to 2024.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Defining libpng bindings, with longjmp catching, is
now possible.
* autoload.c (ffi_set_entries): Add setjmp symbol, which is
a new macro in stdlib/ffi.tl.
* ffi.c (jmp_buf_s): New symbol variable.
(mk_jmp_buf, rt_setjmp, longjmp_wrap): New functions.
(ffi_init): Initialize jmp_buf_s. Register
sys:rt-setjmp and longjmp intrinsics.
* ffi.h (jmp_buf_s): Declared.
* stdlib/ffi.h (setjmp): New macro. Rather than introducing
a new special operator, we use a run-time support function
called sys:rt-setjmp, which takes functional arguments.
* unwind.[ch] (uw_snapshot, uw_restore): New functions.
The rt_setjmp function needs these to restore our unwind
frame stack into a sane state after catching a longjmp,
which bails without unwinding it, leaving the pointers
referring to frames that no longer exist.
* tests/017/setjmp.tl,
* tests/017/setjmp.expected: New files.
* txr.1: Documented.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The vargs typedef is underused. Let's use it consistently
everywhere.
* args.c,
* args.h,
* args.c,
* args.h,
* arith.c,
* eval.c
* ffi.c,
* gc.c,
* hash.c,
* lib.c,
* lib.h,
* parser.c,
* stream.c,
* struct.c,
* struct.h,
* syslog.c,
* syslog.h,
* unwind.c,
* vm.c,
* vm.h: All "struct args * declarations replaced with existing
"varg" typedef that comes from lib.h.
|
|
|
|
|
| |
* ffi.c (ffi_varray_null_term_get): An i variable is
initialized and incremented in a for loop, but never used.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I haven't reproduced a crash with this and --gc-debug
doesn't do it, possibly due to the use of setcheck
in the loop. But make_ffi_type_struct is doing something
wrong: it's creating new compiled type objects in a loop
and sticking them into the memb array, which is not
visible to the garbage collector.
* ffi.c (make_ffi_type_struct): We move the initialization
of ffi->memb to above the loop, so that the object points
to the array. The loop is already setting ft->nelem to
the correct value i + 1 on each iteration of the loop,
thereby revealing each newly populated entry to the garbage
collector.
|
|
|
|
|
|
|
|
|
| |
This is reproducible using
./txr --gc-debug tests/017/ffi-misc.tl
* ffi.c (ffi_enum_type_mark): We must mark the tft->eltype
because enumerations use that member.
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union,
ffi_type_compile): Use convert macro instead of C
cast notation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* LICENSE, LICENSE-CYG, METALICENSE, Makefile, alloca.h,
args.c, args.h, arith.c, arith.h, autoload.c, autoload.h,
buf.c, buf.h, cadr.c, cadr.h, chksum.c, chksum.h,
chksums/crc32.c, chksums/crc32.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, gzio.c,
gzio.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S,
lex.yy.c.shipped, lib.c, lib.h, linenoise/linenoise.c,
linenoise/linenoise.h, match.c, match.h, parser.c, parser.h,
parser.l, parser.y, protsym.c, psquare.h, rand.c, rand.h,
regex.c, regex.h, signal.c, signal.h, socket.c, socket.h,
stdlib/arith-each.tl, stdlib/asm.tl, stdlib/awk.tl,
stdlib/build.tl, stdlib/cadr.tl, stdlib/compiler.tl,
stdlib/constfun.tl, stdlib/conv.tl, stdlib/copy-file.tl,
stdlib/debugger.tl, stdlib/defset.tl, stdlib/doloop.tl,
stdlib/each-prod.tl, stdlib/error.tl, stdlib/except.tl,
stdlib/ffi.tl, stdlib/getopts.tl, stdlib/getput.tl,
stdlib/hash.tl, stdlib/ifa.tl, stdlib/keyparams.tl,
stdlib/match.tl, stdlib/op.tl, stdlib/optimize.tl,
stdlib/package.tl, stdlib/param.tl, stdlib/path-test.tl,
stdlib/pic.tl, stdlib/place.tl, stdlib/pmac.tl,
stdlib/quips.tl, stdlib/save-exe.tl, stdlib/socket.tl,
stdlib/stream-wrap.tl, stdlib/struct.tl, stdlib/tagbody.tl,
stdlib/termios.tl, stdlib/trace.tl, stdlib/txr-case.tl,
stdlib/type.tl, stdlib/vm-param.tl, stdlib/with-resources.tl,
stdlib/with-stream.tl, stdlib/yield.tl, stream.c, stream.h,
struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h,
syslog.c, syslog.h, termios.c, termios.h, time.c, time.h,
tree.c, tree.h, txr.1, txr.c, txr.h, unwind.c, unwind.h,
utf8.c, utf8.h, vm.c, vm.h, vmop.h, win/cleansvg.txr,
y.tab.c.shipped: Copyright year bumped to 2023.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* args.h (args_decl_list): This macro now handles only
constant values of N. It declares an anonyous container
struct type which juxtaposes the struc args header
with exactly N values. This is simply defined as a local
variable without alloca.
(args_decl_constsize): Like args_decl, but requiring a
constant N; implemented via args_decl_list.
(args_decl_list_dyn): New name for the old args_decl_list
which calls alloca. No places in the code depend on this
at all, except the definition of args_decl.
(args_decl): Retargeted to args_decl_list_dyn.
There is some inconsistency in the macro naming in that
args_decl_constsize depends on args_decl_list, and
args_decl depends on arg_decl_list_dyn. This was done
to minimize diffs. Most direct uses of args_decl_list
have a constant size, but a large number of args_decl
uses do not have a constant size.
* eval.c (op_catch): Use args_decl_constsize.
* ffi.c (ffi_struct_in, ffi_struct_get, union_out):
Likewise.
* ftw.c (ftw_callback): Likewise.
* lib.c (funcall, funcall1, funcall2, funcall3,
funcall4, uniq, relate): Likewise.
* socket.c (sockaddr_in_unpack, sockaddr_in6_unpack,
sockaddr_un_unpack):
Likewise.
* stream.c (formatv): Likewise.
* struct.c (struct_from_plist, struct_from_args,
make_struct_lit): Likewise.
* sysif.c (termios_unpack): Likewise.
* time.c (broken_time_struct): Likewise.
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct): Change uint to unsigned.
This is a typo, but a uint type is coming from somewhere.
I discovered this in an environment where there is no uint.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
On platforms with 64 bit pointers, and therefore 64-bit-wide
TXR values, we can use a representation technique which allows
double floating-point values to be unboxed.
Fixnum integers are reduced from 62 bits to 50, and there is
a little more complexity in the run-time type checking and
dispatch which costs extra cycles.
The support is currently off by default; it must be explicitly
enabled with ./configure --nan-boxing.
* lib.h (NUM_MAX, NUM_MIN, NUM_BIT): Define separately for
NaN boxing.
(TAG_FLNUM, TAG_WIDTH, NAN_TAG_BIT, NAN_TAG_MASK, TAG_BIGMASK,
TAG_BIGSHIFT, NAN_FLNUM_DELTA): New preprocessor symbols.
(enum type, type_t): The FLNUM enumeration constant moves
to just after LIT, so that its value is the same as TAG_FLNUM.
(struct flonum): Does not exist under NaN boxing.
(union obj): No fl member under NaN boxing.
(tag, is_ptr): Separately defined for NaN boxing.
(is_flo): New function under NaN boxing.
(tag_ex): New function. It's like tag, but identifies
floating-point values as TAG_FLNUM. The tag function continues
to map them to TAG_PTR, which is wrong under NaN boxing,
but needed in order not to separately write tons of cases in
the arith.c module.
(type): Use tag_ex, so TAG_FLNUM is handled, if it exists.
(auto_str, static_str, litptr, num_fast, chr, c_n, c_u):
Different definition for NaN boxing.
(c_ch, c_f): New function.
(throw_mismatch): Attribute with NORETURN.
(nao): Separate definition for NaN boxing.
* lib.c (seq_kind_tab): Reorder initializer to follow enum
reordering.
(seq_iter_rewind): use c_n and c_ch functions, since type
checking has been done in those cases. The self parameter
is no longer needed.
(iter_more): use c_ch on CHR object.
(equal): Use c_f accessor to get double value rather than
assuming there is a struct flonum representation.
(stringp): Use tag_ex, otherwise a floating-point number
is identified as TAG_PTR.
(diff, isec, isecp): Don't pass removed self parameter
to seq_iter_rewind.
* arith.c (c_unum, c_dbl_num, c_dbl_unum, plus, minus,
signum, gt, lt, ge, le, numeq, logand, logior,
logxor, logxor_old, bit, bitset, tofloat, toint,
width, c_num, c_fixnum): Extract floating-point value
using c_f accessor. Handle CHR type separately from NUM
because the storage representation is no longer identical;
CHR values have a two bit tag over bits where NUM has
ordinary value bits. NUM is tagged at the NaN level with
the upper 14 bits being 0xFFFC. The remaining 50 bits
are the value.
(flo): Construct unboxed float under NaN boxing by taking
image of double as a 64 bit value, and adding the
delta offset, then casting to the val pointer type.
(c_flo): Separate implementation for NaN boxing.
(integerp, numberp): Use tag_ex.
* buf.c (str_buf, buf_int): Separate CHR and NUM cases,
like in numerous arith.c functions.
* chksum.c (sha256_hash, md5_hash): Use c_ch accessor for
CHR value.
* hash.c (equal_hash, eql_hash): Handle CHR separately. Use
c_f accessor for floating-point value.
(eq_hash): Use tag_ex and handle TAG_FLNUM value under NaN
boxing. Handle CHR separately from NUM.
* ffi.c (ffi_float_put, ffi_double_put, carray_uint, carray_int):
Handle CHR and NUM separately.
* stream.c (formatv): Use c_f accessor.
* configure: disable automatic selection of NaN boxing
on 64 bit platforms, for now.
Add test whether -Wno-strict-aliasing is supported by
the compiler, performed only if NaN boxing is enabled.
We need to disable this warning because it goes off on
the code that reinterprets an integer as a double and
vice versa.
|
|
|
|
|
|
| |
* ffi.c (ffi_wchar_get): Reject wchar_t values that are
negative or beyond U+10FFFF; do not convert these to
a character.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We've already taken care of imitating the situation that GNU
C allows __attribute__((aligned(n))) to weaken the alignment
of a bitfield, contrary to it being documented that align only
strengthens alignment. Even a value of n == 1 is meaningful
in that it can cause the bitfield to start allocating from
a new byte.
This patch corrects a newly discovered nuance: when a bitfield
is attributed with a weaker alignment than its underlying
type (e.g. uint32_t field marked with 2 byte alignment),
the original type's alignment is still in effect for calculating
the alignment of the structure, and the padding.
* ffi.c (struct txr_ffi_type): New member oalign, for keeping
track of the type's original alignment, prior to adjustment.
(make_ffi_type_struct): For a named bitfield, take the oalign
value into account when determining the most strict member
alignment.
(ffi_type_compile): When marking a type as aligned, the
we remember the original alignment in atft->oalign.
* tests/017/bitfields.tl: New test case, struct s16.
* txr.1: Documented.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct): Add check for impossible condition.
The bits_alloc variable could only exceed bits_type (and thus
cause the room variable to have a nonsensical, large value)
if the bitfield allocation tried to continue allocating bits into
an aligned unit, whose alignment exceeds the size of the underlying
type. But in that case, tft->aligned would have to be true, and
so the offset would have been aligned prior to this code, rendering
bits_alloc zero.
* tests/017/bitfields.tl: New tests.
|
|
|
|
|
|
| |
* ffi.c (swap_get32, swap_put32, swap_get64, swap_put64):
correct implementations for operating on little-endian
words on big endian.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The bitfield allocation rules are wrong. Some of it is due
to the recent changes which are based on incorrect analysis,
but reverting things doesn't fix it.
The idea that we compare the current member's alignment
with the previous is wrong; it is not borne out by empirical
tests with gcc. So we do a straight revert of that.
In GNU C, an __attribute__((aligned (N))) attribute applied
to a bitfield member will perform the requested alignment if,
evidently, the bit field is already being placed into a new
byte. (If the bit field is about to be packed into an existing
byte, then there is a warning about the align attribute being
ignored). Because we don't have alignment as a member attribute,
but only as a type attribute, we must implement a flag which
indicates that a type has had align applied to it (even if
the alignment didn't change) so we can then honor this in the
right place in the bitfield allocation code.
* ffi.c (struct txr_ffi_type): New attribute flag, aligned.
(make_ffi_type_struct): Remove the prev_align variable and
all related logic. Consolidate all alignment into one place,
which is done before we allocate the bitfield or regular member.
We align if the new member isn't a bitfield, or even if it is
a bitfield if it has the aligned attribute, or if the bitfield
is changing endian compared to the previous member (our local
rule, not from GNU C).
(ffi_type_compile): The align and pack operators now set the
aligned attribute, except in the (pack 1 ...) case which
semantically denotes lack of alignment.
* tests/017/bitfields.tl: New file.
* txr.1: Documented.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is very nice: you can now declaratively match a structure
that uses bitfields, and comes from a different endian system.
* ffi.c (ffi_kind_t): Replace FFI_KIND_NUM type with FFI_KIND_INT,
FFI_KIND_UINT and FFI_KIND_FLO. Now using the tft->kind value,
we can distinguish integer and floating types, and determine
signedness.
(struct txr_ffi_type): New flag, bigendian, which is set to 1
for all big types that are big endian. This is not just the endian
types like be-int32, but natural types like int, if the underlying
platform is big endian.
(swap_get32, swap_put32, swap_get64, swap_put64): New static functions.
(ffi_generic_swap_fat_ubit_put, ffi_generic_swap_fat_sbit_put,
ffi_generic_swap_fat_ubit_get, ffi_generic_swap_fat_sbit_get,
ffi_generic_swap_ubit_put, ffi_generic_swap_sbit_put,
ffi_generic_swap_ubit_get, ffi_generic_swap_sbit_get): New
static functions.
(ffi_make_type_builtin): On big endian, set the bigendian flag on every
type. For the endian types, this will get adjusted as an additional
construction step.
(make_ffi_type_endian): New static function. Calls ffi_make_type_builtin,
and then initializes the bigendian flag with the given value.
(make_ffi_type_struct, make_ffi_type_union): Because bitfields can
have endiannness now, we can no longer refer to the machine's own
endianness in laying them out; we have to look at the mtft->bigendian
value. Furthermore, we need an additional rule: when a bitfield member
follows a member that has different endian, a new allocation unit
has to begin.
(ffi_type_compile): the sbit and ubit types must set the type to
FFI_KIND_INT and FFI_KIND_UINT now. For the big operator, we can
simplify the error checking: instead of exhaustively comparing the
type to all the supported integer types, we just now check whether
it is FFI_KIND_INT or FFI_KIND_UINT. Here, if we detect that an
endian bitfield has opposite byte order from the machine, then we
instantiate the bitfield with the ffi_generic_swap_* virtual
functions. These perform the required byte swapping accesses to
the bitfield storage cells, so then the bit field manipulation
code just works using the local integer representation (shifting
and masking). Of course, the shift amount depends on the endian;
and that is calculated at type creation time in make_ffi_type_struct.
(ffi_init_types): Replace FFI_KIND_NUM with the appropriate constant
for each affected type. In some cases, we have to calculate whether
to use the INT or UINT one, for the types whose signedness is
not specified. We switch all the endian types to new constructor
make_ffi_type_endian, passing the required value of the bigendian
flag.
* txr.1: Documented.
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union): We must
take fat bitfields into account when calculating mtft->shift
on big endian. We must subtract from bits_llint not bits_int
for big endian.
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_init_types): The be-float, be-double, le-float and
le-double types wrongly have integer indicated as their Lisp
type symbol; it should be float. This doesn't fix any actual bug;
the Lisp type is only important for structures/unions. The
conversion of be-double is driven by the behavior of the type's
virtual functions, which don't look at the Lisp type symbol.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_flex_struct_in): Function renamed to ffi_flex_array_len,
because its responsibility is determining the length of a flexible
array that is not null terminated. We don't pass in the structure's
type's descriptor any more, but the member descriptor.
(ffi_struct_in, ffi_struct_get): Follow rename and changed parameter
conventions.
* tests/017/flexstruct.tl: Added test case with nested flexible
structure.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_flex_struct_in): Check for the last member being
an array, and not null-terminated. We now check the character
conversion disposition of the array. If it has character
conversion, then we store the length right into the slot that
will become the string. In the no-conversion case, we assume
that if the member exists, it's a vector we can resize.
Otherwise we plant a vector of the required size.
(ffi_varray_put): Only call ffi_varray_dynsize if the Lisp
object is a vector. If the Lisp objecct is a number, then use
that as the size. Otherwise the size is zero.
* tests/017/flexstruct.tl: New file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_transform_pack): Fix: return the original syntax in
the situation when no cases are recognized, rather than
the cdr of the syntax. When the struct/union syntax has no
members, return the original syntax to indicate no transformation
took place.
* txr.1: Document the feature that pack on a typedef name or struct
name with no members will do the alignment adjustment only, without
the syntactic transformation.
* tests/017/pack-align.tl: New file.
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_compile): Allow align to weaken (lower) alignment
if compatibility 275 or lower is requested.
* txr.1: Compat note added.
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_pack_members): Static function removed.
(ffi_transform_pack): New static function.
(ffi_type_compile): Rely on ffi_transform_pack to recognize
and perform all necessary transformations.
Cosmetic issue: when a struct is compiled, and the individual
member types undergo transformation during member compilation,
the syntax for the struct is nevertheless the original one
with the untransformed members.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_copy, ffi_type_copy_new_ops): The cloned txr_ffi_type
structure must have a self member which points to the new cobj,
not the original one. Otherwise things are inconsistent. For instance
if the clone is being made for the purposes of adjusting alignment,
any operation which chases the self pointer will be accessing incorrect
attributes. One example of this is (alignof foo.bar) where if bar
is the clone of a type, this will incorrectly report the alignment of
the original from which bar was cloned, and the original alignment,
not the adjusted alignment is reported.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (pack_s): New symbol variable.
(ffi_type_compile): Handle new pack type operator together with
align. Allow a one-argument form of align and pack in which
the value is defaulted. The behavior of align changes: align
can only increase alignment now, never decrease, so for
instance (align 1 ...) does nothing. pack must be used to
decrease alignment. Furthermore, for certain argument types,
pack performs transformations of the type syntax, rather than
compiling the argument type and producing a variant of it with
altered alignment.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct): When a bitfield is declared for
a type whose alignment is different from that of the previous
member, then we start the new bitfield on a fresh alignment.
As usual, if the previous member is a bitfield which left a
partially filled byte, we skip to the next byte and then do the
alignment. This seems to match GCC behavior.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In gcc, bitfields can be declared with overridden alignment;
for instance when the entire structure is packed.
We must modify the algorithm to make this work.
Firstly, we must must pretend that we are filling from the start
of the containing alignment unit, not size based unit. For
instance, if the cell is an 8 byte type, but the alignment is 1,
then we are just filling the current byte, not the current 8 byte
multiple. However, the number of bits left (room) is still
calculated from the size: so if the byte has been filled with 3 bits,
we have 4 left in that byte, and then 7 more bytes, and so 61 bits.
Secondly, the case of the zero-bit field is special: it does
perform an alignment calculation in terms of multiples of the
size, ignoring the declared alignment of the field.
Thirdly, when the bits do not fit into the existing room, the
offset does not move by the size of the bitfield, but by the
alignment unit. For instance, if we have 63 bits left in an 8
byte field that has alignment 1, and we want to place 64 bits
into another 8 byte field, then we will just move to the next
byte, not to the next 64 bit cell. Starting at the next byte,
we pretend we have a fres 64 bit cell, albeit misaligned.
* ffi.c (make_ffi_type_struct): Make the above adjustments to
the algorithm. Some common values size, alignment, mask)
are declared in a wider scope and adjustments made.
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union): Initialize
most_align local variable to 1, so the lower bound of alignment
is that, rather than zero.
* tests/017/ffi-misc.tl: Tests added.
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union): Do not fall
back from the fat (64 bit) bitfield case to the regular (32 bit)
case when the number of bits is less than 32. This is completely
wrong.
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_compile): Show the original bitfield syntax
in the invalid size diagnostics. In the case of the (bit n type)
syntax, restrict the maximum bits to the width of the type,
not just to 32 or 64. I realize the 8 * tft->size calculation
can overflow for huge array types, but it makes no sense to use
them as bitfields.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (struct txr_ffi_type): Replace unsigned mask member
with a union m which holds unsigned mask and 64-bit fmask (fat
mask).
(ffi_sbit_put, ffi_sbit_get, ffi_ubit_put, ffi_ubit_get):
Refer to m.mask.
(ffi_fat_sbit_put, ffi_fat_sbit_get, ffi_fat_ubit_put,
ffi_fat_ubit_get): New static functions.
(ffi_generic_fat_sbit_put, ffi_generic_fat_sbit_get,
ffi_generic_fat_ubit_put, ffi_generic_fat_ubit_get):
Likewise.
(make_ffi_type_struct, make_ffi_type_union): Set up fat
mask for bitfields that are wider than int.
(ffi_type_compile): Refer to m.mask for the int and unsigned
int based bitfields declared with sbit and ubit that don't
mention a type. The bit operator now allows int64 and uint64
to be valid types for a bitfield. In this case, the "fat"
get and put functions are selected which use 64 bit operations.
Thus there is no efficiency impact on non-fat bitfields which
continue to use code with 32 bit operands.
(ffi_offsetof): Use the bitfield flag in the member's type
structure to detect bitfields, rather than the mask.
|
|
|
|
|
|
| |
ffi.c (ffi_init_extra_types): Use longlong_t and ulonglong_t, subject
to HAVE_LONGLONG_T. If there is no intmax_t and no longlong_t,
don't define intmax-t and uintmax-t.
|
|
|
|
|
|
| |
* ffi.c (ffi_generic_sbit_put, ffi_generic_sbit_get,
ffi_generic_ubit_put, ffi_generic_ubit_get): Replace int-sized
alloca with declared int object.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Because the varray behavior for undimensioned arrays was introduced
in dubious commit 7880c9b565ab438e1bf0250a967acdbf8d04cb42
in 2017, which used make_ffi_type_pointer to register the type,
claiming that the C representation is pointer (which was not true
in that commit, nor ever since).
As a result, though, undimensioned arrays received the alignment
of pointers, rather than deriving it from the element type.
Thus (array char) has 4 or 8 byte alignment whereas (array 4 char)
correctly has 1 byte alignment.
* ffi.c (ffi_type_compile): Use make_ffi_type_array for the two-element
array syntax, just like for the dimensioned case with three elements.
Then override some of the functions with the varray versions.
* tests/017/ffi-misc.tl: Fix the test case which exposed this.
In the type (struct flex (a char) (b (zarray char)), the array
b must be at offset 1. I didn't notice that the offset of 4
being confirmed by the test case was wrong, but this showed up
when running the test case on a platform with 8 byte pointers.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_char_array_get, ffi_zchar_array_get, ffi_wchar_array_get,
ffi_bchar_array_get): Rearrange so that we test for tft->null_term
first, and not nelem == 0. If nelem happens to be zero, but we are
supposed to decode a null-terminated string, we will do the wrong
thing and return the null string.
(ffi_varray_in): The body can't be conditional on vec being non-nil,
because then we do nothing if we don't have a Lisp object, which means
we skip the cases when we should decode a null-terminated array.
Now if vec is nil, we must guard against calling ffi_varray_dynsize.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (pad_retval): Remove the special case of zero mapping
to zero, which occurs when the return type is void. It's not
clear whether this is correct at all, on any platform. It
hasn't showed up as a problem until now, but on RISC-V,
we have hit a situation in which ffi_call writes a value into
that zero-byte space for the void return value, causing that
to overwrite values[0]: the first element of the argument
array. For reasons not understood, this happens in the qsort
test cases in which which the callback function performs a
block return. It is strange because the block return is
handled entirely in the closure dispatching function.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
These types actually make it possible to receive a string by
pointer from a C function, without trying to free it.
It is now possible to write a FFI wrapper for strtol or
wcstol, which is done in the new test case.
* ffi.c (str_s_s, bstr_s_s, wstr_s_s): New symbol variables.
(ffi_init_types): Register the types str-s, bstr-s and wstr-s.
(ffi_init): Intern the new symbols.
* tests/017/str-s.tl: New file.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
| |
* ffi.c (ffi_init_types): Move initialization of str-d type
from just before wstr to after, for consistency.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In FFI foreign function and closure calls, it behooves us to
iterate over the arguments in the opposite order after the
call is done. By doing that, any freeing of memory that will
be done will be in the opposite order. And that is necessary
if some left argument allocates a pointer that is shared with
a right argument. An example of this occurs in the strtol
function:
long int strtol(const char *nptr, char **endptr, int base);
Here, the function sets *endptr to a value derived by
displacing ptr. If we call this function via FFI, then FFI
will allocate memory for nptr. When the function returns,
if we destroy that memory before processing *endptr
then *endptr contains an invalid pointer.
* ffi.c (ffi_call_wrap): In the in pass, iterate arguments
in reverse.
(ffi_closure_dispatch, ffi_closure_dispatch_safe):
Stack-allocate an array for the argument types, so we don't
have to pop the list twice, and to allow access in reverse
order. In the out pass, iterate arguments in reverse.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* configure: detect intmax_t and place HAVE_INTMAX_T into
config.h.
* ffi.c (ffi_init_extra_types): register intmax-t and
uintmax-t types. If HAVE_INTMAX_T is missing, then make them
aliases for longlong and ulonglong.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* alloca.h (zalloca): Macro moved here from ffi.c; it's useful
to any code that wants to do a zero-filled alloca, and
socket.c needs it now.
* ffi.c (HAVE_SOCKETS): All includes conditional on HAVE_SOCKETS
removed.
(zalloca): Macro removed; moved to alloca.h.
(ffi_type_struct_checked, ffi_type_lookup): Static functions
changed to external linkage.
(ffi_type_size, ffi_type_put, ffi_type_get): New functions,
used by external module that has incomplete definition of
struct txr_ffi_type.
(type_by_size): New static array, moved out of
ffi_init_extra_types function.
(ffi_type_by_size): New function.
(ffi_init_extra_types): type_by_size array relocated to
file scope.
(sock_opt, sock_set_opt): Moved to socket.c, and adjusted to
use newly developed external access to needed ffi mechanisms.
(ffi_init): Numerous definitions related to sockets removed;
these go to socket.c.
* ffi.h (struct txr_ffi_type): Declared here now as
incomplete type.
(ffi_type_struct_checked, ffi_type_size, ffi_type_put,
ffi_type_get, ffi_type_lookup, ffi_type_by_size): Declared.
* lib.c (init): Call new function sock_init.
* socket.c (sock_opt, sock_set_opt): New functions, moved
from ffi.c, and slightly adapted to work with external
interfaces exposed by ffi.c.
(sock_init): New function. This performs unconditional
initializations not keyed to the lazy loading lisplib.c
mechanism. Here we create the socklen-t FFI type.
FFI types lookup doesn't trigger lazy loading, so we do it
this way; the alternative would be to introduce lazy load
triggering to FFI type lookup, just for this one type.
(sock_load_init): All the socket function and variable
registrations move here from ffi_init.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* arith.c (highest_significant_bit): Bugfix: do not pass a
negative value to highest_bit, where we will get then get the
wrong idea about the number of significant bits in the value,
since the __builtin_clz primitives will include the sign bit.
We want to complement the all the bits, so that the sign bit
will go to zero. We can do this arithmetically by taking the
additive inverse (which is the two's complement (which is the
complement plus one)) and subtracting one.
(ash): Avoid left shifting a negative number in HAVE_UBSAN
mode using the same trick as in num_fast.
* ffi.c (ffi_swap_u16): Here the shift and or calculation is
producing a value beyond 16 bits which we are relying on
the implicit conversion back to uin16_t to trim away.
We add the cast to uint16_t to make it explicit.
* hash.c (equal_hash): Also handle the CHR and NUM cases here
via c_u like in eql_hash and eq_hash.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (carray_replace): In the case when we replace a larger
range by a smaller one, when the upper part of the aray shifts
down, we are not correctly clearing to zeros the vacated part
of the array. The variable whole is a displacement from the
base of the array, not from ptr. Secondly, the copying loop
must go rom fr to below sn, not below vn; sn is derived from
vn but truncated not to go past the array.
* tests/017/carray.tl: New file. Several cases here fail
before this fix.
|
|
|
|
|
| |
* ffi.c (carray_sub, carray_replace): Allow t as from or to value, and
also implement the zero's end-of-range floating behavior.
|