[armedbear-cvs] r11837 - trunk/abcl/src/org/armedbear/lisp
Erik Huelsmann
ehuelsmann at common-lisp.net
Wed May 6 20:39:52 UTC 2009
Author: ehuelsmann
Date: Wed May 6 16:39:51 2009
New Revision: 11837
Log:
Fix ticket #21 finally: JVM stack inconsistency error on
inlining unwind-protect.
The issue in the earlier attempts was that p1 outcomes can only
be compiled once (first try) and that one cannot p1 the same form
twice (one needs to create a copy; second try).
Modified:
trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp
trunk/abcl/src/org/armedbear/lisp/compiler-pass2.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 Wed May 6 16:39:51 2009
@@ -299,8 +299,16 @@
(defun p1-unwind-protect (form)
(if (= (length form) 2)
(p1 (second form)) ; No cleanup forms: (unwind-protect (...)) => (...)
+
+ ;; in order to compile the cleanup forms twice (see
+ ;; p2-unwind-protect-node), we need to p1 them twice; p1 outcomes
+ ;; can be compiled (in the same compiland?) only once.
+ ;;
+ ;; However, p1 transforms the forms being processed, so, we
+ ;; need to copy the forms to create a second copy.
(let* ((block (make-block-node '(UNWIND-PROTECT)))
;; a bit of jumping through hoops...
+ (unwinding-forms (p1-body (copy-tree (cddr form))))
(unprotected-forms (p1-body (cddr form)))
;; ... because only the protected form is
;; protected by the UNWIND-PROTECT block
@@ -308,6 +316,7 @@
(protected-form (p1 (cadr form))))
(setf (block-form block)
`(unwind-protect ,protected-form
+ (progn , at unwinding-forms)
, at unprotected-forms))
block)))
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 Wed May 6 16:39:51 2009
@@ -7834,18 +7834,29 @@
(when (= (length form) 2) ; No cleanup form.
(compile-form (second form) target nil)
(return-from p2-unwind-protect-node))
+
+ ;; The internal representation of UNWIND-PROTECT
+ ;; as generated by P1-UNWIND-PROTECT differs a bit
+ ;; from what the spec says; ours is:
+ ;; (UNWIND-PROTECT protected-form (progn cleanup-forms) cleanup-forms),
+ ;; because we need to compile the cleanup forms twice and
+ ;; we can compile a p1 outcome only once.
+ ;;
+ ;; We used to use JSR and RET JVM instructions to prevent
+ ;; duplication of output code. However, this led to JVM stack
+ ;; inconsistency errors
+ ;; (see http://trac.common-lisp.net/armedbear/ticket/21)
(let* ((protected-form (cadr form))
- (cleanup-forms (cddr form))
+ (unwinding-form (caddr form))
+ (cleanup-forms (cdddr form))
(*register* *register*)
(exception-register (allocate-register))
(result-register (allocate-register))
(values-register (allocate-register))
- (return-address-register (allocate-register))
(BEGIN-PROTECTED-RANGE (gensym))
(END-PROTECTED-RANGE (gensym))
(HANDLER (gensym))
- (EXIT (gensym))
- (CLEANUP (gensym)))
+ (EXIT (gensym)))
;; Make sure there are no leftover multiple return values from previous calls.
(emit-clear-values)
@@ -7857,21 +7868,21 @@
(emit 'getfield +lisp-thread-class+ "_values" +lisp-object-array+)
(astore values-register))
(label END-PROTECTED-RANGE))
- (emit 'jsr CLEANUP)
+ (let ((*register* *register*))
+ (compile-form unwinding-form nil nil))
+ (when (single-valued-p protected-form)
+ ;; otherwise, we'll load the values register below
+ (maybe-emit-clear-values unwinding-form))
(emit 'goto EXIT) ; Jump over handler.
(label HANDLER) ; Start of exception handler.
;; The Throwable object is on the runtime stack. Stack depth is 1.
(astore exception-register)
- (emit 'jsr CLEANUP) ; Call cleanup forms.
+ (let ((*register* *register*))
+ (dolist (subform cleanup-forms)
+ (compile-form subform nil nil)))
(maybe-emit-clear-values cleanup-forms)
(aload exception-register)
(emit 'athrow) ; Re-throw exception.
- (label CLEANUP) ; Cleanup forms.
- ;; Return address is on stack here.
- (astore return-address-register)
- (dolist (subform cleanup-forms)
- (compile-form subform nil nil))
- (emit 'ret return-address-register)
(label EXIT)
;; Restore multiple values returned by protected form.
(unless (single-valued-p protected-form)
More information about the armedbear-cvs
mailing list