[armedbear-cvs] r11820 - trunk/abcl/src/org/armedbear/lisp
Erik Huelsmann
ehuelsmann at common-lisp.net
Sun May 3 10:10:24 UTC 2009
Author: ehuelsmann
Date: Sun May 3 06:10:21 2009
New Revision: 11820
Log:
Make local GO restore the environment of the TAGBODY,
in case it jumps out of blocks setting the environment.
Modified:
trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp
trunk/abcl/src/org/armedbear/lisp/compiler-pass2.lisp
trunk/abcl/src/org/armedbear/lisp/jvm.lisp
Modified: trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp (original)
+++ trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp Sun May 3 06:10:21 2009
@@ -360,8 +360,13 @@
(let ((tag-block (tag-block tag)))
(cond ((eq (tag-compiland tag) *current-compiland*)
;; Does the GO leave an enclosing UNWIND-PROTECT?
- (when (enclosed-by-protected-block-p tag-block)
- (setf (block-non-local-go-p tag-block) t)))
+ (if (enclosed-by-protected-block-p tag-block)
+ (setf (block-non-local-go-p tag-block) t)
+ ;; non-local GO's ensure environment restoration
+ ;; find out about this local GO
+ (when (null (block-needs-environment-restoration tag-block))
+ (setf (block-needs-environment-restoration tag-block)
+ (enclosed-by-environment-setting-block-p tag-block)))))
(t
(setf (block-non-local-go-p tag-block) t)))))
form)
Modified: trunk/abcl/src/org/armedbear/lisp/compiler-pass2.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/compiler-pass2.lisp (original)
+++ trunk/abcl/src/org/armedbear/lisp/compiler-pass2.lisp Sun May 3 06:10:21 2009
@@ -4449,13 +4449,32 @@
(BEGIN-BLOCK (gensym))
(END-BLOCK (gensym))
(EXIT (gensym))
- (must-clear-values nil))
+ (must-clear-values nil)
+ environment-register)
+ (when (block-needs-environment-restoration block)
+ (setf environment-register (allocate-register)
+ (block-environment-register block) environment-register))
;; Scan for tags.
(dolist (subform body)
(when (or (symbolp subform) (integerp subform))
(let* ((tag (make-tag :name subform :label (gensym) :block block)))
(push tag local-tags)
(push tag *visible-tags*))))
+
+ (when environment-register
+ ;; Note: we store the environment register,
+ ;; but since we don't manipulate the environment,
+ ;; we don't need to restore.
+ ;;
+ ;; It's here so local transfers of control can restore
+ ;; what we started with.
+ ;;
+ ;; Non-local transfers of control restore the environment
+ ;; themselves (in the finally of LET/LET*, etc.
+ (emit-push-current-thread)
+ (emit 'getfield +lisp-thread-class+ "lastSpecialBinding"
+ +lisp-special-binding+)
+ (astore environment-register))
(label BEGIN-BLOCK)
(do* ((rest body (cdr rest))
(subform (car rest) (car rest)))
@@ -4522,27 +4541,23 @@
;; FIXME What if we're called with a non-NIL representation?
(declare (ignore representation))
(let* ((name (cadr form))
- (tag (find-tag name)))
+ (tag (find-tag name))
+ (tag-block (when tag (tag-block tag))))
(unless tag
(error "p2-go: tag not found: ~S" name))
- (when (eq (tag-compiland tag) *current-compiland*)
- ;; Local case.
- (let* ((tag-block (tag-block tag))
- (register nil))
- (unless (enclosed-by-protected-block-p tag-block)
- (dolist (block *blocks*)
- (if (eq block tag-block)
- (return)
- (setf register (or (block-environment-register block) register))))
- (when register
- ;; Restore dynamic environment.
- (aload *thread*)
- (aload register)
- (emit 'putfield +lisp-thread-class+ "lastSpecialBinding"
- +lisp-special-binding+))
- (maybe-generate-interrupt-check)
- (emit 'goto (tag-label tag))
- (return-from p2-go))))
+ (when (and (eq (tag-compiland tag) *current-compiland*)
+ (not (enclosed-by-protected-block-p tag-block)))
+ ;; Local case with local transfer of control
+ ;; Note: Local case with non-local transfer of control handled below
+ (when (block-environment-register tag-block)
+ ;; If there's a dynamic environment to restore, do it.
+ (aload *thread*)
+ (aload (block-environment-register tag-block))
+ (emit 'putfield +lisp-thread-class+ "lastSpecialBinding"
+ +lisp-special-binding+))
+ (maybe-generate-interrupt-check)
+ (emit 'goto (tag-label tag))
+ (return-from p2-go))
;; Non-local GO.
(emit 'new +lisp-go-class+)
(emit 'dup)
Modified: trunk/abcl/src/org/armedbear/lisp/jvm.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/jvm.lisp (original)
+++ trunk/abcl/src/org/armedbear/lisp/jvm.lisp Sun May 3 06:10:21 2009
@@ -361,6 +361,9 @@
non-local-return-p
;; True if a tag in this tagbody is the target of a non-local GO.
non-local-go-p
+ ;; If non-nil, the TAGBODY contains local blocks which "contaminate" the
+ ;; environment, with GO forms in them which target tags in this TAGBODY
+ needs-environment-restoration
;; If non-nil, register containing saved dynamic environment for this block.
environment-register
;; Only used in LET/LET*/M-V-B nodes.
@@ -409,6 +412,14 @@
(when (block-requires-non-local-exit-p enclosing-block)
(return-from enclosed-by-protected-block-p t))))
+(defknown enclosed-by-environment-setting-block-p (&optional outermost-block)
+ boolean)
+(defun enclosed-by-environment-setting-block-p (&optional outermost-block)
+ (dolist (enclosing-block *blocks*)
+ (when (eq enclosing-block outermost-block)
+ (return nil))
+ (when (block-environment-register enclosing-block)
+ (return t))))
(defstruct tag
name
More information about the armedbear-cvs
mailing list