(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) (FILECREATED "18-Oct-93 16:35:37" "{Pele:mv:envos}Sources>CLTL2>LLMVS.;2" 20546 previous date%: " 3-Sep-91 18:10:25" "{Pele:mv:envos}Sources>CLTL2>LLMVS.;1") (* ; " Copyright (c) 1986, 1987, 1989, 1990, 1991, 1993 by Xerox Corporation. All rights reserved. ") (PRETTYCOMPRINT LLMVSCOMS) (RPAQQ LLMVSCOMS [ (* ;;; "Runtime support for multiple value passing. This file must be present for compiled multiple values to work.") (FNS LISP:VALUES LISP:VALUES-LIST \MVLIST \SIMULATE.UNBIND) (DECLARE%: DONTCOPY (MACROS \VALUES \VALUES-UFN) (LOCALVARS . T)) (VARIABLES LISP:MULTIPLE-VALUES-LIMIT) (* ;; "UFNs for the CL:VALUES and CL:VALUES-LIST sub-opcodes of MISCN:") (FNS LISP::VALUES-UFN LISP::VALUES-LIST-UFN) (PROP FILETYPE LLMVS) (DECLARE%: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDVARS (NLAMA) (NLAML) (LAMA LISP:VALUES]) (* ;;; "Runtime support for multiple value passing. This file must be present for compiled multiple values to work." ) (DEFINEQ (LISP:VALUES [LAMBDA ARGS (* ; "Edited 30-May-90 16:01 by jds") (* ;; "Return multiple values to a caller.") (\VALUES (for I from 1 to ARGS collect (ARG ARGS I)) (AND (IGEQ ARGS 1) (ARG ARGS 1]) (LISP:VALUES-LIST [LAMBDA (LISP:VALUES) (* ; "Edited 30-May-90 16:02 by jds") (* ;; "Given a list of values, return them as multiple values to a caller.") (\VALUES LISP:VALUES (CAR LISP:VALUES]) (\MVLIST [LAMBDA (X) (LIST X]) (\SIMULATE.UNBIND [LAMBDA (FRAME N RETURNER) (* ; "Edited 25-Nov-87 12:54 by bvm:") (* ;; "Simulate the action of N applications of UNBIND occurring in specified FRAME. RETURNER is the frame that will return to FRAME, and hence must be made slow (NIL if my caller). Must be called uninterruptably.") (LET* [(NEXT (fetch (FX NEXTBLOCK) of FRAME)) (SP NEXT) (PVAR0BASE (STACKADDBASE (fetch (FX FIRSTPVAR) of FRAME] [TO N DO (do (* ;  "Pop stack until a bind mark is encountered") (SETQ SP (- SP WORDSPERCELL)) REPEATUNTIL (fetch BINDMARKP of (STACKADDBASE SP)) FINALLY (* ; "Unbind stuff. Bind mark says how many pvars were bound, and gives the offset of the last of them") (LET [(LASTPVAR (fetch BINDLASTPVAR of (STACKADDBASE SP] (to (fetch BINDNVALUES of (STACKADDBASE SP)) do (\PUTBASE PVAR0BASE LASTPVAR 65535) (SETQ LASTPVAR (- LASTPVAR WORDSPERCELL] (replace (FX NEXTBLOCK) of FRAME with SP) (\MAKEFREEBLOCK SP (- NEXT SP)) (* ;; "Now explicitly slow return to FRAME, since we have violated the fast return assumptions by blowing away stack between here and there") (replace (FX FASTP) of (OR RETURNER (\MYALINK)) with NIL]) ) (DECLARE%: DONTCOPY (DECLARE%: EVAL@COMPILE (PUTPROPS \VALUES MACRO [(MANY ONE CALLER-FRAME) (PROG* ((IMMEDIATE-CALLER (OR CALLER-FRAME (\MYALINK))) (CALLER IMMEDIATE-CALLER) PREVFRAME) (* ;; "NB: THIS MACRO MUST TRACK \VALUES-UFN, EXCEPT FOR THE PC-SETTING CODE. THIS ONE IS USED IN THE FUNCTIONS CL:VALUES AND CL:VALUES-LIST.") (* ;; "This macro is used by VALUES and VALUES-LIST to possibly return multiple values. It works by examining the caller to see if the next instruction is MVLIST (currently in the form of a FN1 \MVLIST), which is present in all multiple-value receivers. If so, it bumps the pc past there and returns the MANY expression, whose value is a list of all the values. If it encounters RETURN instead, the call was tail-recursive, so procedure repeats with caller's caller, etc. Otherwise, multiple values are not expected, and the macro returns just ONE value (the first) to the caller.") NEWFRAME (RETURN (PROG ((PC (fetch (FX PC) of CALLER)) (CODE (fetch (FX FNHEADER) of CALLER)) (NUNBINDS 0) BYTE) NEWPC [SELECTC (SETQ BYTE (\GETBASEBYTE CODE PC)) ((LIST (OP# RETURN) (OP# \RETURN)) (* ;  "Call is tail-recursive, so iterate. \RETURN is for LLBREAKing.") (SETQ PREVFRAME CALLER) (SETQ CALLER (fetch (FX CLINK) of CALLER)) (GO NEWFRAME)) ((OP# FN1) (* ; "Could be MVLIST") (SELECTQ [\INDEXATOMDEF (NEW-SYMBOL-CODE [\VAG2 (\GETBASEBYTE CODE (+ PC 1)) (create WORD HIBYTE _ (\GETBASEBYTE CODE (+ PC 2)) LOBYTE _ (\GETBASEBYTE CODE (+ PC 3] (create WORD HIBYTE _ (\GETBASEBYTE CODE (+ PC 1)) LOBYTE _ (\GETBASEBYTE CODE (+ PC 2] (\MVLIST (* ;  "Bump PC past the call, and return the values list") (UNINTERRUPTABLY (COND ((NEQ NUNBINDS 0) (* ;  "Sigh. We have to simulate the unbinding, since we need to get past the MVLIST.") (\SIMULATE.UNBIND CALLER NUNBINDS PREVFRAME))) (* ;;  "Update the PC to skip over the FN1 opcode 1+(# of bytes in a symbol in the code stream):") (replace (FX PC) of CALLER with (NEW-SYMBOL-CODE (+ PC 4) (+ PC 3)))) (RETURN MANY)) NIL)) ((OP# UNBIND) (* ;  "UNBIND appears. This preserves the top of stack, so it should also preserve multiple values.") (add PC 1) (add NUNBINDS 1) (GO NEWPC)) ((OP# JUMPX) (* ; "Follow the jump (yecch)") (add PC (COND ((>= (SETQ BYTE (\GETBASEBYTE CODE (+ PC 1))) 128) (- BYTE 256)) (T BYTE))) (GO NEWPC)) ((OP# JUMPXX) (add PC (SIGNED (create WORD HIBYTE _ (\GETBASEBYTE CODE (+ PC 1)) LOBYTE _ (\GETBASEBYTE CODE (+ PC 2))) BITSPERWORD)) (GO NEWPC)) (LET [(JUMPBASE (CONSTANT (CAAR (\FINDOP 'JUMP] (COND ([<= JUMPBASE BYTE (CONSTANT (CADAR (\FINDOP 'JUMP] (add PC (+ (- BYTE JUMPBASE) 2)) (GO NEWPC] (RETURN ONE]) (PUTPROPS \VALUES-UFN MACRO [(MANY ONE CALLER-FRAME RESULT-IVAR) (PROG* ((IMMEDIATE-CALLER (OR CALLER-FRAME (\MYALINK))) (CALLER IMMEDIATE-CALLER) PREVFRAME) (* ;; "NB: THIS MACRO MUST TRACK \VALUES, EXCEPT FOR THE PC SETTING CODE. THIS ONE IS USED IN THE UFNs FOR VALUES AND VALUES-LIST.") (* ;; "This macro is used by VALUES and VALUES-LIST to possibly return multiple values. It works by examining the caller to see if the next instruction is MVLIST (currently in the form of a FN1 \MVLIST), which is present in all multiple-value receivers. If so, it bumps the pc past there and returns the MANY expression, whose value is a list of all the values. If it encounters RETURN instead, the call was tail-recursive, so procedure repeats with caller's caller, etc. Otherwise, multiple values are not expected, and the macro returns just ONE value (the first) to the caller.") NEWFRAME (RETURN (PROG ((PC (fetch (FX PC) of CALLER)) (CODE (fetch (FX FNHEADER) of CALLER)) (NUNBINDS 0) BYTE) NEWPC [SELECTC (SETQ BYTE (\GETBASEBYTE CODE PC)) ((LIST (OP# RETURN) (OP# \RETURN)) (* ;  "Call is tail-recursive, so iterate. \RETURN is for LLBREAKing.") (SETQ PREVFRAME CALLER) (SETQ CALLER (fetch (FX CLINK) of CALLER)) (GO NEWFRAME)) ((OP# FN1) (* ; "Could be MVLIST") (SELECTQ [\INDEXATOMDEF (create WORD HIBYTE _ (\GETBASEBYTE CODE (+ PC 1)) LOBYTE _ (\GETBASEBYTE CODE (+ PC 2] (\MVLIST (* ;  "Bump PC past the call, and return the values list") (LET (VALS) (SETQ VALS MANY) (* ;; "This LET & SETQ forces MANY to be computed before we dink with the stack (which seems to destroy some of the values!)") (REPLACE (FX NEXTBLOCK) OF IMMEDIATE-CALLER WITH (LOLOC RESULT-IVAR)) (UNINTERRUPTABLY (COND ((NEQ NUNBINDS 0) (* ;  "Sigh. We have to simulate the unbinding, since we need to get past the MVLIST.") (\SIMULATE.UNBIND CALLER NUNBINDS PREVFRAME))) [COND ((EQ CALLER IMMEDIATE-CALLER) (* ;; "If the immediate caller has the MVLIST, then the PC has already been bumped, courtesy of the microcode.") (replace (FX PC) of CALLER with (+ PC 3))) (T (* ;;  "Otherwise, we should skip over the FN1 \MVLIST.") (replace (FX PC) of CALLER with (+ PC 3]) (SI::UNWIND IMMEDIATE-CALLER) (RETURN VALS))) NIL)) ((OP# UNBIND) (* ;  "UNBIND appears. This preserves the top of stack, so it should also preserve multiple values.") (add PC 1) (add NUNBINDS 1) (GO NEWPC)) ((OP# JUMPX) (* ; "Follow the jump (yecch)") (add PC (COND ((>= (SETQ BYTE (\GETBASEBYTE CODE (+ PC 1))) 128) (- BYTE 256)) (T BYTE))) (GO NEWPC)) ((OP# JUMPXX) (add PC (SIGNED (create WORD HIBYTE _ (\GETBASEBYTE CODE (+ PC 1)) LOBYTE _ (\GETBASEBYTE CODE (+ PC 2))) BITSPERWORD)) (GO NEWPC)) (LET [(JUMPBASE (CONSTANT (CAAR (\FINDOP 'JUMP] (COND ([<= JUMPBASE BYTE (CONSTANT (CADAR (\FINDOP 'JUMP] (add PC (+ (- BYTE JUMPBASE) 2)) (GO NEWPC] (RETURN ONE]) ) (DECLARE%: DOEVAL@COMPILE DONTCOPY (LOCALVARS . T) ) ) (LISP:DEFCONSTANT LISP:MULTIPLE-VALUES-LIMIT 512) (* ;; "UFNs for the CL:VALUES and CL:VALUES-LIST sub-opcodes of MISCN:") (DEFINEQ (LISP::VALUES-UFN [LAMBDA (LISP::INDEX LISP::ARGCOUNT LISP::ARG-PTR) (* ; "Edited 5-Jun-90 15:21 by jds") (* ;; "This is the UFN for the VALUES MISCN opcode. Its definition must be analogous to that for CL:VALUES, in case anything changes.") (* ;; "* * * * * * *") (* ;; "Architectural note: This function assumes that it is called by an unwind-protect from \miscn.ufn. Therefore, it skips two frames before deciding whether to pass back one valur or many.") (\VALUES-UFN (for I from 0 to (LLSH (SUB1 LISP::ARGCOUNT) 1) by 2 collect (\GETBASEPTR LISP::ARG-PTR I)) (AND (IGEQ LISP::ARGCOUNT 1) (\GETBASEPTR LISP::ARG-PTR 0)) (fetch (FX CLINK) of (fetch (FX CLINK) of (\MYALINK))) LISP::ARG-PTR]) (LISP::VALUES-LIST-UFN [LAMBDA (LISP::INDEX LISP::ARGCOUNT LISP::ARG-PTR) (* ; "Edited 5-Jun-90 15:21 by jds") (* ;; "This is the UFN for the VALUES-LIST MISCN opcode. Its definition must be analogous to that for CL:VALUES-LIST, in case anything changes.") (* ;; "* * * * * * *") (* ;; "Architectural note: This function assumes that it is called by an unwind-protect from \miscn.ufn. Therefore, it skips two frames before deciding whether to pass back one value or many.") (LET ((LISP:VALUES (\GETBASEPTR LISP::ARG-PTR 0))) (\VALUES-UFN LISP:VALUES (CAR LISP:VALUES) (fetch (FX CLINK) of (fetch (FX CLINK) of (\MYALINK))) LISP::ARG-PTR]) ) (PUTPROPS LLMVS FILETYPE :FAKE-COMPILE-FILE) (DECLARE%: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDTOVAR NLAMA ) (ADDTOVAR NLAML ) (ADDTOVAR LAMA LISP:VALUES) ) (PUTPROPS LLMVS COPYRIGHT ("Xerox Corporation" 1986 1987 1989 1990 1991 1993)) (DECLARE%: DONTCOPY (FILEMAP (NIL (1334 3999 (LISP:VALUES 1344 . 1651) (LISP:VALUES-LIST 1653 . 1908) (\MVLIST 1910 . 1950) (\SIMULATE.UNBIND 1952 . 3997)) (18510 20246 (LISP::VALUES-UFN 18520 . 19489) (LISP::VALUES-LIST-UFN 19491 . 20244))))) STOP