don't reorder some unsafe expressions that can depend on an effect

For example, an `unsafe-unbox` call should not be moved past the
call to an unknown function that might change a box's content.

Thanks to Sergey Pinaev for the report.
This commit is contained in:
Matthew Flatt 2016-12-23 08:00:13 -07:00
parent 5a4391dd90
commit 88aa7fdeff
3 changed files with 15 additions and 3 deletions

View File

@ -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))

View File

@ -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;

View File

@ -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: */