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:
parent
5a4391dd90
commit
88aa7fdeff
|
@ -1026,6 +1026,15 @@
|
||||||
(set! x x))))
|
(set! x x))))
|
||||||
#f)
|
#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
|
(test-comp '(module m racket/base
|
||||||
(define (true) #t)
|
(define (true) #t)
|
||||||
(define no (if (true) (lambda (x) (cons x 'no)) display))
|
(define no (if (true) (lambda (x) (cons x 'no)) display))
|
||||||
|
|
|
@ -72,7 +72,8 @@ struct Optimize_Info
|
||||||
/* Propagated up and down the chain: */
|
/* Propagated up and down the chain: */
|
||||||
int size;
|
int size;
|
||||||
int vclock; /* virtual clock that ticks for a side effect, a branch,
|
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);
|
previous guard on an unsafe operation's argument);
|
||||||
the clock is only compared between binding sites and
|
the clock is only compared between binding sites and
|
||||||
uses, so we can rewind the clock at a join after an
|
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 */
|
unsafe operation is defined */
|
||||||
{
|
{
|
||||||
if (SCHEME_PRIMP(rator)
|
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)->mina)
|
||||||
&& (n <= ((Scheme_Primitive_Proc *)rator)->mu.maxa))
|
&& (n <= ((Scheme_Primitive_Proc *)rator)->mu.maxa))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -81,7 +81,8 @@
|
||||||
#define SCHEME_PRIM_IS_NARY_INLINED (1 << 2)
|
#define SCHEME_PRIM_IS_NARY_INLINED (1 << 2)
|
||||||
/* indicates that a primitive call can be dropped if it's result is not used;
|
/* 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
|
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)
|
#define SCHEME_PRIM_IS_UNSAFE_OMITABLE (1 << 3)
|
||||||
/* indicates that a primitive call can be dropped if it's result is not used,
|
/* 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: */
|
because it has no side-effect and never raises an exception: */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user