add vector-cas! and unsafe-vector*-cas!

This commit is contained in:
Daniel Mendler 2017-10-25 00:47:12 +02:00 committed by Matthew Flatt
parent d8e2192145
commit bc26d29bf8
11 changed files with 870 additions and 753 deletions

View File

@ -12,7 +12,7 @@
(define collection 'multi) (define collection 'multi)
(define version "6.11.0.1") (define version "6.11.0.2")
(define deps `("racket-lib" (define deps `("racket-lib"
["racket" #:version ,version])) ["racket" #:version ,version]))

View File

@ -246,15 +246,17 @@ Unsafe versions of @racket[unbox] and @racket[set-box!], where the
@defproc[(unsafe-vector*-length [v (and/c vector? (not/c impersonator?))]) fixnum?] @defproc[(unsafe-vector*-length [v (and/c vector? (not/c impersonator?))]) fixnum?]
@defproc[(unsafe-vector*-ref [v (and/c vector? (not/c impersonator?))] [k fixnum?]) any/c] @defproc[(unsafe-vector*-ref [v (and/c vector? (not/c impersonator?))] [k fixnum?]) any/c]
@defproc[(unsafe-vector*-set! [v (and/c vector? (not/c impersonator?))] [k fixnum?] [val any/c]) void?] @defproc[(unsafe-vector*-set! [v (and/c vector? (not/c impersonator?))] [k fixnum?] [val any/c]) void?]
@defproc[(unsafe-vector*-cas! [v (and/c vector? (not/c impersonator?))] [k fixnum?] [val any/c] [val any/c]) boolean?]
)]{ )]{
Unsafe versions of @racket[vector-length], @racket[vector-ref], and Unsafe versions of @racket[vector-length], @racket[vector-ref],
@racket[vector-set!], where the @schemeidfont{vector*} variants can be @racket[vector-set!], and @racket[vector-cas!], where the @schemeidfont{vector*} variants can be
faster but do not work on @tech{impersonators}. faster but do not work on @tech{impersonators}.
A vector's size can never be larger than a @tech{fixnum}, so even A vector's size can never be larger than a @tech{fixnum}, so even
@racket[vector-length] always returns a fixnum.} @racket[vector-length] always returns a fixnum.
@history[#:changed "6.11.0.2" @elem{Added @racket[unsafe-vector*-cas!].}]}
@deftogether[( @deftogether[(
@defproc[(unsafe-string-length [str string?]) fixnum?] @defproc[(unsafe-string-length [str string?]) fixnum?]

View File

@ -72,6 +72,17 @@ slot is position @racket[0], and the last slot is one less than
Updates the slot @racket[pos] of @racket[vec] to contain @racket[v].} Updates the slot @racket[pos] of @racket[vec] to contain @racket[v].}
@defproc[(vector-cas! [vec (and/c vector? (not/c immutable?) (not/c impersonator?))]
[pos exact-nonnegative-integer?]
[v any/c]
[v any/c])
boolean?]{
Compare and set operation for vectors. See @racket[box-cas!].
@history[#:added "6.11.0.2"]
}
@defproc[(vector->list [vec vector?]) list?]{ @defproc[(vector->list [vec vector?]) list?]{
Returns a list with the same length and elements as @racket[vec].} Returns a list with the same length and elements as @racket[vec].}

View File

@ -1387,6 +1387,41 @@
(err/rt-test (box-cas! (chaperone-box (box 1) g g) 1 2)) (err/rt-test (box-cas! (chaperone-box (box 1) g g) 1 2))
(err/rt-test (box-cas! (box-immutable 1) 1 2))) (err/rt-test (box-cas! (box-immutable 1) 1 2)))
;; ----------------------------------------
;; vector-cas! tests
;; successful cas
(let ()
(define v (vector #f #t))
(test #t vector-cas! v 0 #f #t)
(test #t vector-ref v 0)
(test #t vector-cas! v 1 #t #f)
(test #f vector-ref v 1))
;; unsuccessful cas
(let ()
(define v (vector #f #t))
(test #f vector-cas! v 0 #t #f)
(test #f vector-ref v 0)
(test #f vector-cas! v 1 #f #t)
(test #t vector-ref v 1))
;; cas using allocated data
(let ()
(define v (vector '()))
(define x (cons 1 (vector-ref v 0)))
(test #t vector-cas! v 0 '() x)
(test x vector-ref v 0)
(test #t vector-cas! v 0 x '())
(test '() vector-ref v 0)
(test #f vector-cas! v 0 x '())
(test '() vector-ref v 0))
(let ([g (lambda (x y) y)])
(err/rt-test (vector-cas! (impersonate-vector (vector 1) g g) 0 1 2))
(err/rt-test (vector-cas! (chaperone-vector (vector 1) g g) 0 1 2))
(err/rt-test (vector-cas! (vector-immutable 1) 0 1 2)))
;; ---------------------------------------- ;; ----------------------------------------
(err/rt-test (sync/enable-break #f (make-semaphore 1))) (err/rt-test (sync/enable-break #f (make-semaphore 1)))

View File

@ -347,6 +347,20 @@
#:post (lambda (x) (list x (unbox b2))) #:post (lambda (x) (list x (unbox b2)))
#:literal-ok? #f)) #:literal-ok? #f))
(let ([v (vector 0 1)])
;; success
(test-tri (list #true 1)
'(lambda (v ov nv) (unsafe-vector*-cas! v 0 ov nv)) v 0 1
#:pre (lambda () (vector-set! v 0 0))
#:post (lambda (x) (list x (vector-ref v 0)))
#:literal-ok? #f)
;; failure
(test-tri (list #false 1)
'(lambda (v ov nv) (unsafe-vector*-cas! v 1 ov nv)) v 0 7
#:pre (lambda () (vector-set! v 1 1))
#:post (lambda (x) (list x (vector-ref v 1)))
#:literal-ok? #f))
(for ([star (list values (add-star "vector"))]) (for ([star (list values (add-star "vector"))])
(test-bin 5 (star 'unsafe-vector-ref) #(1 5 7) 1) (test-bin 5 (star 'unsafe-vector-ref) #(1 5 7) 1)
(test-un 3 (star 'unsafe-vector-length) #(1 5 7)) (test-un 3 (star 'unsafe-vector-length) #(1 5 7))

File diff suppressed because it is too large Load Diff

View File

@ -1874,12 +1874,12 @@ XFORM_SKIP_PROC
*/ */
if (!SCHEME_MUTABLE_BOXP(box)) { if (!SCHEME_MUTABLE_BOXP(box)) {
scheme_wrong_contract("box-cas!", "(and/c box? (not immutable?) (not impersonator?))", 0, 1, &box); scheme_wrong_contract("box-cas!", "(and/c box? (not/c immutable?) (not/c impersonator?))", 0, 1, &box);
} }
#ifdef MZ_USE_FUTURES #ifdef MZ_USE_FUTURES
return mzrt_cas((volatile size_t *)(&SCHEME_BOX_VAL(box)), return mzrt_cas((volatile uintptr_t *)(&SCHEME_BOX_VAL(box)),
(size_t)ov, (size_t)nv) (uintptr_t)ov, (uintptr_t)nv)
? scheme_true : scheme_false; ? scheme_true : scheme_false;
#else #else
/* For cooperative threading, no atomicity required */ /* For cooperative threading, no atomicity required */

View File

@ -14,8 +14,8 @@
#define USE_COMPILED_STARTUP 1 #define USE_COMPILED_STARTUP 1
#define EXPECTED_PRIM_COUNT 1159 #define EXPECTED_PRIM_COUNT 1160
#define EXPECTED_UNSAFE_COUNT 148 #define EXPECTED_UNSAFE_COUNT 149
#define EXPECTED_FLFXNUM_COUNT 69 #define EXPECTED_FLFXNUM_COUNT 69
#define EXPECTED_EXTFL_COUNT 45 #define EXPECTED_EXTFL_COUNT 45
#define EXPECTED_FUTURES_COUNT 15 #define EXPECTED_FUTURES_COUNT 15

View File

@ -532,6 +532,7 @@ extern Scheme_Object *scheme_make_vector_proc;
extern Scheme_Object *scheme_vector_immutable_proc; extern Scheme_Object *scheme_vector_immutable_proc;
extern Scheme_Object *scheme_vector_ref_proc; extern Scheme_Object *scheme_vector_ref_proc;
extern Scheme_Object *scheme_vector_set_proc; extern Scheme_Object *scheme_vector_set_proc;
extern Scheme_Object *scheme_vector_cas_proc;
extern Scheme_Object *scheme_list_to_vector_proc; extern Scheme_Object *scheme_list_to_vector_proc;
extern Scheme_Object *scheme_unsafe_vector_length_proc; extern Scheme_Object *scheme_unsafe_vector_length_proc;
extern Scheme_Object *scheme_unsafe_struct_ref_proc; extern Scheme_Object *scheme_unsafe_struct_ref_proc;
@ -4435,6 +4436,7 @@ Scheme_Object *scheme_checked_set_mcar (int argc, Scheme_Object *argv[]);
Scheme_Object *scheme_checked_set_mcdr (int argc, Scheme_Object *argv[]); Scheme_Object *scheme_checked_set_mcdr (int argc, Scheme_Object *argv[]);
Scheme_Object *scheme_checked_vector_ref(int argc, Scheme_Object **argv); Scheme_Object *scheme_checked_vector_ref(int argc, Scheme_Object **argv);
Scheme_Object *scheme_checked_vector_set(int argc, Scheme_Object **argv); Scheme_Object *scheme_checked_vector_set(int argc, Scheme_Object **argv);
Scheme_Object *scheme_checked_vector_cas(int argc, Scheme_Object **argv);
Scheme_Object *scheme_string_length(Scheme_Object *v); Scheme_Object *scheme_string_length(Scheme_Object *v);
Scheme_Object *scheme_string_eq_2(Scheme_Object *str1, Scheme_Object *str2); Scheme_Object *scheme_string_eq_2(Scheme_Object *str1, Scheme_Object *str2);
Scheme_Object *scheme_checked_string_ref(int argc, Scheme_Object *argv[]); Scheme_Object *scheme_checked_string_ref(int argc, Scheme_Object *argv[]);

View File

@ -13,12 +13,12 @@
consistently.) consistently.)
*/ */
#define MZSCHEME_VERSION "6.11.0.1" #define MZSCHEME_VERSION "6.11.0.2"
#define MZSCHEME_VERSION_X 6 #define MZSCHEME_VERSION_X 6
#define MZSCHEME_VERSION_Y 11 #define MZSCHEME_VERSION_Y 11
#define MZSCHEME_VERSION_Z 0 #define MZSCHEME_VERSION_Z 0
#define MZSCHEME_VERSION_W 1 #define MZSCHEME_VERSION_W 2
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -33,6 +33,7 @@ READ_ONLY Scheme_Object *scheme_make_vector_proc;
READ_ONLY Scheme_Object *scheme_vector_immutable_proc; READ_ONLY Scheme_Object *scheme_vector_immutable_proc;
READ_ONLY Scheme_Object *scheme_vector_ref_proc; READ_ONLY Scheme_Object *scheme_vector_ref_proc;
READ_ONLY Scheme_Object *scheme_vector_set_proc; READ_ONLY Scheme_Object *scheme_vector_set_proc;
READ_ONLY Scheme_Object *scheme_vector_cas_proc;
READ_ONLY Scheme_Object *scheme_list_to_vector_proc; READ_ONLY Scheme_Object *scheme_list_to_vector_proc;
READ_ONLY Scheme_Object *scheme_unsafe_vector_length_proc; READ_ONLY Scheme_Object *scheme_unsafe_vector_length_proc;
READ_ONLY Scheme_Object *scheme_unsafe_string_length_proc; READ_ONLY Scheme_Object *scheme_unsafe_string_length_proc;
@ -64,6 +65,7 @@ static Scheme_Object *unsafe_vector_set (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_vector_star_len (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_vector_star_len (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_vector_star_ref (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_vector_star_ref (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_vector_star_set (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_vector_star_set (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_vector_star_cas (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_struct_ref (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_struct_ref (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_struct_set (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_struct_set (int argc, Scheme_Object *argv[]);
static Scheme_Object *unsafe_struct_star_ref (int argc, Scheme_Object *argv[]); static Scheme_Object *unsafe_struct_star_ref (int argc, Scheme_Object *argv[]);
@ -133,6 +135,13 @@ scheme_init_vector (Scheme_Env *env)
SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED); SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED);
scheme_add_global_constant("vector-set!", p, env); scheme_add_global_constant("vector-set!", p, env);
REGISTER_SO(scheme_vector_cas_proc);
p = scheme_make_noncm_prim(scheme_checked_vector_cas,
"vector-cas!",
4, 4);
scheme_vector_cas_proc = p;
scheme_add_global_constant("vector-cas!", p, env);
scheme_add_global_constant("vector->list", scheme_add_global_constant("vector->list",
scheme_make_immed_prim(vector_to_list, scheme_make_immed_prim(vector_to_list,
"vector->list", "vector->list",
@ -232,6 +241,9 @@ scheme_init_unsafe_vector (Scheme_Env *env)
SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED); SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED);
scheme_add_global_constant("unsafe-vector*-set!", p, env); scheme_add_global_constant("unsafe-vector*-set!", p, env);
p = scheme_make_immed_prim(unsafe_vector_star_cas, "unsafe-vector*-cas!", 4, 4);
scheme_add_global_constant("unsafe-vector*-cas!", p, env);
REGISTER_SO(scheme_unsafe_struct_ref_proc); REGISTER_SO(scheme_unsafe_struct_ref_proc);
p = scheme_make_immed_prim(unsafe_struct_ref, "unsafe-struct-ref", 2, 2); p = scheme_make_immed_prim(unsafe_struct_ref, "unsafe-struct-ref", 2, 2);
scheme_unsafe_struct_ref_proc = p; scheme_unsafe_struct_ref_proc = p;
@ -633,6 +645,25 @@ scheme_checked_vector_set(int argc, Scheme_Object *argv[])
return scheme_void; return scheme_void;
} }
Scheme_Object *
scheme_checked_vector_cas(int argc, Scheme_Object *argv[])
{
Scheme_Object *vec = argv[0];
intptr_t i, len;
if (!SCHEME_MUTABLE_VECTORP(vec))
scheme_wrong_contract("vector-cas!", "(and/c vector? (not/c immutable?) (not/c impersonator?))", 0, argc, argv);
len = SCHEME_VEC_SIZE(vec);
i = scheme_extract_index("vector-cas!", 1, argc, argv, len, 0);
if (i >= len)
return bad_index("vector-cas!", "", argv[1], argv[0], 0);
return unsafe_vector_star_cas(argc, argv);
}
# define cons(car, cdr) scheme_make_pair(car, cdr) # define cons(car, cdr) scheme_make_pair(car, cdr)
Scheme_Object * Scheme_Object *
@ -1076,6 +1107,28 @@ static Scheme_Object *unsafe_vector_star_set (int argc, Scheme_Object *argv[])
return scheme_void; return scheme_void;
} }
static Scheme_Object *unsafe_vector_star_cas (int argc, Scheme_Object *argv[])
{
Scheme_Object *vec = argv[0];
Scheme_Object *idx = argv[1];
Scheme_Object *ov = argv[2];
Scheme_Object *nv = argv[3];
#ifdef MZ_USE_FUTURES
return mzrt_cas((volatile uintptr_t *)(SCHEME_VEC_ELS(vec) + SCHEME_INT_VAL(idx)),
(uintptr_t)ov, (uintptr_t)nv)
? scheme_true : scheme_false;
#else
/* For cooperative threading, no atomicity required */
if (SCHEME_VEC_ELS(vec)[SCHEME_INT_VAL(idx)] == ov) {
SCHEME_VEC_ELS(vec)[SCHEME_INT_VAL(idx)] = nv;
return scheme_true;
} else {
return scheme_false;
}
#endif
}
static Scheme_Object *unsafe_struct_ref (int argc, Scheme_Object *argv[]) static Scheme_Object *unsafe_struct_ref (int argc, Scheme_Object *argv[])
{ {
if (SCHEME_CHAPERONEP(argv[0])) if (SCHEME_CHAPERONEP(argv[0]))