2012-04-12 16:25:45 -07:00
|
|
|
;;; Effects analysis on Tree-IL
|
|
|
|
|
|
2013-03-02 19:04:47 +01:00
|
|
|
;; Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
|
2012-04-12 16:25:45 -07:00
|
|
|
|
|
|
|
|
;;;; This library is free software; you can redistribute it and/or
|
|
|
|
|
;;;; modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
;;;; License as published by the Free Software Foundation; either
|
|
|
|
|
;;;; version 3 of the License, or (at your option) any later version.
|
|
|
|
|
;;;;
|
|
|
|
|
;;;; This library is distributed in the hope that it will be useful,
|
|
|
|
|
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
;;;; Lesser General Public License for more details.
|
|
|
|
|
;;;;
|
|
|
|
|
;;;; You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
;;;; License along with this library; if not, write to the Free Software
|
|
|
|
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
|
|
(define-module (language tree-il effects)
|
|
|
|
|
#:use-module (language tree-il)
|
|
|
|
|
#:use-module (language tree-il primitives)
|
|
|
|
|
#:use-module (ice-9 match)
|
|
|
|
|
#:export (make-effects-analyzer
|
|
|
|
|
&mutable-lexical
|
|
|
|
|
&toplevel
|
|
|
|
|
&fluid
|
|
|
|
|
&definite-bailout
|
|
|
|
|
&possible-bailout
|
|
|
|
|
&zero-values
|
|
|
|
|
&allocation
|
|
|
|
|
&mutable-data
|
|
|
|
|
&type-check
|
|
|
|
|
&all-effects
|
|
|
|
|
effects-commute?
|
|
|
|
|
exclude-effects
|
|
|
|
|
effect-free?
|
|
|
|
|
constant?
|
|
|
|
|
depends-on-effects?
|
|
|
|
|
causes-effects?))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Hey, it's some effects analysis! If you invoke
|
|
|
|
|
;;; `make-effects-analyzer', you get a procedure that computes the set
|
|
|
|
|
;;; of effects that an expression depends on and causes. This
|
|
|
|
|
;;; information is useful when writing algorithms that move code around,
|
|
|
|
|
;;; while preserving the semantics of an input program.
|
|
|
|
|
;;;
|
|
|
|
|
;;; The effects set is represented by a bitfield, as a fixnum. The set
|
|
|
|
|
;;; of possible effects is modelled rather coarsely. For example, a
|
|
|
|
|
;;; toplevel reference to FOO is modelled as depending on the &toplevel
|
|
|
|
|
;;; effect, and causing a &type-check effect. If any intervening code
|
|
|
|
|
;;; sets any toplevel variable, that will block motion of FOO.
|
|
|
|
|
;;;
|
|
|
|
|
;;; For each effect, two bits are reserved: one to indicate that an
|
|
|
|
|
;;; expression depends on the effect, and the other to indicate that an
|
|
|
|
|
;;; expression causes the effect.
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
(define-syntax define-effects
|
|
|
|
|
(lambda (x)
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
((_ all name ...)
|
|
|
|
|
(with-syntax (((n ...) (iota (length #'(name ...)))))
|
|
|
|
|
#'(begin
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-syntax name (identifier-syntax (ash 1 (* n 2))))
|
2012-04-12 16:25:45 -07:00
|
|
|
...
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-syntax all (identifier-syntax (logior name ...)))))))))
|
2012-04-12 16:25:45 -07:00
|
|
|
|
|
|
|
|
;; Here we define the effects, indicating the meaning of the effect.
|
|
|
|
|
;;
|
|
|
|
|
;; Effects that are described in a "depends on" sense can also be used
|
|
|
|
|
;; in the "causes" sense.
|
|
|
|
|
;;
|
|
|
|
|
;; Effects that are described as causing an effect are not usually used
|
|
|
|
|
;; in a "depends-on" sense. Although the "depends-on" sense is used
|
|
|
|
|
;; when checking for the existence of the "causes" effect, the effects
|
|
|
|
|
;; analyzer will not associate the "depends-on" sense of these effects
|
|
|
|
|
;; with any expression.
|
|
|
|
|
;;
|
|
|
|
|
(define-effects &all-effects
|
|
|
|
|
;; Indicates that an expression depends on the value of a mutable
|
|
|
|
|
;; lexical variable.
|
|
|
|
|
&mutable-lexical
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression depends on the value of a toplevel
|
|
|
|
|
;; variable.
|
|
|
|
|
&toplevel
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression depends on the value of a fluid
|
|
|
|
|
;; variable.
|
|
|
|
|
&fluid
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression definitely causes a non-local,
|
|
|
|
|
;; non-resumable exit -- a bailout. Only used in the "changes" sense.
|
|
|
|
|
&definite-bailout
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression may cause a bailout.
|
|
|
|
|
&possible-bailout
|
|
|
|
|
|
|
|
|
|
;; Indicates than an expression may return zero values -- a "causes"
|
|
|
|
|
;; effect.
|
|
|
|
|
&zero-values
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression may return a fresh object -- a
|
|
|
|
|
;; "causes" effect.
|
|
|
|
|
&allocation
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression depends on the value of a mutable data
|
|
|
|
|
;; structure.
|
|
|
|
|
&mutable-data
|
|
|
|
|
|
|
|
|
|
;; Indicates that an expression may cause a type check. A type check,
|
|
|
|
|
;; for the purposes of this analysis, is the possibility of throwing
|
|
|
|
|
;; an exception the first time an expression is evaluated. If the
|
|
|
|
|
;; expression did not cause an exception to be thrown, users can
|
|
|
|
|
;; assume that evaluating the expression again will not cause an
|
|
|
|
|
;; exception to be thrown.
|
|
|
|
|
;;
|
|
|
|
|
;; For example, (+ x y) might throw if X or Y are not numbers. But if
|
|
|
|
|
;; it doesn't throw, it should be safe to elide a dominated, common
|
|
|
|
|
;; subexpression (+ x y).
|
|
|
|
|
&type-check)
|
|
|
|
|
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-syntax &no-effects (identifier-syntax 0))
|
2012-04-12 16:25:45 -07:00
|
|
|
|
|
|
|
|
;; Definite bailout is an oddball effect. Since it indicates that an
|
|
|
|
|
;; expression definitely causes bailout, it's not in the set of effects
|
|
|
|
|
;; of a call to an unknown procedure. At the same time, it's also
|
|
|
|
|
;; special in that a definite bailout in a subexpression doesn't always
|
|
|
|
|
;; cause an outer expression to include &definite-bailout in its
|
|
|
|
|
;; effects. For that reason we have to treat it specially.
|
|
|
|
|
;;
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-syntax &all-effects-but-bailout
|
|
|
|
|
(identifier-syntax
|
|
|
|
|
(logand &all-effects (lognot &definite-bailout))))
|
2012-04-12 16:25:45 -07:00
|
|
|
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (cause effect)
|
2012-04-12 16:25:45 -07:00
|
|
|
(ash effect 1))
|
|
|
|
|
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (&depends-on a)
|
2012-04-12 16:25:45 -07:00
|
|
|
(logand a &all-effects))
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (&causes a)
|
2012-04-12 16:25:45 -07:00
|
|
|
(logand a (cause &all-effects)))
|
|
|
|
|
|
|
|
|
|
(define (exclude-effects effects exclude)
|
|
|
|
|
(logand effects (lognot (cause exclude))))
|
|
|
|
|
(define (effect-free? effects)
|
|
|
|
|
(zero? (&causes effects)))
|
|
|
|
|
(define (constant? effects)
|
|
|
|
|
(zero? effects))
|
|
|
|
|
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (depends-on-effects? x effects)
|
2012-04-12 16:25:45 -07:00
|
|
|
(not (zero? (logand (&depends-on x) effects))))
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (causes-effects? x effects)
|
2012-04-12 16:25:45 -07:00
|
|
|
(not (zero? (logand (&causes x) (cause effects)))))
|
|
|
|
|
|
2012-04-15 13:41:05 -07:00
|
|
|
(define-inlinable (effects-commute? a b)
|
2012-04-12 16:25:45 -07:00
|
|
|
(and (not (causes-effects? a (&depends-on b)))
|
|
|
|
|
(not (causes-effects? b (&depends-on a)))))
|
|
|
|
|
|
|
|
|
|
(define (make-effects-analyzer assigned-lexical?)
|
|
|
|
|
"Returns a procedure of type EXP -> EFFECTS that analyzes the effects
|
|
|
|
|
of an expression."
|
|
|
|
|
|
2012-05-15 17:22:05 +02:00
|
|
|
(let ((cache (make-hash-table)))
|
|
|
|
|
(define* (compute-effects exp #:optional (lookup (lambda (x) #f)))
|
|
|
|
|
(define (compute-effects exp)
|
2012-04-12 16:25:45 -07:00
|
|
|
(or (hashq-ref cache exp)
|
|
|
|
|
(let ((effects (visit exp)))
|
|
|
|
|
(hashq-set! cache exp effects)
|
2012-05-15 17:22:05 +02:00
|
|
|
effects)))
|
|
|
|
|
|
|
|
|
|
(define (accumulate-effects exps)
|
|
|
|
|
(let lp ((exps exps) (out &no-effects))
|
|
|
|
|
(if (null? exps)
|
|
|
|
|
out
|
|
|
|
|
(lp (cdr exps) (logior out (compute-effects (car exps)))))))
|
|
|
|
|
|
|
|
|
|
(define (visit exp)
|
|
|
|
|
(match exp
|
|
|
|
|
(($ <const>)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(($ <void>)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(($ <lexical-ref> _ _ gensym)
|
|
|
|
|
(if (assigned-lexical? gensym)
|
|
|
|
|
&mutable-lexical
|
|
|
|
|
&no-effects))
|
|
|
|
|
(($ <lexical-set> _ name gensym exp)
|
|
|
|
|
(logior (cause &mutable-lexical)
|
|
|
|
|
(compute-effects exp)))
|
|
|
|
|
(($ <let> _ names gensyms vals body)
|
|
|
|
|
(logior (if (or-map assigned-lexical? gensyms)
|
|
|
|
|
(cause &allocation)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(accumulate-effects vals)
|
|
|
|
|
(compute-effects body)))
|
|
|
|
|
(($ <letrec> _ in-order? names gensyms vals body)
|
|
|
|
|
(logior (if (or-map assigned-lexical? gensyms)
|
|
|
|
|
(cause &allocation)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(accumulate-effects vals)
|
|
|
|
|
(compute-effects body)))
|
|
|
|
|
(($ <fix> _ names gensyms vals body)
|
|
|
|
|
(logior (if (or-map assigned-lexical? gensyms)
|
|
|
|
|
(cause &allocation)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(accumulate-effects vals)
|
|
|
|
|
(compute-effects body)))
|
|
|
|
|
(($ <let-values> _ producer consumer)
|
|
|
|
|
(logior (compute-effects producer)
|
|
|
|
|
(compute-effects consumer)
|
|
|
|
|
(cause &type-check)))
|
|
|
|
|
(($ <toplevel-ref>)
|
|
|
|
|
(logior &toplevel
|
|
|
|
|
(cause &type-check)))
|
|
|
|
|
(($ <module-ref>)
|
|
|
|
|
(logior &toplevel
|
|
|
|
|
(cause &type-check)))
|
|
|
|
|
(($ <module-set> _ mod name public? exp)
|
|
|
|
|
(logior (cause &toplevel)
|
|
|
|
|
(cause &type-check)
|
|
|
|
|
(compute-effects exp)))
|
|
|
|
|
(($ <toplevel-define> _ name exp)
|
|
|
|
|
(logior (cause &toplevel)
|
|
|
|
|
(compute-effects exp)))
|
|
|
|
|
(($ <toplevel-set> _ name exp)
|
|
|
|
|
(logior (cause &toplevel)
|
|
|
|
|
(compute-effects exp)))
|
|
|
|
|
(($ <primitive-ref>)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(($ <conditional> _ test consequent alternate)
|
|
|
|
|
(let ((tfx (compute-effects test))
|
|
|
|
|
(cfx (compute-effects consequent))
|
|
|
|
|
(afx (compute-effects alternate)))
|
|
|
|
|
(if (causes-effects? (logior tfx (logand afx cfx))
|
|
|
|
|
&definite-bailout)
|
|
|
|
|
(logior tfx cfx afx)
|
|
|
|
|
(exclude-effects (logior tfx cfx afx)
|
|
|
|
|
&definite-bailout))))
|
|
|
|
|
|
|
|
|
|
;; Zero values.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <primcall> _ 'values ())
|
2012-05-15 17:22:05 +02:00
|
|
|
(cause &zero-values))
|
|
|
|
|
|
|
|
|
|
;; Effect-free primitives.
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ (or 'values 'eq? 'eqv? 'equal?) args)
|
2012-07-05 20:34:28 +02:00
|
|
|
(accumulate-effects args))
|
|
|
|
|
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ (or 'not 'pair? 'null? 'list? 'symbol?
|
|
|
|
|
'vector? 'struct? 'string? 'number?
|
|
|
|
|
'char?)
|
2012-07-05 20:34:28 +02:00
|
|
|
(arg))
|
|
|
|
|
(compute-effects arg))
|
|
|
|
|
|
|
|
|
|
;; Primitives that allocate memory.
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ 'cons (x y))
|
2012-07-05 20:34:28 +02:00
|
|
|
(logior (compute-effects x) (compute-effects y)
|
|
|
|
|
&allocation))
|
|
|
|
|
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ (or 'list 'vector) args)
|
2012-07-05 20:34:28 +02:00
|
|
|
(logior (accumulate-effects args) &allocation))
|
|
|
|
|
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ 'make-prompt-tag ())
|
2012-07-05 20:34:28 +02:00
|
|
|
&allocation)
|
|
|
|
|
|
2012-07-06 16:52:54 +02:00
|
|
|
(($ <primcall> _ 'make-prompt-tag (arg))
|
2012-07-05 20:34:28 +02:00
|
|
|
(logior (compute-effects arg) &allocation))
|
|
|
|
|
|
2013-06-27 19:28:42 +02:00
|
|
|
(($ <primcall> _ 'fluid-ref (fluid))
|
2013-06-27 19:38:32 +02:00
|
|
|
(logior (compute-effects fluid)
|
|
|
|
|
(cause &type-check)
|
|
|
|
|
&fluid))
|
|
|
|
|
|
|
|
|
|
(($ <primcall> _ 'fluid-set! (fluid exp))
|
|
|
|
|
(logior (compute-effects fluid)
|
|
|
|
|
(compute-effects exp)
|
|
|
|
|
(cause &type-check)
|
|
|
|
|
(cause &fluid)))
|
2013-06-27 19:28:42 +02:00
|
|
|
|
Remove with-fluids; replaced by with-fluid* and inlined push-fluid primops
* libguile/vm-i-system.c (push-fluid, pop-fluid):
* doc/ref/vm.texi (Dynamic Environment Instructions): Rename wind-fluids
to push-fluid, and unwind-fluids to pop-fluid. They now only work on
one fluid binding at a time.
* module/ice-9/boot-9.scm (with-fluid*): Implement in Scheme in terms of
primcalls to push-fluid and pop-fluid.
(custom-throw-handler, catch, with-throw-handler): Use with-fluid*
instead of with-fluids, as with-fluids is no longer available before
psyntax is loaded.
(with-fluids): Define in Scheme in terms of with-fluid*.
* libguile/fluids.c (scm_with_fluid): Rename from scm_with_fluids, and
don't expose to Scheme.
* libguile/eval.c (eval): Remove SCM_M_WITH_FLUIDS case.
* libguile/expand.c (expand_with_fluids): Remove with-fluids syntax.
(DYNLET): Remove, no longer defining dynlet in the %expanded-vtables.
* libguile/expand.h: Remove dynlet definitions.
* module/ice-9/eval.scm (primitive-eval): Remove with-fluids case.
* libguile/memoize.c (do_push_fluid, do_pop_fluid): New primitive
helpers, like wind and unwind.
(memoize): Memoize wind and unwind primcalls. Don't memoize dynlet to
with-fluids.
(scm_init_memoize): Initialize push_fluid and pop_fluid here.
* libguile/memoize.h (SCM_M_WITH_FLUIDS): Remove definition.
* module/ice-9/psyntax.scm (build-dynlet): Remove; this just supported
with-fluids, which is now defined in boot-9.
* module/ice-9/psyntax-pp.scm: Regenerate.
* doc/ref/compiler.texi (Tree-IL):
* module/language/tree-il.scm:
* module/language/tree-il/analyze.scm:
* module/language/tree-il/canonicalize.scm:
* module/language/tree-il/compile-glil.scm:
* module/language/tree-il/cse.scm:
* module/language/tree-il/debug.scm:
* module/language/tree-il/effects.scm: Remove <dynlet>. Add cases for
primcalls to push-fluid and pop-fluid in compile-glil.scm and
effects.scm.
* module/language/tree-il/peval.scm (peval): Factor out
with-temporaries; probably a bad idea, but works for now. Factor out
make-begin0 (a better idea). Inline primcalls to with-fluid*, and
remove dynlet cases.
* module/language/tree-il/primitives.scm (*interesting-primitive-names*):
Add with-fluid*.
2013-06-28 19:47:03 +02:00
|
|
|
(($ <primcall> _ 'push-fluid (fluid val))
|
|
|
|
|
(logior (compute-effects fluid)
|
|
|
|
|
(compute-effects val)
|
|
|
|
|
(cause &type-check)
|
|
|
|
|
(cause &fluid)))
|
|
|
|
|
|
|
|
|
|
(($ <primcall> _ 'pop-fluid ())
|
|
|
|
|
(logior (cause &fluid)))
|
|
|
|
|
|
2012-07-05 20:34:28 +02:00
|
|
|
;; Primitives that are normally effect-free, but which might
|
|
|
|
|
;; cause type checks, allocate memory, or access mutable
|
|
|
|
|
;; memory. FIXME: expand, to be more precise.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <primcall> _ (and name (? effect-free-primitive?)) args)
|
2012-05-15 17:22:05 +02:00
|
|
|
(logior (accumulate-effects args)
|
|
|
|
|
(cause &type-check)
|
|
|
|
|
(if (constructor-primitive? name)
|
|
|
|
|
(cause &allocation)
|
|
|
|
|
(if (accessor-primitive? name)
|
|
|
|
|
&mutable-data
|
|
|
|
|
&no-effects))))
|
2012-04-12 16:25:45 -07:00
|
|
|
|
2012-05-15 17:22:05 +02:00
|
|
|
;; Lambda applications might throw wrong-number-of-args.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <call> _ ($ <lambda> _ _ body) args)
|
2012-05-15 17:22:05 +02:00
|
|
|
(logior (accumulate-effects args)
|
|
|
|
|
(match body
|
|
|
|
|
(($ <lambda-case> _ req #f #f #f () syms body #f)
|
|
|
|
|
(logior (compute-effects body)
|
|
|
|
|
(if (= (length req) (length args))
|
|
|
|
|
0
|
|
|
|
|
(cause &type-check))))
|
|
|
|
|
(($ <lambda-case>)
|
|
|
|
|
(logior (compute-effects body)
|
2013-03-02 19:04:47 +01:00
|
|
|
(cause &type-check)))
|
|
|
|
|
(#f
|
|
|
|
|
;; Calling a case-lambda with no clauses
|
|
|
|
|
;; definitely causes bailout.
|
|
|
|
|
(logior (cause &definite-bailout)
|
|
|
|
|
(cause &possible-bailout))))))
|
2012-04-12 16:25:45 -07:00
|
|
|
|
2012-05-15 17:22:05 +02:00
|
|
|
;; Bailout primitives.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <primcall> _ (? bailout-primitive? name) args)
|
2012-05-15 17:22:05 +02:00
|
|
|
(logior (accumulate-effects args)
|
|
|
|
|
(cause &definite-bailout)
|
|
|
|
|
(cause &possible-bailout)))
|
2013-11-10 10:13:37 +01:00
|
|
|
(($ <call> _
|
|
|
|
|
(and proc
|
|
|
|
|
($ <module-ref> _ mod name public?)
|
|
|
|
|
(? (lambda (_)
|
|
|
|
|
(false-if-exception
|
|
|
|
|
(procedure-property
|
|
|
|
|
(module-ref (if public?
|
|
|
|
|
(resolve-interface mod)
|
|
|
|
|
(resolve-module mod))
|
|
|
|
|
name)
|
|
|
|
|
'definite-bailout?)))))
|
|
|
|
|
args)
|
|
|
|
|
(logior (compute-effects proc)
|
|
|
|
|
(accumulate-effects args)
|
|
|
|
|
(cause &definite-bailout)
|
|
|
|
|
(cause &possible-bailout)))
|
2012-05-15 17:22:05 +02:00
|
|
|
|
|
|
|
|
;; A call to a lexically bound procedure, perhaps labels
|
|
|
|
|
;; allocated.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <call> _ (and proc ($ <lexical-ref> _ _ sym)) args)
|
2012-05-15 17:22:05 +02:00
|
|
|
(cond
|
|
|
|
|
((lookup sym)
|
|
|
|
|
=> (lambda (proc)
|
2012-05-21 19:20:27 +02:00
|
|
|
(compute-effects (make-call #f proc args))))
|
2012-05-15 17:22:05 +02:00
|
|
|
(else
|
|
|
|
|
(logior &all-effects-but-bailout
|
|
|
|
|
(cause &all-effects-but-bailout)))))
|
|
|
|
|
|
|
|
|
|
;; A call to an unknown procedure can do anything.
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <primcall> _ name args)
|
|
|
|
|
(logior &all-effects-but-bailout
|
|
|
|
|
(cause &all-effects-but-bailout)))
|
|
|
|
|
(($ <call> _ proc args)
|
2012-05-15 17:22:05 +02:00
|
|
|
(logior &all-effects-but-bailout
|
|
|
|
|
(cause &all-effects-but-bailout)))
|
|
|
|
|
|
|
|
|
|
(($ <lambda> _ meta body)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(($ <lambda-case> _ req opt rest kw inits gensyms body alt)
|
|
|
|
|
(logior (exclude-effects (accumulate-effects inits)
|
|
|
|
|
&definite-bailout)
|
|
|
|
|
(if (or-map assigned-lexical? gensyms)
|
|
|
|
|
(cause &allocation)
|
|
|
|
|
&no-effects)
|
|
|
|
|
(compute-effects body)
|
|
|
|
|
(if alt (compute-effects alt) &no-effects)))
|
|
|
|
|
|
2012-05-21 19:20:27 +02:00
|
|
|
(($ <seq> _ head tail)
|
|
|
|
|
(logior
|
|
|
|
|
;; Returning zero values to a for-effect continuation is
|
|
|
|
|
;; not observable.
|
|
|
|
|
(exclude-effects (compute-effects head)
|
|
|
|
|
(cause &zero-values))
|
|
|
|
|
(compute-effects tail)))
|
2012-05-15 17:22:05 +02:00
|
|
|
|
2013-07-06 20:06:02 +09:00
|
|
|
(($ <prompt> _ escape-only? tag body handler)
|
2012-05-15 17:22:05 +02:00
|
|
|
(logior (compute-effects tag)
|
|
|
|
|
(compute-effects body)
|
|
|
|
|
(compute-effects handler)))
|
|
|
|
|
|
|
|
|
|
(($ <abort> _ tag args tail)
|
|
|
|
|
(logior &all-effects-but-bailout
|
|
|
|
|
(cause &all-effects-but-bailout)))))
|
|
|
|
|
|
|
|
|
|
(compute-effects exp))
|
|
|
|
|
|
|
|
|
|
compute-effects))
|