diff options
Diffstat (limited to 'books/workshops/2003/moore_vcg/support')
-rw-r--r-- | books/workshops/2003/moore_vcg/support/README | 11 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/certify.lsp | 172 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/demo.acl2 | 7 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/demo.lisp | 714 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/m5.acl2 | 160 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/m5.lisp | 3032 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/utilities.acl2 | 7 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/utilities.lisp | 209 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/vcg-examples.acl2 | 6 | ||||
-rw-r--r-- | books/workshops/2003/moore_vcg/support/vcg-examples.lisp | 904 |
10 files changed, 5222 insertions, 0 deletions
diff --git a/books/workshops/2003/moore_vcg/support/README b/books/workshops/2003/moore_vcg/support/README new file mode 100644 index 0000000..ba50c33 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/README @@ -0,0 +1,11 @@ +; Tail-Recursive Completion of Inductive Assertions +; in an Operational Semantics Setting + +; J Strother Moore + +; This directory contains supporting material for the paper above. +; To recertify the books here, type make to the linux prompt or +; get into ACL2 while standing on this directory and type + +; (ld "certify.lsp" :ld-pre-eval-print t) + diff --git a/books/workshops/2003/moore_vcg/support/certify.lsp b/books/workshops/2003/moore_vcg/support/certify.lsp new file mode 100644 index 0000000..93d7d98 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/certify.lsp @@ -0,0 +1,172 @@ + +;(certify-book "defpun") +;(u) + +(defpkg "LABEL" '(nil t)) +(defpkg "JVM" '(nil t)) +(defpkg "M5" + (set-difference-equal + (union-eq + '(JVM::SCHEDULED + JVM::UNSCHEDULED + JVM::REF + JVM::LOCKED + JVM::S_LOCKED + JVM::UNLOCKED + JVM::AALOAD + JVM::AASTORE + JVM::ACONST_NULL + JVM::ALOAD + JVM::ALOAD_0 + JVM::ALOAD_1 + JVM::ALOAD_2 + JVM::ALOAD_3 + JVM::ANEWARRAY + JVM::ARETURN + JVM::ARRAYLENGTH + JVM::ASTORE + JVM::ASTORE_0 + JVM::ASTORE_1 + JVM::ASTORE_2 + JVM::ASTORE_3 + JVM::BALOAD + JVM::BASTORE + JVM::BIPUSH + JVM::CALOAD + JVM::CASTORE + JVM::DUP + JVM::DUP_X1 + JVM::DUP_X2 + JVM::DUP2 + JVM::DUP2_X1 + JVM::DUP2_X2 + JVM::GETFIELD + JVM::GETSTATIC + JVM::GOTO + JVM::GOTO_W + JVM::I2B + JVM::I2C + JVM::I2L + JVM::I2S + JVM::IADD + JVM::IALOAD + JVM::IAND + JVM::IASTORE + JVM::ICONST_M1 + JVM::ICONST_0 + JVM::ICONST_1 + JVM::ICONST_2 + JVM::ICONST_3 + JVM::ICONST_4 + JVM::ICONST_5 + JVM::IDIV + JVM::IF_ACMPEQ + JVM::IF_ACMPNE + JVM::IF_ICMPEQ + JVM::IF_ICMPGE + JVM::IF_ICMPGT + JVM::IF_ICMPLE + JVM::IF_ICMPLT + JVM::IF_ICMPNE + JVM::IFEQ + JVM::IFGE + JVM::IFGT + JVM::IFLE + JVM::IFLT + JVM::IFNE + JVM::IFNONNULL + JVM::IFNULL + JVM::IINC + JVM::ILOAD + JVM::ILOAD_0 + JVM::ILOAD_1 + JVM::ILOAD_2 + JVM::ILOAD_3 + JVM::IMUL + JVM::INEG + JVM::INSTANCEOF + JVM::INVOKESPECIAL + JVM::INVOKESTATIC + JVM::INVOKEVIRTUAL + JVM::IOR + JVM::IREM + JVM::IRETURN + JVM::ISHL + JVM::ISHR + JVM::ISTORE + JVM::ISTORE_0 + JVM::ISTORE_1 + JVM::ISTORE_2 + JVM::ISTORE_3 + JVM::ISUB + JVM::IUSHR + JVM::IXOR + JVM::JSR + JVM::JSR_W + JVM::L2I + JVM::LADD + JVM::LALOAD + JVM::LAND + JVM::LASTORE + JVM::LCMP + JVM::LCONST_0 + JVM::LCONST_1 + JVM::LDC + JVM::LDC_W + JVM::LDC2_W + JVM::LDIV + JVM::LLOAD + JVM::LLOAD_0 + JVM::LLOAD_1 + JVM::LLOAD_2 + JVM::LLOAD_3 + JVM::LMUL + JVM::LNEG + JVM::LOR + JVM::LREM + JVM::LRETURN + JVM::LSHL + JVM::LSHR + JVM::LSTORE + JVM::LSTORE_0 + JVM::LSTORE_1 + JVM::LSTORE_2 + JVM::LSTORE_3 + JVM::LSUB + JVM::LUSHR + JVM::LXOR + JVM::MONITORENTER + JVM::MONITOREXIT + JVM::MULTIANEWARRAY + JVM::NEW + JVM::NEWARRAY + JVM::NOP + JVM::POP + JVM::POP2 + JVM::PUTFIELD + JVM::PUTSTATIC + JVM::RET + JVM::RETURN + JVM::SALOAD + JVM::SASTORE + JVM::SIPUSH + JVM::SWAP + ASSOC-EQUAL LEN NTH ZP SYNTAXP + QUOTEP FIX NFIX E0-ORDINALP E0-ORD-<) + (union-eq *acl2-exports* + *common-lisp-symbols-from-main-lisp-package*)) + '(PC PROGRAM PUSH POP RETURN REVERSE STEP ++))) +(certify-book "m5" 3) +(u) (u) (u) (u) + +(include-book "m5") +(certify-book "utilities" 1) +(u) (u) + +(include-book "utilities") +(certify-book "demo" 1) +(u) (u) + +(include-book "utilities") +(certify-book "vcg-examples" 1) +(u) (u) diff --git a/books/workshops/2003/moore_vcg/support/demo.acl2 b/books/workshops/2003/moore_vcg/support/demo.acl2 new file mode 100644 index 0000000..4b92f00 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/demo.acl2 @@ -0,0 +1,7 @@ +(value :q) + +(lp) + +(include-book "utilities") + +(certify-book "demo" ? t) diff --git a/books/workshops/2003/moore_vcg/support/demo.lisp b/books/workshops/2003/moore_vcg/support/demo.lisp new file mode 100644 index 0000000..8d07589 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/demo.lisp @@ -0,0 +1,714 @@ +; Copyright (C) 2001, Regents of the University of Texas +; Written by J Strother Moore +; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2. + +; This book proves the correctness of a recursive static method +; for factorial on M5. + +#| +; Certification Instructions. + +(include-book + "utilities") + +(certify-book "demo" 1) + +J Moore + +Here is the Java for a factorial method. + +class Demo { + + static int ans; + + public static int fact(int n){ + if (n>0) + {return n*fact(n-1);} + else return 1; + } + + public static void main(String[] args){ + int k = 4; + ans = fact(k+1); + return; + } + } + +If you put this into Demo.java and run + +% javac Demo.java +% javap -o Demo + +you get the following: + +Compiled from Demo.java +synchronized class Demo extends java.lang.Object + /* ACC_SUPER bit set */ +{ + static int ans; + public static int fact(int); + public static void main(java.lang.String[]); + Demo(); +} + +Method int fact(int) + 0 iload_0 + 1 ifle 13 + 4 iload_0 + 5 iload_0 + 6 iconst_1 + 7 isub + 8 invokestatic #5 <Method int fact(int)> + 11 imul + 12 ireturn + 13 iconst_1 + 14 ireturn + +Method void main(java.lang.String[]) + 0 iconst_4 + 1 istore_1 + 2 iload_1 + 3 iconst_1 + 4 iadd + 5 invokestatic #5 <Method int fact(int)> + 8 putstatic #4 <Field int ans> + 11 return + +Method Demo() + 0 aload_0 + 1 invokespecial #3 <Method java.lang.Object()> + 4 return + +Below is the output of jvm2acl2 for M5. + +|# + +(in-package "M5") + +(defconst *Demo-class-table-in-tagged-form* + (make-class-def + (list + (make-class-decl + "Demo" + '("java.lang.Object") + '() + '("ans") + '() + (list + '("<init>" () nil + (aload_0) + (invokespecial "java.lang.Object" "<init>" 0) + (return)) + '("fact" (int) nil + (iload_0) + (ifle LABEL::TAG_0) + (iload_0) + (iload_0) + (iconst_1) + (isub) + (invokestatic "Demo" "fact" 1) + (imul) + (ireturn) + (LABEL::TAG_0 iconst_1) + (ireturn)) + '("main" (java.lang.String[]) nil + (iconst_4) + (istore_1) + (iload_1) + (iconst_1) + (iadd) + (invokestatic "Demo" "fact" 1) + (putstatic "Demo" "ans" nil) + (return))) + '(REF -1))))) + +(defconst *Demo-main* + '((iconst_4) + (istore_1) + (iload_1) + (iconst_1) + (iadd) + (invokestatic "Demo" "fact" 1) + (putstatic "Demo" "ans" nil) + (return))) + +(defun Demo-ms () + (make-state + (make-tt (push (make-frame 0 + nil + nil + *Demo-main* + 'UNLOCKED + "Demo") + nil)) + nil + *Demo-class-table-in-tagged-form*)) + +(defun Demo () + (m5_load (Demo-ms))) + +; Here is the state created by (Demo): +#| +(((0 ((0 NIL NIL + ((ICONST_4) + (ISTORE_1) + (ILOAD_1) + (ICONST_1) + (IADD) + (INVOKESTATIC "Demo" "fact" 1) + (PUTSTATIC "Demo" "ans" NIL) + (RETURN)) + UNLOCKED "Demo")) + SCHEDULED NIL)) + ((0 ("java.lang.Class" ("<name>" . "java.lang.Object")) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0))) + (1 ("java.lang.Class" ("<name>" . "ARRAY")) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0))) + (2 ("java.lang.Class" ("<name>" . "java.lang.Thread")) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0))) + (3 ("java.lang.Class" ("<name>" . "java.lang.String")) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0))) + (4 ("java.lang.Class" ("<name>" . "java.lang.Class")) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0))) + (5 ("java.lang.Class" ("<name>" . "Demo") + ("ans" . 0)) + ("java.lang.Object" ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (("java.lang.Object" NIL ("monitor" "mcount" "wait-set") + NIL NIL (("<init>" NIL NIL (RETURN))) + (REF 0)) + ("ARRAY" ("java.lang.Object") + (("<array>" . *ARRAY*)) + NIL NIL NIL (REF 1)) + ("java.lang.Thread" + ("java.lang.Object") + NIL NIL NIL + (("run" NIL NIL (RETURN)) + ("start" NIL NIL NIL) + ("stop" NIL NIL NIL) + ("<init>" NIL NIL (ALOAD_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 2)) + ("java.lang.String" + ("java.lang.Object") + ("strcontents") + NIL NIL + (("<init>" NIL NIL (ALOAD_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 3)) + ("java.lang.Class" ("java.lang.Object") + NIL NIL NIL + (("<init>" NIL NIL (ALOAD_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 4)) + ("Demo" ("java.lang.Object") + NIL ("ans") + NIL + (("<init>" NIL NIL (ALOAD_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN)) + ("fact" (INT) + NIL (ILOAD_0) + (IFLE 12) + (ILOAD_0) + (ILOAD_0) + (ICONST_1) + (ISUB) + (INVOKESTATIC "Demo" "fact" 1) + (IMUL) + (IRETURN) + (ICONST_1) + (IRETURN)) + ("main" (|JAVA.LANG.STRING[]|) + NIL (ICONST_4) + (ISTORE_1) + (ILOAD_1) + (ICONST_1) + (IADD) + (INVOKESTATIC "Demo" "fact" 1) + (PUTSTATIC "Demo" "ans" NIL) + (RETURN))) + (REF 5)))) +|# + +; But in the paper we discuss it component by component and +; define constants for each. Note that we can write ICONST_4 or +; ICONST\_4 in Common Lisp. We use the latter so that we can +; pick these forms up and dump them into LaTeX. + +(defconst *Demo-thread-table* + (list + (cons 0 + (make-thread + (push + (make-frame + 0 + nil + nil + '((ICONST\_4) + (ISTORE\_1) + (ILOAD\_1) + (ICONST\_1) + (IADD) + (INVOKESTATIC "Demo" "fact" 1) + (PUTSTATIC "Demo" "ans" NIL) + (RETURN)) + 'UNLOCKED + "Demo") + nil) + 'SCHEDULED + nil)))) + +(defconst *Demo-heap* + '((0 . (("java.lang.Class" + ("<name>" . "java.lang.Object")) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (1 . (("java.lang.Class" + ("<name>" . "ARRAY")) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (2 . (("java.lang.Class" + ("<name>" . "java.lang.Thread")) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (3 . (("java.lang.Class" + ("<name>" . "java.lang.String")) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (4 . (("java.lang.Class" + ("<name>" . "java.lang.Class")) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))) + (5 . (("java.lang.Class" + ("<name>" . "Demo") + ("ans" . 0)) + ("java.lang.Object" + ("monitor" . 0) + ("mcount" . 0) + ("wait-set" . 0)))))) + +(defconst *Demo-class-table* + '(("java.lang.Object" + NIL + ("monitor" "mcount" "wait-set") + NIL + NIL + (("<init>" NIL NIL (RETURN))) + (REF 0)) + ("ARRAY" + ("java.lang.Object") + (("<array>" . *ARRAY*)) + NIL + NIL + NIL + (REF 1)) + ("java.lang.Thread" + ("java.lang.Object") + NIL + NIL + NIL + (("run" NIL NIL (RETURN)) + ("start" NIL NIL NIL) + ("stop" NIL NIL NIL) + ("<init>" NIL NIL (ALOAD\_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 2)) + ("java.lang.String" + ("java.lang.Object") + ("strcontents") + NIL + NIL + (("<init>" NIL NIL + (ALOAD\_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 3)) + ("java.lang.Class" + ("java.lang.Object") + NIL + NIL + NIL + (("<init>" NIL NIL + (ALOAD\_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN))) + (REF 4)) + ("Demo" + ("java.lang.Object") + NIL + ("ans") + NIL + (("<init>" NIL NIL + (ALOAD\_0) + (INVOKESPECIAL "java.lang.Object" "<init>" 0) + (RETURN)) + ("fact" (INT) NIL + (ILOAD\_0) + (IFLE 12) + (ILOAD\_0) + (ILOAD\_0) + (ICONST\_1) + (ISUB) + (INVOKESTATIC "Demo" "fact" 1) + (IMUL) + (IRETURN) + (ICONST\_1) + (IRETURN)) + ("main" (|JAVA.LANG.STRING[]|) NIL + (ICONST\_4) + (ISTORE\_1) + (ILOAD\_1) + (ICONST\_1) + (IADD) + (INVOKESTATIC "Demo" "fact" 1) + (PUTSTATIC "Demo" "ans" NIL) + (RETURN))) + (REF 5)))) + +(defconst *Demo-state* + (make-state *demo-thread-table* + *demo-heap* + *demo-class-table*)) + +(defthm demo-state-is-demo + (equal (Demo) + *Demo-state*) + :rule-classes nil) + +; The Mathematical Function + +(defun factorial (n) + (if (zp n) + 1 + (* n (factorial (- n 1))))) + +(defthm integerp-factorial + (integerp (factorial n)) + :rule-classes :type-prescription) + +; A Schedule that Runs fact to Completion + +(defun fact-sched (th n) + (if (zp n) + (repeat th 5) + (append (repeat th 7) + (fact-sched th (- n 1)) + (repeat th 2)))) + +(defthm len-repeat + (equal (len (repeat th n)) (nfix n))) + +(defthm len-append + (equal (len (append a b)) + (+ (len a) (len b)))) + +(defthm len-fact-sched + (equal (len (fact-sched th n)) + (+ 5 (* 9 (nfix n))))) + +; Playing Around with Main + +; This schedule executes main to termination. + +(defun main-sched (th) + (append (repeat th 5) + (fact-sched th 5) + (repeat th 2))) + +(defthm sample-execution + (equal (static-field-value "Demo" "ans" + (run (main-sched 0) *Demo-state*)) + 120) + :rule-classes nil) + +#| + +; Below is a fact-test function. I define it in raw Lisp rather +; than ACL2 so that I can time the execution of the JVM model +; without timing the construction of the schedule. To define +; this function, exit the loop with :q and do these two forms. + +(in-package "M5") +(compile + (defun fact-test (n) + (format t "Computing schedule for ~a.~%" n) + (let ((sched (append (repeat 0 1) + (fact-sched 0 n) + (repeat 0 2)))) + (format t "Schedule length: ~a.~%" (len sched)) + (time + (static-field-value + "Demo" "ans" + (run sched + (make-state + (list + (cons 0 + (make-thread + (push + (make-frame + 0 + (list n) + nil + '((ILOAD\_0) + (INVOKESTATIC "Demo" "fact" 1) + (PUTSTATIC "Demo" "ans" NIL) + (RETURN)) + 'UNLOCKED + "Demo") + nil) + 'SCHEDULED + nil))) + *demo-heap* + *demo-class-table*))))))) +; Allocate additional bignum space +(si::allocate 'lisp::bignum 400 t) +T + +; Then do things like (fact-test 17) or (fact-test 1000). On a 797 +; MHz Pentium III, the latter requires a schedule of length 9008 and +; takes 0.100 seconds to execute, provided no (BIGNUM) gcs occur. +; This gives a simulation speed of 90K JVM bytecodes per second. + +|# + +; Proving Fact Correct + +(defconst *fact-def* + '("fact" (INT) NIL + (ILOAD_0) ;;; 0 + (IFLE 12) ;;; 1 + (ILOAD_0) ;;; 4 + (ILOAD_0) ;;; 5 + (ICONST_1) ;;; 6 + (ISUB) ;;; 7 + (INVOKESTATIC "Demo" "fact" 1) ;;; 8 + (IMUL) ;;; 11 + (IRETURN) ;;; 12 + (ICONST_1) ;;; 13 + (IRETURN))) ;;; 14 + +(defun poised-to-invoke-fact (th s n) + (and (equal (status th s) 'SCHEDULED) + (equal (next-inst th s) '(invokestatic "Demo" "fact" 1)) + (equal n (top (stack (top-frame th s)))) + (intp n) + (equal (lookup-method "fact" "Demo" (class-table s)) + *fact-def*))) + +(defun induction-hint (th s n) + (if (zp n) + s + (induction-hint + th + (make-state ;;; (run (repeat th 7) s) + (bind + th + (make-thread + (push + (make-frame + 8 + (list (top (stack (top-frame th s)))) + (push (- (top (stack (top-frame th s))) 1) + (push (top (stack (top-frame th s))) + nil)) + (method-program *fact-def*) + 'UNLOCKED + "Demo") + (push (make-frame (+ 3 (pc (top (call-stack th s)))) + (locals (top (call-stack th s))) + (pop (stack (top (call-stack th s)))) + (program (top (call-stack th s))) + (sync-flg (top (call-stack th s))) + (cur-class (top (call-stack th s)))) + (pop (call-stack th s)))) + 'scheduled + (rref th s)) + (thread-table s)) + (heap s) + (class-table s)) + (- n 1)))) + +; The make-state in the induction-hint above is equivalent to +; (run (repeat th 7) s), under the hypotheses that s is poised to +; invoke fact and that n is non-0. We prove that below, just to +; demonstrate this claim. The import of this claim is that we +; could use this to help generate the induction hint, i.e., the +; make-state is not "magic." + +(defthm induction-hint-explanation + (implies (and (poised-to-invoke-fact th s n) + (not (zp n))) + (equal (run (repeat th 7) s) + (make-state ;;; (run (repeat th 7) s) + (bind + th + (make-thread + (push + (make-frame + 8 + (list (top (stack (top-frame th s)))) + (push (- (top (stack (top-frame th s))) 1) + (push (top (stack (top-frame th s))) + nil)) + (method-program *fact-def*) + 'UNLOCKED + "Demo") + (push (make-frame (+ 3 (pc (top (call-stack th s)))) + (locals (top (call-stack th s))) + (pop (stack (top (call-stack th s)))) + (program (top (call-stack th s))) + (sync-flg (top (call-stack th s))) + (cur-class (top (call-stack th s)))) + (pop (call-stack th s)))) + 'scheduled + (rref th s)) + (thread-table s)) + (heap s) + (class-table s)))) + :rule-classes nil) + +(defthm fact-is-correct + (implies (poised-to-invoke-fact th s n) + (equal + (run (fact-sched th n) s) + (modify th s + :pc (+ 3 (pc (top-frame th s))) + :stack (push (int-fix (factorial n)) + (pop (stack (top-frame th s))))))) + :hints (("Goal" + :induct (induction-hint th s n)))) + +(in-theory (disable fact-sched)) + +(defthm weak-version-of-fact-is-correct + (implies (poised-to-invoke-fact th s n) + (equal (top + (stack + (top-frame + th + (run (fact-sched th n) s)))) + (int-fix (factorial n))))) + +; Symbolic Computation and Use of fact as a Subroutine + +(defthm symbolic-computation + (implies + (intp (+ 1 k)) + (equal + (nth 3 + (locals + (top-frame 0 + (run (append (repeat 0 4) + (fact-sched 0 (+ 1 k)) + (repeat 0 2)) + (make-state + (make-tt + (push + (make-frame 0 + (list v0 v1 v2 k) + stk + '((iconst_2) + (iload_3) + (iconst_1) + (iadd) + (invokestatic "Demo" "fact" 1) + (imul) + (istore_3)) + 'UNLOCKED + "Test") + nil)) + *demo-heap* + *demo-class-table*))))) + + (int-fix (* 2 (factorial (+ 1 k))))))) + +; In the steps below we demonstrate the key steps in the +; simplification above, to check the claims made in the paper. + +(defun alpha (pc locals stk) + (make-state + (make-tt + (push (make-frame pc + locals + stk + '((iconst_2) + (iload_3) + (iconst_1) + (iadd) + (invokestatic "Demo" "fact" 1) + (imul) + (istore_3)) + 'UNLOCKED + "Test") + nil)) + *demo-heap* + *demo-class-table*)) + +(defthm symbolic-computation-step1 + (implies + (intp (+ 1 k)) + (equal (run (append (repeat 0 4) + (fact-sched 0 (+ 1 k)) + (repeat 0 2)) + (alpha 0 (list v0 v1 v2 k) stk)) + (run (repeat 0 2) + (run (fact-sched 0 (+ 1 k)) + (run (repeat 0 4) + (alpha 0 (list v0 v1 v2 k) stk))))))) + +(defthm symbolic-computation-step2 + (implies + (intp (+ 1 k)) + (equal (run (repeat 0 4) + (alpha 0 (list v0 v1 v2 k) stk)) + (alpha 4 (list v0 v1 v2 k) + (push (+ 1 k) (push 2 stk)))))) + +(defthm symbolic-computation-step3 + (implies + (intp (+ 1 k)) + (equal (run (fact-sched 0 (+ 1 k)) + (alpha 4 (list v0 v1 v2 k) + (push (+ 1 k) (push 2 stk)))) + (alpha 7 (list v0 v1 v2 k) + (push (int-fix (factorial (+ 1 k))) + (push 2 stk)))))) + + +(defthm symbolic-computation-step4 + (implies + (intp (+ 1 k)) + (equal (run (repeat 0 2) + (alpha 7 (list v0 v1 v2 k) + (push (int-fix (factorial (+ 1 k))) + (push 2 stk)))) + (alpha 9 (list v0 v1 v2 + (int-fix + (* 2 (factorial (+ 1 k))))) stk)))) + diff --git a/books/workshops/2003/moore_vcg/support/m5.acl2 b/books/workshops/2003/moore_vcg/support/m5.acl2 new file mode 100644 index 0000000..3113f2e --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/m5.acl2 @@ -0,0 +1,160 @@ +(value :q) + +(lp) + +(defpkg "LABEL" '(nil t)) +(defpkg "JVM" '(nil t)) + +(DEFPKG "M5" + (set-difference-equal + (union-eq '(JVM::SCHEDULED + JVM::UNSCHEDULED + JVM::REF + JVM::LOCKED + JVM::S_LOCKED + JVM::UNLOCKED + JVM::AALOAD + JVM::AASTORE + JVM::ACONST_NULL + JVM::ALOAD + JVM::ALOAD_0 + JVM::ALOAD_1 + JVM::ALOAD_2 + JVM::ALOAD_3 + JVM::ANEWARRAY + JVM::ARETURN + JVM::ARRAYLENGTH + JVM::ASTORE + JVM::ASTORE_0 + JVM::ASTORE_1 + JVM::ASTORE_2 + JVM::ASTORE_3 + JVM::BALOAD + JVM::BASTORE + JVM::BIPUSH + JVM::CALOAD + JVM::CASTORE + JVM::DUP + JVM::DUP_X1 + JVM::DUP_X2 + JVM::DUP2 + JVM::DUP2_X1 + JVM::DUP2_X2 + JVM::GETFIELD + JVM::GETSTATIC + JVM::GOTO + JVM::GOTO_W + JVM::I2B + JVM::I2C + JVM::I2L + JVM::I2S + JVM::IADD + JVM::IALOAD + JVM::IAND + JVM::IASTORE + JVM::ICONST_M1 + JVM::ICONST_0 + JVM::ICONST_1 + JVM::ICONST_2 + JVM::ICONST_3 + JVM::ICONST_4 + JVM::ICONST_5 + JVM::IDIV + JVM::IF_ACMPEQ + JVM::IF_ACMPNE + JVM::IF_ICMPEQ + JVM::IF_ICMPGE + JVM::IF_ICMPGT + JVM::IF_ICMPLE + JVM::IF_ICMPLT + JVM::IF_ICMPNE + JVM::IFEQ + JVM::IFGE + JVM::IFGT + JVM::IFLE + JVM::IFLT + JVM::IFNE + JVM::IFNONNULL + JVM::IFNULL + JVM::IINC + JVM::ILOAD + JVM::ILOAD_0 + JVM::ILOAD_1 + JVM::ILOAD_2 + JVM::ILOAD_3 + JVM::IMUL + JVM::INEG + JVM::INSTANCEOF + JVM::INVOKESPECIAL + JVM::INVOKESTATIC + JVM::INVOKEVIRTUAL + JVM::IOR + JVM::IREM + JVM::IRETURN + JVM::ISHL + JVM::ISHR + JVM::ISTORE + JVM::ISTORE_0 + JVM::ISTORE_1 + JVM::ISTORE_2 + JVM::ISTORE_3 + JVM::ISUB + JVM::IUSHR + JVM::IXOR + JVM::JSR + JVM::JSR_W + JVM::L2I + JVM::LADD + JVM::LALOAD + JVM::LAND + JVM::LASTORE + JVM::LCMP + JVM::LCONST_0 + JVM::LCONST_1 + JVM::LDC + JVM::LDC_W + JVM::LDC2_W + JVM::LDIV + JVM::LLOAD + JVM::LLOAD_0 + JVM::LLOAD_1 + JVM::LLOAD_2 + JVM::LLOAD_3 + JVM::LMUL + JVM::LNEG + JVM::LOR + JVM::LREM + JVM::LRETURN + JVM::LSHL + JVM::LSHR + JVM::LSTORE + JVM::LSTORE_0 + JVM::LSTORE_1 + JVM::LSTORE_2 + JVM::LSTORE_3 + JVM::LSUB + JVM::LUSHR + JVM::LXOR + JVM::MONITORENTER + JVM::MONITOREXIT + JVM::MULTIANEWARRAY + JVM::NEW + JVM::NEWARRAY + JVM::NOP + JVM::POP + JVM::POP2 + JVM::PUTFIELD + JVM::PUTSTATIC + JVM::RET + JVM::RETURN + JVM::SALOAD + JVM::SASTORE + JVM::SIPUSH + JVM::SWAP + ASSOC-EQUAL LEN NTH ZP SYNTAXP + QUOTEP FIX NFIX E0-ORDINALP E0-ORD-<) + (union-eq *acl2-exports* + *common-lisp-symbols-from-main-lisp-package*)) + '(PC PROGRAM PUSH POP RETURN REVERSE STEP ++))) + +(certify-book "m5" ? t) diff --git a/books/workshops/2003/moore_vcg/support/m5.lisp b/books/workshops/2003/moore_vcg/support/m5.lisp new file mode 100644 index 0000000..80a75ec --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/m5.lisp @@ -0,0 +1,3032 @@ +; Copyright (C) 2001, Regents of the University of Texas +; Written by J Strother Moore and George Porter +; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2. + +; M5.lisp +; J Strother Moore <moore@cs.utexas.edu> +; George Porter <george@cs.utexas.edu> +; +; Fixed arithmetic work by Robert Krug <rkrug@cs.utexas.edu> +; Support for Arrays by Hanbing Liu <hbl@cs.utexas.edu> +; +; $Id: m5.lisp,v 1.1 2001/07/10 17:37:06 george Exp $ + +#| + +(defpkg "LABEL" '(nil t)) +(defpkg "JVM" '(nil t)) + +(DEFPKG "M5" + (set-difference-equal + (union-eq '(JVM::SCHEDULED + JVM::UNSCHEDULED + JVM::REF + JVM::LOCKED + JVM::S_LOCKED + JVM::UNLOCKED + JVM::AALOAD + JVM::AASTORE + JVM::ACONST_NULL + JVM::ALOAD + JVM::ALOAD_0 + JVM::ALOAD_1 + JVM::ALOAD_2 + JVM::ALOAD_3 + JVM::ANEWARRAY + JVM::ARETURN + JVM::ARRAYLENGTH + JVM::ASTORE + JVM::ASTORE_0 + JVM::ASTORE_1 + JVM::ASTORE_2 + JVM::ASTORE_3 + JVM::BALOAD + JVM::BASTORE + JVM::BIPUSH + JVM::CALOAD + JVM::CASTORE + JVM::DUP + JVM::DUP_X1 + JVM::DUP_X2 + JVM::DUP2 + JVM::DUP2_X1 + JVM::DUP2_X2 + JVM::GETFIELD + JVM::GETSTATIC + JVM::GOTO + JVM::GOTO_W + JVM::I2B + JVM::I2C + JVM::I2L + JVM::I2S + JVM::IADD + JVM::IALOAD + JVM::IAND + JVM::IASTORE + JVM::ICONST_M1 + JVM::ICONST_0 + JVM::ICONST_1 + JVM::ICONST_2 + JVM::ICONST_3 + JVM::ICONST_4 + JVM::ICONST_5 + JVM::IDIV + JVM::IF_ACMPEQ + JVM::IF_ACMPNE + JVM::IF_ICMPEQ + JVM::IF_ICMPGE + JVM::IF_ICMPGT + JVM::IF_ICMPLE + JVM::IF_ICMPLT + JVM::IF_ICMPNE + JVM::IFEQ + JVM::IFGE + JVM::IFGT + JVM::IFLE + JVM::IFLT + JVM::IFNE + JVM::IFNONNULL + JVM::IFNULL + JVM::IINC + JVM::ILOAD + JVM::ILOAD_0 + JVM::ILOAD_1 + JVM::ILOAD_2 + JVM::ILOAD_3 + JVM::IMUL + JVM::INEG + JVM::INSTANCEOF + JVM::INVOKESPECIAL + JVM::INVOKESTATIC + JVM::INVOKEVIRTUAL + JVM::IOR + JVM::IREM + JVM::IRETURN + JVM::ISHL + JVM::ISHR + JVM::ISTORE + JVM::ISTORE_0 + JVM::ISTORE_1 + JVM::ISTORE_2 + JVM::ISTORE_3 + JVM::ISUB + JVM::IUSHR + JVM::IXOR + JVM::JSR + JVM::JSR_W + JVM::L2I + JVM::LADD + JVM::LALOAD + JVM::LAND + JVM::LASTORE + JVM::LCMP + JVM::LCONST_0 + JVM::LCONST_1 + JVM::LDC + JVM::LDC_W + JVM::LDC2_W + JVM::LDIV + JVM::LLOAD + JVM::LLOAD_0 + JVM::LLOAD_1 + JVM::LLOAD_2 + JVM::LLOAD_3 + JVM::LMUL + JVM::LNEG + JVM::LOR + JVM::LREM + JVM::LRETURN + JVM::LSHL + JVM::LSHR + JVM::LSTORE + JVM::LSTORE_0 + JVM::LSTORE_1 + JVM::LSTORE_2 + JVM::LSTORE_3 + JVM::LSUB + JVM::LUSHR + JVM::LXOR + JVM::MONITORENTER + JVM::MONITOREXIT + JVM::MULTIANEWARRAY + JVM::NEW + JVM::NEWARRAY + JVM::NOP + JVM::POP + JVM::POP2 + JVM::PUTFIELD + JVM::PUTSTATIC + JVM::RET + JVM::RETURN + JVM::SALOAD + JVM::SASTORE + JVM::SIPUSH + JVM::SWAP + ASSOC-EQUAL LEN NTH ZP SYNTAXP + QUOTEP FIX NFIX E0-ORDINALP E0-ORD-<) + (union-eq *acl2-exports* + *common-lisp-symbols-from-main-lisp-package*)) + '(PC PROGRAM PUSH POP RETURN REVERSE STEP ++))) + +(certify-book "m5" 3) + +J & George +|# + +(in-package "M5") + +(include-book "../../../../ordinals/e0-ordinal") +(set-well-founded-relation e0-ord-<) + +; ----------------------------------------------------------------------------- +; Utilities + +(defun push (obj stack) (cons obj stack)) +(defun top (stack) (car stack)) +(defun pop (stack) (cdr stack)) + +(defun popn (n stack) + (if (zp n) + stack + (popn (- n 1) (pop stack)))) + +(defun bound? (x alist) (assoc-equal x alist)) + +(defun bind (x y alist) + (cond ((endp alist) (list (cons x y))) + ((equal x (car (car alist))) + (cons (cons x y) (cdr alist))) + (t (cons (car alist) (bind x y (cdr alist)))))) + +(defun binding (x alist) (cdr (assoc-equal x alist))) + +(defun op-code (inst) (car inst)) +(defun arg1 (inst) (car (cdr inst))) +(defun arg2 (inst) (car (cdr (cdr inst)))) +(defun arg3 (inst) (car (cdr (cdr (cdr inst))))) + +(defun nullrefp (ref) + (equal ref '(ref -1))) + +; Imported from ACL2 + +(defun reverse (x) + (if (consp x) + (append (reverse (cdr x)) (list (car x))) + nil)) + +; The following are constants and functions related to fixed integer sizes + +(defconst *largest-integer-value* (- (expt 2 31) 1)) +(defconst *largest-long-value* (- (expt 2 63) 1)) +(defconst *most-negative-integer* (- (expt 2 31))) +(defconst *most-negative-long* (- (expt 2 63))) + +; Coerce x to an unsigned integer which will fit in n bits. +(defun u-fix (x n) + (mod (ifix x) (expt 2 n))) + +; Coerce x to a signed integer which will fit in n bits. +(defun s-fix (x n) + (let ((temp (mod (ifix x) (expt 2 n)))) + (if (< temp (expt 2 (1- n))) + temp + (- temp (expt 2 n))))) + +(defun byte-fix (x) + (s-fix x 8)) + +(defun ubyte-fix (x) + (u-fix x 8)) + +(defun short-fix (x) + (s-fix x 16)) + +(defun int-fix (x) + (s-fix x 32)) + +(defun uint-fix (x) + (u-fix x 32)) + +(defun long-fix (x) + (s-fix x 64)) + +(defun ulong-fix (x) + (u-fix x 64)) + +(defun char-fix (x) + (u-fix x 16)) + +(defun 6-bit-fix (x) + (u-fix x 6)) + +(defun 5-bit-fix (x) + (u-fix x 5)) + +(defun expt2 (n) + (expt 2 n)) + +(defun shl (x n) + (* x (expt2 n))) + +(defun shr (x n) + (floor (* x (expt2 (- n))) 1)) + +; ----------------------------------------------------------------------------- +; States + +(defun make-state (thread-table heap class-table) + (list thread-table heap class-table)) +(defun thread-table (s) (nth 0 s)) +(defun heap (s) (nth 1 s)) +(defun class-table (s) (nth 2 s)) + +(defun make-thread (call-stack status rref) + (list call-stack status rref)) + +(defun call-stack (th s) + (nth 0 (binding th (thread-table s)))) + +(defun status (th s) + (nth 1 (binding th (thread-table s)))) + +(defun rref (th s) + (nth 2 (binding th (thread-table s)))) + +; ----------------------------------------------------------------------------- +; Class Declarations and the Class Table + +; The class table of a state is an alist. Each entry in a class table is +; a "class declaration" and is of the form + +; (class-name super-class-names fields defs) + +; Note that the definition below of the Thread class includes a 'run' method, +; which most applications will override. The definition is consistent +; with the default run method provided by the Thread class [O'Reily] + +(defun make-class-decl (name superclasses fields sfields cp methods href) + (list name superclasses fields sfields cp methods href)) + +(defun class-decl-name (dcl) + (nth 0 dcl)) +(defun class-decl-superclasses (dcl) + (nth 1 dcl)) +(defun class-decl-fields (dcl) + (nth 2 dcl)) +(defun class-decl-sfields (dcl) + (nth 3 dcl)) +(defun class-decl-cp (dcl) + (nth 4 dcl)) +(defun class-decl-methods (dcl) + (nth 5 dcl)) +(defun class-decl-heapref (dcl) + (nth 6 dcl)) + +(defun base-class-def () + (list (make-class-decl "java.lang.Object" + nil + '("monitor" "mcount" "wait-set") + '() + '() + '(("<init>" () nil (RETURN))) + '(REF -1)) + (make-class-decl "ARRAY" + '("java.lang.Object") + '(("<array>" . *ARRAY*)) + '() + '() + '() + '(REF -1)) + (make-class-decl "java.lang.Thread" + '("java.lang.Object") + '() + '() + '() + '(("run" () nil + (RETURN)) + ("start" () nil ()) + ("stop" () nil ()) + ("<init>" () + nil + (aload_0) + (invokespecial "java.lang.Object" "<init>" 0) + (return))) + '(REF -1)) + (make-class-decl "java.lang.String" + '("java.lang.Object") + '("strcontents") + '() + '() + '(("<init>" () + nil + (aload_0) + (invokespecial "java.lang.Object" "<init>" 0) + (return))) + '(REF -1)) + (make-class-decl "java.lang.Class" + '("java.lang.Object") + '() + '() + '() + '(("<init>" () + nil + (aload_0) + (invokespecial "java.lang.Object" "<init>" 0) + (return))) + '(REF -1)))) + +(defun make-class-def (list-of-class-decls) + (append (base-class-def) list-of-class-decls)) + +; ----------------------------------------------------------------------------- +; A Constant Pool +; +; There is one constant pool per class + +; A constant pool is a list of entries. Each entry is either: +; +; '(INT n) +; Where n is a 32-bit number, in the range specified by the JVM spec +; +; '(STRING (REF -1) "Hello, World!") +; The 3rd element (a string) is resolved to a heap reference the +; first time it is used. Once it is resolved, its reference is placed +; as the second element (displacing the null ref currently there). + +(defun cp-make-int-entry (n) + (list 'INT n)) + +(defun cp-make-string-entry (str) + (list 'STRING '(REF -1) str)) + +(defun cp-string-resolved? (entry) + (not (equal (cadr (caddr entry)) -1))) + +(defun retrieve-cp (class-name class-table) + (class-decl-cp (bound? class-name class-table))) + +(defun update-ct-string-ref (class idx newval ct) + (let* ((class-entry (bound? class ct)) + (oldstrval (caddr (nth idx (retrieve-cp class ct)))) + (newstrentry (list 'STRING newval oldstrval)) + (new-cp (update-nth idx + newstrentry + (class-decl-cp class-entry))) + (new-class-entry + (make-class-decl (class-decl-name class-entry) + (class-decl-superclasses class-entry) + (class-decl-fields class-entry) + (class-decl-sfields class-entry) + new-cp + (class-decl-methods class-entry) + (class-decl-heapref class-entry)))) + (bind class (cdr new-class-entry) ct))) + +; ----------------------------------------------------------------------------- +; Thread Tables +; +; A "thread table" might be used to represent threads in m5. It consists of +; a reference, a call stack, a flag to indicate whether its call-stack +; should be stepped by the scheduler, and a ref to the original object +; in the heap. +; +; Thread table: +; ((n . (call-stack flag reverse-ref)) +; (n+1 . (call-stack flag reverse-ref))) +; +; The flags 'SCHEDULED and 'UNSCHEDULED correspond to two of the +; four states threads can be in (according to [O'Reily]). For our +; model, this will suffice. + +(defun make-tt (call-stack) + (bind 0 (list call-stack 'SCHEDULED nil) nil)) + +(defun addto-tt (call-stack status heapRef tt) + (bind (len tt) (list call-stack status heapRef) tt)) + +(defun mod-thread-scheduling (th sched tt) + (let* ((thrd (binding th tt)) + (oldcs (car thrd)) + (oldhr (caddr thrd)) + (newTH (list oldcs sched oldhr))) + (bind th newTH tt))) + +(defun schedule-thread (th tt) + (mod-thread-scheduling th 'SCHEDULED tt)) + +(defun unschedule-thread (th tt) + (mod-thread-scheduling th 'UNSCHEDULED tt)) + +(defun rrefToThread (ref tt) + (cond ((endp tt) nil) + ((equal ref (cadddr (car tt))) (caar tt)) + (t (rrefToThread ref (cdr tt))))) + +; ---------------------------------------------------------------------------- +; Helper function for determining if an object is a 'Thread' object + +(defun in-list (item list) + (cond ((endp list) nil) + ((equal item (car list)) t) + (t (in-list item (cdr list))))) + +(defun isThreadObject? (class-name class-table) + (let* ((class (bound? class-name class-table)) + (psupers (class-decl-superclasses class)) + (supers (cons class-name psupers))) + (or (in-list "java.lang.Thread" supers) + (in-list "java.lang.ThreadGroup" supers)))) + +; ---------------------------------------------------------------------------- +; Helper functions for locking and unlocking objects + +; lock-object and unlock-object will obtain a lock on an instance +; of an object, using th as the locking id (a thread owns a lock). If th +; already has a lock on an object, then the mcount of the object is +; incremented. Likewise if you unlock an object with mcount > 0, then +; the lock will be decremented. Note: you must make sure that th can +; and should get the lock, since this function will blindly go ahead and +; get the lock + +(defun lock-object (th obj-ref heap) + (let* ((obj-ref-num (cadr obj-ref)) + (instance (binding (cadr obj-ref) heap)) + (obj-fields (binding "java.lang.Object" instance)) + (new-mcount (+ 1 (binding "mcount" obj-fields))) + (new-obj-fields + (bind "monitor" th + (bind "mcount" new-mcount obj-fields))) + (new-object (bind "java.lang.Object" new-obj-fields instance))) + (bind obj-ref-num new-object heap))) + +(defun unlock-object (th obj-ref heap) + (let* ((obj-ref-num (cadr obj-ref)) + (instance (binding (cadr obj-ref) heap)) + (obj-fields (binding "java.lang.Object" instance)) + (old-mcount (binding "mcount" obj-fields)) + (new-mcount (ACL2::max 0 (- old-mcount 1))) + (new-monitor (if (zp new-mcount) + 0 + th)) + (new-obj-fields + (bind "monitor" new-monitor + (bind "mcount" new-mcount obj-fields))) + (new-object (bind "java.lang.Object" new-obj-fields instance))) + (bind obj-ref-num new-object heap))) + +; objectLockable? is used to determine if th can unlock instance. This +; occurs when either mcount is zero (nobody has a lock), or mcount is +; greater than zero, but monitor is equal to th. This means that th +; already has a lock on the object, and when the object is locked yet again, +; monitor will remain the same, but mcount will be incremented. +; +; objectUnLockable? determins if a thread can unlock an object (ie if it +; has a lock on that object) +(defun objectLockable? (instance th) + (let* ((obj-fields (binding "java.lang.Object" instance)) + (monitor (binding "monitor" obj-fields)) + (mcount (binding "mcount" obj-fields))) + (or (zp mcount) + (equal monitor th)))) + +(defun objectUnLockable? (instance th) + (let* ((obj-fields (binding "java.lang.Object" instance)) + (monitor (binding "monitor" obj-fields))) + (equal monitor th))) + +; ----------------------------------------------------------------------------- +; Frames + +(defun make-frame (pc locals stack program sync-flg cur-class) + (list pc locals stack program sync-flg cur-class)) + +(defun top-frame (th s) (top (call-stack th s))) + +(defun pc (frame) (nth 0 frame)) +(defun locals (frame) (nth 1 frame)) +(defun stack (frame) (nth 2 frame)) +(defun program (frame) (nth 3 frame)) +(defun sync-flg (frame) (nth 4 frame)) +(defun cur-class (frame) (nth 5 frame)) + +; ----------------------------------------------------------------------------- +; Method Declarations + +; The methods component of a class declaration is a list of method definitions. +; A method definition is a list of the form + +; (name formals sync-status . program) + +; We never build these declarations but just enter list constants for them, + +; Note the similarity to our old notion of a program definition. We +; will use strings to name methods now. + +; sync-status is 't' if the method is synchronized, 'nil' if not + +; Method definitions will be constructed by expressions such as: +; (Note: all of the symbols below are understood to be in the pkg "JVM".) + +; ("move" (dx dy) nil +; (load this) +; (load this) +; (getfield "Point" "x") +; (load dx) +; (add) +; (putfield "Point" "x") ; this.x = this.x + dx; +; (load :this) +; (load :this) +; (getfield "Point" "y") +; (load dy) +; (add) +; (putfield "Point" "y") ; this.y = this.y + dy; +; (push 1) +; (xreturn))) ; return 1; + +; Provided this method is defined in the class "Point" it can be invoked by + +; (invokevirtual "Point" "move" 2) + +; This assumes that the stack, at the time of invocation, contains an +; reference to an object of type "Point" and two numbers, dx and dy. + +; If a method declaration has an empty list for the program (ie- there are +; no bytecodes associated with the method), then the method is considered +; native. Native methods are normally written in something like C or +; assembly language. The JVM would normally ensure that the correct number +; and type of arguments are passed to the native method, and would then hand +; over control to C. In our model, we simply "hardwire" invokevirtual to +; to handle these methods. +; * Note that a method in Java will never have 0 bytecodes, since even if +; it has no body, it will consist of at least the (xreturn) bytecode. + +; The accessors for methods are: + +(defun method-name (m) + (nth 0 m)) +(defun method-formals (m) + (nth 1 m)) +(defun method-sync (m) + (nth 2 m)) +(defun method-program (m) + (cdddr m)) +(defun method-isNative? (m) + (equal '(NIL) + (method-program m))) + +; The Standard Modify + +(defun suppliedp (key args) + (cond ((endp args) nil) + ((equal key (car args)) t) + (t (suppliedp key (cdr args))))) + +(defun actual (key args) + (cond ((endp args) nil) + ((equal key (car args)) (cadr args)) + (t (actual key (cdr args))))) + +(defmacro modify (th s &rest args) + (list 'make-state + (cond + ((or (suppliedp :call-stack args) + (suppliedp :pc args) + (suppliedp :locals args) + (suppliedp :stack args) + (suppliedp :program args) + (suppliedp :sync-flg args) + (suppliedp :cur-class args) + (suppliedp :status args)) + (list 'bind + th + (list 'make-thread + (cond + ((suppliedp :call-stack args) + (actual :call-stack args)) + ((and (suppliedp :status args) + (null (cddr args))) + (list 'call-stack th s)) + (t + (list 'push + (list 'make-frame + (if (suppliedp :pc args) + (actual :pc args) + (list 'pc (list 'top-frame th s))) + (if (suppliedp :locals args) + (actual :locals args) + (list 'locals (list 'top-frame th s))) + (if (suppliedp :stack args) + (actual :stack args) + (list 'stack (list 'top-frame th s))) + (if (suppliedp :program args) + (actual :program args) + (list 'program (list 'top-frame th s))) + (if (suppliedp :sync-flg args) + (actual :sync-flg args) + (list 'sync-flg (list 'top-frame th s))) + (if (suppliedp :cur-class args) + (actual :cur-class args) + (list 'cur-class + (list 'top-frame th s)))) + (list 'pop (list 'call-stack th s))))) + (if (suppliedp :status args) + (actual :status args) + (list 'status th s)) + (list 'rref th s)) + (list 'thread-table s))) + ((suppliedp :thread-table args) + (actual :thread-table args)) + (t (list 'thread-table s))) + (if (suppliedp :heap args) + (actual :heap args) + (list 'heap s)) + (if (suppliedp :class-table args) + (actual :class-table args) + (list 'class-table s)))) + +; ----------------------------------------------------------------------------- +; Helper functions related to building instances of objects + +(defun deref (ref heap) + (binding (cadr ref) heap)) + +(defun field-value (class-name field-name instance) + (binding field-name + (binding class-name instance))) + +(defun build-class-field-bindings (field-names) + (if (endp field-names) + nil + (cons (cons (car field-names) 0) + (build-class-field-bindings (cdr field-names))))) + +(defun build-class-object-field-bindings () + '(("monitor" . 0) ("monitor-count" . 0) ("wait-set" . nil))) + +(defun build-immediate-instance-data (class-name class-table) + (cons class-name + (build-class-field-bindings + (class-decl-fields + (bound? class-name class-table))))) + +(defun build-an-instance (class-names class-table) + (if (endp class-names) + nil + (cons (build-immediate-instance-data (car class-names) class-table) + (build-an-instance (cdr class-names) class-table)))) + +(defun build-class-data (sfields) + (cons "java.lang.Class" + (build-class-field-bindings + (cons "<name>" sfields)))) + +(defun build-a-class-instance (sfields class-table) + (list (build-class-data sfields) + (build-immediate-instance-data "java.lang.Object" class-table))) + + +; ----------------------------------------------------------------------------- +; Arrays + +(defun value-of (obj) + (cdr obj)) + +(defun superclasses-of (class ct) + (class-decl-superclasses (bound? class ct))) + +(defun array-content (array) + (value-of (field-value "ARRAY" "<array>" array))) + +(defun array-type (array) + (nth 0 (array-content array))) + +(defun array-bound (array) + (nth 1 (array-content array))) + +(defun array-data (array) + (nth 2 (array-content array))) + +(defun element-at (index array) + (nth index (array-data array))) + +(defun makearray (type bound data class-table) + (cons (list "ARRAY" + (cons "<array>" (cons '*array* (list type bound data)))) + (build-an-instance + (superclasses-of "ARRAY" class-table) + class-table))) + +(defun set-element-at (value index array class-table) + (makearray (array-type array) + (array-bound array) + (update-nth index value (array-data array)) + class-table)) + +(defun primitive-type (type) + (cond ((equal type 'T_BYTE) t) + ((equal type 'T_SHORT) t) + ((equal type 'T_INT) t) + ((equal type 'T_LONG) t) + ((equal type 'T_FLOAT) t) + ((equal type 'T_DOUBLE) t) + ((equal type 'T_CHAR) t) + ((equal type 'T_BOOLEAN) t) + (t nil))) + +(defun atype-to-identifier (atype-num) + (cond ((equal atype-num 4) 'T_BOOLEAN) + ((equal atype-num 5) 'T_CHAR) + ((equal atype-num 6) 'T_FLOAT) + ((equal atype-num 7) 'T_DOUBLE) + ((equal atype-num 8) 'T_BYTE) + ((equal atype-num 9) 'T_SHORT) + ((equal atype-num 10) 'T_INT) + ((equal atype-num 11) 'T_LONG) + (t nil))) + +(defun identifier-to-atype (ident) + (cond ((equal ident 'T_BOOLEAN) 4) + ((equal ident 'T_CHAR) 5) + ((equal ident 'T_FLOAT) 6) + ((equal ident 'T_DOUBLE) 7) + ((equal ident 'T_BYTE) 8) + ((equal ident 'T_SHORT) 9) + ((equal ident 'T_INT) 10) + ((equal ident 'T_LONG) 11) + (t nil))) + +(defun default-value1 (type) + (if (primitive-type type) + 0 + nil)) + +(defun init-array (type count) + (if (zp count) + nil + (cons (default-value1 type) (init-array type (- count 1))))) + +; The following measure is due to J +(defun natural-sum (lst) + (cond ((endp lst) 0) + (t (+ (nfix (car lst)) (natural-sum (cdr lst)))))) + +(mutual-recursion + + ; makemultiarray2 :: num, counts, s, ac --> [refs] + (defun makemultiarray2 (car-counts cdr-counts s ac) + (declare (xargs :measure (cons (len (cons car-counts cdr-counts)) + (natural-sum (cons car-counts cdr-counts))))) + (if (zp car-counts) + (mv (heap s) ac) + (mv-let (new-addr new-heap) + (makemultiarray cdr-counts s) + (makemultiarray2 (- car-counts 1) + cdr-counts + (make-state (thread-table s) + new-heap + (class-table s)) + (cons (list 'REF new-addr) ac))))) + + ; makemultiarray :: [counts], s --> addr, new-heap + (defun makemultiarray (counts s) + (declare (xargs :measure (cons (+ 1 (len counts)) + (natural-sum counts)))) + (if (<= (len counts) 1) + + ; "Base case" Handles initializing the final dimension + (mv (len (heap s)) + (bind (len (heap s)) + (makearray 'T_REF + (car counts) + (init-array 'T_REF (car counts)) + (class-table s)) + (heap s))) + + ; "Recursive Case" + (mv-let (heap-prime lst-of-refs) + (makemultiarray2 (car counts) + (cdr counts) + s + nil) + (let* ((obj (makearray 'T_REF + (car counts) + lst-of-refs + (class-table s))) + (new-addr (len heap-prime)) + (new-heap (bind new-addr obj heap-prime))) + (mv new-addr new-heap))))) +) + +; ----------------------------------------------------------------------------- +; Instruction length table -- PCs are now in bytes, not # of instructions + +(defun inst-length (inst) + (case (op-code inst) + (AALOAD 1) + (AASTORE 1) + (ACONST_NULL 1) + (ALOAD 2) + (ALOAD_0 1) + (ALOAD_1 1) + (ALOAD_2 1) + (ALOAD_3 1) + (ANEWARRAY 3) + (ARETURN 1) + (ARRAYLENGTH 1) + (ASTORE 2) + (ASTORE_0 1) + (ASTORE_1 1) + (ASTORE_2 1) + (ASTORE_3 1) + (BALOAD 1) + (BASTORE 1) + (BIPUSH 2) + (CALOAD 1) + (CASTORE 1) + (DUP 1) + (DUP_X1 1) + (DUP_X2 1) + (DUP2 1) + (DUP2_X1 1) + (DUP2_X2 1) + (GETFIELD 3) + (GETSTATIC 3) + (GOTO 3) + (GOTO_W 5) + (I2B 1) + (I2C 1) + (I2L 1) + (I2S 1) + (IADD 1) + (IALOAD 1) + (IAND 1) + (IASTORE 1) + (ICONST_M1 1) + (ICONST_0 1) + (ICONST_1 1) + (ICONST_2 1) + (ICONST_3 1) + (ICONST_4 1) + (ICONST_5 1) + (IDIV 1) + (IF_ACMPEQ 3) + (IF_ACMPNE 3) + (IF_ICMPEQ 3) + (IF_ICMPGE 3) + (IF_ICMPGT 3) + (IF_ICMPLE 3) + (IF_ICMPLT 3) + (IF_ICMPNE 3) + (IFEQ 3) + (IFGE 3) + (IFGT 3) + (IFLE 3) + (IFLT 3) + (IFNE 3) + (IFNONNULL 3) + (IFNULL 3) + (IINC 3) + (ILOAD 2) + (ILOAD_0 1) + (ILOAD_1 1) + (ILOAD_2 1) + (ILOAD_3 1) + (IMUL 1) + (INEG 1) + (INSTANCEOF 3) + (INVOKESPECIAL 3) + (INVOKESTATIC 3) + (INVOKEVIRTUAL 3) + (IOR 1) + (IREM 1) + (IRETURN 1) + (ISHL 1) + (ISHR 1) + (ISTORE 2) + (ISTORE_0 1) + (ISTORE_1 1) + (ISTORE_2 1) + (ISTORE_3 1) + (ISUB 1) + (IUSHR 1) + (IXOR 1) + (JSR 3) + (JSR_W 5) + (L2I 1) + (LADD 1) + (LALOAD 1) + (LAND 1) + (LASTORE 1) + (LCMP 1) + (LCONST_0 1) + (LCONST_1 1) + (LDC 2) + (LDC_W 3) + (LDC2_W 3) + (LDIV 1) + (LLOAD 2) + (LLOAD_0 1) + (LLOAD_1 1) + (LLOAD_2 1) + (LLOAD_3 1) + (LMUL 1) + (LNEG 1) + (LOR 1) + (LREM 1) + (LRETURN 1) + (LSHL 1) + (LSHR 1) + (LSTORE 2) + (LSTORE_0 1) + (LSTORE_1 1) + (LSTORE_2 1) + (LSTORE_3 1) + (LSUB 1) + (LUSHR 1) + (LXOR 1) + (MONITORENTER 1) + (MONITOREXIT 1) + (MULTIANEWARRAY 4) + (NEW 3) + (NEWARRAY 2) + (NOP 1) + (POP 1) + (POP2 1) + (PUTFIELD 3) + (PUTSTATIC 3) + (RET 2) + (RETURN 1) + (SALOAD 1) + (SASTORE 1) + (SIPUSH 3) + (SWAP 1) + (t 1))) + + +; ============================================================================= +; JVM INSTRUCTIONS BEGIN HERE +; ============================================================================= + +; ----------------------------------------------------------------------------- +; (AALOAD) Instruction + +(defun execute-AALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (element-at index array) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (AASTORE) Instruction + +(defun execute-AASTORE (inst th s) + (let* ((value (top (stack (top-frame th s)))) + (index (top (pop (stack (top-frame th s))))) + (arrayref (top (pop (pop (stack (top-frame th s))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (pop (pop (stack (top-frame th s))))) + :heap (bind (cadr arrayref) + (set-element-at value + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (ACONST_NULL) Instruction + +(defun execute-ACONST_NULL (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push '(REF -1) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ALOAD idx) Instruction - load a reference from the locals + +(defun execute-ALOAD (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (nth (arg1 inst) + (locals (top-frame th s))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ALOAD_X) Instruction - load a reference from the locals +; covers ALOAD_{0, 1, 2, 3} + +(defun execute-ALOAD_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (nth n (locals (top-frame th s))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ANEWARRAY) Instruction + +(defun execute-ANEWARRAY (inst th s) + (let* ((type 'T_REF) + (count (top (stack (top-frame th s)))) + (addr (len (heap s))) + (obj (makearray type + count + (init-array type count) + (class-table s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (list 'REF addr) + (pop (stack (top-frame th s)))) + :heap (bind addr + obj + (heap s))))) + +; ----------------------------------------------------------------------------- +; (ARETURN) Instruction - return a reference to the preceeding frame + +(defun execute-ARETURN (inst th s) + (declare (ignore inst)) + (let* ((val (top (stack (top-frame th s)))) + (obj-ref (nth 0 (locals (top-frame th s)))) + (sync-status (sync-flg (top-frame th s))) + (class (cur-class (top-frame th s))) + (ret-ref (class-decl-heapref (bound? class (class-table s)))) + (new-heap (cond ((equal sync-status 'LOCKED) + (unlock-object th obj-ref (heap s))) + ((equal sync-status 'S_LOCKED) + (unlock-object th ret-ref (heap s))) + (t (heap s)))) + (s1 (modify th s + :call-stack (pop (call-stack th s)) + :heap new-heap))) + (modify th s1 + :stack (push val (stack (top-frame th s1)))))) + +; ----------------------------------------------------------------------------- +; (ARRAYLENGTH) Instruction + +(defun execute-ARRAYLENGTH (inst th s) + (let* ((arrayref (top (stack (top-frame th s)))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (array-bound array) + (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (ASTORE idx) Instruction - store a reference into the locals + +(defun execute-ASTORE (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth (arg1 inst) + (top (stack (top-frame th s))) + (locals (top-frame th s))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ASTORE_X) Instruction - store a reference into the locals +; covers ASTORE_{0, 1, 2, 3} + +(defun execute-ASTORE_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth n + (top (stack (top-frame th s))) + (locals (top-frame th s))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (BALOAD) Instruction + +(defun execute-BALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s))) + (element (if (equal (array-type array) + 'T_BOOLEAN) + (ubyte-fix (element-at index array)) + (byte-fix (element-at index array))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push element + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (BASTORE) Instruction + +(defun execute-BASTORE (inst th s) + (let* ((value (top (stack (top-frame th s)))) + (index (top (pop (stack (top-frame th s))))) + (arrayref (top (pop (pop (stack (top-frame th s)))))) + (element (if (equal (array-type (deref arrayref (heap s))) + 'T_BYTE) + (byte-fix value) + (u-fix value 1)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (pop (pop (stack (top-frame th s))))) + :heap (bind (cadr arrayref) + (set-element-at element + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (BIPUSH const) Instruction + +(defun execute-BIPUSH (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (byte-fix (arg1 inst)) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (CALOAD) Instruction + +(defun execute-CALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (char-fix (element-at index array)) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (CASTORE) Instruction + +(defun execute-CASTORE (inst th s) + (let* ((value (top (stack (top-frame th s)))) + (index (top (pop (stack (top-frame th s))))) + (arrayref (top (pop (pop (stack (top-frame th s))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (pop (pop (stack (top-frame th s))))) + :heap (bind (cadr arrayref) + (set-element-at (char-fix value) + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (DUP) Instruction + +(defun execute-DUP (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (top (stack (top-frame th s))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (DUP_X1) Instruction + +(defun execute-DUP_X1 (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s))))) + (stack_prime (pop (pop (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val1 (push val2 (push val1 stack_prime)))))) + +; ----------------------------------------------------------------------------- +; (DUP_X2) Instruction + +(defun execute-DUP_X2 (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s))))) + (val3 (top (popn 2 (stack (top-frame th s))))) + (stack_prime (popn 3 (stack (top-frame th s))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val1 + (push val2 + (push val3 + (push val1 stack_prime))))))) + +; ----------------------------------------------------------------------------- +; (DUP2) Instruction + +(defun execute-DUP2 (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s))))) + (stack_prime (pop (pop (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val1 + (push val2 + (push val1 + (push val2 stack_prime))))))) + +; ----------------------------------------------------------------------------- +; (DUP2_X1) Instruction + +(defun execute-DUP2_X1 (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s))))) + (val3 (top (popn 2 (stack (top-frame th s))))) + (stack_prime (popn 3 (stack (top-frame th s))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val1 + (push val2 + (push val3 + (push val1 + (push val2 stack_prime)))))))) + +; ----------------------------------------------------------------------------- +; (DUP2_X2) Instruction + +(defun execute-DUP2_X2 (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s))))) + (val3 (top (popn 2 (stack (top-frame th s))))) + (val4 (top (popn 3 (stack (top-frame th s))))) + (stack_prime (popn 4 (stack (top-frame th s))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val1 + (push val2 + (push val3 + (push val4 + (push val1 + (push val2 stack_prime))))))))) + +; ----------------------------------------------------------------------------- +; (GETFIELD "class" "field" ?long-flag?) Instruction + +(defun execute-GETFIELD (inst th s) + (let* ((class-name (arg1 inst)) + (field-name (arg2 inst)) + (long-flag (arg3 inst)) + (instance (deref (top (stack (top-frame th s))) (heap s))) + (field-value (field-value class-name field-name instance))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (if long-flag + (push 0 (push field-value + (pop (stack (top-frame th s))))) + (push field-value + (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (GETSTATIC "class" "field" ?long-flag?) Instruction + +(defun static-field-value (class-name field-name s) + (let* ((class-ref (class-decl-heapref + (bound? class-name (class-table s)))) + (instance (deref class-ref (heap s)))) + (field-value "java.lang.Class" field-name instance))) + +(defun execute-GETSTATIC (inst th s) + (let* ((class-name (arg1 inst)) + (field-name (arg2 inst)) + (long-flag (arg3 inst)) + (class-ref (class-decl-heapref + (bound? class-name (class-table s)))) + (instance (deref class-ref (heap s))) + (field-value (field-value "java.lang.Class" field-name instance))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (if long-flag + (push 0 (push field-value (stack (top-frame th s)))) + (push field-value (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (GOTO pc) Instruction + +(defun execute-GOTO (inst th s) + (modify th s + :pc (+ (arg1 inst) (pc (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (GOTO_W pc) Instruction + +(defun execute-GOTO_W (inst th s) + (modify th s + :pc (+ (arg1 inst) (pc (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (I2B) Instruction - int to byte narrowing conversion + +(defun execute-I2B (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (byte-fix (top (stack (top-frame th s)))) + (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (I2C) Instruction - int to char narrowing conversion + +(defun execute-I2C (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (char-fix (top (stack (top-frame th s)))) + (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (I2L) Instruction - int to long conversion + +(defun execute-I2L (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (long-fix (top (stack (top-frame th s)))) + (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (I2S) Instruction - int to short narrowing conversion + +(defun execute-I2S (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (short-fix (top (stack (top-frame th s)))) + (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IADD) Instruction + +(defun execute-IADD (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix + (+ (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IALOAD) Instruction + +(defun execute-IALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (element-at index array) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (IAND) Instruction + +(defun execute-IAND (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (logand (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IASTORE) Instruction + +(defun execute-IASTORE (inst th s) + (let* ((value (top (stack (top-frame th s)))) + (index (top (pop (stack (top-frame th s))))) + (arrayref (top (pop (pop (stack (top-frame th s))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (pop (pop (stack (top-frame th s))))) + :heap (bind (cadr arrayref) + (set-element-at value + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (ICONST_X) Instruction - push a certain constant onto the stack +; covers ICONST_{M1, 0, 1, 2, 3, 4, 5} + +(defun execute-ICONST_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push n (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IDIV) Instruction + +(defun execute-IDIV (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix + (truncate (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IF_ACMPEQ pc) Instruction + +(defun execute-IF_ACMPEQ (inst th s) + (modify th s + :pc (if (equal (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ACMPNE pc) Instruction + +(defun execute-IF_ACMPNE (inst th s) + (modify th s + :pc (if (equal (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (inst-length inst) (pc (top-frame th s))) + (+ (arg1 inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPEQ pc) Instruction + +(defun execute-IF_ICMPEQ (inst th s) + (modify th s + :pc (if (equal (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPGE pc) Instruction + +(defun execute-IF_ICMPGE (inst th s) + (modify th s + :pc (if (>= (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPGT pc) Instruction + +(defun execute-IF_ICMPGT (inst th s) + (modify th s + :pc (if (> (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPLT pc) Instruction + +(defun execute-IF_ICMPLT (inst th s) + (modify th s + :pc (if (< (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPLE pc) Instruction + +(defun execute-IF_ICMPLE (inst th s) + (modify th s + :pc (if (<= (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IF_ICMPNE pc) Instruction + +(defun execute-IF_ICMPNE (inst th s) + (modify th s + :pc (if (equal (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (+ (inst-length inst) (pc (top-frame th s))) + (+ (arg1 inst) (pc (top-frame th s)))) + :stack (pop (pop (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (IFEQ pc) Instruction + +(defun execute-IFEQ (inst th s) + (modify th s + :pc (if (equal (top (stack (top-frame th s))) 0) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFGE pc) Instruction + +(defun execute-IFGE (inst th s) + (modify th s + :pc (if (>= (top (stack (top-frame th s))) 0) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFGT pc) Instruction + +(defun execute-IFGT (inst th s) + (modify th s + :pc (if (> (top (stack (top-frame th s))) 0) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFLE pc) Instruction + +(defun execute-IFLE (inst th s) + (modify th s + :pc (if (<= (top (stack (top-frame th s))) 0) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFLT pc) Instruction + +(defun execute-IFLT (inst th s) + (modify th s + :pc (if (< (top (stack (top-frame th s))) 0) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFNE pc) Instruction + +(defun execute-IFNE (inst th s) + (modify th s + :pc (if (equal (top (stack (top-frame th s))) 0) + (+ (inst-length inst) (pc (top-frame th s))) + (+ (arg1 inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFNONNULL pc) Instruction + +(defun execute-IFNONNULL (inst th s) + (modify th s + :pc (if (equal (top (stack (top-frame th s))) '(REF -1)) + (+ (inst-length inst) (pc (top-frame th s))) + (+ (arg1 inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IFNULL pc) Instruction + +(defun execute-IFNULL (inst th s) + (modify th s + :pc (if (equal (top (stack (top-frame th s))) '(REF -1)) + (+ (arg1 inst) (pc (top-frame th s))) + (+ (inst-length inst) (pc (top-frame th s)))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IINC idx const) Instruction - Increment local variable by a constant + +(defun execute-IINC (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth (arg1 inst) + (int-fix + (+ (arg2 inst) + (nth (arg1 inst) + (locals (top-frame th s))))) + (locals (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ILOAD idx) Instruction - Push a local onto the stack + +(defun execute-ILOAD (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (nth (arg1 inst) + (locals (top-frame th s))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ILOAD_X) Instruction - Push a local onto the stack +; covers ILOAD_{0, 1, 2, 3} + +(defun execute-ILOAD_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (nth n (locals (top-frame th s))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (IMUL) Instruction + +(defun execute-IMUL (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix + (* (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (INEG) Instruction +; Because of the way the JVM represents 2's complement ints, +; the negation of the most negative int is itself + +(defun execute-INEG (inst th s) + (let* ((result (if (equal (top (stack (top-frame th s))) + *most-negative-integer*) + *most-negative-integer* + (- (top (stack (top-frame th s))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push result (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (INSTANCEOF) Instruction + +(defun execute-INSTANCEOF (inst th s) + (let* ((ref (top (stack (top-frame th s)))) + (obj (deref ref (heap s))) + (obj-class (caar obj)) + (obj-supers (cons obj-class (class-decl-superclasses + (bound? obj-class (class-table s))))) + (value (if (nullrefp ref) + 0 + (if (member-equal (arg1 inst) obj-supers) + 1 + 0)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push value (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IOR) Instruction + +(defun execute-IOR (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (logior (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IREM) Instruction + +(defun execute-IREM (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (result (- val1 (* (truncate val1 val2) val2)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push result + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (IRETURN) Instruction - return an int + +(defun execute-IRETURN (inst th s) + (declare (ignore inst)) + (let* ((val (top (stack (top-frame th s)))) + (obj-ref (nth 0 (locals (top-frame th s)))) + (sync-status (sync-flg (top-frame th s))) + (class (cur-class (top-frame th s))) + (ret-ref (class-decl-heapref (bound? class (class-table s)))) + (new-heap (cond ((equal sync-status 'LOCKED) + (unlock-object th obj-ref (heap s))) + ((equal sync-status 'S_LOCKED) + (unlock-object th ret-ref (heap s))) + (t (heap s)))) + (s1 (modify th s + :call-stack (pop (call-stack th s)) + :heap new-heap))) + (modify th s1 + :stack (push val (stack (top-frame th s1)))))) + +; ----------------------------------------------------------------------------- +; (ISHL) Instruction + +(defun execute-ISHL (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (5-bit-fix val2)) + (result (shl val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix result) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (ISHR) Instruction + +(defun execute-ISHR (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (5-bit-fix val2)) + (result (shr val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix result) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (ISTORE idx) Instruction - store an int into the locals + +(defun execute-ISTORE (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth (arg1 inst) + (top (stack (top-frame th s))) + (locals (top-frame th s))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ISTORE_X) Instruction - store an int into the locals +; covers ISTORE_{0, 1, 2, 3} + +(defun execute-ISTORE_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth n + (top (stack (top-frame th s))) + (locals (top-frame th s))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (ISUB) Instruction + +(defun execute-ISUB (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix (- (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (IUSHR) Instruction + +(defun execute-IUSHR (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (5-bit-fix val2)) + (result (shr val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix result) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (IXOR) Instruction + +(defun execute-IXOR (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (logxor (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s)))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (JSR) Instruction + +(defun execute-JSR (inst th s) + (modify th s + :pc (+ (arg1 inst) (pc (top-frame th s))) + :stack (push (list 'RETURNADDRESS + (+ (inst-length inst) + (pc (top-frame th s)))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (JSR_W) Instruction + +(defun execute-JSR_W (inst th s) + (modify th s + :pc (+ (arg1 inst) (pc (top-frame th s))) + :stack (push (list 'RETURNADDRESS + (+ (inst-length inst) + (pc (top-frame th s)))) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (INVOKESPECIAL "class" "name" n) Instruction + +(defun class-name-of-ref (ref heap) + (car (car (deref ref heap)))) + +(defun bind-formals (n stack) + (if (zp n) + nil + (cons (top stack) + (bind-formals (- n 1) (pop stack))))) + +(defun lookup-method-in-superclasses (name classes class-table) + (cond ((endp classes) nil) + (t (let* ((class-name (car classes)) + (class-decl (bound? class-name class-table)) + (method (bound? name (class-decl-methods class-decl)))) + (if method + method + (lookup-method-in-superclasses name (cdr classes) + class-table)))))) + +(defun lookup-method (name class-name class-table) + (lookup-method-in-superclasses name + (cons class-name + (class-decl-superclasses + (bound? class-name class-table))) + class-table)) + +(defun execute-INVOKESPECIAL (inst th s) + (let* ((method-name (arg2 inst)) + (nformals (arg3 inst)) + (obj-ref (top (popn nformals (stack (top-frame th s))))) + (instance (deref obj-ref (heap s))) + (obj-class-name (arg1 inst)) + (closest-method + (lookup-method method-name + obj-class-name + (class-table s))) + (prog (method-program closest-method)) + (s1 (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (popn (+ nformals 1) + (stack (top-frame th s))))) + (tThread (rrefToThread obj-ref (thread-table s)))) + (cond + ((method-isNative? closest-method) + (cond ((equal method-name "start") + (modify tThread s1 :status 'SCHEDULED)) + ((equal method-name "stop") + (modify tThread s1 + :status 'UNSCHEDULED)) + (t s))) + ((and (method-sync closest-method) + (objectLockable? instance th)) + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals (+ nformals 1) + (stack (top-frame th s)))) + nil + prog + 'LOCKED + (arg1 inst)) + (call-stack th s1)) + :heap (lock-object th obj-ref (heap s)))) + ((method-sync closest-method) + s) + (t + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals (+ nformals 1) + (stack (top-frame th s)))) + nil + prog + 'UNLOCKED + (arg1 inst)) + (call-stack th s1))))))) + +; ----------------------------------------------------------------------------- +; (INVOKESTATIC "class" "name" n) Instruction + +(defun execute-INVOKESTATIC (inst th s) + (let* ((class (arg1 inst)) + (method-name (arg2 inst)) + (nformals (arg3 inst)) + (obj-ref (class-decl-heapref (bound? class (class-table s)))) + (instance (deref obj-ref (heap s))) + (closest-method + (lookup-method method-name + (arg1 inst) + (class-table s))) + (prog (method-program closest-method)) + (s1 (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (popn nformals (stack (top-frame th s)))))) + (cond + ((and (method-sync closest-method) + (objectLockable? instance th)) + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals nformals + (stack (top-frame th s)))) + nil + prog + 'S_LOCKED + (arg1 inst)) + (call-stack th s1)) + :heap (lock-object th obj-ref (heap s)))) + ((method-sync closest-method) + s) + (t + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals nformals + (stack (top-frame th s)))) + nil + prog + 'UNLOCKED + (arg1 inst)) + (call-stack th s1))))))) + +; ----------------------------------------------------------------------------- +; (INVOKEVIRTUAL "class" "name" n) Instruction + +(defun execute-INVOKEVIRTUAL (inst th s) + (let* ((method-name (arg2 inst)) + (nformals (arg3 inst)) + (obj-ref (top (popn nformals (stack (top-frame th s))))) + (instance (deref obj-ref (heap s))) + (obj-class-name (class-name-of-ref obj-ref (heap s))) + (closest-method + (lookup-method method-name + obj-class-name + (class-table s))) + (prog (method-program closest-method)) + (s1 (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (popn (+ nformals 1) + (stack (top-frame th s))))) + (tThread (rrefToThread obj-ref (thread-table s)))) + (cond + ((method-isNative? closest-method) + (cond ((equal method-name "start") + (modify tThread s1 :status 'SCHEDULED)) + ((equal method-name "stop") + (modify tThread s1 + :status 'UNSCHEDULED)) + (t s))) + ((and (method-sync closest-method) + (objectLockable? instance th)) + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals (+ nformals 1) + (stack (top-frame th s)))) + nil + prog + 'LOCKED + (arg1 inst)) + (call-stack th s1)) + :heap (lock-object th obj-ref (heap s)))) + ((method-sync closest-method) + s) + (t + (modify th s1 + :call-stack + (push (make-frame 0 + (reverse + (bind-formals (+ nformals 1) + (stack (top-frame th s)))) + nil + prog + 'UNLOCKED + (arg1 inst)) + (call-stack th s1))))))) + +; ----------------------------------------------------------------------------- +; (L2I) Instruction - long to int narrowing conversion + +(defun execute-L2I (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (int-fix (top (pop (stack (top-frame th s))))) + (pop (pop (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LADD) Instruction - Add to longs from the top of the stack + +(defun execute-LADD (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (popn 3 (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (long-fix (+ val1 val2)) + (popn 4 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LALOAD) Instruction + +(defun execute-LALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (element-at index array) + (pop (pop (stack (top-frame th s))))))))) + +; ----------------------------------------------------------------------------- +; (LAND) Instruction + +(defun execute-LAND (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (popn 3 (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (logand val1 val2) + (popn 4 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LASTORE) Instruction + +(defun execute-LASTORE (inst th s) + (let* ((value (top (pop (stack (top-frame th s))))) + (index (top (pop (pop (stack (top-frame th s)))))) + (arrayref (top (popn 3 (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (popn 4 (stack (top-frame th s))) + :heap (bind (cadr arrayref) + (set-element-at value + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (LCMP) Instruction - compare two longs +; val1 > val2 --> 1 +; val1 = val2 --> 0 +; val1 < val2 --> -1 + +(defun execute-LCMP (inst th s) + (let* ((val2 (top (pop (stack (top-frame th s))))) + (val1 (top (popn 3 (stack (top-frame th s))))) + (result (cond ((> val1 val2) 1) + ((< val1 val2) -1) + (t 0)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push result + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LCONST_X) Instruction - push a certain long constant onto the stack +; covers LCONST_{0, 1} + +(defun execute-LCONST_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push n (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (LDC) Instruction + +(defun set-instance-field (class-name field-name value instance) + (bind class-name + (bind field-name value + (binding class-name instance)) + instance)) + +(defun execute-LDC (inst th s) + (let* ((class (cur-class (top-frame th s))) + (cp (retrieve-cp class (class-table s))) + (entry (nth (arg1 inst) cp)) + (value (cadr entry))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push value (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (LDC2_W) Instruction + +(defun execute-LDC2_W (inst th s) + (let* ((class (cur-class (top-frame th s))) + (cp (retrieve-cp class (class-table s))) + (entry (nth (arg1 inst) cp)) + (value (cadr entry))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push value (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (LDIV) Instruction + +(defun execute-LDIV (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push + (long-fix + (truncate (top (popn 3 (stack (top-frame th s)))) + (top (pop (stack (top-frame th s)))))) + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LLOAD idx) Instruction - Push a long local onto the stack + +(defun execute-LLOAD (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (nth (arg1 inst) + (locals (top-frame th s))) + (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (LLOAD_X) Instruction - Push a long local onto the stack +; covers LLOAD_{0, 1, 2, 3} + +(defun execute-LLOAD_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (nth n (locals (top-frame th s))) + (stack (top-frame th s)))))) + +; ----------------------------------------------------------------------------- +; (LMUL) Instruction + +(defun execute-LMUL (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (ulong-fix + (* (top (pop (stack (top-frame th s)))) + (top (popn 3 (stack (top-frame th s)))))) + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LNEG) Instruction +; Because of the way the JVM represents 2's complement ints, +; the negation of the most negative int is itself + +(defun execute-LNEG (inst th s) + (let* ((result (if (equal (top (pop (stack (top-frame th s)))) + *most-negative-long*) + *most-negative-long* + (- (top (pop (stack (top-frame th s)))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push result (popn 2 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LOR) Instruction + +(defun execute-LOR (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (logior (top (pop (stack (top-frame th s)))) + (top (popn 3 (stack (top-frame th s))))) + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LREM) Instruction + +(defun execute-LREM (inst th s) + (let* ((val1 (top (pop (stack (top-frame th s))))) + (val2 (top (popn 3 (stack (top-frame th s))))) + (result (- val1 (* (truncate val1 val2) val2)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push result + (popn 4 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LRETURN) Instruction - return a long + +(defun execute-LRETURN (inst th s) + (declare (ignore inst)) + (let* ((val (top (pop (stack (top-frame th s))))) + (obj-ref (nth 0 (locals (top-frame th s)))) + (sync-status (sync-flg (top-frame th s))) + (class (cur-class (top-frame th s))) + (ret-ref (class-decl-heapref (bound? class (class-table s)))) + (new-heap (cond ((equal sync-status 'LOCKED) + (unlock-object th obj-ref (heap s))) + ((equal sync-status 'S_LOCKED) + (unlock-object th ret-ref (heap s))) + (t (heap s)))) + (s1 (modify th s + :call-stack (pop (call-stack th s)) + :heap new-heap))) + (modify th s1 + :stack (push 0 (push val (stack (top-frame th s1))))))) + +; ----------------------------------------------------------------------------- +; (LSHL) Instruction + +(defun execute-LSHL (inst th s) + (let* ((val1 (top (popn 2 (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (6-bit-fix val2)) + (result (shl val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (long-fix result) + (popn 3 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LSHR) Instruction + +(defun execute-LSHR (inst th s) + (let* ((val1 (top (popn 2 (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (6-bit-fix val2)) + (result (shr val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (long-fix result) + (popn 3 (pop (stack (top-frame th s))))))))) + +; ----------------------------------------------------------------------------- +; (LSTORE idx) Instruction - store a long into the locals + +(defun execute-LSTORE (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth (arg1 inst) + (top (pop (stack (top-frame th s)))) + (locals (top-frame th s))) + :stack (popn 2 (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (LSTORE_X) Instruction - store a long into the locals +; covers LSTORE_{0, 1, 2, 3} + +(defun execute-LSTORE_X (inst th s n) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :locals (update-nth n + (top (pop (stack (top-frame th s)))) + (locals (top-frame th s))) + :stack (popn 2 (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (LSUB) Instruction + +(defun execute-LSUB (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push + (ulong-fix (- (top (popn 3 (stack (top-frame th s)))) + (top (pop (stack (top-frame th s)))))) + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (LUSHR) Instruction + +(defun execute-LUSHR (inst th s) + (let* ((val1 (top (popn 2 (stack (top-frame th s))))) + (val2 (top (stack (top-frame th s)))) + (shiftval (6-bit-fix val2)) + (result (shr val1 shiftval))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (long-fix result) + (popn 3 (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (LXOR) Instruction + +(defun execute-LXOR (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push 0 + (push (logxor (top (pop (stack (top-frame th s)))) + (top (popn 3 (stack (top-frame th s))))) + (popn 4 (stack (top-frame th s))))))) + +; ----------------------------------------------------------------------------- +; (MONITORENTER) Instruction + +(defun execute-MONITORENTER (inst th s) + (let* ((obj-ref (top (stack (top-frame th s)))) + (instance (deref obj-ref (heap s)))) + (cond + ((objectLockable? instance th) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (stack (top-frame th s))) + :heap (lock-object th obj-ref (heap s)))) + (t s)))) + +; ----------------------------------------------------------------------------- +; (MONITOREXIT) Instruction + +(defun execute-MONITOREXIT (inst th s) + (let* ((obj-ref (top (stack (top-frame th s)))) + (instance (deref obj-ref (heap s)))) + (cond + ((objectUnLockable? instance th) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (stack (top-frame th s))) + :heap (unlock-object th obj-ref (heap s)))) + (t s)))) + +; ----------------------------------------------------------------------------- +; (MULTIANEWARRAY) Instruction + +(defun execute-MULTIANEWARRAY (inst th s) + (let* ((dimentions (arg1 inst)) + (counts (reverse (take dimentions (stack (top-frame th s)))))) + (mv-let (addr new-heap) + (makemultiarray counts s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (list 'REF addr) + (nthcdr dimentions (stack (top-frame th s)))) + :heap new-heap)))) + +; ----------------------------------------------------------------------------- +; (NEW "class") Instruction + +(defun execute-NEW (inst th s) + (let* ((class-name (arg1 inst)) + (class-table (class-table s)) + (closest-method (lookup-method "run" class-name class-table)) + (prog (method-program closest-method)) + (new-object (build-an-instance + (cons class-name + (class-decl-superclasses + (bound? class-name class-table))) + class-table)) + (new-address (len (heap s))) + (s1 (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (list 'REF new-address) + (stack (top-frame th s))) + :heap (bind new-address new-object (heap s))))) + (if (isThreadObject? class-name class-table) + (modify nil s1 + :thread-table + (addto-tt + (push + (make-frame 0 + (list (list 'REF new-address)) + nil + prog + 'UNLOCKED + class-name) + nil) + 'UNSCHEDULED + (list 'REF new-address) + (thread-table s1))) + s1))) + +; ----------------------------------------------------------------------------- +; (NEWARRAY) Instruction + +(defun execute-NEWARRAY (inst th s) + (let* ((type (arg1 inst)) + (count (top (stack (top-frame th s)))) + (addr (len (heap s))) + (obj (makearray type + count + (init-array type count) + (class-table s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (list 'REF addr) + (pop (stack (top-frame th s)))) + :heap (bind addr + obj + (heap s))))) + +; ----------------------------------------------------------------------------- +; (NOP) Instruction + +(defun execute-NOP (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (POP) Instruction + +(defun execute-POP (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (POP2) Instruction + +(defun execute-POP2 (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (popn 2 (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (PUTFIELD "class" "field" ?long-flag?) Instruction + +(defun execute-PUTFIELD (inst th s) + (let* ((class-name (arg1 inst)) + (field-name (arg2 inst)) + (long-flag (arg3 inst)) + (value (if long-flag + (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (instance (if long-flag + (deref (top (popn 2 (stack (top-frame th s)))) (heap s)) + (deref (top (pop (stack (top-frame th s)))) (heap s)))) + (address (cadr (if long-flag + (top (popn 2 (stack (top-frame th s)))) + (top (pop (stack (top-frame th s)))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (if long-flag + (popn 3 (stack (top-frame th s))) + (pop (pop (stack (top-frame th s))))) + :heap (bind address + (set-instance-field class-name + field-name + value + instance) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (PUTSTATIC "class" "field" ?long-flag?) Instruction + +(defun execute-PUTSTATIC (inst th s) + (let* ((class-name (arg1 inst)) + (field-name (arg2 inst)) + (long-flag (arg3 inst)) + (class-ref (class-decl-heapref + (bound? class-name (class-table s)))) + (value (if long-flag + (top (pop (stack (top-frame th s)))) + (top (stack (top-frame th s))))) + (instance (deref class-ref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (if long-flag + (popn 2 (stack (top-frame th s))) + (pop (stack (top-frame th s)))) + :heap (bind (cadr class-ref) + (set-instance-field "java.lang.Class" + field-name + value + instance) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (RET) Instruction + +(defun execute-RET (inst th s) + (let* ((ret-addr (nth (arg1 inst) (locals (top-frame th s)))) + (addr (cadr ret-addr))) + (modify th s :pc addr))) + +; ----------------------------------------------------------------------------- +; (RETURN) Instruction - Void Return + +(defun execute-RETURN (inst th s) + (declare (ignore inst)) + (let* ((obj-ref (nth 0 (locals (top-frame th s)))) + (sync-status (sync-flg (top-frame th s))) + (class (cur-class (top-frame th s))) + (ret-ref (class-decl-heapref (bound? class (class-table s)))) + (new-heap (cond ((equal sync-status 'LOCKED) + (unlock-object th obj-ref (heap s))) + ((equal sync-status 'S_LOCKED) + (unlock-object th ret-ref (heap s))) + (t (heap s))))) + (modify th s + :call-stack (pop (call-stack th s)) + :heap new-heap))) + +; ----------------------------------------------------------------------------- +; (SALOAD) Instruction + +(defun execute-SALOAD (inst th s) + (let* ((index (top (stack (top-frame th s)))) + (arrayref (top (pop (stack (top-frame th s))))) + (array (deref arrayref (heap s)))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (element-at index array) + (pop (pop (stack (top-frame th s)))))))) + +; ----------------------------------------------------------------------------- +; (SASTORE) Instruction + +(defun execute-SASTORE (inst th s) + (let* ((value (top (stack (top-frame th s)))) + (index (top (pop (stack (top-frame th s))))) + (arrayref (top (pop (pop (stack (top-frame th s))))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (pop (pop (pop (stack (top-frame th s))))) + :heap (bind (cadr arrayref) + (set-element-at (short-fix value) + index + (deref arrayref (heap s)) + (class-table s)) + (heap s))))) + +; ----------------------------------------------------------------------------- +; (SIPUSH const) Instruction + +(defun execute-SIPUSH (inst th s) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push (short-fix (arg1 inst)) + (stack (top-frame th s))))) + +; ----------------------------------------------------------------------------- +; (SWAP) Instruction + +(defun execute-SWAP (inst th s) + (let* ((val1 (top (stack (top-frame th s)))) + (val2 (top (pop (stack (top-frame th s)))))) + (modify th s + :pc (+ (inst-length inst) (pc (top-frame th s))) + :stack (push val2 + (push val1 + (pop (pop (stack (top-frame th s))))))))) + +; ----------------------------------------------------------------------------- +; Putting it all together + +(defun index-into-program (byte-offset program) + (declare (xargs :measure (len program))) + (if (endp program) + nil + (if (zp byte-offset) + (car program) + (index-into-program (- byte-offset + (inst-length (car program))) + (cdr program))))) + +(defun next-inst (th s) + (index-into-program (pc (top-frame th s)) + (program (top-frame th s)))) + +(defun do-inst (inst th s) + (case (op-code inst) + (AALOAD (execute-AALOAD inst th s)) + (AASTORE (execute-AASTORE inst th s)) + (ACONST_NULL (execute-ACONST_NULL inst th s)) + (ALOAD (execute-ALOAD inst th s)) + (ALOAD_0 (execute-ALOAD_X inst th s 0)) + (ALOAD_1 (execute-ALOAD_X inst th s 1)) + (ALOAD_2 (execute-ALOAD_X inst th s 2)) + (ALOAD_3 (execute-ALOAD_X inst th s 3)) + (ANEWARRAY (execute-ANEWARRAY inst th s)) + (ARETURN (execute-ARETURN inst th s)) + (ARRAYLENGTH (execute-ARRAYLENGTH inst th s)) + (ASTORE (execute-ASTORE inst th s)) + (ASTORE_0 (execute-ASTORE_X inst th s 0)) + (ASTORE_1 (execute-ASTORE_X inst th s 1)) + (ASTORE_2 (execute-ASTORE_X inst th s 2)) + (ASTORE_3 (execute-ASTORE_X inst th s 3)) + (BALOAD (execute-BALOAD inst th s)) + (BASTORE (execute-BASTORE inst th s)) + (BIPUSH (execute-BIPUSH inst th s)) + (CALOAD (execute-CALOAD inst th s)) + (CASTORE (execute-CASTORE inst th s)) + (DUP (execute-DUP inst th s)) + (DUP_X1 (execute-DUP_X1 inst th s)) + (DUP_X2 (execute-DUP_X2 inst th s)) + (DUP2 (execute-DUP2 inst th s)) + (DUP2_X1 (execute-DUP2_X1 inst th s)) + (DUP2_X2 (execute-DUP2_X2 inst th s)) + (GETFIELD (execute-GETFIELD inst th s)) + (GETSTATIC (execute-GETSTATIC inst th s)) + (GOTO (execute-GOTO inst th s)) + (GOTO_W (execute-GOTO_W inst th s)) + (I2B (execute-I2B inst th s)) + (I2C (execute-I2C inst th s)) + (I2L (execute-I2L inst th s)) + (I2S (execute-I2S inst th s)) + (IADD (execute-IADD inst th s)) + (IALOAD (execute-IALOAD inst th s)) + (IAND (execute-IAND inst th s)) + (IASTORE (execute-IASTORE inst th s)) + (ICONST_M1 (execute-ICONST_X inst th s -1)) + (ICONST_0 (execute-ICONST_X inst th s 0)) + (ICONST_1 (execute-ICONST_X inst th s 1)) + (ICONST_2 (execute-ICONST_X inst th s 2)) + (ICONST_3 (execute-ICONST_X inst th s 3)) + (ICONST_4 (execute-ICONST_X inst th s 4)) + (ICONST_5 (execute-ICONST_X inst th s 5)) + (IDIV (execute-IDIV inst th s)) + (IF_ACMPEQ (execute-IF_ACMPEQ inst th s)) + (IF_ACMPNE (execute-IF_ACMPNE inst th s)) + (IF_ICMPEQ (execute-IF_ICMPEQ inst th s)) + (IF_ICMPGE (execute-IF_ICMPGE inst th s)) + (IF_ICMPGT (execute-IF_ICMPGT inst th s)) + (IF_ICMPLE (execute-IF_ICMPLE inst th s)) + (IF_ICMPLT (execute-IF_ICMPLT inst th s)) + (IF_ICMPNE (execute-IF_ICMPNE inst th s)) + (IFEQ (execute-IFEQ inst th s)) + (IFGE (execute-IFGE inst th s)) + (IFGT (execute-IFGT inst th s)) + (IFLE (execute-IFLE inst th s)) + (IFLT (execute-IFLT inst th s)) + (IFNE (execute-IFNE inst th s)) + (IFNONNULL (execute-IFNONNULL inst th s)) + (IFNULL (execute-IFNULL inst th s)) + (IINC (execute-IINC inst th s)) + (ILOAD (execute-ILOAD inst th s)) + (ILOAD_0 (execute-ILOAD_X inst th s 0)) + (ILOAD_1 (execute-ILOAD_X inst th s 1)) + (ILOAD_2 (execute-ILOAD_X inst th s 2)) + (ILOAD_3 (execute-ILOAD_X inst th s 3)) + (IMUL (execute-IMUL inst th s)) + (INEG (execute-INEG inst th s)) + (INSTANCEOF (execute-INSTANCEOF inst th s)) + (INVOKESPECIAL (execute-INVOKESPECIAL inst th s)) + (INVOKESTATIC (execute-INVOKESTATIC inst th s)) + (INVOKEVIRTUAL (execute-INVOKEVIRTUAL inst th s)) + (IOR (execute-IOR inst th s)) + (IREM (execute-IREM inst th s)) + (IRETURN (execute-IRETURN inst th s)) + (ISHL (execute-ISHL inst th s)) + (ISHR (execute-ISHR inst th s)) + (ISTORE (execute-ISTORE inst th s)) + (ISTORE_0 (execute-ISTORE_X inst th s 0)) + (ISTORE_1 (execute-ISTORE_X inst th s 1)) + (ISTORE_2 (execute-ISTORE_X inst th s 2)) + (ISTORE_3 (execute-ISTORE_X inst th s 3)) + (ISUB (execute-ISUB inst th s)) + (IUSHR (execute-IUSHR inst th s)) + (IXOR (execute-IXOR inst th s)) + (JSR (execute-JSR inst th s)) + (JSR_W (execute-JSR_W inst th s)) + (L2I (execute-L2I inst th s)) + (LADD (execute-LADD inst th s)) + (LALOAD (execute-LALOAD inst th s)) + (LAND (execute-LAND inst th s)) + (LASTORE (execute-LASTORE inst th s)) + (LCMP (execute-LCMP inst th s)) + (LCONST_0 (execute-LCONST_X inst th s 0)) + (LCONST_1 (execute-LCONST_X inst th s 1)) + (LDC (execute-LDC inst th s)) + (LDC_W (execute-LDC inst th s)) + (LDC2_W (execute-LDC2_W inst th s)) + (LDIV (execute-LDIV inst th s)) + (LLOAD (execute-LLOAD inst th s)) + (LLOAD_0 (execute-LLOAD_X inst th s 0)) + (LLOAD_1 (execute-LLOAD_X inst th s 1)) + (LLOAD_2 (execute-LLOAD_X inst th s 2)) + (LLOAD_3 (execute-LLOAD_X inst th s 3)) + (LMUL (execute-LMUL inst th s)) + (LNEG (execute-LNEG inst th s)) + (LOR (execute-LOR inst th s)) + (LREM (execute-LREM inst th s)) + (LRETURN (execute-LRETURN inst th s)) + (LSHL (execute-LSHL inst th s)) + (LSHR (execute-LSHR inst th s)) + (LSTORE (execute-LSTORE inst th s)) + (LSTORE_0 (execute-LSTORE_X inst th s 0)) + (LSTORE_1 (execute-LSTORE_X inst th s 1)) + (LSTORE_2 (execute-LSTORE_X inst th s 2)) + (LSTORE_3 (execute-LSTORE_X inst th s 3)) + (LSUB (execute-LSUB inst th s)) + (LUSHR (execute-LUSHR inst th s)) + (LXOR (execute-LXOR inst th s)) + (MONITORENTER (execute-MONITORENTER inst th s)) + (MONITOREXIT (execute-MONITOREXIT inst th s)) + (MULTIANEWARRAY (execute-MULTIANEWARRAY inst th s)) + (NEW (execute-NEW inst th s)) + (NEWARRAY (execute-NEWARRAY inst th s)) + (NOP (execute-NOP inst th s)) + (POP (execute-POP inst th s)) + (POP2 (execute-POP2 inst th s)) + (PUTFIELD (execute-PUTFIELD inst th s)) + (PUTSTATIC (execute-PUTSTATIC inst th s)) + (RET (execute-RET inst th s)) + (RETURN (execute-RETURN inst th s)) + (SALOAD (execute-SALOAD inst th s)) + (SASTORE (execute-SASTORE inst th s)) + (SIPUSH (execute-SIPUSH inst th s)) + (SWAP (execute-SWAP inst th s)) + (HALT s) + (otherwise s))) + +(defun step (th s) + (if (equal (status th s) 'SCHEDULED) + (do-inst (next-inst th s) th s) + s)) + +(defun run (sched s) + (if (endp sched) + s + (run (cdr sched) (step (car sched) s)))) + +; Begin the simulator +; + +(defun ack2 (num n lst) + (if (zp n) + lst + (ack2 num (- n 1) (cons num lst)))) + +(defun ack0 (n) + (ack2 0 n nil)) + +(acl2::set-state-ok t) + +(defun sim-loop (s acl2::state) + (declare (acl2::xargs :mode :program)) + (prog2$ + (acl2::cw "~%>>") ;;; Print prompt + (acl2::mv-let + (flg cmd acl2::state) + (acl2::read-object acl2::*standard-oi* acl2::state) ;;; read next command + (declare (ignore flg)) + (cond + ((equal cmd :q) (acl2::value t)) ;;; quit on :q + ((and (consp cmd) ;;; recognize (step i) and (step i j) + (acl2::eq (car cmd) 'step) ;;; where i and j are integers + (true-listp cmd) + (consp (cdr cmd)) + (integerp (cadr cmd)) + (or (acl2::null (cddr cmd)) + (and (integerp (caddr cmd)) + (acl2::null (cdddr cmd))))) + (let ((thread (cadr cmd)) + (n (if (cddr cmd) (caddr cmd) 1))) + (sim-loop (run (ack2 thread n nil) s) acl2::state))) + (t (acl2::mv-let (flg val acl2::state) + (acl2::simple-translate-and-eval cmd + (list (cons 's s)) + nil + "Your command" 'sim + (acl2::w acl2::state) + acl2::state + nil) + (prog2$ + (cond (flg nil) + (t (acl2::cw "~x0~%" (cdr val)))) + (sim-loop s acl2::state)))))))) + +(defun sim (s acl2::state) + (declare (acl2::xargs :mode :program)) + (prog2$ + (acl2::cw "~%M5 Simulator.~%~%") + (sim-loop s acl2::state))) + +; A small assembler to resolve labels into relative byte addresses +; +; Labels are symbols in the "LABEL" package. Examples include: +; LABEL::JUMP LABEL::FOR LABEL::START1 +; +; To denote the jump-to point, insert a label before the opcode +; +; '((aconst_null) '((aconst_null) +; (goto LABEL::TARGET) (goto 5) +; (iconst_0) =====> (iconst_0) +; (iconst_2) (iconst_2) +; (LABEL::TARGET ADD) (add) +; (ireturn)) (ireturn)) + +(defun isLabel? (sym) + (and (symbolp sym) + (equal (symbol-package-name sym) "LABEL"))) + +(defun isLabeledInst? (inst) + (isLabel? (car inst))) + +(defun gen_label_alist (bytecodes cur_pc label_alist) + (if (endp bytecodes) + label_alist + (let* ((bare_inst (if (isLabeledInst? (car bytecodes)) + (cdr (car bytecodes)) + (car bytecodes)))) + (gen_label_alist (cdr bytecodes) + (+ cur_pc + (inst-length bare_inst)) + (if (isLabeledInst? (car bytecodes)) + (bind (car (car bytecodes)) + cur_pc + label_alist) + label_alist))))) + +(defun resolve_labels (bytecodes cur_pc label_alist) + (if (endp bytecodes) + nil + (let* ((inst (car bytecodes)) + (bare-inst (if (isLabeledInst? inst) + (cdr inst) + inst)) + (resolved-inst (if (isLabel? (arg1 bare-inst)) + (list (op-code bare-inst) + (- (binding (arg1 bare-inst) + label_alist) + cur_pc)) + bare-inst))) + (append (list resolved-inst) + (resolve_labels (cdr bytecodes) + (+ cur_pc + (inst-length bare-inst)) + label_alist))))) + +; resolve_basic_block takes a method and resolves all of the labels +; +; note that the JVM restricts jumps to within the method + +(defun resolve_basic_block (bytecodes) + (resolve_labels bytecodes + 0 + (gen_label_alist bytecodes 0 nil))) + +; The following functions are used to strip a state down to resolve +; all of the basic blocks and build up the newly resolved state + +; resolving thread tables +; +(defun assemble_frame (frame) + (make-frame (pc frame) + (locals frame) + (stack frame) + (resolve_basic_block (program frame)) + (sync-flg frame) + (cur-class frame))) + +(defun assemble_call_stack (cs) + (if (endp cs) + nil + (cons (assemble_frame (car cs)) + (assemble_call_stack (cdr cs))))) + +(defun assemble_thread (thread) + (list (assemble_call_stack (car thread)) + (cadr thread) + (caddr thread))) + +(defun assemble_thread_table (tt) + (if (endp tt) + nil + (cons (cons (caar tt) + (assemble_thread (cdar tt))) + (assemble_thread_table (cdr tt))))) + +; resolving class tables +; +(defun assemble_method (method) + (append (list (method-name method) + (method-formals method) + (method-sync method)) + (resolve_basic_block (method-program method)))) + +(defun assemble_methods (methods) + (if (endp methods) + nil + (cons (assemble_method (car methods)) + (assemble_methods (cdr methods))))) + +(defun assemble_class (class) + (make-class-decl (class-decl-name class) + (class-decl-superclasses class) + (class-decl-fields class) + (class-decl-sfields class) + (class-decl-cp class) + (assemble_methods (class-decl-methods class)) + (class-decl-heapref class))) + +(defun assemble_class_table (ct) + (if (endp ct) + nil + (cons (assemble_class (car ct)) + (assemble_class_table (cdr ct))))) + +(defun assemble_state (s) + (make-state (assemble_thread_table (thread-table s)) + (heap s) + (assemble_class_table (class-table s)))) + +; ----------------------------------------------------------------------------- +; load_class_library: a utility for populating the heap with Class and +; String objects + +(defun make-string-obj (class cpentry s idx) + (let* ((new-object (build-an-instance + (cons "java.lang.String" + (class-decl-superclasses + (bound? "java.lang.String" (class-table s)))) + (class-table s))) + (stuffed-obj (set-instance-field "java.lang.String" + "strcontents" + (caddr cpentry) + new-object)) + (new-address (len (heap s)))) + (modify th s + :heap (bind new-address stuffed-obj (heap s)) + :class-table (update-ct-string-ref + class + idx + (list 'REF new-address) + (class-table s))))) + + +(defun resolve-string-constants (class cp s idx) + (cond ((endp cp) s) + ((equal (caar cp) 'STRING) + (resolve-string-constants class + (cdr cp) + (make-string-obj class (car cp) s idx) + (+ idx 1))) + (t (resolve-string-constants class (cdr cp) s (+ idx 1))))) + + +(defun gen_class_obj (class s) + (let* ((new-state (resolve-string-constants class + (retrieve-cp class (class-table s)) + s + 0)) + (new-heap (heap new-state)) + (new-ct (class-table new-state)) + (new-object (build-a-class-instance + (class-decl-sfields (bound? class new-ct)) + new-ct)) + (stuffed-obj (set-instance-field "java.lang.Class" + "<name>" + class + new-object)) + (new-address (len new-heap)) + (old-class-ent (bound? class new-ct)) + (new-class-ent + (make-class-decl (class-decl-name old-class-ent) + (class-decl-superclasses old-class-ent) + (class-decl-fields old-class-ent) + (class-decl-sfields old-class-ent) + (class-decl-cp old-class-ent) + (class-decl-methods old-class-ent) + (list 'REF new-address))) + (new-class-table (bind class + (cdr new-class-ent) + new-ct))) + (make-state (thread-table s) + (bind new-address stuffed-obj new-heap) + new-class-table))) + +(defun ld_class_lib (classes s) + (if (endp classes) + s + (ld_class_lib (cdr classes) (gen_class_obj (car classes) s)))) + +(defun load_class_library (s) + (ld_class_lib (strip-cars (class-table s)) s)) + +; ----------------------------------------------------------------------------- +; m5_load: both load and resolve a given state + +(defun m5_load (s) + (load_class_library (assemble_state s))) + diff --git a/books/workshops/2003/moore_vcg/support/utilities.acl2 b/books/workshops/2003/moore_vcg/support/utilities.acl2 new file mode 100644 index 0000000..af0e795 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/utilities.acl2 @@ -0,0 +1,7 @@ +(value :q) + +(lp) + +(include-book "m5") + +(certify-book "utilities" ? t) diff --git a/books/workshops/2003/moore_vcg/support/utilities.lisp b/books/workshops/2003/moore_vcg/support/utilities.lisp new file mode 100644 index 0000000..ea8c44b --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/utilities.lisp @@ -0,0 +1,209 @@ +; Copyright (C) 2001, Regents of the University of Texas +; Written by J Strother Moore +; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2. + +#| +; Certification Instructions. + +(include-book + "m5") + +(certify-book "utilities" 1) + +J Moore +|# + +(in-package "M5") + +; Here we develop the general theory for proving things about the +; M5 bytecode. + +; Arithmetic + +(include-book "../../../../arithmetic/top-with-meta") + +; We prove a few things about int arithmetic. We ought to prove +; many more, but I just put enough here to get the factorial +; proof to go through. + +(include-book "../../../../ihs/quotient-remainder-lemmas") + +(defun intp (x) + (and (integerp x) + (<= (- (expt 2 31)) x) + (< x (expt 2 31)))) + +(defthm int-lemma0 + (implies (intp x) + (integerp x)) + :rule-classes (:rewrite :forward-chaining)) + +(defthm int-lemma1 + (intp (int-fix x))) + +(local (in-theory (cons 'zp (disable mod)))) + +(defthm int-lemma2 + (implies (and (intp x) + (not (zp x))) + (equal (int-fix (+ -1 x)) + (+ -1 x)))) + +(defthm int-lemma3 + (implies (and (intp x) + (not (zp x))) + (intp (+ -1 x)))) + +(defthm int-lemma4a + (implies (and (integerp x) + (integerp y)) + (equal (int-fix (* x (int-fix y))) + (int-fix (* x y))))) + +(defthm int-lemma5a + (implies (and (integerp x) + (integerp y)) + (equal (int-fix (+ x (int-fix y))) + (int-fix (+ x y))))) + +; This is a special case of the above. I need a more general +; handling of this, but this will do for the moment. + +(defthm int-lemma5a1 + (implies (and (integerp x1) + (integerp x2) + (integerp y)) + (equal (int-fix (+ x1 x2 (int-fix y))) + (int-fix (+ x1 x2 y)))) + :hints (("Goal" :use (:instance int-lemma5a (x (+ x1 x2)))))) + +(defthm int-lemma6 + (implies (intp x) + (equal (int-fix x) x))) + +(in-theory (disable intp int-fix)) + +(defthm int-lemma4b + (implies (and (integerp x) + (integerp y)) + (equal (int-fix (* (int-fix y) x)) + (int-fix (* y x))))) + +(defthm int-lemma5b + (implies (and (integerp x) + (integerp y)) + (equal (int-fix (+ (int-fix y) x)) + (int-fix (+ y x))))) + +; Structures + +(defthm states + (and (equal (thread-table (make-state tt h c)) tt) + (equal (heap (make-state tt h c)) h) + (equal (class-table (make-state tt h c)) c))) + +(in-theory (disable make-state thread-table heap class-table)) + +(defthm frames + (and + (equal (pc (make-frame pc l s prog sync-flg cur-class)) + pc) + (equal (locals (make-frame pc l s prog sync-flg cur-class)) + l) + (equal (stack (make-frame pc l s prog sync-flg cur-class)) + s) + (equal (program (make-frame pc l s prog sync-flg cur-class)) + prog) + (equal (sync-flg (make-frame pc l s prog sync-flg cur-class)) + sync-flg) + (equal (cur-class (make-frame pc l s prog sync-flg cur-class)) + cur-class))) + +(in-theory + (disable make-frame pc locals stack program sync-flg cur-class)) + +(defthm stacks + (and (equal (top (push x s)) x) + (equal (pop (push x s)) s))) + +(in-theory (disable push top pop)) + +; Mappings + +(defthm assoc-equal-bind + (equal (assoc-equal key1 (bind key2 val alist)) + (if (equal key1 key2) + (cons key1 val) + (assoc-equal key1 alist)))) + +(defthm bind-bind + (equal (bind x v (bind x w a)) + (bind x v a))) + +; Semi-Ground Terms + +(defthm bind-formals-opener + (implies (and (integerp n) + (<= 0 n)) + (equal (bind-formals (+ 1 n) stack) + (cons (top stack) + (bind-formals n (pop stack)))))) + +(defthm nth-opener + (and (equal (nth 0 lst) (car lst)) + (implies (and (integerp n) + (<= 0 n)) + (equal (nth (+ 1 n) lst) + (nth n (cdr lst)))))) + +(in-theory (disable nth)) + +(defthm popn-opener + (implies (and (integerp n) + (<= 0 n)) + (equal (popn (+ 1 n) stack) + (popn n (pop stack))))) + +(defun repeat (th n) + (if (zp n) + nil + (cons th (repeat th (- n 1))))) + +(defthm repeat-opener + (implies (and (integerp n) + (<= 0 n)) + (equal (repeat th (+ 1 n)) + (cons th (repeat th n))))) + +; The nil conjunct below is needed because we will disable run. + +(defthm run-opener + (and (equal (run nil s) s) + (equal (run (cons th sched) s) + (run sched (step th s)))) + :hints (("Goal" :in-theory (disable step)))) + +;(in-theory (enable top pop push lookup-method)) + +; Step Stuff + +(defthm step-opener + (implies (consp (next-inst th s)) + (equal (step th s) + (if (equal (status th s) 'SCHEDULED) + (do-inst (next-inst th s) th s) + s))) + :hints (("Goal" :in-theory (disable do-inst)))) + +(in-theory (disable step)) + +; Clocks + + + +(defthm run-append + (equal (run (append sched1 sched2) s) + (run sched2 (run sched1 s)))) + +(in-theory (disable run)) + diff --git a/books/workshops/2003/moore_vcg/support/vcg-examples.acl2 b/books/workshops/2003/moore_vcg/support/vcg-examples.acl2 new file mode 100644 index 0000000..ce63104 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/vcg-examples.acl2 @@ -0,0 +1,6 @@ +(value :q) + +(lp) + +(include-book "utilities") +(certify-book "vcg-examples" ? t) diff --git a/books/workshops/2003/moore_vcg/support/vcg-examples.lisp b/books/workshops/2003/moore_vcg/support/vcg-examples.lisp new file mode 100644 index 0000000..d3e17a4 --- /dev/null +++ b/books/workshops/2003/moore_vcg/support/vcg-examples.lisp @@ -0,0 +1,904 @@ +; Copyright (C) 2003, Regents of the University of Texas +; Written by J Strother Moore +; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2. + +; Use of Tail-Recursion to Propagate Inductive Assertions +; J Strother Moore +; February 26, 2003 + +; cd /u/moore/m5/tolquhon +; (include-book "utilities") +; (ld "vcg-examples.lisp" :ld-pre-eval-print t) + +; Certification: +; (include-book "utilities") +; (certify-book "vcg-examples" 1) + +; --------------------------------------------------------------------------- +; Preliminaries + +; This first part is just ``prelude''. It has nothing to do with the +; specific programs we will verify. + +(in-package "M5") + +(include-book "../../../../misc/defpun") + +(defmacro defpun (g args &rest tail) + `(acl2::defpun ,g ,args ,@tail)) + +;(ACL2::SET-MATCH-FREE-ERROR NIL) + +(defthm update-nth-opener + (and (equal (update-nth 0 x a) (cons x (cdr a))) + (implies (not (zp n)) + (equal (update-nth n x a) + (cons (car a) (update-nth (- n 1) x (cdr a))))))) + +; --------------------------------------------------------------------------- +; Some Preliminaries for Our First Program + +(defthm int-evenp-inv-a + (implies (intp i) + (iff (evenp (int-fix (- i 2))) + (evenp i))) + :hints + (("Goal" :in-theory (e/d (intp int-fix) + (floor))))) + +(defthm int-evenp-inv-b + (implies (intp i) + (iff (evenp (- i 2)) + (evenp i))) + :hints + (("Goal" :in-theory (e/d (intp int-fix) + (floor))))) + +(in-theory (disable evenp)) + +(defthm int-lemma2a + (implies (and (intp x) + (<= 0 x)) + (equal (int-fix (+ -2 x)) + (+ -2 x))) + :hints (("Goal" :in-theory (e/d (intp) nil)))) + +(defthm int-lemma2b + (implies (and (intp x) + (<= 0 x)) + (intp (+ -2 x))) + :hints (("Goal" :in-theory (e/d (intp) nil)))) + +; --------------------------------------------------------------------------- +; Our First Program + +; Below is an m5 program that decrements its first local, n, by 2 and +; iterates until the result is 0. On each iteration it adds 1 to a +; local variable, a, which is initialized to 0. The program ends with +; a HALT instruction, which puts the machine in an infinite loop, i.e., +; executing HALT doesn't change the pc and the machine "stops." Later +; we deal with the more realistic situation of a RETURN to some caller. +; We will prove that if the program below reaches the HALT instruction, +; the initial value, n0, of n was even and the result on the stack is +; n0/2. This program does not terminate when n0 is odd. + +; To make the program slightly simpler to deal with, I only consider +; the case where n0 is a non-negative int. (Java programmers will note +; that the program actually halts for even negative ints, because of +; wrap-around.) + +(defconst *flat-prog* + '((iconst_0) ; 0 + (istore_1) ; 1 a := 0; + (iload_0) ; 2 top of loop: + (ifeq 14) ; 3 if n=0, goto 17; + (iload_1) ; 6 + (iconst_1) ; 7 + (iadd) ; 8 + (istore_1) ; 9 a := a+1; + (iload_0) ;10 + (iconst_2) ;11 + (isub) ;12 + (istore_0) ;13 n := n-2; + (goto -12) ;14 goto top of loop + (iload_1) ;17 + (halt))) ;18 + +; Here is the ``semantics'' of the loop, in the case in interest. + +(defun halfa (n a) + (declare (xargs :measure (nfix n))) + (if (zp n) + a + (halfa (- n 2) (int-fix (+ a 1))))) + +; --------------------------------------------------------------------------- +; The Assertions at the Three Cut Points + +; We will use a classic ``inductive assertion'' method. The following +; function takes a state, s, and the ``initial'' value of n, n0, and +; states the assertions we wish to attach to pcs 0, 2, and 18. These +; are the so-called ``cut points'' of my choice: the entry to the +; program, the top of the loop, and exit from the program. + +; The particular assertions are not my main interest in this paper. +; You can read them if you want. The real nugget in this paper is not +; the assertions but the fact that I use tail recursion by step to +; propagate assertions from the cut points to all the pcs. + +; That said, let me note that the assertions are complicated because +; they have to handle the fact that halfa tracks the program only as +; long as n stays non-negative. Things would be simpler if I assumed +; that n0 was even. But I like illustrating the capability of +; establishing conditions that hold for n0 in the event of +; termination. + +(defun flat-pre-condition (n0 n) + (and (equal n n0) + (intp n0) + (<= 0 n0))) + +(defun flat-loop-invariant (n0 n a) + (and (intp n0) + (<= 0 n0) + (intp n) + (if (and (<= 0 n) + (evenp n)) + (equal (halfa n a) + (halfa n0 0)) + (not (evenp n))) + (iff (evenp n0) (evenp n)))) + +(defun flat-post-condition (n0 value) + (and (evenp n0) + (equal value (halfa n0 0)))) + +(defun flat-assertion (n0 th s) + (let ((n (nth 0 (locals (top-frame th s)))) + (a (nth 1 (locals (top-frame th s))))) + (and (equal (program (top-frame th s)) *flat-prog*) + (case (pc (top-frame th s)) + (0 (flat-pre-condition n0 n)) + (2 (flat-loop-invariant n0 n a)) + (18 (let ((value (top (stack (top-frame th s))))) + (flat-post-condition n0 value))) + (otherwise nil))))) + +; Observe that the output condition is that n0 is even and that the +; top of the stack contains the semantic expression (halfa n0 0). +; We will later convert this to n0/2. + +; --------------------------------------------------------------------------- +; The Invariant -- The Only New Idea in this Note + +; Here is the new idea. I define the invariant for the program by +; using defpun. The assertions are attached at the three cut points +; and all other statements inherit the invariant of the next +; statement. + +(defpun flat-inv (n0 th s) + (if (or (equal (pc (top-frame th s)) 0) + (equal (pc (top-frame th s)) 2) + (equal (pc (top-frame th s)) 18)) + (flat-assertion n0 th s) + (flat-inv n0 th (step th s)))) + +; In one sense, the next lemma is just a technical lemma to force +; flat-inv to keep opening if it hasn't reached a cut point yet. But +; in another sense, this lemma highlights the nice feature of this +; approach. Suppose that in our function flat-assertion we had failed +; to supply a cut point for some loop. Then we'll get a stack +; overflow from the repeated indefinite application of this rewrite +; rule. But we do not have to prove we've cut every loop, because the +; flat-inv function is tail recursive and so was admitted by defpun. + +; In the past when I've used the classic inductive invariant approach +; and used recursion in flat-inv to avoid an assertion at every pc, I +; had to invent some kind of measure (``distance to the next cut +; point'') to prove that I had cut every loop. That annoyed me +; because in the classic inductive invariant approach that burden is +; merely pragmatic -- you had to cut every loop or you couldn't +; generate verification conditions. But you didn't have to prove you +; had cut every loop. In my past attempts to mimic this, I had to +; prove more stuff! + +(defthm flat-inv-opener + (implies (and (equal pc (pc (top-frame th s))) + (syntaxp (quotep pc)) + (not (equal pc 0)) + (not (equal pc 2)) + (not (equal pc 18))) + (equal (flat-inv n0 th s) + (flat-inv n0 th (step th s))))) + +; --------------------------------------------------------------------------- +; The Verification Conditions + +(defthm VC1 + (implies (flat-pre-condition n0 n) (flat-loop-invariant n0 n 0))) + + +(defthm VC2 + (implies (and (flat-loop-invariant n0 n a) + (not (equal n 0))) + (flat-loop-invariant n0 (int-fix (- n 2)) (int-fix (+ 1 a))))) + +(defthm VC3 + (implies (and (flat-loop-invariant N0 n a) + (EQUAL n 0)) + (flat-post-condition N0 a))) + +(in-theory (disable flat-pre-condition + flat-loop-invariant + flat-post-condition)) + +; --------------------------------------------------------------------------- +; Using the VCs in the Operational Semantics + +; So here is the key theorem of the inductive invariant approach, showing +; that inv is an invariant. + +(defthm flat-inv-step + (implies (flat-inv n0 th s) + (flat-inv n0 th (step th s)))) + +; We can immediately conclude that flat-inv is an invariant under run, +; as long as the only thread we step is th. + +(defun mono-threadedp (th sched) + (if (endp sched) + t + (and (equal th (car sched)) + (mono-threadedp th (cdr sched))))) + +(defthm flat-inv-run + (implies (and (mono-threadedp th sched) + (flat-inv n0 th s)) + (flat-inv n0 th (run sched s))) + :rule-classes nil + :hints (("Goal" :in-theory (e/d (run)(flat-inv-def))))) + +; And so we're done. If we plug in an initial state satisfying the +; invariant we get a final state satisfying it. If the final state is +; supposed to have pc 18, then we can read out what the invariant +; tells us about that cut point. + +(defthm flat-main + (let ((s1 (run sched s0))) + (implies (and (intp n0) + (<= 0 n0) + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0 any)) + (equal (program (top-frame th s0)) *flat-prog*) + (mono-threadedp th sched) + (equal (pc (top-frame th s1)) 18)) + (and (evenp n0) + (equal (top (stack (top-frame th s1))) + (halfa n0 0))))) + + :hints (("Goal" :use + (:instance flat-inv-run + (n0 n0) + (s s0) + (th th) + (sched sched)) + :in-theory (enable flat-pre-condition flat-post-condition))) + :rule-classes nil) + +; --------------------------------------------------------------------------- +; Getting Rid of the Semantic Function + +; Now, following our standard paradigm, we get rid of halfa and +; introduce n/2 instead. There is nothing new here, but I have to +; fight intp and int-fix. + +(defthm int-back + (implies (and (intp (+ a x)) + (integerp a) + (<= 0 a) + (integerp x) + (<= 0 x) + (integerp y) + (<= 0 y) + (<= y x)) + (intp (+ y a))) + :hints (("Goal" :in-theory (enable intp)))) + +(defthm halfa-is-half + (implies (and (intp n) + (<= 0 n) + (evenp n) + (integerp a) + (<= 0 a) + (intp (+ (/ n 2) a))) + (equal (halfa n a) + (+ (/ n 2) a))) + :hints (("Goal" :in-theory (enable evenp)))) + +(defthm intp-half-n + (implies (and (intp n) + (<= 0 n) + (evenp n)) + (intp (* 1/2 n))) + :hints (("Goal" :in-theory (enable evenp intp)))) + +; --------------------------------------------------------------------------- +; The (Partial) Correctness Theorem for Half + +; The following theorem summarizes what we now know. Start with a a +; state running *flat-prog* from pc 0 with initial n=n0 and run it +; under an arbitrary mono-threaded schedule to get to s1. Suppose n0 +; is a non-negative int and the pc of s1 is 18. + +; Then we conclude that n0 is even and that the top of the stack is +; n0/2. + +(defthm flat-is-partially-correct + (let ((s1 (run sched s0))) + (implies (and (intp n0) + (<= 0 n0) + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0 any)) + (equal (program (top-frame th s0)) *flat-prog*) + (mono-threadedp th sched) + (equal (pc (top-frame th s1)) 18)) + (and (evenp n0) + (equal (top (stack (top-frame th s1))) + (/ n0 2))))) + :rule-classes nil + :hints (("Goal" + :use ((:instance flat-main))))) + +; Note that at no point in this exercise have we counted instructions +; or defined a clock or schedule generator. + +; --------------------------------------------------------------------------- +; Dealing with Return + +(defconst *half-prog* + '((iconst_0) ; 0 + (istore_1) ; 1 a := 0; + (iload_0) ; 2 top of loop: + (ifeq 14) ; 3 if n=0, goto 17; + (iload_1) ; 6 + (iconst_1) ; 7 + (iadd) ; 8 + (istore_1) ; 9 a := a+1; + (iload_0) ;10 + (iconst_2) ;11 + (isub) ;12 + (istore_0) ;13 n := n-2; + (goto -12) ;14 goto top of loop + (iload_1) ;17 + (ireturn))) ;18 return a; + +(defun sdepth (stk) + (declare (xargs :hints (("Goal" :in-theory (enable pop))))) + (if (endp stk) + 0 + (+ 1 (sdepth (pop stk))))) + +(defun half-assertion (n0 d0 th s) + (cond + ((< (sdepth (call-stack th s)) d0) + (let ((value (top (stack (top-frame th s))))) + (flat-post-condition n0 value))) + (t + (let ((n (nth 0 (locals (top-frame th s)))) + (a (nth 1 (locals (top-frame th s))))) + (and (equal (sdepth (call-stack th s)) d0) + (equal (program (top-frame th s)) *half-prog*) + (equal (sync-flg (top-frame th s)) 'UNLOCKED) + (case (pc (top-frame th s)) + (0 (flat-pre-condition n0 n)) + (2 (flat-loop-invariant n0 n a)) + (18 (let ((value (top (stack (top-frame th s))))) + (flat-post-condition n0 value))) + (otherwise nil))))))) + +(defpun half-inv (n0 d0 th s) + (if (or (< (sdepth (call-stack th s)) d0) + (equal (pc (top-frame th s)) 0) + (equal (pc (top-frame th s)) 2) + (equal (pc (top-frame th s)) 18)) + (half-assertion n0 d0 th s) + (half-inv n0 d0 th (step th s)))) + +(defthm half-inv-opener + (implies (and (equal pc (pc (top-frame th s))) + (syntaxp (quotep pc)) + (not (equal pc 0)) + (not (equal pc 2)) + (not (equal pc 18))) + (equal (half-inv n0 d0 th s) + (if (< (sdepth (call-stack th s)) d0) + (half-assertion n0 d0 th s) + (half-inv n0 d0 th (step th s)))))) + +(defthm half-inv-step + (implies (and (integerp d0) + (< 1 d0) + (<= d0 (sdepth (call-stack th s))) + (half-inv n0 d0 th s)) + (half-inv n0 d0 th (step th s))) + :hints (("Goal" :in-theory (disable halfa-is-half)))) + +(defun run-to-return (sched th d0 s) + (cond ((endp sched) s) + ((<= d0 (sdepth (call-stack th s))) + (run-to-return (cdr sched) th d0 (step (car sched) s))) + (t s))) + +(defthm half-inv-run-to-return + (implies (and (mono-threadedp th sched) + (integerp d0) + (< 1 d0) + (half-inv n0 d0 th s)) + (half-inv n0 d0 th (run-to-return sched th d0 s))) + :rule-classes nil + :hints (("Goal" :in-theory (disable half-inv-def)))) + +; And so we're done. If we plug in an initial state satisfying the +; invariant we get a final state satisfying it. If the final state is +; supposed to have pc 18, then we can read out what the invariant +; tells us about that cut point. + +(defthm half-main + (let ((s1 (run-to-return sched th (sdepth (call-stack th s0)) s0))) + (implies (and (intp n0) + (<= 0 n0) + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0 any)) + (equal (program (top-frame th s0)) *half-prog*) + (equal (sync-flg (top-frame th s0)) 'unlocked) + (< 1 (sdepth (call-stack th s0))) + (mono-threadedp th sched) + (< (sdepth (call-stack th s1)) + (sdepth (call-stack th s0)))) + (and (evenp n0) + (equal (top (stack (top-frame th s1))) + (halfa n0 0))))) + :hints (("Goal" :use + (:instance half-inv-run-to-return + (n0 n0) + (d0 (sdepth (call-stack th s0))) + (s s0) + (th th) + (sched sched)) + :in-theory (enable flat-pre-condition + flat-post-condition))) + :rule-classes nil) + +(defthm half-partially-correct + (let ((s1 (run-to-return sched th (sdepth (call-stack th s0)) s0))) + (implies (and (intp n0) + (<= 0 n0) + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0 any)) + (equal (program (top-frame th s0)) *half-prog*) + (equal (sync-flg (top-frame th s0)) 'unlocked) + (< 1 (sdepth (call-stack th s0))) + (mono-threadedp th sched) + (< (sdepth (call-stack th s1)) + (sdepth (call-stack th s0)))) + (and (evenp n0) + (equal (top (stack (top-frame th s1))) + (/ n0 2))))) + :hints (("Goal" :use half-main)) + :rule-classes nil) + +; --------------------------------------------------------------------------- +; Doing a Sum Program + +; To re-illustrate the same methodology, without worrying about +; demonstrating that we can conclude things about the input if we're +; told we terminate, here is a program that sums the ints from n0 down +; to 0. + +(defconst *sum-prog* + ; We name local[0] n and local[1] a. + '((iconst_0) ; 0 + (istore_1) ; 1 a := 0; + (iload_0) ; 2 top of loop: + (ifeq 14) ; 3 if n=0, goto 17; + (iload_0) ; 6 + (iload_1) ; 7 + (iadd) ; 8 + (istore_1) ; 9 a := n+a; + (iload_0) ;10 + (iconst_m1) ;11 + (iadd) ;12 + (istore_0) ;13 n := n-1; + (goto -12) ;14 goto top of loop + (iload_1) ;17 + (ireturn))) ;18 return a; + +(defun suma (n a) + (if (zp n) + a + (suma (- n 1) (int-fix (+ n a))))) + +(defun sum-pre-condition (n0 n) + (and (equal n n0) + (intp n0) + (<= 0 n0))) + +(defun sum-loop-invariant (n0 n a) + (and (intp n0) + (intp n) + (<= 0 n) + (<= n n0) + (equal (suma n a) + (suma n0 0)))) + +(defun sum-post-condition (n0 value) + (equal value (suma n0 0))) + +(defun sum-assertion (n0 d0 th s) + (cond ((< (sdepth (call-stack th s)) d0) + (let ((value (top (stack (top-frame th s))))) + (sum-post-condition n0 value))) + (t + (let ((n (nth 0 (locals (top-frame th s)))) + (a (nth 1 (locals (top-frame th s))))) + (and (equal (sdepth (call-stack th s)) d0) + (equal (program (top-frame th s)) *sum-prog*) + (equal (sync-flg (top-frame th s)) 'UNLOCKED) + (case (pc (top-frame th s)) + (0 (sum-pre-condition n0 n)) + (2 (sum-loop-invariant n0 n a)) + (18 (let ((value (top (stack (top-frame th s))))) + (sum-post-condition n0 value))) + (otherwise nil))))))) + +(defpun sum-inv (n0 d0 th s) + (if (or (< (sdepth (call-stack th s)) d0) + (equal (pc (top-frame th s)) 0) + (equal (pc (top-frame th s)) 2) + (equal (pc (top-frame th s)) 18)) + (sum-assertion n0 d0 th s) + (sum-inv n0 d0 th (step th s)))) + +(defthm sum-inv-opener + (implies (and (equal pc (pc (top-frame th s))) + (syntaxp (quotep pc)) + (not (equal pc 0)) + (not (equal pc 2)) + (not (equal pc 18))) + (equal (sum-inv n0 d0 th s) + (if (< (sdepth (call-stack th s)) d0) + (sum-assertion n0 d0 th s) + (sum-inv n0 d0 th (step th s)))))) + +(defthm sum-VC1 + (implies (sum-pre-condition n0 n) (sum-loop-invariant n0 n 0))) + +(defthm sum-VC2 + (implies (and (sum-loop-invariant n0 n a) + (not (equal n 0))) + (sum-loop-invariant n0 (int-fix (- n 1)) (int-fix (+ n a))))) + +(defthm sum-VC3 + (implies (and (sum-loop-invariant N0 n a) + (EQUAL n 0)) + (sum-post-condition N0 a))) + +(in-theory (disable sum-pre-condition + sum-loop-invariant + sum-post-condition)) + +(defthm sum-inv-step + (implies (and (integerp d0) + (< 1 d0) + (<= d0 (sdepth (call-stack th s))) + (sum-inv n0 d0 th s)) + (sum-inv n0 d0 th (step th s)))) + +(defthm sum-inv-run-to-return + (implies (and (mono-threadedp th sched) + (integerp d0) + (< 1 d0) + (sum-inv n0 d0 th s)) + (sum-inv n0 d0 th (run-to-return sched th d0 s))) + :rule-classes nil + :hints (("Goal" :in-theory (disable sum-inv-def)))) + +(defthm sum-main + (let ((s1 (run-to-return sched th (sdepth (call-stack th s0)) s0))) + (implies (and (intp n0) + (<= 0 n0) + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0 any)) + (equal (program (top-frame th s0)) *sum-prog*) + (equal (sync-flg (top-frame th s0)) 'unlocked) + (< 1 (sdepth (call-stack th s0))) + (mono-threadedp th sched) + (< (sdepth (call-stack th s1)) + (sdepth (call-stack th s0)))) + (equal (top (stack (top-frame th s1))) + (suma n0 0)))) + :hints (("Goal" :use + (:instance sum-inv-run-to-return + (n0 n0) + (d0 (sdepth (call-stack th s0))) + (s s0) + (th th) + (sched sched)) + :in-theory (enable sum-pre-condition + sum-post-condition))) + :rule-classes nil) + +; We don't bother to eliminate suma, though we could if we hacked around +; with intp long enough! + +; --------------------------------------------------------------------------- +; A Recursive Method + +; Now let's do recursive factorial. We'll bring in the clocked work +; we have already done, just to have the *demo-state* etc. + +(include-book "demo") + +(defun ! (n) + (if (zp n) + 1 + (* n (! (- n 1))))) + +; Here is the (redundant) definition of the program. + +(defconst *fact-def* + '("fact" (INT) NIL + (ILOAD_0) ;;; 0 + (IFLE 12) ;;; 1 + (ILOAD_0) ;;; 4 + (ILOAD_0) ;;; 5 + (ICONST_1) ;;; 6 + (ISUB) ;;; 7 + (INVOKESTATIC "Demo" "fact" 1) ;;; 8 + (IMUL) ;;; 11 + (IRETURN) ;;; 12 + (ICONST_1) ;;; 13 + (IRETURN))) ;;; 14 + +; The following function recognizes the call stack (cs) of a call of +; the "fact" method on n0. The function is not applied to the +; top-most frame, because the constraints on the frame are so +; pc-sensitive and the top-most frame may have "any" pc. So the +; function actually recognizes the rest of the "fact" call stack. +; Here is a picture of the entire call stack. + +; ------------------- top-most frame +; pc: any +; locals: (n) 5 <- suppose n=5 +; stack: any +; program: fact prog +; ------------------- caller-frame +; pc: 11 +; locals: (n+1) 6 this is caller-frame 3 +; stack: (n+1) +; program: fact prog +; ------------------- caller-frame +; pc: 11 +; locals: (n+2) 7 this is caller-frame 2 +; stack: (n+2) +; program: fact prog +; ------------------- caller-frame +; ... +; ------------------- caller-frame +; pc: 11 +; locals: (n0) 8 <- suppose n0 = 8 ; this is caller frame 1 +; stack: (n0) +; program: fact prog +; ------------------- the frame below called fact on n0 +; ... this is caller frame 0 + +; Note that there are n0-n fact caller frames. We number them from +; n0-n down to 1. Caller frame 0 is actually the ``external'' entry +; into fact on n0. We don't know (or care) whether fact or some other +; program is running there. Let k be the number of the caller frame. +; Then note that the value of n in that frame is n0-k+1. + +(defun fact-caller-framesp (cs n0 k) + (declare (xargs :measure (acl2-count k))) + (cond ((zp k) t) + ((and (equal (pc (top cs)) 11) + (equal (program (top cs)) (cdddr *fact-def*)) + (equal (sync-flg (top cs)) 'UNLOCKED) + (intp (nth 0 (locals (top cs)))) + (equal (+ n0 (- k)) (- (nth 0 (locals (top cs))) 1)) + (equal (nth 0 (locals (top cs))) + (top (stack (top cs))))) + (fact-caller-framesp (pop cs) n0 (- k 1))) + (t nil))) + +(defun fact-assertion (n0 d0 th s) + (cond + ((< (sdepth (call-stack th s)) d0) + (equal (top (stack (top-frame th s))) + (int-fix (! n0)))) + (t + (let ((n (nth 0 (locals (top-frame th s))))) + (and (equal (program (top-frame th s)) (cdddr *fact-def*)) + (equal (lookup-method "fact" "Demo" (class-table s)) + *fact-def*) + (equal (sync-flg (top-frame th s)) 'UNLOCKED) + (intp n0) + (intp n) + (<= 0 n) + (<= n n0) + (equal (sdepth (call-stack th s)) (+ d0 (- n0 n))) + (fact-caller-framesp (pop (call-stack th s)) n0 (- n0 n)) + (case (pc (top-frame th s)) + (0 t) + ((12 14) (equal (top (stack (top-frame th s))) + (int-fix (! n)))) + (otherwise nil))))))) + +(defpun fact-inv (n0 d0 th s) + (if (or (< (sdepth (call-stack th s)) d0) + (equal (pc (top-frame th s)) 0) + (equal (pc (top-frame th s)) 12) + (equal (pc (top-frame th s)) 14)) + (fact-assertion n0 d0 th s) + (fact-inv n0 d0 th (step th s)))) + +(defthm fact-inv-opener + (implies (and (equal pc (pc (top-frame th s))) + (syntaxp (quotep pc)) + (not (equal pc 0)) + (not (equal pc 12)) + (not (equal pc 14))) + (equal (fact-inv n0 d0 th s) + (if (< (sdepth (call-stack th s)) d0) + (fact-assertion n0 d0 th s) + (fact-inv n0 d0 th (step th s)))))) + +; These next three lemmas are technical. The first two force +; substitutions. The last opens the stack predicate when we're +; returning and need to know what we're being told about the caller. + +(DEFTHM KB-HACK1 + (IMPLIES + (AND + (FACT-CALLER-FRAMESP + (POP (POP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S))))) + N0 + (+ -1 N0 (- NNN))) + (EQUAL + NNN + (+ -1 + (CAR (LOCALS (TOP (POP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S)))))))))) + (FACT-CALLER-FRAMESP + (POP (POP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S))))) + N0 + (+ + N0 + (- + (CAR (LOCALS (TOP (POP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S)))))))))))) + +(defthm kb-hack2 + (implies + (and (integerp n) + (EQUAL + tos + (INT-FIX + (! (CAR (LOCALS (TOP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S)))))))))) + + (EQUAL + (INT-FIX (* tos n)) + (INT-FIX + (* (! (CAR (LOCALS (TOP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S))))))) + n))))) + +(defthm fact-caller-framesp-opener-1 + (implies (and (syntaxp + (equal cs + '(POP (CAR (CDR (ASSOC-EQUAL TH (THREAD-TABLE S))))))) + (EQUAL (PC (TOP (CADR (ASSOC-EQUAL TH (THREAD-TABLE S))))) pc0) + (syntaxp (or (equal pc0 ''12) (equal pc0 ''14)))) + (equal (fact-caller-framesp cs n0 k) + (COND ((ZP K) T) + ((AND (EQUAL (PC (TOP CS)) 11) + (EQUAL (PROGRAM (TOP CS)) + (CDDDR *FACT-DEF*)) + (EQUAL (SYNC-FLG (TOP CS)) 'UNLOCKED) + (INTP (NTH 0 (LOCALS (TOP CS)))) + (EQUAL (+ N0 (- K)) + (- (NTH 0 (LOCALS (TOP CS))) 1)) + (EQUAL (NTH 0 (LOCALS (TOP CS))) + (TOP (STACK (TOP CS))))) + (FACT-CALLER-FRAMESP (POP CS) + N0 (- K 1))) + (T NIL))))) + +(defthm fact-inv-step + (implies (and (integerp d0) + (< 1 d0) + (<= d0 (sdepth (call-stack th s))) + (fact-inv n0 d0 th s)) + (fact-inv n0 d0 th (step th s)))) + +(defthm fact-inv-run-to-return + (implies (and (mono-threadedp th sched) + (integerp d0) + (< 1 d0) + (fact-inv n0 d0 th s)) + (fact-inv n0 d0 th (run-to-return sched th d0 s))) + :rule-classes nil + :hints (("Goal" :in-theory (disable fact-inv-def)))) + +; Here is the main theorem. It opens by letting s1 be a run-to-return +; of s0. That particular call runs s0 with an abitrarily long +; schedule, sched. Note that run-to-return does not always return a +; state that has returned to a shorter call-stack depth -- if the +; schedule is exhausted before that happens, the final state may still +; be as deep or deeper than the initial state. In any case, s0 is the +; initial state and s1 is the final state. + +; Now let's read the hypotheses of the implication. There are five +; blocks of hypotheses. The first says that n0 is a positive intp. +; The second says that the top-frame of thread th of s0 is a call of +; our "fact" method on n0. The third says that the depth of the +; call-stack of thread th is greater than 1. That means there is a +; frame under the call of "fact". We will call that frame the +; ``caller's frame.'' Of course, if s1 has a shorter call-stack than +; s0, then the caller's frame will be its top-frame, since +; run-to-return stops as soon as we've returned to that depth. The +; fourth says the schedule consists of nothing but th steps. Note +; that otherwise we say nothing about the schedule -- it may be +; arbitrarily long. The fifth block says that the depth of the call +; stack of s1 is less than that of s0, so we know the initial state +; did run long enough to return and hence, the caller's frame is the +; top-frame of s1. + +; Then the conclusion is that (int-fix (! n0)) is on top of +; the stack of the caller's frame. + +(defthm fact-main + (let ((s1 (run-to-return sched th (sdepth (call-stack th s0)) s0))) + (implies (and (intp n0) + (<= 0 n0) + + (equal (pc (top-frame th s0)) 0) + (equal (locals (top-frame th s0)) (list n0)) + (equal (program (top-frame th s0)) + (cdddr *fact-def*)) + (equal (sync-flg (top-frame th s0)) 'unlocked) + (equal (lookup-method "fact" "Demo" (class-table s0)) + *fact-def*) + + (< 1 (sdepth (call-stack th s0))) + + (mono-threadedp th sched) + + (< (sdepth (call-stack th s1)) + (sdepth (call-stack th s0)))) + (equal (top (stack (top-frame th s1))) + (int-fix (! n0))))) + + :hints (("Goal" + :use + (:instance fact-inv-run-to-return + (n0 n0) + (d0 (sdepth (call-stack th s0))) + (s s0) + (th th) + (sched sched)))) + :rule-classes nil) + +; --------------------------------------------------------------------------- +; The Basic Relation Between Run-to-Return and Run + +(defun sched-to-return (sched th d0 s) + (cond ((endp sched) sched) + ((<= d0 (sdepth (call-stack th s))) + (sched-to-return (cdr sched) th d0 (step (car sched) s))) + (t sched))) + +(defthm run-to-return-v-run + (equal (run sched s) + (run (sched-to-return sched th d0 s) + (run-to-return sched th d0 s))) + :rule-classes nil) + +; I need to develop the compositional rules. |