diff --git a/pkgs/racket-test-core/tests/racket/optimize.rktl b/pkgs/racket-test-core/tests/racket/optimize.rktl index f9d9d35278..ef985a25ca 100644 --- a/pkgs/racket-test-core/tests/racket/optimize.rktl +++ b/pkgs/racket-test-core/tests/racket/optimize.rktl @@ -1026,6 +1026,15 @@ (set! x x)))) #f) +;; Don't move a side-effecting experssion past an unsafe operation +;; that observes effects: +(test-comp '(lambda (b f) + (let* ([x (f (lambda () b))]) + (cons (unsafe-unbox b) x))) + '(lambda (b f) + (cons (unsafe-unbox b) (f (lambda () b)))) + #f) + (test-comp '(module m racket/base (define (true) #t) (define no (if (true) (lambda (x) (cons x 'no)) display)) diff --git a/racket/src/racket/src/optimize.c b/racket/src/racket/src/optimize.c index 1dc433dd45..fd26ba58be 100644 --- a/racket/src/racket/src/optimize.c +++ b/racket/src/racket/src/optimize.c @@ -72,7 +72,8 @@ struct Optimize_Info /* Propagated up and down the chain: */ int size; int vclock; /* virtual clock that ticks for a side effect, a branch, - or a dependency on an earlier side-effect (such as a + observation of a side effect (such as an unbox), + or a dependency on an earlier side effect (such as a previous guard on an unsafe operation's argument); the clock is only compared between binding sites and uses, so we can rewind the clock at a join after an @@ -2983,7 +2984,8 @@ static int is_nonmutating_nondependant_primitive(Scheme_Object *rator, int n) unsafe operation is defined */ { if (SCHEME_PRIMP(rator) - && (SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_OMITABLE_ALLOCATION)) + && ((SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_OMITABLE_ALLOCATION)) + && !(SCHEME_PRIM_PROC_OPT_FLAGS(rator) & (SCHEME_PRIM_IS_UNSAFE_OMITABLE))) && (n >= ((Scheme_Primitive_Proc *)rator)->mina) && (n <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)) return 1; diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index 9121f4f180..16e765b0c8 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -81,7 +81,8 @@ #define SCHEME_PRIM_IS_NARY_INLINED (1 << 2) /* indicates that a primitive call can be dropped if it's result is not used; although the function never raises an exception, it should not be reordered - past a test that might be a guard: */ + past a test that might be a guard or past an expression that might + have a side effect: */ #define SCHEME_PRIM_IS_UNSAFE_OMITABLE (1 << 3) /* indicates that a primitive call can be dropped if it's result is not used, because it has no side-effect and never raises an exception: */