Some VOPs: Primitive accessors: {small, fast} slot-ref (thing) => value {small, fast} slot-set (thing new-value) Read or write a slot in some fixed size primitive object, where we aren't interested in having detailed effects information. The offset and supposed type are passed as codegen info. This is used for the other symbol slots and anything else that seems reasonable. Miscellaneous: error (arg0 ... arg) For some small N. Signal an error using the internal error mechanism. The error code is in the codegen info. check-in-bounds (index bound) check-in-bounds-c (index) Check that Index is >= 0 and < Bound. The -C version takes the bound as codegen info. check-bound (object) Check that Object is not an unbound trap. if-boundp (object) Test whether Object is an unbound trap. if-eq (x y) if-eql (x y) EQ is presumably always open-coded, while EQL is presumably never open-coded. If we can show that at least one argument is not a non-immediate number, then we can transform EQL into EQ. If both arguments can be shown to be a particular numeric type, then we can transform EQL into some variant of =. If one argument can be shown to be a particular numeric type, then we can transform into a combination of a type test and =. We could have an IF-TRUE VOP that tests for something being non-null, but we should be able to generate better code using IF-EQ, since that way the compiler can cache the constant NIL in a register. Sub-primitives: Operations not emitted by generators or standard transforms. They may be emitted by implementation-dependent transforms. Sub-primitives may be unsafe even when they don't have a "SMALL-" or "FAST-" prefix, so they should be used with care. Allocation: allocation-space set-allocation-space get-space collect-garbage newspace-bit System hacking: [signed-]bit-system-ref (sap index) => value bit-system-set (sap index new-value) kernel-trap halt stack-ref (pointer offset) => object stack-set (pointer offset new-value) Read or write a lisp object at Offset words from Pointer. This is used by the debugger and similar things. pointer+ (pointer offset) => pointer sap+ Pointer+ returns a pointer that is Offset lisp objects from Pointer. Sap+ is similar, but offset is in the architecture dependent address units, rather than Lisp objects. Compiler frobs: Things emitted by the compiler for its internal use, and cannot be meaningfully used as sub-primitives. The purpose of many of these operations is more delayed binding than abstraction. For example, the generators for stack hacking know all about the stacks and where their pointers are, they just don't know how much stuff is on the stack at any given point. So we put off deciding how much stuff to pop by emitting stack hacking operations. {small, fast} move (source) => destination Copy the Source to the Destination. We have policy variants, since these operations may be non-trivial in the case of boxing numbers and similar things. May want special versions of this VOP for moves that might require hairy things such as number consing so that we can allocate temporaries. For example, Move-XXX-Float might be required whenever the source has a float primitive type. uplevel-ref (tn, environment) => destination uplevel-set (new-value, environment) => tn Read or write a TN in an environment other than the current one. These VOPs are used to make the environment manipulation explicit. Note that Environment is the environment that the TN is directly stored in. It may be necessary to thread through several enclosing environments to get the correct environment pointer. This is done explicitly using Uplevel-Ref VOPs. closure-ref (tn, environment) => destination Closure-Ref is similar to Uplevel-Ref, but is affected by the Closure-Ref side-effect. Closure variables are set using Uplevel-Set. Closure variables that are not set after initialization may be read using Uplevel-Ref. set-up-arguments (count) => arg0 ... arg Place the first N of the top Count values on the stack in the argument passing registers, blt'ing the remaining values down. Used for multiple-value-call, apply and values-list. spread (list) => count Push the elements in List on the stack, returning the number of things pushed. more-blt (address offset count) Blt some value up the stack. This is used at external more-arg entries where some of the more-args are in registers, so we must move the stack arguments up to make room. Also useful for multiple-value call? function-entry This VOP does argument count checking and dispatching for a function entry. The functional that the entry is for is in the codegen info, and so is a list of continuations, one per legal entry point. If a legal number of arguments is passed, then we just jump to the location pointed to by the continuation. If an illegal number of arguments is passed, we signal an error. allocate-environment () => old-env allocate-environment-args (count) => old-env args-tn These VOPs deal with setting up stack information at the beginning of an environment. It allocates stack stuff and sets up the current environment, returning the old current environment as a result. The environment structure is in the codegen info. Allocate-Environment-Args is used when there are incoming stack arguments. It sets up Args-TN to refer to the stack arguments in a call with Count args. allocate-heap-environment () => env This VOP allocates a heap-closure environment and returns it. The environment to allocate is the codegen info. Allocating a heap environment doesn't do anything to the current environment. deallocate-environment (old-env) deallocate-environment-values (old-env return-values) This VOP deallocates any stack stuff associated with the current environment and restores the old current environment which is given as an argument. The environment to deallocate is the codegen info. Deallocate-Environment-Values is similar, but takes an additional argument which is a stack TN allocated in the current environment that is to be left on the top of the stack when the deallocation is done. This is used for returning stack values and making tail-recursive calls with stack arguments. save-environment () => snapshot This VOP makes a snapshot of the stack top pointers and dynamic context pointers. It is used by functions that are the target of a non-local exit. restore-environment (snapshot) restore-environment-values (snapshot) Restore-Environment tells the code generator that the stack top pointers may be arbitrarily messed up, and thus must be restored. This VOP is used at the entry-points for non-local exits. Restore-Environment-Values is used when stack values are being received; it deals with squeezing out any crap between the values and the original stack top. [Should this restore the dynamic environment? If so, the current cleanup should be in the codegen info.] restore-environment-unwind-protect This VOP is used at the entries for unwind-protect cleanup code. It tells the code generator that there may be random garbage on the stack that it should leave it alone. push-tn () => tn pop-tn () => tn tn-popped () => tn These VOPs are used for management of TNs that are allocated on the top of the stack. Push-TN allocates storage for TN on the top of the stack. Pop-TN deallocates TN (which must be on the top of the stack). TN-Popped informs codegen that someone has deallocated the TN somehow. For example, if the TN held stack arguments to a function, then they would be deallocated when the function returns. pop-to-here This VOP is emitted by stack analyze when it discovers that some stuff has to be popped off the stack due to a control transfer. The codegen info is the TN that should be on TOS when the popping is done. tn-address () => address Return the address of a stack TN in the codegen info. VM characteristics: We assume that if an unboxed, non-immediate object is bit copied into the same type space in another lisp, an object of the same type will result. Unboxed non-immediate objects are floats, i-vectors, bit-vectors, strings and bignums. "Header" supertype of various g-vector like things. VM characteristics assumed by system code: Structures assume g-vectors have a subtype. Hashtables assume g-vector subtype and GC cooperation. Array routines assume array subtype, array format. Full call conventions: Some number of register args + stack args. Entry point for each legal "fixed" arg count, + more args. Arg count passed if stack args. Return PC and previous cont passed in, along with function-entry object. Named and anonymous call are distinct. Named can use link-table. Can also have unknown-args anonymous call. Caller must save all registers it doesn't want trashed. On return, caller must receive or discard any stack values. Values locations same as args, but we pass a flag saying whether we use MV convention. If not MV, one value in first arg register. If MV, values as needed, with values count. Any unused arg registers are set to NIL. Can have a stack closure on the control stack. Format assumed. Unwind values convention: stack values left on stack top while unwind-protects processed. We assume format of environments that allows necessary run-time information to be located: debug info, documentation, arg-count info, defined-from. Format of debug info dumped by the compiler. Core file format.