* libguile/array-handle.c (initialize_vector_handle): Add mutable_p
argument. Unless the vector handle is mutable, null out its
writable_elements member.
(scm_array_get_handle): Adapt to determine mutability of the various
arrays.
(scm_array_handle_elements, scm_array_handle_writable_elements):
Reverse the sense: instead of implementing read-only in terms of
read-write, go the other way around, adding an assertion in the
read-write case that the array handle is mutable.
* libguile/array-map.c (racp): Assert that the destination is mutable.
* libguile/bitvectors.c (SCM_F_BITVECTOR_IMMUTABLE, IS_BITVECTOR):
(IS_MUTABLE_BITVECTOR): Add a flag to indicate immutability.
(scm_i_bitvector_bits): Fix indentation.
(scm_i_is_mutable_bitvector): New helper.
(scm_array_handle_bit_elements)
((scm_array_handle_bit_writable_elements): Build writable_elements in
terms of elements.
(scm_bitvector_elements, scm_bitvector_writable_elements): Likewise.
(scm_c_bitvector_set_x): Require a mutable bitvector for the
fast-path.
(scm_bitvector_to_list, scm_bit_count): Use read-only elements()
function.
* libguile/bitvectors.h (scm_i_is_mutable_bitvector): New decl.
* libguile/bytevectors.c (INTEGER_ACCESSOR_PROLOGUE):
(INTEGER_GETTER_PROLOGUE, INTEGER_SETTER_PROLOGUE):
(INTEGER_REF, INTEGER_NATIVE_REF, INTEGER_SET, INTEGER_NATIVE_SET):
(GENERIC_INTEGER_ACCESSOR_PROLOGUE):
(GENERIC_INTEGER_GETTER_PROLOGUE, GENERIC_INTEGER_SETTER_PROLOGUE):
(LARGE_INTEGER_NATIVE_REF, LARGE_INTEGER_NATIVE_SET):
(IEEE754_GETTER_PROLOGUE, IEEE754_SETTER_PROLOGUE):
(IEEE754_REF, IEEE754_NATIVE_REF, IEEE754_SET, IEEE754_NATIVE_SET):
Setters require a mutable bytevector.
(SCM_BYTEVECTOR_SET_FLAG): New helper.
(SCM_BYTEVECTOR_SET_CONTIGUOUS_P, SCM_BYTEVECTOR_SET_ELEMENT_TYPE):
Remove helpers.
(SCM_VALIDATE_MUTABLE_BYTEVECTOR): New helper.
(make_bytevector, make_bytevector_from_buffer): Use
SCM_SET_BYTEVECTOR_FLAGS.
(scm_c_bytevector_set_x, scm_bytevector_fill_x)
(scm_bytevector_copy_x): Require a mutable bytevector.
* libguile/bytevectors.h (SCM_F_BYTEVECTOR_CONTIGUOUS)
(SCM_F_BYTEVECTOR_IMMUTABLE, SCM_MUTABLE_BYTEVECTOR_P): New
definitions.
* libguile/bytevectors.h (SCM_BYTEVECTOR_CONTIGUOUS_P): Just access one
bit.
* libguile/srfi-4.c (DEFINE_SRFI_4_C_FUNCS): Implement
writable_elements() in terms of elements().
* libguile/strings.c (scm_i_string_is_mutable): New helper.
* libguile/uniform.c (scm_array_handle_uniform_elements):
(scm_array_handle_uniform_writable_elements): Implement
writable_elements in terms of elements.
* libguile/vectors.c (SCM_VALIDATE_MUTABLE_VECTOR): New helper.
(scm_vector_elements, scm_vector_writable_elements): Implement
writable_elements in terms of elements.
(scm_c_vector_set_x): Require a mutable vector.
* libguile/vectors.h (SCM_F_VECTOR_IMMUTABLE, SCM_I_IS_MUTABLE_VECTOR):
New definitions.
* libguile/vm-engine.c (VM_VALIDATE_MUTABLE_BYTEVECTOR):
(VM_VALIDATE_MUTABLE_VECTOR, vector-set!, vector-set!/immediate)
(BV_BOUNDED_SET, BV_SET): Require mutable bytevector/vector.
* libguile/vm.c (vm_error_not_a_mutable_bytevector):
(vm_error_not_a_mutable_vector): New definitions.
* module/system/vm/assembler.scm (link-data): Mark residualized vectors,
bytevectors, and bitvectors as being read-only.
Benchmark:
(define type #t)
(define A (make-typed-array 's32 0 10000 1000))
(define B (make-typed-array 's32 0 10000 1000))
(define C (make-typed-array 's32 0 10000 1000))
before:
scheme@(guile-user)> ,time (array-map! C + A B)
;; 0.792653s real time, 0.790970s run time. 0.000000s spent in GC.
after:
scheme@(guile-user)> ,time (array-map! C + A B)
;; 0.598513s real time, 0.597146s run time. 0.000000s spent in GC.
* libguile/array-map.c (ramap): Add special case with 3 arguments.
This patch results in a 20%-40% speedup in the > 1 argument cases of
the following microbenchmarks:
(define A (make-shared-array #0(1) (const '()) #e1e7))
; 1, 2, 3 arguments.
(define a 0) ,time (array-for-each (lambda (b) (set! a (+ a b))) A)
(define a 0) ,time (array-for-each (lambda (b c) (set! a (+ a b c))) A A)
(define a 0) ,time (array-for-each (lambda (b c d) (set! a (+ a b c d))) A A A)
(define A (make-shared-array (make-array 1) (const '()) #e1e7))
(define B (make-shared-array #0(1) (const '()) #e1e7))
; 1, 2, 3 arguments.
,time (array-map! A + B)
,time (array-map! A + B B)
,time (array-map! A + B B B)
* libguile/array-map.c (scm_ramap): Note on cproc arguments.
(rafill): Assume that dst's lbnd is 0.
(racp): Assume that src's lbnd is 0.
(ramap): Assume that ra0's lbnd is 0. When there're more than two
arguments, compute the array handles before the loop. Allocate the arg
list once and reuse it in the loop.
(rafe): Do as in ramap(), when there's more than one argument.
(AREF, ASET): Remove.
* libguile/root.h:
* libguile/root.c: Remove these files.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_internal_cwdr, scm_call_with_dynamic_root)
(scm_dynamic_root, scm_apply_with_dynamic_root): Deprecate.
Remove all root.h usage, which was vestigial.
* module/ice-9/serialize.scm: Use (current-thread) instead
of (dynamic-root).
* libguile/array-map.c
- (scm_array_index_map_x): preallocate the index list instead of
constructing it on each rank-1 iteration.
- (ramap, rafe): use SCM_I_ARRAY_V just once.
* libguile/array-map.c: (scm_ramapc)
- Don't check emptiness while preparing ra0, but only after kroll is known,
and only before kroll. len = 0 will be caught by the unrolled loop.
- Use ra0 axis length in unroll check depth for rest args, not ra1's.
- Recover early exit feature when cproc returns 0.
* libguile/array-map.c
- (scm_ramapc): mismatched axes limit unrollk (kroll). Reorganize
the function to do all checking as we go.
- (scm_ra_matchp): unused; remove.
- (find_unrollk): inlined in scm_ramapc; remove.
- (klen): inlined in scm_ramapc; remove.
- (rafill): n is size_t.
- (racp): n is size_t. Use n and not i0end to bound the loop.
- (ramap): Use n and not i0end to bound the loop. This is needed for the rank
0 case to work with the new scm_ramapc, as inc may be set to 0 in that case.
- (rafe): idem.
* test-suite/tests/ramap.test
- check that size mismatch prevents unrolling (matching behavior III) with
both array-copy! and array-map!.
- check that non-contiguous stride in non-ref args prevents unrolling
(rank 2, discontinuous) with both array-copy! and array-map!.
- check rank 0 cases with array-for-each, array-map!.
- Test the 0-inc, non empty case for both array-map! and array-copy!.
* libguile/array-map.c
- (cind): replace by cindk, that operates only on the unrolled index set.
- (klen): new function.
- (make1array): take extra inc argument.
- (scm_ramapc): rewrite to unroll as many axes as possible instead of just all
or one.
- (AREF): lbnd is known to be 0: remove.
- (ASET): v is known to come from SCM_I_ARRAY_V; assume base, inc, lbnd.
- (racp): use ssize_t instead of long for the indices.
- (scm_array_index_map_x): build the index list at the last-but-one axis, then
set the car of the last element, instead of building the list at the last axis.
* test-suite/tests/ramap.test
- add array-map! test with offset arguments.
This special case improves
(define a (make-array 1. 1000000 10))
(define b (make-array *unspecified* 1000000 10))
(define c (transpose-array (make-array *unspecified* 10 1000000) 1 0))
,time (array-copy! a b)
,time (array-copy! a c)
from 0.041598s / 0.072561 to 0.012164s / 0.041886s on a i7-3930K.
* libguile/array-map.c: (racp): if both src and dst are on vectors, use
the element pointers to do the copy.
* libguile/array-handle.h (scm_t_vector_ref, scm_t_vector_set): Rename
from scm_t_array_ref, scm_t_array_set. These were named
scm_i_t_array_ref and scm_i_t_array_set in 1.8 and 2.0. Change to
take the vector directly, instead of the array handle. In this way,
generic array handles are layered on top of specific implementations
of backing stores.
Remove scm_t_array_implementation, introduced in 2.0 but never
documented. It was a failed attempt to layer the array implementation
that actually introduced too many layers, as it prevented the "vref"
and "vset" members of scm_t_array_handle (called "ref" and "set" in
1.8, not present in 2.0) from specializing on array backing stores.
(scm_i_register_array_implementation) (scm_i_array_implementation_for_obj):
Remove these internal interfaces.
(scm_t_array_handle): Adapt to scm_t_vector_ref / scm_t_vector_set
change.
(scm_array_handle_ref, scm_array_handle_set): Adapt to change in
vref/vset prototype.
* libguile/array-handle.c (scm_array_get_handle): Inline all the
necessary initializations here for all specific array types.
* libguile/array-map.c (rafill, racp, ramap, rafe, array_index_map_1):
* libguile/arrays.c: Remove array implementation code.
* libguile/bitvectors.h:
* libguile/bitvectors.c: Remove array implementation code.
(scm_i_bitvector_bits): New internal interface.
* libguile/bytevectors.c: Remove array implementation code.
* libguile/srfi-4.h: Remove declarations for internal procedures that
don't exist (!).
* libguile/strings.c: Remove array implementation code.
* libguile/vectors.c: Remove array implementation code.
* libguile/array-map.c
- scm_ra_matchp: look for empty axes and return new case 5 if so. Use
array handles to remove the SCM_I_ARRAYP / not branch.
- scm_ramapc: Heed case 5.
* test-suite/tests/ramap.test
- test empty arguments for array-copy! and array-for-each. Note those
that failed in 2.0.9.
* libguile/array-map.c: (scm_array_index_map_x): bail out if any one of the
axes is empty.
* test-suite/tests/ramap.test: add tests for empty array-case of
array-index-map!. The 'f64 case with not-last emtpy axis is broken in 2.0.9.
* libguile/array-map.c
- rafill, ramap, rafe, racp: object from SCM_I_ARRAY_V always
has base 0, lbnd 0 and inc 1; make use of this.
* libguile/arrays.c
- array_handle_ref, array_handle_set: idem.
- array_get_handle: sanity check.
* libguile/generalized-vectors.c
- scm_c_generalized_vector_ref, scm_c_generalized_vector_set_x:
pos should be base when idx is lbnd. Furthermore, pos should be signed and
have its overflow checked; do this by handling the job to
scm_c_array_ref_1, scm_c_array_set_1_x.
* libguile/generalized-vectors.h
- fix prototypes.
* libguile/array-map.c (scm_ra_matchp): Refactor logic a bit.
(array_index_map_1, array_index_map_n)
(scm_array_index_map_x): Internally refactor array-index-map! to use
separate implementations for rank 1 versus rank >1 arrays.
* libguile/array-map.c: new function rafill, like scm_array_fill_int,
but factors GVSET out of the loop. Use it in scm_array_fill_x instead of
scm_array_fill_int.
* test-suite/tests/arrays.test: add test for array-fill! with stride != 1.
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
* libguile/array-map.c: (racp): factor scm_generalized_vector_ref,
scm_generalized_vector_set_x out of the rank-1 loop.
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
* libguile/tags.h (scm_tc7_array): Allocate a tag for arrays.
* libguile/arrays.h (SCM_I_ARRAYP): Change to use scm_tc7_array. The
previous definition was not externally usable because scm_i_tc16_array
was internal.
(scm_i_print_array): Declare, though internally.
* libguile/arrays.c (scm_i_make_array): Use scm_cell with the tc7
instead of NEWSMOB.
(scm_i_print_array): Make not static.
(SCM_ARRAY_IMPLEMENTATION): Adapt.
(scm_init_arrays): Remove array smob declaration.
* libguile/eq.c (scm_equal_p): Refactor to put the string, pointer, and
bytevector cases in the switch. Add a case for arrays.
* libguile/goops.c: Add <array> declarations.
* libguile/print.c (iprin1): Call scm_i_print_array as needed.
* libguile/evalext.c (scm_self_evaluating_p): Add a case for arrays.
* libguile/array-map.c (array_compare, scm_array_equal_p): Rewrite as
something that operates on the generic array handle infrastructure.
Based on array->list.
(scm_i_array_equal_p): Change the docs, as array-equal? is now the same
as equal?, except that it typechecks its args.
* doc/ref/api-compound.texi (Array Procedures): Update array-equal?
docs.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_raequal): Deprecate.
* libguile/bytevectors.c (scm_bytevector_eq_p): Bugfix: bytevectors are
bytevector=? only if their element type is the same.
* libguile/eq.c (scm_equal_p): Only dispatch to scm_array_equal_p if
both args are arrays (generically).
* test-suite/tests/arrays.test ("equal?"): Add some more tests.
OK let's try again. While the thanks go to Daniel Llorens del Río for
the tip, the blame continues going to me :)
* test-suite/Makefile.am:
* test-suite/tests/arrays.test: Add a test.
* libguile/array-map.c (raeql): Handle a few 0-dimensional cases. If the
shapes of the arrays don't match, just return #f instead of raising
an error.
* libguile/root.h
* libguile/root.c (scm_sys_protects): It used to be that for some reason
we'd define a special array of "protected" values. This was a little
silly, always, but with the BDW GC it's completely unnecessary. Also
many of these variables were unused, and none of them were good API.
So remove this array, and either eliminate, make static, or make
internal the various values.
* libguile/snarf.h: No need to generate calls to scm_permanent_object.
* guile-readline/readline.c (scm_init_readline): No need to call
scm_permanent_object.
* libguile/array-map.c (ramap, rafe): Remove the dubious nullvect
optimizations.
* libguile/async.c (scm_init_async): No need to init scm_asyncs, it is
no more.
* libguile/eval.c (scm_init_eval): No need to init scm_listofnull, it is
no more.
* libguile/gc.c: Make scm_protects a static var.
(scm_storage_prehistory): Change the sanity check to use the address
of protects.
(scm_init_gc_protect_object): No need to clear the scm_sys_protects,
as it is no more.
* libguile/keywords.c: Make the keyword obarray a static var.
* libguile/numbers.c: Make flo0 a static var.
* libguile/objprop.c: Make object_whash a static var.
* libguile/properties.c: Make properties_whash a static var.
* libguile/srcprop.h:
* libguile/srcprop.c: Make scm_source_whash a global with internal
linkage.
* libguile/strings.h:
* libguile/strings.c: Make scm_nullstr a global with internal linkage.
* libguile/vectors.c (scm_init_vectors): No need to init scm_nullvect,
it's unused.
* libguile/tags.h: Remove rpsubrs (I chose to interpret the terse name
as "recursive predicate subrs"). Just use gsubrs with rest arguments,
or do a fold yourself.
* libguile/array-map.c (scm_i_array_equal_p): Do the comparison in
order, why not.
* libguile/chars.c:
* libguile/eq.c:
* libguile/numbers.c:
* libguile/strorder.c: Add 0,2,1 gsubr wrappers for rpsubrs like eq?, <,
etc.
* libguile/goops.c (scm_class_of)
* libguile/procprop.c (scm_i_procedure_arity)
* libguile/procs.c (scm_thunk_p)
* libguile/vm.c (apply_foreign): Remove rpsubr cases.
* test-suite/tests/numbers.test ("=", "<"): Turn a couple xfails into
passes.
* libguile/tags.h (scm_tcs_subrs, scm_tc7_asubr): Remove definitions.
* libguile/goops.c (scm_class_of)
* libguile/procprop.c (scm_i_procedure_arity)
* libguile/procs.c (scm_thunk_p)
* libguile/vm.c (apply_foreign): Remove cases for asubrs.
* libguile/array-map.c: Gut all of the optimizations, because there are
no more asubrs, soon won't be rpsubrs, and all of this should happen
on the Scheme level, ideally.
* libguile/tags.h: Remove scm_tc7_dsubr. There are no more users of
this.
* libguile/array-map.c:
* libguile/eval.c:
* libguile/eval.i.c:
* libguile/goops.c:
* libguile/procprop.c:
* libguile/procs.h: Remove all dsubr cases.
* libguile/tags.h: Remove tc7 #defines for subrs, replacing them with
placeholders. These were public, but hopfully unused. I don't see how
to usefully deprecate them.
* libguile/array-map.c (scm_array_map_x): Remove special cases for
certain subr types. This might make things slower for the moment,
otoh, native compilation should moot that question.
* libguile/eval.i.c:
* libguile/eval.c: Remove subr-handling cases. To regain this speed and
more won't have to wait for native compilation, though -- this change
smooths the way for subr dispatch in the VM.
* libguile/gsubr.c (scm_i_gsubr_apply): Fix a bug in which we didn't
detect too-many-arguments. This would only show up when using ceval,
as only ceval called this function.
* test-suite/tests/ramap.test ("array-map!"): Change the expected
exception if passed a procedure of the wrong arity. It now gives
wrong-num-args.
more won't have to wait for native compilation, though -- this change
smooths the way for subr dispatch in the VM.
* libguile/goops.c (scm_class_of): Remove subr cases. No speed
implication.
* libguile/objects.c (scm_valid_object_procedure_p): Remove this public
but undocumented, and useless, function. I do not think this will
affect anyone at all.
(scm_set_object_procedure_x): Replace a call to
scm_valid_object_procedure_p with scm_procedure_p, and actually wrap
with a scm_is_true.
* module/oop/goops.scm (initialize-object-procedure): Don't call
valid-object-procedure?.