From 07e35566e2a39a526cac877517d2856834b34359 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 8 Jun 2019 13:15:19 -0600 Subject: [PATCH] optimizer: repair `unsafe-mutable-hash-iterate-next` and similar Related to #2685 --- .../tests/racket/optimize.rktl | 29 +++++++++++++++++ racket/src/racket/src/list.c | 32 +++---------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/pkgs/racket-test-core/tests/racket/optimize.rktl b/pkgs/racket-test-core/tests/racket/optimize.rktl index 6959c90140..65fa30c495 100644 --- a/pkgs/racket-test-core/tests/racket/optimize.rktl +++ b/pkgs/racket-test-core/tests/racket/optimize.rktl @@ -3330,6 +3330,35 @@ '(lambda (x) 5) #f)) +(let () + ;; Although these are unsafe operations, they are obliged to + ;; raise an exception if the iteration value used to be + ;; ok and has become not ok due to a mutation (possibly + ;; by the GC to drop a weakly held key) + (define (check-keep-iterate op-name) + (test-comp `(lambda (ht i) (,op-name ht i) 5) + `(lambda (ht i) 5) + #f)) + (check-keep-iterate 'unsafe-mutable-hash-iterate-next) + (check-keep-iterate 'unsafe-weak-hash-iterate-next) + (check-keep-iterate 'unsafe-mutable-hash-iterate-key) + (check-keep-iterate 'unsafe-weak-hash-iterate-key) + (check-keep-iterate 'unsafe-mutable-hash-iterate-value) + (check-keep-iterate 'unsafe-weak-hash-iterate-value) + (check-keep-iterate 'unsafe-mutable-hash-iterate-key+value) + (check-keep-iterate 'unsafe-weak-hash-iterate-key+value) + (check-keep-iterate 'unsafe-mutable-hash-iterate-pair) + (check-keep-iterate 'unsafe-weak-hash-iterate-pair) + + (define (check-discard-iterate op-name) + (test-comp `(lambda (ht i) (,op-name ht i) 5) + `(lambda (ht i) 5))) + (check-discard-iterate 'unsafe-immutable-hash-iterate-next) + (check-discard-iterate 'unsafe-immutable-hash-iterate-key) + (check-discard-iterate 'unsafe-immutable-hash-iterate-value) + (check-discard-iterate 'unsafe-immutable-hash-iterate-key+value) + (check-discard-iterate 'unsafe-immutable-hash-iterate-pair)) + ;; Check elimination of ignored structure predicate ;; and constructor applications: diff --git a/racket/src/racket/src/list.c b/racket/src/racket/src/list.c index 1d037eb7f8..c0f0d2641f 100644 --- a/racket/src/racket/src/list.c +++ b/racket/src/racket/src/list.c @@ -967,11 +967,13 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-first", p, env); + /* For the rest, only immutable variants can have + SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL, because a key can disappear + from mutable variants and trigger an error. */ + /* unsafe-hash-iterate-next ---------------------------------------- */ p = scheme_make_immed_prim(unsafe_hash_table_iterate_next, "unsafe-mutable-hash-iterate-next", 2, 2); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL); scheme_addto_prim_instance ("unsafe-mutable-hash-iterate-next", p, env); p = scheme_make_immed_prim(unsafe_hash_tree_iterate_next, @@ -982,16 +984,11 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) p = scheme_make_immed_prim(unsafe_bucket_table_iterate_next, "unsafe-weak-hash-iterate-next", 2, 2); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_UNSAFE_FUNCTIONAL); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-next", p, env); /* unsafe-hash-iterate-key ---------------------------------------- */ p = scheme_make_noncm_prim(unsafe_hash_table_iterate_key, "unsafe-mutable-hash-iterate-key", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-mutable-hash-iterate-key", p, env); p = scheme_make_noncm_prim(unsafe_hash_tree_iterate_key, @@ -1003,17 +1000,11 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) p = scheme_make_noncm_prim(unsafe_bucket_table_iterate_key, "unsafe-weak-hash-iterate-key", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-key", p, env); /* unsafe-hash-iterate-value ---------------------------------------- */ p = scheme_make_noncm_prim(unsafe_hash_table_iterate_value, "unsafe-mutable-hash-iterate-value", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-mutable-hash-iterate-value", p, env); p = scheme_make_noncm_prim(unsafe_hash_tree_iterate_value, @@ -1025,18 +1016,12 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) p = scheme_make_noncm_prim(unsafe_bucket_table_iterate_value, "unsafe-weak-hash-iterate-value", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-value", p, env); /* unsafe-hash-iterate-key+value ---------------------------------------- */ p = scheme_make_prim_w_arity2(unsafe_hash_table_iterate_key_value, "unsafe-mutable-hash-iterate-key+value", 2, 3, 2, 2); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-mutable-hash-iterate-key+value", p, env); p = scheme_make_prim_w_arity2(unsafe_hash_tree_iterate_key_value, @@ -1050,18 +1035,12 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) p = scheme_make_prim_w_arity2(unsafe_bucket_table_iterate_key_value, "unsafe-weak-hash-iterate-key+value", 2, 3, 2, 2); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-key+value", p, env); /* unsafe-hash-iterate-pair ---------------------------------------- */ p = scheme_make_immed_prim(unsafe_hash_table_iterate_pair, "unsafe-mutable-hash-iterate-pair", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE_ALLOCATION - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-mutable-hash-iterate-pair", p, env); p = scheme_make_immed_prim(unsafe_hash_tree_iterate_pair, @@ -1074,9 +1053,6 @@ scheme_init_unsafe_hash (Scheme_Startup_Env *env) p = scheme_make_immed_prim(unsafe_bucket_table_iterate_pair, "unsafe-weak-hash-iterate-pair", 2, 3); - SCHEME_PRIM_PROC_FLAGS(p) |= - scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_OMITABLE_ALLOCATION - | SCHEME_PRIM_IS_UNSAFE_OMITABLE); scheme_addto_prim_instance ("unsafe-weak-hash-iterate-pair", p, env); }