bytecode.c revision 5dfecf96
15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/bytecode.c,v 1.17 2003/05/27 22:27:01 tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg
335dfecf96Smrg/*
345dfecf96Smrgsomethings TODO:
355dfecf96Smrg
365dfecf96Smrg o Write code for allowing storing the bytecode on disk. Basically
375dfecf96Smrg   write a section of the bytecode with the package name of the symbol
385dfecf96Smrg   pointers, and after that, the symbols used. At load time just put
395dfecf96Smrg   the pointers in the bytecode. Constants can be stored as the string
405dfecf96Smrg   representation. Probably just storing the gc protected code as a
415dfecf96Smrg   string is enough to rebuild it.
425dfecf96Smrg
435dfecf96Smrg o Write code to store tags of BLOCK/CATCH and setjump buffer stacks,
445dfecf96Smrg   and, only keep track of this if non byte-compiled code is called,
455dfecf96Smrg   as after byte-compilation RETURN and THROW are just jumps.
465dfecf96Smrg
475dfecf96Smrg o Remove not reliable "optmization code" code from Com_XXX functions
485dfecf96Smrg   and do it later, removing dead code, tests with a constant argument,
495dfecf96Smrg   etc, in the "link time". Frequently joining sequential opcodes to a
505dfecf96Smrg   compound version.
515dfecf96Smrg
525dfecf96Smrg o Write an optimizer to do code transformation.
535dfecf96Smrg
545dfecf96Smrg o Write code to know when variables can be changed in place, this
555dfecf96Smrg   can save a huge time in loop counters.
565dfecf96Smrg
575dfecf96Smrg o Write code for fast garbage collection of objects that can be
585dfecf96Smrg   safely collected.
595dfecf96Smrg
605dfecf96Smrg o Cleanup of interpreted code. Having bytecode mean that the interpreter
615dfecf96Smrg   now is better having a clean and small code. If speed is important,
625dfecf96Smrg   it should be byte compiled.
635dfecf96Smrg
645dfecf96Smrg o Limit the stacks length. So that instead of using an index, use the
655dfecf96Smrg   pointer where an object value should be read/stored as the stack address
665dfecf96Smrg   would not change during the program execution.
675dfecf96Smrg
685dfecf96Smrg o Optimize jump to jump. Common in code like:
695dfecf96Smrg	(IF test
705dfecf96Smrg	    (GO somewhere)
715dfecf96Smrg	    (GO elsewhere)
725dfecf96Smrg	)
735dfecf96Smrg	(GO there)
745dfecf96Smrg   that generates a bytecode like:
755dfecf96Smrg	<code to evaluate test>
765dfecf96Smrg	JUMPNIL :NIL-RESULT
775dfecf96Smrg	:T-RESULT
785dfecf96Smrg	    JUMP :SOMEWHERE
795dfecf96Smrg	JUMP :END-OF-IF			;; <- this is not required, or even
805dfecf96Smrg	:NIL-RESULT			;;    better, notice the jump after
815dfecf96Smrg	    JUMP :ELSEWHERE		;;    the if and transform it into
825dfecf96Smrg	:END-OF-IF			;;    a JUMP :THERE (assuming there
835dfecf96Smrg	JUMP :THERE			;;    (was no jump in the T code).
845dfecf96Smrg
855dfecf96Smrg o Optimize variables that are known to not change it's value, i.e. pseudo
865dfecf96Smrg   constants. Loading the value of a constant should be faster than loading
875dfecf96Smrg   the current value of a variable; the constant table could fit in the
885dfecf96Smrg   processor cache line and needs less calculation to find the object address.
895dfecf96Smrg
905dfecf96Smrg o Fix some known problems, like when calling return or return-from while
915dfecf96Smrg   building the argument list to a builtin function, or inline of recursive
925dfecf96Smrg   functions.
935dfecf96Smrg */
945dfecf96Smrg
955dfecf96Smrg
965dfecf96Smrg#include "lisp/bytecode.h"
975dfecf96Smrg#include "lisp/write.h"
985dfecf96Smrg
995dfecf96Smrg#define	SYMBOL_KEYWORD	-1	/* A keyword, load as constant */
1005dfecf96Smrg#define	SYMBOL_CONSTANT	-2	/* Defined as constant at compile time */
1015dfecf96Smrg#define	SYMBOL_UNBOUND	-3	/* Not a local variable */
1025dfecf96Smrg
1035dfecf96Smrg#define NEW_TREE(type)		CompileNewTree(com, type)
1045dfecf96Smrg
1055dfecf96Smrg/* If in tagbody, ignore anything that is not code */
1065dfecf96Smrg#define	IN_TAGBODY()		(com->block->type == LispBlockBody && \
1075dfecf96Smrg				 com->level == com->tagbody)
1085dfecf96Smrg#define	FORM_ENTER()		++com->level
1095dfecf96Smrg#define	FORM_LEAVE()		--com->level
1105dfecf96Smrg
1115dfecf96Smrg#define COMPILE_FAILURE(message)			\
1125dfecf96Smrg    LispMessage("COMPILE: %s", message);		\
1135dfecf96Smrg    longjmp(com->jmp, 1)
1145dfecf96Smrg
1155dfecf96Smrg/*
1165dfecf96Smrg * Types
1175dfecf96Smrg */
1185dfecf96Smrgtypedef struct _CodeTree CodeTree;
1195dfecf96Smrgtypedef struct _CodeBlock CodeBlock;
1205dfecf96Smrg
1215dfecf96Smrgtypedef enum {
1225dfecf96Smrg    CodeTreeBytecode,
1235dfecf96Smrg    CodeTreeLabel,
1245dfecf96Smrg    CodeTreeGo,
1255dfecf96Smrg    CodeTreeJump,
1265dfecf96Smrg    CodeTreeJumpIf,
1275dfecf96Smrg    CodeTreeCond,
1285dfecf96Smrg    CodeTreeBlock,
1295dfecf96Smrg    CodeTreeReturn
1305dfecf96Smrg} CodeTreeType;
1315dfecf96Smrg
1325dfecf96Smrgstruct _CodeTree {
1335dfecf96Smrg    CodeTreeType type;
1345dfecf96Smrg
1355dfecf96Smrg    /* Resolved when linking, may be adjusted while optimizing */
1365dfecf96Smrg    long offset;
1375dfecf96Smrg
1385dfecf96Smrg    LispByteOpcode code;
1395dfecf96Smrg
1405dfecf96Smrg    union {
1415dfecf96Smrg	signed char signed_char;
1425dfecf96Smrg	signed short signed_short;
1435dfecf96Smrg	signed int signed_int;
1445dfecf96Smrg	LispAtom *atom;
1455dfecf96Smrg	LispObj *object;
1465dfecf96Smrg	CodeTree *tree;
1475dfecf96Smrg	CodeBlock *block;
1485dfecf96Smrg	struct {
1495dfecf96Smrg	    unsigned char num_arguments;
1505dfecf96Smrg	    LispBuiltin *builtin;
1515dfecf96Smrg	    signed short offset;	/* Used if opcode is XBC_CALL_SET */
1525dfecf96Smrg	} builtin;
1535dfecf96Smrg	struct {
1545dfecf96Smrg	    unsigned char num_arguments;
1555dfecf96Smrg	    LispObj *name;
1565dfecf96Smrg	    LispObj *lambda;
1575dfecf96Smrg	} call;
1585dfecf96Smrg	struct {
1595dfecf96Smrg	    unsigned char num_arguments;
1605dfecf96Smrg	    LispObj *code;
1615dfecf96Smrg	} bytecall;
1625dfecf96Smrg	struct {
1635dfecf96Smrg	    short offset;
1645dfecf96Smrg	    LispAtom *name;
1655dfecf96Smrg	} let;
1665dfecf96Smrg	struct {
1675dfecf96Smrg	    LispAtom *symbol;
1685dfecf96Smrg	    LispAtom *name;
1695dfecf96Smrg	} let_sym;
1705dfecf96Smrg	struct {
1715dfecf96Smrg	    LispObj *object;
1725dfecf96Smrg	    LispAtom *name;
1735dfecf96Smrg	} let_con;
1745dfecf96Smrg	struct {
1755dfecf96Smrg	    signed short load;
1765dfecf96Smrg	    signed short set;
1775dfecf96Smrg	} load_set;
1785dfecf96Smrg	struct {
1795dfecf96Smrg	    LispObj *object;
1805dfecf96Smrg	    signed short offset;
1815dfecf96Smrg	} load_con_set;
1825dfecf96Smrg	struct {
1835dfecf96Smrg	    LispObj *car;
1845dfecf96Smrg	    LispObj *cdr;
1855dfecf96Smrg	} cons;
1865dfecf96Smrg	struct {
1875dfecf96Smrg	    short offset;
1885dfecf96Smrg	    LispObj *definition;
1895dfecf96Smrg	} struc;
1905dfecf96Smrg    } data;
1915dfecf96Smrg
1925dfecf96Smrg    CodeTree *next;
1935dfecf96Smrg    CodeTree *group;
1945dfecf96Smrg    CodeBlock *block;
1955dfecf96Smrg};
1965dfecf96Smrg
1975dfecf96Smrgstruct _CodeBlock {
1985dfecf96Smrg    LispBlockType type;
1995dfecf96Smrg    LispObj *tag;
2005dfecf96Smrg
2015dfecf96Smrg    struct {
2025dfecf96Smrg	LispObj **labels;
2035dfecf96Smrg	CodeTree **codes;	/* Filled at link time */
2045dfecf96Smrg	int length;
2055dfecf96Smrg	int space;
2065dfecf96Smrg    } tagbody;
2075dfecf96Smrg
2085dfecf96Smrg    struct {
2095dfecf96Smrg	LispAtom **symbols;	/* Identifiers of variables in a block */
2105dfecf96Smrg	int *flags;		/* Information about usage of the variable */
2115dfecf96Smrg	int length;
2125dfecf96Smrg    } variables;
2135dfecf96Smrg
2145dfecf96Smrg    int bind;			/* Used in case of RETURN from LET */
2155dfecf96Smrg    int level;			/* Nesting level block was created */
2165dfecf96Smrg
2175dfecf96Smrg    CodeTree *tree, *tail;
2185dfecf96Smrg    CodeBlock *prev;		/* Linked list as a stack */
2195dfecf96Smrg    CodeTree *parent;		/* Back reference */
2205dfecf96Smrg};
2215dfecf96Smrg
2225dfecf96Smrgstruct _LispCom {
2235dfecf96Smrg    unsigned char *bytecode;	/* Bytecode generated so far */
2245dfecf96Smrg    long length;
2255dfecf96Smrg
2265dfecf96Smrg    CodeBlock *block, *toplevel;
2275dfecf96Smrg
2285dfecf96Smrg    int tagbody;		/* Inside a tagbody block? */
2295dfecf96Smrg    int level;			/* Nesting level */
2305dfecf96Smrg    int macro;			/* Expanding a macro? */
2315dfecf96Smrg
2325dfecf96Smrg    int lex;
2335dfecf96Smrg
2345dfecf96Smrg    int warnings;
2355dfecf96Smrg
2365dfecf96Smrg    LispObj *form, *plist;
2375dfecf96Smrg
2385dfecf96Smrg    jmp_buf jmp;		/* Used if compilation cannot be finished */
2395dfecf96Smrg
2405dfecf96Smrg    struct {
2415dfecf96Smrg	int cstack;	/* Current number of objects in forms evaluation */
2425dfecf96Smrg	int cbstack;
2435dfecf96Smrg	int cpstack;
2445dfecf96Smrg	int stack;	/* max number of objects will be loaded in stack */
2455dfecf96Smrg	int bstack;
2465dfecf96Smrg	int pstack;
2475dfecf96Smrg    } stack;
2485dfecf96Smrg
2495dfecf96Smrg    struct {
2505dfecf96Smrg	/* Constant table */
2515dfecf96Smrg	LispObj **constants;
2525dfecf96Smrg	int num_constants;
2535dfecf96Smrg	/* Symbol table */
2545dfecf96Smrg	LispAtom **symbols;
2555dfecf96Smrg	int num_symbols;
2565dfecf96Smrg	/* Builtin table */
2575dfecf96Smrg	LispBuiltin **builtins;
2585dfecf96Smrg	int num_builtins;
2595dfecf96Smrg	/* Bytecode table */
2605dfecf96Smrg	LispObj **bytecodes;
2615dfecf96Smrg	int num_bytecodes;
2625dfecf96Smrg    } table;
2635dfecf96Smrg};
2645dfecf96Smrg
2655dfecf96Smrg/*
2665dfecf96Smrg * Prototypes
2675dfecf96Smrg */
2685dfecf96Smrgstatic LispObj *MakeBytecodeObject(LispCom*, LispObj*, LispObj*);
2695dfecf96Smrg
2705dfecf96Smrgstatic CodeTree *CompileNewTree(LispCom*, CodeTreeType);
2715dfecf96Smrgstatic void CompileFreeState(LispCom*);
2725dfecf96Smrgstatic void CompileFreeBlock(CodeBlock*);
2735dfecf96Smrgstatic void CompileFreeTree(CodeTree*);
2745dfecf96Smrg
2755dfecf96Smrgstatic void CompileIniBlock(LispCom*, LispBlockType, LispObj*);
2765dfecf96Smrgstatic void CompileFiniBlock(LispCom*);
2775dfecf96Smrg
2785dfecf96Smrgstatic void com_BytecodeChar(LispCom*, LispByteOpcode, char);
2795dfecf96Smrgstatic void com_BytecodeShort(LispCom*, LispByteOpcode, short);
2805dfecf96Smrgstatic void com_BytecodeObject(LispCom*, LispByteOpcode, LispObj*);
2815dfecf96Smrgstatic void com_BytecodeCons(LispCom*, LispByteOpcode, LispObj*, LispObj*);
2825dfecf96Smrg
2835dfecf96Smrgstatic void com_BytecodeAtom(LispCom*, LispByteOpcode, LispAtom*);
2845dfecf96Smrg
2855dfecf96Smrgstatic void com_Bytecode(LispCom*, LispByteOpcode);
2865dfecf96Smrg
2875dfecf96Smrgstatic void com_Load(LispCom*, short);
2885dfecf96Smrgstatic void com_LoadLet(LispCom*, short, LispAtom*);
2895dfecf96Smrgstatic void com_LoadPush(LispCom*, short);
2905dfecf96Smrg
2915dfecf96Smrgstatic void com_Let(LispCom*, LispAtom*);
2925dfecf96Smrg
2935dfecf96Smrgstatic void com_Bind(LispCom*, short);
2945dfecf96Smrgstatic void com_Unbind(LispCom*, short);
2955dfecf96Smrg
2965dfecf96Smrgstatic void com_LoadSym(LispCom*, LispAtom*);
2975dfecf96Smrgstatic void com_LoadSymLet(LispCom*, LispAtom*, LispAtom*);
2985dfecf96Smrgstatic void com_LoadSymPush(LispCom*, LispAtom*);
2995dfecf96Smrg
3005dfecf96Smrgstatic void com_LoadCon(LispCom*, LispObj*);
3015dfecf96Smrgstatic void com_LoadConLet(LispCom*, LispObj*, LispAtom*);
3025dfecf96Smrgstatic void com_LoadConPush(LispCom*, LispObj*);
3035dfecf96Smrg
3045dfecf96Smrgstatic void com_Set(LispCom*, short);
3055dfecf96Smrgstatic void com_SetSym(LispCom*, LispAtom*);
3065dfecf96Smrg
3075dfecf96Smrgstatic void com_Struct(LispCom*, short, LispObj*);
3085dfecf96Smrgstatic void com_Structp(LispCom*, LispObj*);
3095dfecf96Smrg
3105dfecf96Smrgstatic void com_Call(LispCom*, unsigned char, LispBuiltin*);
3115dfecf96Smrgstatic void com_Bytecall(LispCom*, unsigned char, LispObj*);
3125dfecf96Smrgstatic void com_Funcall(LispCom*, LispObj*, LispObj*);
3135dfecf96Smrg
3145dfecf96Smrgstatic void CompileStackEnter(LispCom*, int, int);
3155dfecf96Smrgstatic void CompileStackLeave(LispCom*, int, int);
3165dfecf96Smrg
3175dfecf96Smrgstatic void LinkBytecode(LispCom*);
3185dfecf96Smrg
3195dfecf96Smrgstatic LispObj *ExecuteBytecode(unsigned char*);
3205dfecf96Smrg
3215dfecf96Smrg
3225dfecf96Smrg/* Defined in lisp.c */
3235dfecf96Smrgvoid LispMoreStack(void);
3245dfecf96Smrgvoid LispMoreEnvironment(void);
3255dfecf96Smrgvoid LispMoreGlobals(LispPackage*);
3265dfecf96SmrgLispObj *LispEvalBackquote(LispObj*, int);
3275dfecf96Smrgvoid LispSetAtomObjectProperty(LispAtom*, LispObj*);
3285dfecf96Smrg
3295dfecf96Smrg/*
3305dfecf96Smrg * Initialization
3315dfecf96Smrg */
3325dfecf96Smrgextern int pagesize;
3335dfecf96Smrg
3345dfecf96SmrgLispObj x_cons[8];
3355dfecf96Smrgstatic LispObj *cons, *cons1, *cons2, *cons3, *cons4, *cons5, *cons6, *cons7;
3365dfecf96Smrg
3375dfecf96Smrg/*
3385dfecf96Smrg * Implementation
3395dfecf96Smrg */
3405dfecf96Smrg#include "lisp/compile.c"
3415dfecf96Smrg
3425dfecf96Smrgvoid
3435dfecf96SmrgLispBytecodeInit(void)
3445dfecf96Smrg{
3455dfecf96Smrg    cons = &x_cons[7];
3465dfecf96Smrg    cons->type = LispCons_t;
3475dfecf96Smrg    CDR(cons) = NIL;
3485dfecf96Smrg    cons1 = &x_cons[6];
3495dfecf96Smrg    cons1->type = LispCons_t;
3505dfecf96Smrg    CDR(cons1) = cons;
3515dfecf96Smrg    cons2 = &x_cons[5];
3525dfecf96Smrg    cons2->type = LispCons_t;
3535dfecf96Smrg    CDR(cons2) = cons1;
3545dfecf96Smrg    cons3 = &x_cons[4];
3555dfecf96Smrg    cons3->type = LispCons_t;
3565dfecf96Smrg    CDR(cons3) = cons2;
3575dfecf96Smrg    cons4 = &x_cons[3];
3585dfecf96Smrg    cons4->type = LispCons_t;
3595dfecf96Smrg    CDR(cons4) = cons3;
3605dfecf96Smrg    cons5 = &x_cons[2];
3615dfecf96Smrg    cons5->type = LispCons_t;
3625dfecf96Smrg    CDR(cons5) = cons4;
3635dfecf96Smrg    cons6 = &x_cons[1];
3645dfecf96Smrg    cons6->type = LispCons_t;
3655dfecf96Smrg    CDR(cons6) = cons5;
3665dfecf96Smrg    cons7 = &x_cons[0];
3675dfecf96Smrg    cons7->type = LispCons_t;
3685dfecf96Smrg    CDR(cons7) = cons6;
3695dfecf96Smrg}
3705dfecf96Smrg
3715dfecf96SmrgLispObj *
3725dfecf96SmrgLisp_Compile(LispBuiltin *builtin)
3735dfecf96Smrg/*
3745dfecf96Smrg compile name &optional definition
3755dfecf96Smrg */
3765dfecf96Smrg{
3775dfecf96Smrg    GC_ENTER();
3785dfecf96Smrg    LispObj *result, *warnings_p, *failure_p;
3795dfecf96Smrg
3805dfecf96Smrg    LispObj *name, *definition;
3815dfecf96Smrg
3825dfecf96Smrg    definition = ARGUMENT(1);
3835dfecf96Smrg    name = ARGUMENT(0);
3845dfecf96Smrg
3855dfecf96Smrg    result = name;
3865dfecf96Smrg    warnings_p = NIL;
3875dfecf96Smrg    failure_p = T;
3885dfecf96Smrg
3895dfecf96Smrg    if (name != NIL) {
3905dfecf96Smrg	LispAtom *atom;
3915dfecf96Smrg
3925dfecf96Smrg	CHECK_SYMBOL(name);
3935dfecf96Smrg	atom = name->data.atom;
3945dfecf96Smrg	if (atom->a_builtin || atom->a_compiled)
3955dfecf96Smrg	    goto finished_compilation;
3965dfecf96Smrg	else if (atom->a_function) {
3975dfecf96Smrg	    LispCom com;
3985dfecf96Smrg	    int failed;
3995dfecf96Smrg	    int lex = 0, base;
4005dfecf96Smrg	    LispArgList *alist;
4015dfecf96Smrg	    LispObj *lambda, *form, *arguments;
4025dfecf96Smrg
4035dfecf96Smrg	    lambda = atom->property->fun.function;
4045dfecf96Smrg	    if (definition != UNSPEC || lambda->funtype != LispFunction)
4055dfecf96Smrg		/* XXX TODO replace definition etc. */
4065dfecf96Smrg		goto finished_compilation;
4075dfecf96Smrg	    alist = atom->property->alist;
4085dfecf96Smrg
4095dfecf96Smrg	    memset(&com, 0, sizeof(LispCom));
4105dfecf96Smrg	    com.toplevel = com.block = LispCalloc(1, sizeof(CodeBlock));
4115dfecf96Smrg	    com.block->type = LispBlockClosure;
4125dfecf96Smrg	    com.block->tag = name;
4135dfecf96Smrg
4145dfecf96Smrg	    /*  Create a fake argument list to avoid yet another flag
4155dfecf96Smrg	     * for ComCall. The value does not matter, just the fact
4165dfecf96Smrg	     * that the symbol will be bound or not in the implicit
4175dfecf96Smrg	     * PROGN of the function body. */
4185dfecf96Smrg	    base = alist->num_arguments - alist->auxs.num_symbols;
4195dfecf96Smrg	    if (base) {
4205dfecf96Smrg		LispObj *argument;
4215dfecf96Smrg		int i, sforms;
4225dfecf96Smrg
4235dfecf96Smrg		for (i = sforms = 0; i < alist->optionals.num_symbols; i++)
4245dfecf96Smrg		    if (alist->optionals.sforms[i])
4255dfecf96Smrg			++sforms;
4265dfecf96Smrg
4275dfecf96Smrg		arguments = form = NIL;
4285dfecf96Smrg		i = sforms +
4295dfecf96Smrg		    alist->normals.num_symbols + alist->optionals.num_symbols;
4305dfecf96Smrg
4315dfecf96Smrg		if (i) {
4325dfecf96Smrg		    arguments = form = CONS(NIL, NIL);
4335dfecf96Smrg		    GC_PROTECT(arguments);
4345dfecf96Smrg		    for (--i; i > 0; i--) {
4355dfecf96Smrg			RPLACD(form, CONS(NIL, NIL));
4365dfecf96Smrg			form = CDR(form);
4375dfecf96Smrg		    }
4385dfecf96Smrg		}
4395dfecf96Smrg
4405dfecf96Smrg		for (i = 0; i < alist->keys.num_symbols; i++) {
4415dfecf96Smrg		    /* key symbol */
4425dfecf96Smrg		    if (alist->keys.keys[i])
4435dfecf96Smrg			argument = QUOTE(alist->keys.keys[i]);
4445dfecf96Smrg		    else
4455dfecf96Smrg			argument = alist->keys.symbols[i];
4465dfecf96Smrg
4475dfecf96Smrg		    /* add key */
4485dfecf96Smrg		    if (arguments == NIL) {
4495dfecf96Smrg			arguments = form = CONS(argument, NIL);
4505dfecf96Smrg			GC_PROTECT(arguments);
4515dfecf96Smrg		    }
4525dfecf96Smrg		    else {
4535dfecf96Smrg			RPLACD(form, CONS(argument, NIL));
4545dfecf96Smrg			form = CDR(form);
4555dfecf96Smrg		    }
4565dfecf96Smrg
4575dfecf96Smrg		    /* add value */
4585dfecf96Smrg		    RPLACD(form, CONS(NIL, NIL));
4595dfecf96Smrg		    form = CDR(form);
4605dfecf96Smrg
4615dfecf96Smrg		    if (alist->keys.sforms[i]) {
4625dfecf96Smrg			RPLACD(form, CONS(NIL, NIL));
4635dfecf96Smrg			form = CDR(form);
4645dfecf96Smrg		    }
4655dfecf96Smrg		}
4665dfecf96Smrg
4675dfecf96Smrg		if (alist->rest) {
4685dfecf96Smrg		    if (arguments == NIL) {
4695dfecf96Smrg			arguments = form = CONS(NIL, NIL);
4705dfecf96Smrg			GC_PROTECT(arguments);
4715dfecf96Smrg		    }
4725dfecf96Smrg		    else {
4735dfecf96Smrg			RPLACD(form, CONS(NIL, NIL));
4745dfecf96Smrg			form = CDR(form);
4755dfecf96Smrg		    }
4765dfecf96Smrg		}
4775dfecf96Smrg	    }
4785dfecf96Smrg	    else
4795dfecf96Smrg		arguments = NIL;
4805dfecf96Smrg
4815dfecf96Smrg	    form = CONS(lambda->data.lambda.code, NIL);
4825dfecf96Smrg	    GC_PROTECT(form);
4835dfecf96Smrg	    com.form = form;
4845dfecf96Smrg	    com.plist = CONS(NIL, NIL);
4855dfecf96Smrg	    GC_PROTECT(com.plist);
4865dfecf96Smrg
4875dfecf96Smrg	    failed = 1;
4885dfecf96Smrg	    if (setjmp(com.jmp) == 0) {
4895dfecf96Smrg		/* Save interpreter state */
4905dfecf96Smrg		lex = com.lex = lisp__data.env.lex;
4915dfecf96Smrg		base = ComCall(&com, alist, name, arguments, 1, 0, 1);
4925dfecf96Smrg
4935dfecf96Smrg		/* Generate code tree */
4945dfecf96Smrg		lisp__data.env.lex = base;
4955dfecf96Smrg		ComProgn(&com, CAR(form));
4965dfecf96Smrg		failed = 0;
4975dfecf96Smrg	    }
4985dfecf96Smrg
4995dfecf96Smrg	    /* Restore interpreter state */
5005dfecf96Smrg	    lisp__data.env.lex = lex;
5015dfecf96Smrg	    lisp__data.env.head = lisp__data.env.length = base;
5025dfecf96Smrg
5035dfecf96Smrg	    if (!failed) {
5045dfecf96Smrg		failure_p = NIL;
5055dfecf96Smrg		result = MakeBytecodeObject(&com, name,
5065dfecf96Smrg					    lambda->data.lambda.data);
5075dfecf96Smrg		LispSetAtomCompiledProperty(atom, result);
5085dfecf96Smrg		result = name;
5095dfecf96Smrg	    }
5105dfecf96Smrg	    if (com.warnings)
5115dfecf96Smrg		warnings_p = FIXNUM(com.warnings);
5125dfecf96Smrg	    goto finished_compilation;
5135dfecf96Smrg	}
5145dfecf96Smrg	else
5155dfecf96Smrg	    goto undefined_function;
5165dfecf96Smrg    }
5175dfecf96Smrg
5185dfecf96Smrgundefined_function:
5195dfecf96Smrg    LispDestroy("%s: the function %s is undefined",
5205dfecf96Smrg		STRFUN(builtin), STROBJ(name));
5215dfecf96Smrg
5225dfecf96Smrgfinished_compilation:
5235dfecf96Smrg    RETURN(0) = warnings_p;
5245dfecf96Smrg    RETURN(1) = failure_p;
5255dfecf96Smrg    RETURN_COUNT = 2;
5265dfecf96Smrg    GC_LEAVE();
5275dfecf96Smrg
5285dfecf96Smrg    return (result);
5295dfecf96Smrg}
5305dfecf96Smrg
5315dfecf96SmrgLispObj *
5325dfecf96SmrgLisp_Disassemble(LispBuiltin *builtin)
5335dfecf96Smrg/*
5345dfecf96Smrg disassemble function
5355dfecf96Smrg */
5365dfecf96Smrg{
5375dfecf96Smrg    int macro;
5385dfecf96Smrg    char buffer[128];
5395dfecf96Smrg    LispAtom *atom;
5405dfecf96Smrg    LispArgList *alist;
5415dfecf96Smrg    LispBuiltin *xbuiltin;
5425dfecf96Smrg    LispObj *name, *lambda, *bytecode;
5435dfecf96Smrg
5445dfecf96Smrg    LispObj *function;
5455dfecf96Smrg
5465dfecf96Smrg    function = ARGUMENT(0);
5475dfecf96Smrg
5485dfecf96Smrg    macro = 0;
5495dfecf96Smrg    alist = NULL;
5505dfecf96Smrg    xbuiltin = NULL;
5515dfecf96Smrg    name = bytecode = NULL;
5525dfecf96Smrg
5535dfecf96Smrg    switch (OBJECT_TYPE(function)) {
5545dfecf96Smrg	case LispAtom_t:
5555dfecf96Smrg	    name = function;
5565dfecf96Smrg	    atom = function->data.atom;
5575dfecf96Smrg	    alist = atom->property->alist;
5585dfecf96Smrg	    if (atom->a_builtin) {
5595dfecf96Smrg		xbuiltin = atom->property->fun.builtin;
5605dfecf96Smrg		macro = xbuiltin->type == LispMacro;
5615dfecf96Smrg	    }
5625dfecf96Smrg	    else if (atom->a_compiled)
5635dfecf96Smrg		bytecode = atom->property->fun.function;
5645dfecf96Smrg	    else if (atom->a_function) {
5655dfecf96Smrg		lambda = atom->property->fun.function;
5665dfecf96Smrg		macro = lambda->funtype == LispMacro;
5675dfecf96Smrg	    }
5685dfecf96Smrg	    else if (atom->a_defstruct &&
5695dfecf96Smrg		     atom->property->structure.function != STRUCT_NAME) {
5705dfecf96Smrg		if (atom->property->structure.function == STRUCT_CONSTRUCTOR)
5715dfecf96Smrg		    atom = Omake_struct->data.atom;
5725dfecf96Smrg		else if (atom->property->structure.function == STRUCT_CHECK)
5735dfecf96Smrg		    atom = Ostruct_type->data.atom;
5745dfecf96Smrg		else
5755dfecf96Smrg		    atom = Ostruct_access->data.atom;
5765dfecf96Smrg		xbuiltin = atom->property->fun.builtin;
5775dfecf96Smrg	    }
5785dfecf96Smrg	    else
5795dfecf96Smrg		LispDestroy("%s: the function %s is not defined",
5805dfecf96Smrg			    STRFUN(builtin), STROBJ(function));
5815dfecf96Smrg	    break;
5825dfecf96Smrg	case LispBytecode_t:
5835dfecf96Smrg	    name = Olambda;
5845dfecf96Smrg	    bytecode = function;
5855dfecf96Smrg	    break;
5865dfecf96Smrg	case LispLambda_t:
5875dfecf96Smrg	    name = Olambda;
5885dfecf96Smrg	    alist = (LispArgList*)function->data.lambda.name->data.opaque.data;
5895dfecf96Smrg	    break;
5905dfecf96Smrg	case LispCons_t:
5915dfecf96Smrg	    if (CAR(function) == Olambda) {
5925dfecf96Smrg		function = EVAL(function);
5935dfecf96Smrg		if (OBJECT_TYPE(function) == LispLambda_t) {
5945dfecf96Smrg		    name = Olambda;
5955dfecf96Smrg		    alist = (LispArgList*)
5965dfecf96Smrg			function->data.lambda.name->data.opaque.data;
5975dfecf96Smrg		    break;
5985dfecf96Smrg		}
5995dfecf96Smrg	    }
6005dfecf96Smrg	default:
6015dfecf96Smrg	    LispDestroy("%s: %s is not a function",
6025dfecf96Smrg			STRFUN(builtin), STROBJ(function));
6035dfecf96Smrg	    break;
6045dfecf96Smrg    }
6055dfecf96Smrg
6065dfecf96Smrg    if (xbuiltin) {
6075dfecf96Smrg	LispWriteStr(NIL, "Builtin ", 8);
6085dfecf96Smrg	if (macro)
6095dfecf96Smrg	    LispWriteStr(NIL, "macro ", 6);
6105dfecf96Smrg	else
6115dfecf96Smrg	    LispWriteStr(NIL, "function ", 9);
6125dfecf96Smrg    }
6135dfecf96Smrg    else if (macro)
6145dfecf96Smrg	LispWriteStr(NIL, "Macro ", 6);
6155dfecf96Smrg    else
6165dfecf96Smrg	LispWriteStr(NIL, "Function ", 9);
6175dfecf96Smrg    LispWriteObject(NIL, name);
6185dfecf96Smrg    LispWriteStr(NIL, ":\n", 2);
6195dfecf96Smrg
6205dfecf96Smrg    if (alist) {
6215dfecf96Smrg	int i;
6225dfecf96Smrg
6235dfecf96Smrg	sprintf(buffer, "%d required argument%s",
6245dfecf96Smrg		alist->normals.num_symbols,
6255dfecf96Smrg		alist->normals.num_symbols != 1 ? "s" : "");
6265dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6275dfecf96Smrg	for (i = 0; i < alist->normals.num_symbols; i++) {
6285dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6295dfecf96Smrg	    LispWriteChar(NIL, ' ');
6305dfecf96Smrg	    LispWriteStr(NIL, ATOMID(alist->normals.symbols[i]),
6315dfecf96Smrg			 strlen(ATOMID(alist->normals.symbols[i])));
6325dfecf96Smrg	}
6335dfecf96Smrg	LispWriteChar(NIL, '\n');
6345dfecf96Smrg
6355dfecf96Smrg	sprintf(buffer, "%d optional argument%s",
6365dfecf96Smrg		alist->optionals.num_symbols,
6375dfecf96Smrg		alist->optionals.num_symbols != 1 ? "s" : "");
6385dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6395dfecf96Smrg	for (i = 0; i < alist->optionals.num_symbols; i++) {
6405dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6415dfecf96Smrg	    LispWriteChar(NIL, ' ');
6425dfecf96Smrg	    LispWriteStr(NIL, ATOMID(alist->optionals.symbols[i]),
6435dfecf96Smrg			 strlen(ATOMID(alist->optionals.symbols[i])));
6445dfecf96Smrg	}
6455dfecf96Smrg	LispWriteChar(NIL, '\n');
6465dfecf96Smrg
6475dfecf96Smrg	sprintf(buffer, "%d keyword parameter%s",
6485dfecf96Smrg		alist->keys.num_symbols,
6495dfecf96Smrg		alist->keys.num_symbols != 1 ? "s" : "");
6505dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6515dfecf96Smrg	for (i = 0; i < alist->keys.num_symbols; i++) {
6525dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6535dfecf96Smrg	    LispWriteChar(NIL, ' ');
6545dfecf96Smrg	    LispWriteObject(NIL, alist->keys.symbols[i]);
6555dfecf96Smrg	}
6565dfecf96Smrg	LispWriteChar(NIL, '\n');
6575dfecf96Smrg
6585dfecf96Smrg	if (alist->rest) {
6595dfecf96Smrg	    LispWriteStr(NIL, "Rest argument: ", 15);
6605dfecf96Smrg	    LispWriteStr(NIL, ATOMID(alist->rest),
6615dfecf96Smrg			 strlen(ATOMID(alist->rest)));
6625dfecf96Smrg	    LispWriteChar(NIL, '\n');
6635dfecf96Smrg	}
6645dfecf96Smrg	else
6655dfecf96Smrg	    LispWriteStr(NIL, "No rest argument\n", 17);
6665dfecf96Smrg    }
6675dfecf96Smrg
6685dfecf96Smrg    if (bytecode) {
6695dfecf96Smrg	char *ptr;
6705dfecf96Smrg	int *offsets[4];
6715dfecf96Smrg	int i, done, j, sym0, sym1, con0, con1, bui0, byt0, strd, strf;
6725dfecf96Smrg	LispObj **constants;
6735dfecf96Smrg	LispAtom **symbols;
6745dfecf96Smrg	LispBuiltin **builtins;
6755dfecf96Smrg	LispObj **names;
6765dfecf96Smrg	short stack, num_constants, num_symbols, num_builtins, num_bytecodes;
6775dfecf96Smrg	unsigned char *base, *stream = bytecode->data.bytecode.bytecode->code;
6785dfecf96Smrg
6795dfecf96Smrg	LispWriteStr(NIL, "\nBytecode header:\n", 18);
6805dfecf96Smrg
6815dfecf96Smrg	/* Header information */
6825dfecf96Smrg	stack = *(short*)stream;
6835dfecf96Smrg	stream += sizeof(short);
6845dfecf96Smrg	sprintf(buffer, "%d element%s used in the stack\n",
6855dfecf96Smrg		stack, stack != 1 ? "s" : "");
6865dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6875dfecf96Smrg	stack = *(short*)stream;
6885dfecf96Smrg	stream += sizeof(short);
6895dfecf96Smrg	sprintf(buffer, "%d element%s used in the builtin stack\n",
6905dfecf96Smrg		stack, stack != 1 ? "s" : "");
6915dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6925dfecf96Smrg	stack = *(short*)stream;
6935dfecf96Smrg	stream += sizeof(short);
6945dfecf96Smrg	sprintf(buffer, "%d element%s used in the protected stack\n",
6955dfecf96Smrg		stack, stack != 1 ? "s" : "");
6965dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6975dfecf96Smrg
6985dfecf96Smrg	num_constants = *(short*)stream;
6995dfecf96Smrg	stream += sizeof(short);
7005dfecf96Smrg	num_symbols = *(short*)stream;
7015dfecf96Smrg	stream += sizeof(short);
7025dfecf96Smrg	num_builtins = *(short*)stream;
7035dfecf96Smrg	stream += sizeof(short);
7045dfecf96Smrg	num_bytecodes = *(short*)stream;
7055dfecf96Smrg	stream += sizeof(short);
7065dfecf96Smrg
7075dfecf96Smrg	constants = (LispObj**)stream;
7085dfecf96Smrg	stream += num_constants * sizeof(LispObj*);
7095dfecf96Smrg	symbols = (LispAtom**)stream;
7105dfecf96Smrg	stream += num_symbols * sizeof(LispAtom*);
7115dfecf96Smrg	builtins = (LispBuiltin**)stream;
7125dfecf96Smrg	stream += num_builtins * sizeof(LispBuiltin*);
7135dfecf96Smrg	stream += num_bytecodes * sizeof(unsigned char*);
7145dfecf96Smrg	names = (LispObj**)stream;
7155dfecf96Smrg	stream += num_bytecodes * sizeof(LispObj*);
7165dfecf96Smrg
7175dfecf96Smrg	for (i = 0; i < num_constants; i++) {
7185dfecf96Smrg	    sprintf(buffer, "Constant %d = %s\n", i, STROBJ(constants[i]));
7195dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7205dfecf96Smrg	}
7215dfecf96Smrg
7225dfecf96Smrg/* Macro XSTRING avoids some noisy in the output, if it were defined as
7235dfecf96Smrg * #define XSTRING(object) object ? STROBJ(object) : #<UNBOUND>
7245dfecf96Smrg *	and called as XSTRING(atom->object)
7255dfecf96Smrg * it would also print the package name were the symbol was first defined,
7265dfecf96Smrg * but for local variables, only the symbol string is important. */
7275dfecf96Smrg#define XSTRING(string)		string ? string : "#<UNBOUND>"
7285dfecf96Smrg
7295dfecf96Smrg	for (i = 0; i < num_symbols; i++) {
7305dfecf96Smrg	    sprintf(buffer, "Symbol %d = %s\n",
7315dfecf96Smrg		    i, XSTRING(symbols[i]->string));
7325dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7335dfecf96Smrg	}
7345dfecf96Smrg	for (i = 0; i < num_builtins; i++) {
7355dfecf96Smrg	    sprintf(buffer, "Builtin %d = %s\n",
7365dfecf96Smrg		    i, STROBJ(builtins[i]->symbol));
7375dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7385dfecf96Smrg	}
7395dfecf96Smrg	for (i = 0; i < num_bytecodes; i++) {
7405dfecf96Smrg	    sprintf(buffer, "Bytecode %d = %s\n",
7415dfecf96Smrg		    i, STROBJ(names[i]));
7425dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7435dfecf96Smrg	}
7445dfecf96Smrg
7455dfecf96Smrg	/*  Make readability slightly easier printing the names of local
7465dfecf96Smrg	 * variables where it's offset is known, i.e. function arguments. */
7475dfecf96Smrg	if (alist) {
7485dfecf96Smrg	    if (alist->num_arguments == 0)
7495dfecf96Smrg		LispWriteStr(NIL, "\nNo initial stack\n", 18);
7505dfecf96Smrg	    else {
7515dfecf96Smrg		int len1, len2;
7525dfecf96Smrg
7535dfecf96Smrg		j = 0;
7545dfecf96Smrg		LispWriteStr(NIL, "\nInitial stack:\n", 16);
7555dfecf96Smrg
7565dfecf96Smrg		for (i = 0; i < alist->normals.num_symbols; i++, j++) {
7575dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7585dfecf96Smrg		    LispWriteStr(NIL, buffer, strlen(buffer));
7595dfecf96Smrg		    ptr = alist->normals.symbols[i]->data.atom->string;
7605dfecf96Smrg		    LispWriteStr(NIL, ptr, strlen(ptr));
7615dfecf96Smrg		    LispWriteChar(NIL, '\n');
7625dfecf96Smrg		}
7635dfecf96Smrg
7645dfecf96Smrg		for (i = 0; i < alist->optionals.num_symbols; i++, j++) {
7655dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7665dfecf96Smrg		    LispWriteStr(NIL, buffer, strlen(buffer));
7675dfecf96Smrg		    ptr = alist->optionals.symbols[i]->data.atom->string;
7685dfecf96Smrg		    LispWriteStr(NIL, ptr, strlen(ptr));
7695dfecf96Smrg		    LispWriteChar(NIL, '\n');
7705dfecf96Smrg		    if (alist->optionals.sforms[i]) {
7715dfecf96Smrg			sprintf(buffer, "%d = ", j);
7725dfecf96Smrg			len1 = strlen(buffer);
7735dfecf96Smrg			LispWriteStr(NIL, buffer, len1);
7745dfecf96Smrg			ptr = alist->optionals.sforms[i]->data.atom->string;
7755dfecf96Smrg			len2 = strlen(ptr);
7765dfecf96Smrg			LispWriteStr(NIL, ptr, len2);
7775dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
7785dfecf96Smrg			LispWriteStr(NIL, ";  sform\n", 9);
7795dfecf96Smrg			j++;
7805dfecf96Smrg		    }
7815dfecf96Smrg		}
7825dfecf96Smrg
7835dfecf96Smrg		for (i = 0; i < alist->keys.num_symbols; i++, j++) {
7845dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7855dfecf96Smrg		    len1 = strlen(buffer);
7865dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
7875dfecf96Smrg		    if (alist->keys.keys[i]) {
7885dfecf96Smrg			ptr = alist->keys.keys[i]->data.atom->string;
7895dfecf96Smrg			len2 = strlen(ptr);
7905dfecf96Smrg			LispWriteStr(NIL, ptr, strlen(ptr));
7915dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
7925dfecf96Smrg			LispWriteStr(NIL, ";  special key", 14);
7935dfecf96Smrg		    }
7945dfecf96Smrg		    else {
7955dfecf96Smrg			ptr = alist->keys.symbols[i]->data.atom->string;
7965dfecf96Smrg			LispWriteStr(NIL, ptr, strlen(ptr));
7975dfecf96Smrg		    }
7985dfecf96Smrg		    LispWriteChar(NIL, '\n');
7995dfecf96Smrg		    if (alist->keys.sforms[i]) {
8005dfecf96Smrg			sprintf(buffer, "%d = ", j);
8015dfecf96Smrg			len1 = strlen(buffer);
8025dfecf96Smrg			LispWriteStr(NIL, buffer, len1);
8035dfecf96Smrg			ptr = alist->keys.sforms[i]->data.atom->string;
8045dfecf96Smrg			len2 = strlen(ptr);
8055dfecf96Smrg			LispWriteStr(NIL, ptr, len2);
8065dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
8075dfecf96Smrg			LispWriteStr(NIL, ";  sform\n", 9);
8085dfecf96Smrg			j++;
8095dfecf96Smrg		    }
8105dfecf96Smrg		}
8115dfecf96Smrg
8125dfecf96Smrg		if (alist->rest) {
8135dfecf96Smrg		    sprintf(buffer, "%d = ", j);
8145dfecf96Smrg		    len1 = strlen(buffer);
8155dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
8165dfecf96Smrg		    ptr = alist->rest->data.atom->string;
8175dfecf96Smrg		    len2 = strlen(ptr);
8185dfecf96Smrg		    LispWriteStr(NIL, ptr, len2);
8195dfecf96Smrg		    LispWriteChar(NIL, '\n');
8205dfecf96Smrg		    j++;
8215dfecf96Smrg		}
8225dfecf96Smrg
8235dfecf96Smrg		for (i = 0; i < alist->auxs.num_symbols; i++, j++) {
8245dfecf96Smrg		    sprintf(buffer, "%d = ", j);
8255dfecf96Smrg		    len1 = strlen(buffer);
8265dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
8275dfecf96Smrg		    ptr = alist->auxs.symbols[i]->data.atom->string;
8285dfecf96Smrg		    len2 = strlen(ptr);
8295dfecf96Smrg		    LispWriteStr(NIL, ptr, len2);
8305dfecf96Smrg		    LispWriteChars(NIL, ' ', 28 - (len1 + len2));
8315dfecf96Smrg		    LispWriteStr(NIL, ";  aux\n", 7);
8325dfecf96Smrg		}
8335dfecf96Smrg	    }
8345dfecf96Smrg	}
8355dfecf96Smrg
8365dfecf96Smrg	LispWriteStr(NIL, "\nBytecode stream:\n", 18);
8375dfecf96Smrg
8385dfecf96Smrg	base = stream;
8395dfecf96Smrg	for (done = j = 0; !done; j = 0) {
8405dfecf96Smrg	    sym0 = sym1 = con0 = con1 = bui0 = byt0 = strd = strf = -1;
8415dfecf96Smrg	    sprintf(buffer, "%4ld  ", (long)(stream - base));
8425dfecf96Smrg	    ptr = buffer + strlen(buffer);
8435dfecf96Smrg	    switch (*stream++) {
8445dfecf96Smrg		case XBC_NOOP:	strcpy(ptr, "NOOP");	break;
8455dfecf96Smrg		case XBC_PRED:
8465dfecf96Smrg		    strcpy(ptr, "PRED:");
8475dfecf96Smrg		    ptr += strlen(ptr);
8485dfecf96Smrg		    goto predicate;
8495dfecf96Smrg		case XBC_INV:	strcpy(ptr, "INV");	break;
8505dfecf96Smrg		case XBC_NIL:	strcpy(ptr, "NIL");	break;
8515dfecf96Smrg		case XBC_T:	strcpy(ptr, "T");	break;
8525dfecf96Smrg		case XBC_CAR:	strcpy(ptr, "CAR");	break;
8535dfecf96Smrg		case XBC_CDR:	strcpy(ptr, "CDR");	break;
8545dfecf96Smrg		case XBC_RPLACA:strcpy(ptr, "RPLACA");	break;
8555dfecf96Smrg		case XBC_RPLACD:strcpy(ptr, "RPLACD");	break;
8565dfecf96Smrg		case XBC_EQ:	strcpy(ptr, "EQ");	break;
8575dfecf96Smrg		case XBC_EQL:	strcpy(ptr, "EQL");	break;
8585dfecf96Smrg		case XBC_EQUAL:	strcpy(ptr, "EQUAL");	break;
8595dfecf96Smrg		case XBC_EQUALP:strcpy(ptr, "EQUALP");	break;
8605dfecf96Smrg		case XBC_LENGTH:strcpy(ptr, "LENGTH");	break;
8615dfecf96Smrg		case XBC_LAST:	strcpy(ptr, "LAST");	break;
8625dfecf96Smrg		case XBC_NTHCDR:strcpy(ptr, "NTHCDR");	break;
8635dfecf96Smrg		case XBC_PUSH:	strcpy(ptr, "PUSH");	break;
8645dfecf96Smrg		case XBC_CAR_PUSH:
8655dfecf96Smrg		    strcpy(ptr, "CAR&PUSH");
8665dfecf96Smrg		    break;
8675dfecf96Smrg		case XBC_CDR_PUSH:
8685dfecf96Smrg		    strcpy(ptr, "CDR&PUSH");
8695dfecf96Smrg		    break;
8705dfecf96Smrg		case XBC_PUSH_NIL:
8715dfecf96Smrg		    strcpy(ptr, "PUSH NIL");
8725dfecf96Smrg		    break;
8735dfecf96Smrg		case XBC_PUSH_UNSPEC:
8745dfecf96Smrg		    strcpy(ptr, "PUSH #<UNSPEC>");
8755dfecf96Smrg		    break;
8765dfecf96Smrg		case XBC_PUSH_T:
8775dfecf96Smrg		    strcpy(ptr, "PUSH T");
8785dfecf96Smrg		    break;
8795dfecf96Smrg		case XBC_PUSH_NIL_N:
8805dfecf96Smrg		    strcpy(ptr, "PUSH NIL ");
8815dfecf96Smrg		    ptr += strlen(ptr);
8825dfecf96Smrg		    sprintf(ptr, "%d", (int)(*stream++));
8835dfecf96Smrg		    break;
8845dfecf96Smrg		case XBC_PUSH_UNSPEC_N:
8855dfecf96Smrg		    strcpy(ptr, "PUSH #<UNSPEC> ");
8865dfecf96Smrg		    ptr += strlen(ptr);
8875dfecf96Smrg		    sprintf(ptr, "%d", (int)(*stream++));
8885dfecf96Smrg		    break;
8895dfecf96Smrg		case XBC_LET:
8905dfecf96Smrg		    strcpy(ptr, "LET");
8915dfecf96Smrg/* update sym0 */
8925dfecf96Smrgsymbol:
8935dfecf96Smrg		    offsets[j++] = &sym0;
8945dfecf96Smrg/* update <offsets> - print [byte] */
8955dfecf96Smrgoffset:
8965dfecf96Smrg		    ptr += strlen(ptr);
8975dfecf96Smrg		    i = *stream++;
8985dfecf96Smrg		    *(offsets[j - 1]) = i;
8995dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9005dfecf96Smrg		    break;
9015dfecf96Smrg		case XBC_LETX:
9025dfecf96Smrg		    strcpy(ptr, "LET*");
9035dfecf96Smrg		    goto symbol;
9045dfecf96Smrg		case XBC_LET_NIL:
9055dfecf96Smrg		    strcpy(ptr, "LET NIL");
9065dfecf96Smrg		    goto symbol;
9075dfecf96Smrg		case XBC_LETX_NIL:
9085dfecf96Smrg		    strcpy(ptr, "LET* NIL");
9095dfecf96Smrg		    goto symbol;
9105dfecf96Smrg		case XBC_LETBIND:
9115dfecf96Smrg		    strcpy(ptr, "LETBIND");
9125dfecf96Smrg/* print byte */
9135dfecf96Smrgvalue:
9145dfecf96Smrg		    ptr += strlen(ptr);
9155dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
9165dfecf96Smrg		    break;
9175dfecf96Smrg		case XBC_UNLET:strcpy(ptr, "UNLET");	goto value;
9185dfecf96Smrg		case XBC_LOAD:
9195dfecf96Smrg		    strcpy(ptr, "LOAD");
9205dfecf96Smrg/* print (byte) */
9215dfecf96Smrgreference:
9225dfecf96Smrg		    ptr += strlen(ptr);
9235dfecf96Smrg		    i = *stream++;
9245dfecf96Smrg		    sprintf(ptr, " (%d)", i);
9255dfecf96Smrg		    break;
9265dfecf96Smrg		case XBC_LOAD_CAR:
9275dfecf96Smrg		    strcpy(ptr, "LOAD&CAR");
9285dfecf96Smrg		    goto reference;
9295dfecf96Smrg		case XBC_LOAD_CDR:
9305dfecf96Smrg		    strcpy(ptr, "LOAD&CDR");
9315dfecf96Smrg		    goto reference;
9325dfecf96Smrg		case XBC_LOAD_CAR_STORE:
9335dfecf96Smrg		    strcpy(ptr, "LOAD&CAR&STORE");
9345dfecf96Smrg		    goto reference;
9355dfecf96Smrg		case XBC_LOAD_CDR_STORE:
9365dfecf96Smrg		    strcpy(ptr, "LOAD&CDR&STORE");
9375dfecf96Smrg		    goto reference;
9385dfecf96Smrg		case XBC_LOAD_LET:
9395dfecf96Smrg		    strcpy(ptr, "LOAD&LET");
9405dfecf96Smrgload_let:
9415dfecf96Smrg		    offsets[j++] = &sym0;
9425dfecf96Smrg		    i = *stream++;
9435dfecf96Smrg		    ptr += strlen(ptr);
9445dfecf96Smrg		    sprintf(ptr, " (%d)", i);
9455dfecf96Smrg		    goto offset;
9465dfecf96Smrg		case XBC_LOAD_LETX:
9475dfecf96Smrg		    strcpy(ptr, "LOAD&LET*");
9485dfecf96Smrg		    goto load_let;
9495dfecf96Smrg		case XBC_STRUCT:
9505dfecf96Smrg		    strcpy(ptr, "STRUCT");
9515dfecf96Smrg		    offsets[j++] = &strf;
9525dfecf96Smrg		    offsets[j++] = &strd;
9535dfecf96Smrg/* update <offsets> - print [byte] - update <offsets> - print [byte] */
9545dfecf96Smrgoffset_offset:
9555dfecf96Smrg		    ptr += strlen(ptr);
9565dfecf96Smrg		    i = *stream++;
9575dfecf96Smrg		    *(offsets[j - 2]) = i;
9585dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9595dfecf96Smrg		    goto offset;
9605dfecf96Smrg		case XBC_LOAD_PUSH:
9615dfecf96Smrg		    strcpy(ptr, "LOAD&PUSH");
9625dfecf96Smrg		    goto reference;
9635dfecf96Smrg		case XBC_LOADCON:
9645dfecf96Smrg		    strcpy(ptr, "LOADCON");
9655dfecf96Smrgconstant:
9665dfecf96Smrg		    offsets[j++] = &con0;
9675dfecf96Smrg		    goto offset;
9685dfecf96Smrg		case XBC_LOADCON_SET:
9695dfecf96Smrg		    strcpy(ptr, "LOADCON&SET");
9705dfecf96Smrg		    offsets[j++] = &con0;
9715dfecf96Smrg/* update <offsets> - print [byte] - print (byte) */
9725dfecf96Smrgoffset_reference:
9735dfecf96Smrg		    i = *stream++;
9745dfecf96Smrg		    *(offsets[j - 1]) = i;
9755dfecf96Smrg		    ptr += strlen(ptr);
9765dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9775dfecf96Smrg		    goto reference;
9785dfecf96Smrg		case XBC_STRUCTP:
9795dfecf96Smrg		    strcpy(ptr, "STRUCTP");
9805dfecf96Smrg		    offsets[j++] = &strd;
9815dfecf96Smrg		    goto offset;
9825dfecf96Smrg		case XBC_LOADCON_LET:
9835dfecf96Smrg		    strcpy(ptr, "LOADCON&LET");
9845dfecf96Smrgloadcon_let:
9855dfecf96Smrg		    offsets[j++] = &con0;
9865dfecf96Smrg		    offsets[j++] = &sym0;
9875dfecf96Smrg		    goto offset_offset;
9885dfecf96Smrg		case XBC_LOADCON_LETX:
9895dfecf96Smrg		    strcpy(ptr, "LOADCON&LET*");
9905dfecf96Smrg		    goto loadcon_let;
9915dfecf96Smrg		case XBC_LOADCON_PUSH:
9925dfecf96Smrg		    strcpy(ptr, "LOADCON&PUSH");
9935dfecf96Smrg		    goto constant;
9945dfecf96Smrg		case XBC_LOADSYM:
9955dfecf96Smrg		    strcpy(ptr, "LOADSYM");
9965dfecf96Smrg		    goto symbol;
9975dfecf96Smrg		case XBC_LOADSYM_LET:
9985dfecf96Smrg		    strcpy(ptr, "LOADSYM&LET");
9995dfecf96Smrgloadsym_let:
10005dfecf96Smrg		    offsets[j++] = &sym0;
10015dfecf96Smrg		    offsets[j++] = &sym1;
10025dfecf96Smrg		    goto offset_offset;
10035dfecf96Smrg		case XBC_LOADSYM_LETX:
10045dfecf96Smrg		    strcpy(ptr, "LOADSYM&LET*");
10055dfecf96Smrg		    goto loadsym_let;
10065dfecf96Smrg		case XBC_LOADSYM_PUSH:
10075dfecf96Smrg		    strcpy(ptr, "LOADSYM&PUSH");
10085dfecf96Smrg		    goto symbol;
10095dfecf96Smrg		case XBC_LOAD_SET:
10105dfecf96Smrg		    strcpy(ptr, "LOAD&SET");
10115dfecf96Smrg/* print (byte) - print (byte) */
10125dfecf96Smrgreference_reference:
10135dfecf96Smrg		    ptr += strlen(ptr);
10145dfecf96Smrg		    i = *stream++;
10155dfecf96Smrg		    sprintf(ptr, " (%d)", i);
10165dfecf96Smrg		    goto reference;
10175dfecf96Smrg		case XBC_LOAD_CAR_SET:
10185dfecf96Smrg		    strcpy(ptr, "LOAD&CAR&SET");
10195dfecf96Smrg		    goto reference_reference;
10205dfecf96Smrg		case XBC_LOAD_CDR_SET:
10215dfecf96Smrg		    strcpy(ptr, "LOAD&CDR&SET");
10225dfecf96Smrg		    goto reference_reference;
10235dfecf96Smrg		case XBC_CAR_SET:
10245dfecf96Smrg		    strcpy(ptr, "CAR&SET");
10255dfecf96Smrg		    goto reference;
10265dfecf96Smrg		case XBC_CDR_SET:
10275dfecf96Smrg		    strcpy(ptr, "CDR&SET");
10285dfecf96Smrg		    goto reference;
10295dfecf96Smrg		case XBC_SET:
10305dfecf96Smrg		    strcpy(ptr, "SET");
10315dfecf96Smrg		    goto reference;
10325dfecf96Smrg		case XBC_SETSYM:
10335dfecf96Smrg		    strcpy(ptr, "SETSYM");
10345dfecf96Smrg		    goto symbol;
10355dfecf96Smrg		case XBC_SET_NIL:
10365dfecf96Smrg		    strcpy(ptr, "SET NIL");
10375dfecf96Smrg		    goto reference;
10385dfecf96Smrg		case XBC_CALL:
10395dfecf96Smrg		    strcpy(ptr, "CALL");
10405dfecf96Smrg		    ptr += strlen(ptr);
10415dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10425dfecf96Smrg		    offsets[j++] = &bui0;
10435dfecf96Smrg		    goto offset;
10445dfecf96Smrg		case XBC_CALL_SET:
10455dfecf96Smrg		    strcpy(ptr, "CALL&SET");
10465dfecf96Smrg		    ptr += strlen(ptr);
10475dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10485dfecf96Smrg		    offsets[j++] = &bui0;
10495dfecf96Smrg		    goto offset_reference;
10505dfecf96Smrg		case XBC_BYTECALL:
10515dfecf96Smrg		    strcpy(ptr, "BYTECALL");
10525dfecf96Smrg		    ptr += strlen(ptr);
10535dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10545dfecf96Smrg		    offsets[j++] = &byt0;
10555dfecf96Smrg		    goto offset;
10565dfecf96Smrg		case XBC_FUNCALL:
10575dfecf96Smrg		    strcpy(ptr, "FUNCALL");
10585dfecf96Smrgconstant_constant:
10595dfecf96Smrg		    offsets[j++] = &con0;
10605dfecf96Smrg		    offsets[j++] = &con1;
10615dfecf96Smrg		    goto offset_offset;
10625dfecf96Smrg		case XBC_CCONS:
10635dfecf96Smrg		    strcpy(ptr, "CCONS");
10645dfecf96Smrg		    goto constant_constant;
10655dfecf96Smrg		case XBC_CSTAR:	strcpy(ptr, "CSTAR");	break;
10665dfecf96Smrg		case XBC_CFINI:	strcpy(ptr, "CFINI");	break;
10675dfecf96Smrg		case XBC_LSTAR:	strcpy(ptr, "LSTAR");	break;
10685dfecf96Smrg		case XBC_LCONS:	strcpy(ptr, "LCONS");	break;
10695dfecf96Smrg		case XBC_LFINI:	strcpy(ptr, "LFINI");	break;
10705dfecf96Smrg		case XBC_BCONS:	strcpy(ptr, "BCONS");	break;
10715dfecf96Smrg		case XBC_BCONS1:	case XBC_BCONS2:	case XBC_BCONS3:
10725dfecf96Smrg		case XBC_BCONS4:	case XBC_BCONS5:	case XBC_BCONS6:
10735dfecf96Smrg		case XBC_BCONS7:
10745dfecf96Smrg		    strcpy(ptr, "BCONS");
10755dfecf96Smrg		    ptr += strlen(ptr);
10765dfecf96Smrg		    sprintf(ptr, "%d", (int)(stream[-1] - XBC_BCONS));
10775dfecf96Smrg		    break;
10785dfecf96Smrg		case XBC_JUMP:
10795dfecf96Smrg		    strcpy(ptr, "JUMP");
10805dfecf96Smrginteger:
10815dfecf96Smrg		    ptr += strlen(ptr);
10825dfecf96Smrg		    sprintf(ptr, " %d", *(signed short*)stream);
10835dfecf96Smrg		    stream += sizeof(short);
10845dfecf96Smrg		    break;
10855dfecf96Smrg		case XBC_JUMPT:
10865dfecf96Smrg		    strcpy(ptr, "JUMPT");
10875dfecf96Smrg		    goto integer;
10885dfecf96Smrg		case XBC_JUMPNIL:
10895dfecf96Smrg		    strcpy(ptr, "JUMPNIL");
10905dfecf96Smrg		    goto integer;
10915dfecf96Smrg		case XBC_LETREC:
10925dfecf96Smrg		    strcpy(ptr, "LETREC");
10935dfecf96Smrg		    ptr += strlen(ptr);
10945dfecf96Smrg		    sprintf(ptr, " %d", (int)*stream++);
10955dfecf96Smrg		    break;
10965dfecf96Smrg		case XBC_RETURN:
10975dfecf96Smrg		    strcpy(ptr, "RETURN");
10985dfecf96Smrg		    done = 1;
10995dfecf96Smrg		    break;
11005dfecf96Smrg	    }
11015dfecf96Smrg	    i = ptr - buffer + strlen(ptr);
11025dfecf96Smrg	    LispWriteStr(NIL, buffer, i);
11035dfecf96Smrg	    if (j) {
11045dfecf96Smrg
11055dfecf96Smrg		/* Pad */
11065dfecf96Smrg		LispWriteChars(NIL, ' ', 28 - i);
11075dfecf96Smrg		LispWriteChar(NIL, ';');
11085dfecf96Smrg
11095dfecf96Smrg		ptr = buffer;
11105dfecf96Smrg
11115dfecf96Smrg		/* Structure */
11125dfecf96Smrg		if (strf >= 0) {
11135dfecf96Smrg		    /* strd is valid if strf set */
11145dfecf96Smrg		    LispObj *fields = constants[strd];
11155dfecf96Smrg
11165dfecf96Smrg		    for (; strf >= 0; strf--)
11175dfecf96Smrg			fields = CDR(fields);
11185dfecf96Smrg		    strcpy(ptr, "  ");	    ptr += 2;
11195dfecf96Smrg		    strcpy(ptr, CAR(fields)->data.atom->string);
11205dfecf96Smrg		    ptr += strlen(ptr);
11215dfecf96Smrg		}
11225dfecf96Smrg		if (strd >= 0) {
11235dfecf96Smrg		    strcpy(ptr, "  ");		ptr += 2;
11245dfecf96Smrg		    strcpy(ptr, STROBJ(CAR(constants[strd])));
11255dfecf96Smrg		    ptr += strlen(ptr);
11265dfecf96Smrg		}
11275dfecf96Smrg
11285dfecf96Smrg		/* Constants */
11295dfecf96Smrg		if (con0 >= 0) {
11305dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11315dfecf96Smrg		    strcpy(ptr, STROBJ(constants[con0]));
11325dfecf96Smrg		    ptr += strlen(ptr);
11335dfecf96Smrg		    if (con1 >= 0) {
11345dfecf96Smrg			strcpy(ptr, "  ");	ptr += 2;
11355dfecf96Smrg			strcpy(ptr, STROBJ(constants[con1]));
11365dfecf96Smrg			ptr += strlen(ptr);
11375dfecf96Smrg		    }
11385dfecf96Smrg		}
11395dfecf96Smrg
11405dfecf96Smrg		/* Builtin */
11415dfecf96Smrg		if (bui0 >= 0) {
11425dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11435dfecf96Smrg		    strcpy(ptr, STROBJ(builtins[bui0]->symbol));
11445dfecf96Smrg		    ptr += strlen(ptr);
11455dfecf96Smrg		}
11465dfecf96Smrg
11475dfecf96Smrg		/* Bytecode */
11485dfecf96Smrg		if (byt0 >= 0) {
11495dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11505dfecf96Smrg		    strcpy(ptr, STROBJ(names[byt0]));
11515dfecf96Smrg		    ptr += strlen(ptr);
11525dfecf96Smrg		}
11535dfecf96Smrg
11545dfecf96Smrg		/* Symbols */
11555dfecf96Smrg		if (sym0 >= 0) {
11565dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11575dfecf96Smrg		    strcpy(ptr, XSTRING(symbols[sym0]->string));
11585dfecf96Smrg		    ptr += strlen(ptr);
11595dfecf96Smrg		    if (sym1 >= 0) {
11605dfecf96Smrg			strcpy(ptr, "  ");	ptr += 2;
11615dfecf96Smrg			strcpy(ptr, XSTRING(symbols[sym1]->string));
11625dfecf96Smrg			ptr += strlen(ptr);
11635dfecf96Smrg		    }
11645dfecf96Smrg		}
11655dfecf96Smrg
11665dfecf96Smrg		i = ptr - buffer;
11675dfecf96Smrg		LispWriteStr(NIL, buffer, i);
11685dfecf96Smrg	    }
11695dfecf96Smrg	    LispWriteChar(NIL, '\n');
11705dfecf96Smrg	    continue;
11715dfecf96Smrgpredicate:
11725dfecf96Smrg	    switch (*stream++) {
11735dfecf96Smrg		case XBP_CONSP:     strcpy(ptr, "CONSP");   break;
11745dfecf96Smrg		case XBP_LISTP:     strcpy(ptr, "LISTP");   break;
11755dfecf96Smrg		case XBP_NUMBERP:   strcpy(ptr, "NUMBERP"); break;
11765dfecf96Smrg	    }
11775dfecf96Smrg	    LispWriteStr(NIL, buffer, ptr - buffer + strlen(ptr));
11785dfecf96Smrg	    LispWriteChar(NIL, '\n');
11795dfecf96Smrg	}
11805dfecf96Smrg#undef XSTRING
11815dfecf96Smrg    }
11825dfecf96Smrg
11835dfecf96Smrg    return (function);
11845dfecf96Smrg}
11855dfecf96Smrg
11865dfecf96Smrg
11875dfecf96Smrg
11885dfecf96SmrgLispObj *
11895dfecf96SmrgLispCompileForm(LispObj *form)
11905dfecf96Smrg{
11915dfecf96Smrg    GC_ENTER();
11925dfecf96Smrg    int failed;
11935dfecf96Smrg    LispCom com;
11945dfecf96Smrg
11955dfecf96Smrg    if (!CONSP(form))
11965dfecf96Smrg	/* Incorrect call or NIL */
11975dfecf96Smrg	return (form);
11985dfecf96Smrg
11995dfecf96Smrg    memset(&com, 0, sizeof(LispCom));
12005dfecf96Smrg
12015dfecf96Smrg    com.toplevel = com.block = LispCalloc(1, sizeof(CodeBlock));
12025dfecf96Smrg    com.block->type = LispBlockNone;
12035dfecf96Smrg    com.lex = lisp__data.env.lex;
12045dfecf96Smrg
12055dfecf96Smrg    com.plist = CONS(NIL, NIL);
12065dfecf96Smrg    GC_PROTECT(com.plist);
12075dfecf96Smrg
12085dfecf96Smrg    failed = 1;
12095dfecf96Smrg    if (setjmp(com.jmp) == 0) {
12105dfecf96Smrg	for (; CONSP(form); form = CDR(form)) {
12115dfecf96Smrg	    com.form = form;
12125dfecf96Smrg	    ComEval(&com, CAR(form));
12135dfecf96Smrg	}
12145dfecf96Smrg	failed = 0;
12155dfecf96Smrg    }
12165dfecf96Smrg    GC_LEAVE();
12175dfecf96Smrg
12185dfecf96Smrg    return (failed ? NIL : MakeBytecodeObject(&com, NIL, NIL));
12195dfecf96Smrg}
12205dfecf96Smrg
12215dfecf96SmrgLispObj *
12225dfecf96SmrgLispExecuteBytecode(LispObj *object)
12235dfecf96Smrg{
12245dfecf96Smrg    if (!BYTECODEP(object))
12255dfecf96Smrg	return (EVAL(object));
12265dfecf96Smrg
12275dfecf96Smrg    return (ExecuteBytecode(object->data.bytecode.bytecode->code));
12285dfecf96Smrg}
12295dfecf96Smrg
12305dfecf96Smrgstatic LispObj *
12315dfecf96SmrgMakeBytecodeObject(LispCom *com, LispObj *name, LispObj *plist)
12325dfecf96Smrg{
12335dfecf96Smrg    LispObj *object;
12345dfecf96Smrg    LispBytecode *bytecode;
12355dfecf96Smrg
12365dfecf96Smrg    GC_ENTER();
12375dfecf96Smrg    unsigned char *stream;
12385dfecf96Smrg    short i, num_constants;
12395dfecf96Smrg    LispObj **constants, *code, *cons, *prev;
12405dfecf96Smrg
12415dfecf96Smrg    /* Resolve dependencies, optimize and create byte stream */
12425dfecf96Smrg    LinkBytecode(com);
12435dfecf96Smrg
12445dfecf96Smrg    object = LispNew(NIL, NIL);
12455dfecf96Smrg    GC_PROTECT(object);
12465dfecf96Smrg    bytecode = LispMalloc(sizeof(LispBytecode));
12475dfecf96Smrg    bytecode->code = com->bytecode;
12485dfecf96Smrg    bytecode->length = com->length;
12495dfecf96Smrg
12505dfecf96Smrg
12515dfecf96Smrg    stream = bytecode->code;
12525dfecf96Smrg
12535dfecf96Smrg    /* Skip stack information */
12545dfecf96Smrg    stream += sizeof(short) * 3;
12555dfecf96Smrg
12565dfecf96Smrg    /* Get information */
12575dfecf96Smrg    num_constants = *(short*)stream;
12585dfecf96Smrg    stream += sizeof(short) * 4;
12595dfecf96Smrg    constants = (LispObj**)stream;
12605dfecf96Smrg
12615dfecf96Smrg    GC_PROTECT(plist);
12625dfecf96Smrg    code = cons = prev = NIL;
12635dfecf96Smrg    for (i = 0; i < num_constants; i++) {
12645dfecf96Smrg	if (POINTERP(constants[i]) && !XSYMBOLP(constants[i])) {
12655dfecf96Smrg	    if (code == NIL) {
12665dfecf96Smrg		code = cons = prev = CONS(constants[i], NIL);
12675dfecf96Smrg		GC_PROTECT(code);
12685dfecf96Smrg	    }
12695dfecf96Smrg	    else {
12705dfecf96Smrg		RPLACD(cons, CONS(constants[i], NIL));
12715dfecf96Smrg		prev = cons;
12725dfecf96Smrg		cons = CDR(cons);
12735dfecf96Smrg	    }
12745dfecf96Smrg	}
12755dfecf96Smrg    }
12765dfecf96Smrg
12775dfecf96Smrg    /* Protect this in case the function is redefined */
12785dfecf96Smrg    for (i = 0; i < com->table.num_bytecodes; i++) {
12795dfecf96Smrg	if (code == NIL) {
12805dfecf96Smrg	    code = cons = prev = CONS(com->table.bytecodes[i], NIL);
12815dfecf96Smrg	    GC_PROTECT(code);
12825dfecf96Smrg	}
12835dfecf96Smrg	else {
12845dfecf96Smrg	    RPLACD(cons, CONS(com->table.bytecodes[i], NIL));
12855dfecf96Smrg	    prev = cons;
12865dfecf96Smrg	    cons = CDR(cons);
12875dfecf96Smrg	}
12885dfecf96Smrg    }
12895dfecf96Smrg
12905dfecf96Smrg    /* Free everything, but the LispCom structure and the generated bytecode */
12915dfecf96Smrg    CompileFreeState(com);
12925dfecf96Smrg
12935dfecf96Smrg    /* Allocate the minimum required number of cons cells to protect objects */
12945dfecf96Smrg    if (!CONSP(code))
12955dfecf96Smrg	code = plist;
12965dfecf96Smrg    else if (CONSP(plist)) {
12975dfecf96Smrg	if (code == cons)
12985dfecf96Smrg	    RPLACD(code, plist);
12995dfecf96Smrg	else
13005dfecf96Smrg	    RPLACD(cons, plist);
13015dfecf96Smrg    }
13025dfecf96Smrg    else {
13035dfecf96Smrg	if (code == cons)
13045dfecf96Smrg	    code = CAR(code);
13055dfecf96Smrg	else
13065dfecf96Smrg	    CDR(prev) = CAR(cons);
13075dfecf96Smrg    }
13085dfecf96Smrg
13095dfecf96Smrg    object->data.bytecode.bytecode = bytecode;
13105dfecf96Smrg    /* Byte code references this object, so it cannot be garbage collected */
13115dfecf96Smrg    object->data.bytecode.code = code;
13125dfecf96Smrg    object->data.bytecode.name = name;
13135dfecf96Smrg    object->type = LispBytecode_t;
13145dfecf96Smrg
13155dfecf96Smrg    LispMused(bytecode);
13165dfecf96Smrg    LispMused(bytecode->code);
13175dfecf96Smrg    GC_LEAVE();
13185dfecf96Smrg
13195dfecf96Smrg    return (object);
13205dfecf96Smrg}
13215dfecf96Smrg
13225dfecf96Smrgstatic void
13235dfecf96SmrgCompileFreeTree(CodeTree *tree)
13245dfecf96Smrg{
13255dfecf96Smrg    if (tree->type == CodeTreeBlock)
13265dfecf96Smrg	CompileFreeBlock(tree->data.block);
13275dfecf96Smrg    LispFree(tree);
13285dfecf96Smrg}
13295dfecf96Smrg
13305dfecf96Smrgstatic void
13315dfecf96SmrgCompileFreeBlock(CodeBlock *block)
13325dfecf96Smrg{
13335dfecf96Smrg    CodeTree *tree = block->tree, *next;
13345dfecf96Smrg
13355dfecf96Smrg    while (tree) {
13365dfecf96Smrg	next = tree->next;
13375dfecf96Smrg	CompileFreeTree(tree);
13385dfecf96Smrg	tree = next;
13395dfecf96Smrg    }
13405dfecf96Smrg    if (block->type == LispBlockBody) {
13415dfecf96Smrg	LispFree(block->tagbody.labels);
13425dfecf96Smrg	LispFree(block->tagbody.codes);
13435dfecf96Smrg    }
13445dfecf96Smrg    LispFree(block->variables.symbols);
13455dfecf96Smrg    LispFree(block->variables.flags);
13465dfecf96Smrg    LispFree(block);
13475dfecf96Smrg}
13485dfecf96Smrg
13495dfecf96Smrgstatic void
13505dfecf96SmrgCompileFreeState(LispCom *com)
13515dfecf96Smrg{
13525dfecf96Smrg    CompileFreeBlock(com->block);
13535dfecf96Smrg    LispFree(com->table.constants);
13545dfecf96Smrg    LispFree(com->table.symbols);
13555dfecf96Smrg    LispFree(com->table.builtins);
13565dfecf96Smrg    LispFree(com->table.bytecodes);
13575dfecf96Smrg}
13585dfecf96Smrg
13595dfecf96Smrg/* XXX Put a breakpoint here when changing the macro expansion code.
13605dfecf96Smrg *     No opcodes should be generated during macro expansion. */
13615dfecf96Smrgstatic CodeTree *
13625dfecf96SmrgCompileNewTree(LispCom *com, CodeTreeType type)
13635dfecf96Smrg{
13645dfecf96Smrg    CodeTree *tree = LispMalloc(sizeof(CodeTree));
13655dfecf96Smrg
13665dfecf96Smrg    tree->type = type;
13675dfecf96Smrg    tree->next = NULL;
13685dfecf96Smrg    tree->block = com->block;
13695dfecf96Smrg    if (com->block->tree == NULL)
13705dfecf96Smrg	com->block->tree = tree;
13715dfecf96Smrg    else
13725dfecf96Smrg	com->block->tail->next = tree;
13735dfecf96Smrg    com->block->tail = tree;
13745dfecf96Smrg
13755dfecf96Smrg    return (tree);
13765dfecf96Smrg}
13775dfecf96Smrg
13785dfecf96Smrgstatic void
13795dfecf96SmrgCompileIniBlock(LispCom *com, LispBlockType type, LispObj *tag)
13805dfecf96Smrg{
13815dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBlock);
13825dfecf96Smrg    CodeBlock *block = LispCalloc(1, sizeof(CodeBlock));
13835dfecf96Smrg
13845dfecf96Smrg    tree->data.block = block;
13855dfecf96Smrg
13865dfecf96Smrg    block->type = type;
13875dfecf96Smrg    block->tag = tag;
13885dfecf96Smrg    block->prev = com->block;
13895dfecf96Smrg    block->parent = tree;
13905dfecf96Smrg    block->level = com->level;
13915dfecf96Smrg    com->block = block;
13925dfecf96Smrg
13935dfecf96Smrg    if (type == LispBlockBody)
13945dfecf96Smrg	com->tagbody = com->level;
13955dfecf96Smrg}
13965dfecf96Smrg
13975dfecf96Smrgstatic void
13985dfecf96SmrgCompileFiniBlock(LispCom *com)
13995dfecf96Smrg{
14005dfecf96Smrg    com->block = com->block->prev;
14015dfecf96Smrg    if (com->block && com->block->type == LispBlockBody)
14025dfecf96Smrg	com->tagbody = com->block->level;
14035dfecf96Smrg}
14045dfecf96Smrg
14055dfecf96Smrgstatic void
14065dfecf96Smrgcom_BytecodeChar(LispCom *com, LispByteOpcode code, char value)
14075dfecf96Smrg{
14085dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14095dfecf96Smrg
14105dfecf96Smrg    tree->code = code;
14115dfecf96Smrg    tree->data.signed_char = value;
14125dfecf96Smrg}
14135dfecf96Smrg
14145dfecf96Smrgstatic void
14155dfecf96Smrgcom_BytecodeShort(LispCom *com, LispByteOpcode code, short value)
14165dfecf96Smrg{
14175dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14185dfecf96Smrg
14195dfecf96Smrg    tree->code = code;
14205dfecf96Smrg    tree->data.signed_short = value;
14215dfecf96Smrg}
14225dfecf96Smrg
14235dfecf96Smrgstatic void
14245dfecf96Smrgcom_BytecodeAtom(LispCom *com, LispByteOpcode code, LispAtom *atom)
14255dfecf96Smrg{
14265dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14275dfecf96Smrg
14285dfecf96Smrg    tree->code = code;
14295dfecf96Smrg    tree->data.atom = atom;
14305dfecf96Smrg}
14315dfecf96Smrg
14325dfecf96Smrgstatic void
14335dfecf96Smrgcom_BytecodeObject(LispCom *com, LispByteOpcode code, LispObj *object)
14345dfecf96Smrg{
14355dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14365dfecf96Smrg
14375dfecf96Smrg    tree->code = code;
14385dfecf96Smrg    tree->data.object = object;
14395dfecf96Smrg}
14405dfecf96Smrg
14415dfecf96Smrgstatic void
14425dfecf96Smrgcom_BytecodeCons(LispCom *com, LispByteOpcode code, LispObj *car, LispObj *cdr)
14435dfecf96Smrg{
14445dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14455dfecf96Smrg
14465dfecf96Smrg    tree->code = code;
14475dfecf96Smrg    tree->data.cons.car = car;
14485dfecf96Smrg    tree->data.cons.cdr = cdr;
14495dfecf96Smrg}
14505dfecf96Smrg
14515dfecf96Smrgstatic void
14525dfecf96Smrgcom_Bytecode(LispCom *com, LispByteOpcode code)
14535dfecf96Smrg{
14545dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14555dfecf96Smrg
14565dfecf96Smrg    tree->code = code;
14575dfecf96Smrg}
14585dfecf96Smrg
14595dfecf96Smrgstatic void
14605dfecf96Smrgcom_Load(LispCom *com, short offset)
14615dfecf96Smrg{
14625dfecf96Smrg    com_BytecodeShort(com, XBC_LOAD, offset);
14635dfecf96Smrg}
14645dfecf96Smrg
14655dfecf96Smrgstatic void
14665dfecf96Smrgcom_LoadLet(LispCom *com, short offset, LispAtom *name)
14675dfecf96Smrg{
14685dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14695dfecf96Smrg
14705dfecf96Smrg    tree->code = XBC_LOAD_LET;
14715dfecf96Smrg    tree->data.let.offset = offset;
14725dfecf96Smrg    tree->data.let.name = name;
14735dfecf96Smrg}
14745dfecf96Smrg
14755dfecf96Smrgstatic void
14765dfecf96Smrgcom_LoadPush(LispCom *com, short offset)
14775dfecf96Smrg{
14785dfecf96Smrg    com_BytecodeShort(com, XBC_LOAD_PUSH, offset);
14795dfecf96Smrg}
14805dfecf96Smrg
14815dfecf96Smrgstatic void
14825dfecf96Smrgcom_Let(LispCom *com, LispAtom *name)
14835dfecf96Smrg{
14845dfecf96Smrg    com_BytecodeAtom(com, XBC_LET, name);
14855dfecf96Smrg}
14865dfecf96Smrg
14875dfecf96Smrgstatic void
14885dfecf96Smrgcom_Bind(LispCom *com, short count)
14895dfecf96Smrg{
14905dfecf96Smrg    if (count)
14915dfecf96Smrg	com_BytecodeShort(com, XBC_LETBIND, count);
14925dfecf96Smrg}
14935dfecf96Smrg
14945dfecf96Smrgstatic void
14955dfecf96Smrgcom_Unbind(LispCom *com, short count)
14965dfecf96Smrg{
14975dfecf96Smrg    if (count)
14985dfecf96Smrg	com_BytecodeShort(com, XBC_UNLET, count);
14995dfecf96Smrg}
15005dfecf96Smrg
15015dfecf96Smrgstatic void
15025dfecf96Smrgcom_LoadSym(LispCom *com, LispAtom *atom)
15035dfecf96Smrg{
15045dfecf96Smrg    com_BytecodeAtom(com, XBC_LOADSYM, atom);
15055dfecf96Smrg}
15065dfecf96Smrg
15075dfecf96Smrgstatic void
15085dfecf96Smrgcom_LoadSymLet(LispCom *com, LispAtom *symbol, LispAtom *name)
15095dfecf96Smrg{
15105dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15115dfecf96Smrg
15125dfecf96Smrg    tree->code = XBC_LOADSYM_LET;
15135dfecf96Smrg    tree->data.let_sym.symbol = symbol;
15145dfecf96Smrg    tree->data.let_sym.name = name;
15155dfecf96Smrg}
15165dfecf96Smrg
15175dfecf96Smrgstatic void
15185dfecf96Smrgcom_LoadSymPush(LispCom *com, LispAtom *name)
15195dfecf96Smrg{
15205dfecf96Smrg    com_BytecodeAtom(com, XBC_LOADSYM_PUSH, name);
15215dfecf96Smrg}
15225dfecf96Smrg
15235dfecf96Smrgstatic void
15245dfecf96Smrgcom_LoadCon(LispCom *com, LispObj *constant)
15255dfecf96Smrg{
15265dfecf96Smrg    if (constant == NIL)
15275dfecf96Smrg	com_Bytecode(com, XBC_NIL);
15285dfecf96Smrg    else if (constant == T)
15295dfecf96Smrg	com_Bytecode(com, XBC_T);
15305dfecf96Smrg    else if (constant == UNSPEC) {
15315dfecf96Smrg	COMPILE_FAILURE("internal error: loading #<UNSPEC>");
15325dfecf96Smrg    }
15335dfecf96Smrg    else
15345dfecf96Smrg	com_BytecodeObject(com, XBC_LOADCON, constant);
15355dfecf96Smrg}
15365dfecf96Smrg
15375dfecf96Smrgstatic void
15385dfecf96Smrgcom_LoadConLet(LispCom *com, LispObj *constant, LispAtom *name)
15395dfecf96Smrg{
15405dfecf96Smrg    if (constant == NIL)
15415dfecf96Smrg	com_BytecodeAtom(com, XBC_LET_NIL, name);
15425dfecf96Smrg    else {
15435dfecf96Smrg	CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15445dfecf96Smrg
15455dfecf96Smrg	tree->code = XBC_LOADCON_LET;
15465dfecf96Smrg	tree->data.let_con.object = constant;
15475dfecf96Smrg	tree->data.let_con.name = name;
15485dfecf96Smrg    }
15495dfecf96Smrg}
15505dfecf96Smrg
15515dfecf96Smrgstatic void
15525dfecf96Smrgcom_LoadConPush(LispCom *com, LispObj *constant)
15535dfecf96Smrg{
15545dfecf96Smrg    if (constant == NIL)
15555dfecf96Smrg	com_Bytecode(com, XBC_PUSH_NIL);
15565dfecf96Smrg    else if (constant == T)
15575dfecf96Smrg	com_Bytecode(com, XBC_PUSH_T);
15585dfecf96Smrg    else if (constant == UNSPEC)
15595dfecf96Smrg	com_Bytecode(com, XBC_PUSH_UNSPEC);
15605dfecf96Smrg    else
15615dfecf96Smrg	com_BytecodeObject(com, XBC_LOADCON_PUSH, constant);
15625dfecf96Smrg}
15635dfecf96Smrg
15645dfecf96Smrgstatic void
15655dfecf96Smrgcom_Set(LispCom *com, short offset)
15665dfecf96Smrg{
15675dfecf96Smrg    com_BytecodeShort(com, XBC_SET, offset);
15685dfecf96Smrg}
15695dfecf96Smrg
15705dfecf96Smrgstatic void
15715dfecf96Smrgcom_SetSym(LispCom *com, LispAtom *symbol)
15725dfecf96Smrg{
15735dfecf96Smrg    com_BytecodeAtom(com, XBC_SETSYM, symbol);
15745dfecf96Smrg}
15755dfecf96Smrg
15765dfecf96Smrgstatic void
15775dfecf96Smrgcom_Struct(LispCom *com, short offset, LispObj *definition)
15785dfecf96Smrg{
15795dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15805dfecf96Smrg
15815dfecf96Smrg    tree->code = XBC_STRUCT;
15825dfecf96Smrg    tree->data.struc.offset = offset;
15835dfecf96Smrg    tree->data.struc.definition = definition;
15845dfecf96Smrg}
15855dfecf96Smrg
15865dfecf96Smrgstatic void
15875dfecf96Smrgcom_Structp(LispCom *com, LispObj *definition)
15885dfecf96Smrg{
15895dfecf96Smrg    com_BytecodeObject(com, XBC_STRUCTP, definition);
15905dfecf96Smrg}
15915dfecf96Smrg
15925dfecf96Smrgstatic void
15935dfecf96Smrgcom_Call(LispCom *com, unsigned char num_arguments, LispBuiltin *builtin)
15945dfecf96Smrg{
15955dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15965dfecf96Smrg
15975dfecf96Smrg    tree->code = XBC_CALL;
15985dfecf96Smrg    tree->data.builtin.num_arguments = num_arguments;
15995dfecf96Smrg    tree->data.builtin.builtin = builtin;
16005dfecf96Smrg}
16015dfecf96Smrg
16025dfecf96Smrgstatic void
16035dfecf96Smrgcom_Bytecall(LispCom *com, unsigned char num_arguments, LispObj *code)
16045dfecf96Smrg{
16055dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
16065dfecf96Smrg
16075dfecf96Smrg    tree->code = XBC_BYTECALL;
16085dfecf96Smrg    tree->data.bytecall.num_arguments = num_arguments;
16095dfecf96Smrg    tree->data.bytecall.code = code;
16105dfecf96Smrg}
16115dfecf96Smrg
16125dfecf96Smrgstatic void
16135dfecf96Smrgcom_Funcall(LispCom *com, LispObj *function, LispObj *arguments)
16145dfecf96Smrg{
16155dfecf96Smrg    com_BytecodeCons(com, XBC_FUNCALL, function, arguments);
16165dfecf96Smrg}
16175dfecf96Smrg
16185dfecf96Smrgstatic void
16195dfecf96SmrgCompileStackEnter(LispCom *com, int count, int builtin)
16205dfecf96Smrg{
16215dfecf96Smrg    if (!com->macro) {
16225dfecf96Smrg	if (builtin) {
16235dfecf96Smrg	    com->stack.cbstack += count;
16245dfecf96Smrg	    if (com->stack.bstack < com->stack.cbstack)
16255dfecf96Smrg		com->stack.bstack = com->stack.cbstack;
16265dfecf96Smrg	}
16275dfecf96Smrg	else {
16285dfecf96Smrg	    com->stack.cstack += count;
16295dfecf96Smrg	    if (com->stack.stack < com->stack.cstack)
16305dfecf96Smrg		com->stack.stack = com->stack.cstack;
16315dfecf96Smrg	}
16325dfecf96Smrg    }
16335dfecf96Smrg}
16345dfecf96Smrg
16355dfecf96Smrgstatic void
16365dfecf96SmrgCompileStackLeave(LispCom *com, int count, int builtin)
16375dfecf96Smrg{
16385dfecf96Smrg    if (!com->macro) {
16395dfecf96Smrg	if (builtin)
16405dfecf96Smrg	    com->stack.cbstack -= count;
16415dfecf96Smrg	else
16425dfecf96Smrg	    com->stack.cstack -= count;
16435dfecf96Smrg    }
16445dfecf96Smrg}
16455dfecf96Smrg
16465dfecf96Smrgstatic void
16475dfecf96SmrgLinkWarnUnused(LispCom *com, CodeBlock *block)
16485dfecf96Smrg{
16495dfecf96Smrg    int i;
16505dfecf96Smrg    CodeTree *tree;
16515dfecf96Smrg
16525dfecf96Smrg    for (tree = block->tree; tree; tree = tree->next) {
16535dfecf96Smrg	if (tree->type == CodeTreeBlock)
16545dfecf96Smrg	    LinkWarnUnused(com, tree->data.block);
16555dfecf96Smrg    }
16565dfecf96Smrg
16575dfecf96Smrg    for (i = 0; i < block->variables.length; i++)
16585dfecf96Smrg	if (!(block->variables.flags[i] & (VARIABLE_USED | VARIABLE_ARGUMENT))) {
16595dfecf96Smrg	    ++com->warnings;
16605dfecf96Smrg	    LispWarning("the variable %s is unused",
16615dfecf96Smrg			block->variables.symbols[i]->string);
16625dfecf96Smrg	}
16635dfecf96Smrg}
16645dfecf96Smrg
16655dfecf96Smrg#define	INTERNAL_ERROR_STRING "COMPILE: internal error #%d"
16665dfecf96Smrg#define	INTERNAL_ERROR(value) LispDestroy(INTERNAL_ERROR_STRING, value)
16675dfecf96Smrgstatic long
16685dfecf96SmrgLinkBuildOffsets(LispCom *com, CodeTree *tree, long offset)
16695dfecf96Smrg{
16705dfecf96Smrg    for (; tree; tree = tree->next) {
16715dfecf96Smrg	tree->offset = offset;
16725dfecf96Smrg	switch (tree->type) {
16735dfecf96Smrg	    case CodeTreeBytecode:
16745dfecf96Smrg		switch (tree->code) {
16755dfecf96Smrg		    case XBC_NOOP:
16765dfecf96Smrg			INTERNAL_ERROR(__LINE__);
16775dfecf96Smrg			break;
16785dfecf96Smrg
16795dfecf96Smrg		    /* byte */
16805dfecf96Smrg		    case XBC_BCONS:
16815dfecf96Smrg		    case XBC_BCONS1:
16825dfecf96Smrg		    case XBC_BCONS2:
16835dfecf96Smrg		    case XBC_BCONS3:
16845dfecf96Smrg		    case XBC_BCONS4:
16855dfecf96Smrg		    case XBC_BCONS5:
16865dfecf96Smrg		    case XBC_BCONS6:
16875dfecf96Smrg		    case XBC_BCONS7:
16885dfecf96Smrg		    case XBC_INV:
16895dfecf96Smrg		    case XBC_NIL:
16905dfecf96Smrg		    case XBC_T:
16915dfecf96Smrg		    case XBC_PUSH:
16925dfecf96Smrg		    case XBC_CAR_PUSH:
16935dfecf96Smrg		    case XBC_CDR_PUSH:
16945dfecf96Smrg		    case XBC_PUSH_NIL:
16955dfecf96Smrg		    case XBC_PUSH_UNSPEC:
16965dfecf96Smrg		    case XBC_PUSH_T:
16975dfecf96Smrg		    case XBC_LSTAR:
16985dfecf96Smrg		    case XBC_LCONS:
16995dfecf96Smrg		    case XBC_LFINI:
17005dfecf96Smrg		    case XBC_RETURN:
17015dfecf96Smrg		    case XBC_CSTAR:
17025dfecf96Smrg		    case XBC_CFINI:
17035dfecf96Smrg		    case XBC_CAR:
17045dfecf96Smrg		    case XBC_CDR:
17055dfecf96Smrg		    case XBC_RPLACA:
17065dfecf96Smrg		    case XBC_RPLACD:
17075dfecf96Smrg		    case XBC_EQ:
17085dfecf96Smrg		    case XBC_EQL:
17095dfecf96Smrg		    case XBC_EQUAL:
17105dfecf96Smrg		    case XBC_EQUALP:
17115dfecf96Smrg		    case XBC_LENGTH:
17125dfecf96Smrg		    case XBC_LAST:
17135dfecf96Smrg		    case XBC_NTHCDR:
17145dfecf96Smrg			++offset;
17155dfecf96Smrg			break;
17165dfecf96Smrg
17175dfecf96Smrg		    /* byte + byte */
17185dfecf96Smrg		    case XBC_PUSH_NIL_N:
17195dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
17205dfecf96Smrg		    case XBC_PRED:
17215dfecf96Smrg		    case XBC_LETREC:
17225dfecf96Smrg		    case XBC_LOAD_PUSH:
17235dfecf96Smrg		    case XBC_CAR_SET:
17245dfecf96Smrg		    case XBC_CDR_SET:
17255dfecf96Smrg		    case XBC_SET:
17265dfecf96Smrg		    case XBC_SET_NIL:
17275dfecf96Smrg		    case XBC_LETBIND:
17285dfecf96Smrg		    case XBC_UNLET:
17295dfecf96Smrg		    case XBC_LOAD:
17305dfecf96Smrg		    case XBC_LOAD_CAR:
17315dfecf96Smrg		    case XBC_LOAD_CDR:
17325dfecf96Smrg		    case XBC_LOAD_CAR_STORE:
17335dfecf96Smrg		    case XBC_LOAD_CDR_STORE:
17345dfecf96Smrg		    case XBC_LET:
17355dfecf96Smrg		    case XBC_LETX:
17365dfecf96Smrg		    case XBC_LET_NIL:
17375dfecf96Smrg		    case XBC_LETX_NIL:
17385dfecf96Smrg		    case XBC_STRUCTP:
17395dfecf96Smrg		    case XBC_SETSYM:
17405dfecf96Smrg		    case XBC_LOADCON_PUSH:
17415dfecf96Smrg		    case XBC_LOADSYM_PUSH:
17425dfecf96Smrg		    case XBC_LOADCON:
17435dfecf96Smrg		    case XBC_LOADSYM:
17445dfecf96Smrg			offset += 2;
17455dfecf96Smrg			break;
17465dfecf96Smrg
17475dfecf96Smrg		    /* byte + byte + byte */
17485dfecf96Smrg		    case XBC_CALL:
17495dfecf96Smrg		    case XBC_BYTECALL:
17505dfecf96Smrg		    case XBC_LOAD_SET:
17515dfecf96Smrg		    case XBC_LOAD_CAR_SET:
17525dfecf96Smrg		    case XBC_LOAD_CDR_SET:
17535dfecf96Smrg		    case XBC_LOADCON_SET:
17545dfecf96Smrg		    case XBC_LOAD_LET:
17555dfecf96Smrg		    case XBC_LOAD_LETX:
17565dfecf96Smrg		    case XBC_STRUCT:
17575dfecf96Smrg		    case XBC_LOADCON_LET:
17585dfecf96Smrg		    case XBC_LOADCON_LETX:
17595dfecf96Smrg		    case XBC_LOADSYM_LET:
17605dfecf96Smrg		    case XBC_LOADSYM_LETX:
17615dfecf96Smrg		    case XBC_CCONS:
17625dfecf96Smrg		    case XBC_FUNCALL:
17635dfecf96Smrg			offset += 3;
17645dfecf96Smrg			break;
17655dfecf96Smrg
17665dfecf96Smrg		    /* byte + short */
17675dfecf96Smrg		    case XBC_JUMP:
17685dfecf96Smrg		    case XBC_JUMPT:
17695dfecf96Smrg		    case XBC_JUMPNIL:
17705dfecf96Smrg			/* XXX this is likely a jump to random address here */
17715dfecf96Smrg			INTERNAL_ERROR(__LINE__);
17725dfecf96Smrg			offset += sizeof(short) + 1;
17735dfecf96Smrg			break;
17745dfecf96Smrg
17755dfecf96Smrg		    /* byte + byte + byte + byte */
17765dfecf96Smrg		    case XBC_CALL_SET:
17775dfecf96Smrg			offset += 4;
17785dfecf96Smrg			break;
17795dfecf96Smrg		}
17805dfecf96Smrg		break;
17815dfecf96Smrg	    case CodeTreeLabel:
17825dfecf96Smrg		/* Labels are not loaded */
17835dfecf96Smrg		break;
17845dfecf96Smrg	    case CodeTreeJump:
17855dfecf96Smrg	    case CodeTreeJumpIf:
17865dfecf96Smrg	    case CodeTreeCond:
17875dfecf96Smrg		/* If not the point where the conditional block finishes */
17885dfecf96Smrg		if (tree->code != XBC_NOOP)
17895dfecf96Smrg		    /* Reserve space for the jump opcode */
17905dfecf96Smrg		    offset += sizeof(short) + 1;
17915dfecf96Smrg		break;
17925dfecf96Smrg	    case CodeTreeGo:
17935dfecf96Smrg	    case CodeTreeReturn:
17945dfecf96Smrg		/* Reserve space for the jump opcode */
17955dfecf96Smrg		offset += sizeof(short) + 1;
17965dfecf96Smrg		break;
17975dfecf96Smrg	    case CodeTreeBlock:
17985dfecf96Smrg		offset = LinkBuildOffsets(com, tree->data.block->tree, offset);
17995dfecf96Smrg		break;
18005dfecf96Smrg	}
18015dfecf96Smrg    }
18025dfecf96Smrg
18035dfecf96Smrg    return (offset);
18045dfecf96Smrg}
18055dfecf96Smrg
18065dfecf96Smrgstatic void
18075dfecf96SmrgLinkDoOptimize_0(LispCom *com, CodeBlock *block)
18085dfecf96Smrg{
18095dfecf96Smrg    CodeTree *tree, *prev, *next;
18105dfecf96Smrg
18115dfecf96Smrg    /*  Remove redundant or join opcodes that can be joined. Do it here
18125dfecf96Smrg     * because some of these are hard to detect earlier, and/or would
18135dfecf96Smrg     * require a lot of duplicated code or more time. */
18145dfecf96Smrg    tree = prev = block->tree;
18155dfecf96Smrg    while (tree) {
18165dfecf96Smrg	next = tree->next;
18175dfecf96Smrg
18185dfecf96Smrg	/* LET -> LET* */
18195dfecf96Smrg	if (next &&
18205dfecf96Smrg	    next->type == CodeTreeBytecode &&
18215dfecf96Smrg	    next->code == XBC_LETBIND &&
18225dfecf96Smrg	    next->data.signed_short == 1) {
18235dfecf96Smrg	    switch (tree->code) {
18245dfecf96Smrg		case XBC_LET:
18255dfecf96Smrg		    tree->code = XBC_LETX;
18265dfecf96Smrg		    goto remove_next_label;
18275dfecf96Smrg		case XBC_LET_NIL:
18285dfecf96Smrg		    tree->code = XBC_LETX_NIL;
18295dfecf96Smrg		    goto remove_next_label;
18305dfecf96Smrg		case XBC_LOAD_LET:
18315dfecf96Smrg		    tree->code = XBC_LOAD_LETX;
18325dfecf96Smrg		    goto remove_next_label;
18335dfecf96Smrg		case XBC_LOADCON_LET:
18345dfecf96Smrg		    tree->code = XBC_LOADCON_LETX;
18355dfecf96Smrg		    goto remove_next_label;
18365dfecf96Smrg		case XBC_LOADSYM_LET:
18375dfecf96Smrg		    tree->code = XBC_LOADSYM_LETX;
18385dfecf96Smrg		    goto remove_next_label;
18395dfecf96Smrg		default:
18405dfecf96Smrg		    break;
18415dfecf96Smrg	    }
18425dfecf96Smrg	}
18435dfecf96Smrg
18445dfecf96Smrg	switch (tree->type) {
18455dfecf96Smrg	    case CodeTreeBytecode:
18465dfecf96Smrg		switch (tree->code) {
18475dfecf96Smrg		    case XBC_LOADCON:
18485dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
18495dfecf96Smrg			    switch (next->code) {
18505dfecf96Smrg				case XBC_LET:
18515dfecf96Smrg				    next->code = XBC_LOADCON_LET;
18525dfecf96Smrg				    next->data.let_con.name =
18535dfecf96Smrg					next->data.atom;
18545dfecf96Smrg				    next->data.let_con.object =
18555dfecf96Smrg					tree->data.object;
18565dfecf96Smrg				    goto remove_label;
18575dfecf96Smrg				case XBC_PUSH:
18585dfecf96Smrg				    next->code = XBC_LOADCON_PUSH;
18595dfecf96Smrg				    next->data.object = tree->data.object;
18605dfecf96Smrg				    goto remove_label;
18615dfecf96Smrg				case XBC_CAR:
18625dfecf96Smrg				    if (tree->data.object != NIL) {
18635dfecf96Smrg					if (!CONSP(tree->data.object))
18645dfecf96Smrg					    LispDestroy("CAR: %s is not a list",
18655dfecf96Smrg						        STROBJ(
18665dfecf96Smrg							tree->data.object));
18675dfecf96Smrg					next->code = XBC_LOADCON;
18685dfecf96Smrg					next->data.object =
18695dfecf96Smrg					    CAR(tree->data.object);
18705dfecf96Smrg				    }
18715dfecf96Smrg				    goto remove_label;
18725dfecf96Smrg				case XBC_CDR:
18735dfecf96Smrg				    if (tree->data.object != NIL) {
18745dfecf96Smrg					if (!CONSP(tree->data.object))
18755dfecf96Smrg					    LispDestroy("CAR: %s is not a list",
18765dfecf96Smrg						        STROBJ(
18775dfecf96Smrg							tree->data.object));
18785dfecf96Smrg					next->code = XBC_LOADCON;
18795dfecf96Smrg					next->data.object =
18805dfecf96Smrg					    CDR(tree->data.object);
18815dfecf96Smrg				    }
18825dfecf96Smrg				    goto remove_label;
18835dfecf96Smrg				case XBC_SET:
18845dfecf96Smrg				    next->code = XBC_LOADCON_SET;
18855dfecf96Smrg				    next->data.load_con_set.offset =
18865dfecf96Smrg					next->data.signed_short;
18875dfecf96Smrg				    next->data.load_con_set.object =
18885dfecf96Smrg					tree->data.object;
18895dfecf96Smrg				    goto remove_label;
18905dfecf96Smrg				default:
18915dfecf96Smrg				    break;
18925dfecf96Smrg			    }
18935dfecf96Smrg			}
18945dfecf96Smrg			break;
18955dfecf96Smrg		    case XBC_LOADSYM:
18965dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
18975dfecf96Smrg			    switch (next->code) {
18985dfecf96Smrg				case XBC_LET:
18995dfecf96Smrg				    next->code = XBC_LOADSYM_LET;
19005dfecf96Smrg				    next->data.let_sym.name =
19015dfecf96Smrg					next->data.atom;
19025dfecf96Smrg				    next->data.let_sym.symbol =
19035dfecf96Smrg					tree->data.atom;
19045dfecf96Smrg				    goto remove_label;
19055dfecf96Smrg				case XBC_PUSH:
19065dfecf96Smrg				    next->code = XBC_LOADSYM_PUSH;
19075dfecf96Smrg				    next->data.atom = tree->data.atom;
19085dfecf96Smrg				    goto remove_label;
19095dfecf96Smrg				default:
19105dfecf96Smrg				    break;
19115dfecf96Smrg			    }
19125dfecf96Smrg			}
19135dfecf96Smrg			break;
19145dfecf96Smrg		    case XBC_LOAD:
19155dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
19165dfecf96Smrg			    switch (next->code) {
19175dfecf96Smrg				case XBC_SET:
19185dfecf96Smrg				    next->code = XBC_LOAD_SET;
19195dfecf96Smrg				    next->data.load_set.set =
19205dfecf96Smrg					next->data.signed_short;
19215dfecf96Smrg				    next->data.load_set.load =
19225dfecf96Smrg					tree->data.signed_short;
19235dfecf96Smrg				    goto remove_label;
19245dfecf96Smrg				/* TODO add XBC_LOAD_SETSYM */
19255dfecf96Smrg				case XBC_CAR:
19265dfecf96Smrg				    next->code = XBC_LOAD_CAR;
19275dfecf96Smrg				    next->data.signed_short =
19285dfecf96Smrg					tree->data.signed_short;
19295dfecf96Smrg				    goto remove_label;
19305dfecf96Smrg				case XBC_CDR:
19315dfecf96Smrg				    next->code = XBC_LOAD_CDR;
19325dfecf96Smrg				    next->data.signed_short =
19335dfecf96Smrg					tree->data.signed_short;
19345dfecf96Smrg				    goto remove_label;
19355dfecf96Smrg				case XBC_PUSH:
19365dfecf96Smrg				    tree->code = XBC_LOAD_PUSH;
19375dfecf96Smrg				    goto remove_next_label;
19385dfecf96Smrg				case XBC_LET:
19395dfecf96Smrg				    next->code = XBC_LOAD_LET;
19405dfecf96Smrg				    next->data.let.name = next->data.atom;
19415dfecf96Smrg				    next->data.let.offset =
19425dfecf96Smrg					tree->data.signed_short;
19435dfecf96Smrg				    goto remove_label;
19445dfecf96Smrg				default:
19455dfecf96Smrg				    break;
19465dfecf96Smrg			    }
19475dfecf96Smrg			}
19485dfecf96Smrg			break;
19495dfecf96Smrg		    case XBC_LOAD_CAR:
19505dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
19515dfecf96Smrg			    next->code == XBC_SET) {
19525dfecf96Smrg			    if (next->data.signed_short ==
19535dfecf96Smrg				tree->data.signed_short)
19545dfecf96Smrg				next->code = XBC_LOAD_CAR_STORE;
19555dfecf96Smrg			    else {
19565dfecf96Smrg				next->code = XBC_LOAD_CAR_SET;
19575dfecf96Smrg				next->data.load_set.set =
19585dfecf96Smrg				    next->data.signed_short;
19595dfecf96Smrg				next->data.load_set.load =
19605dfecf96Smrg				    tree->data.signed_short;
19615dfecf96Smrg			    }
19625dfecf96Smrg			    goto remove_label;
19635dfecf96Smrg			}
19645dfecf96Smrg			break;
19655dfecf96Smrg		    case XBC_LOAD_CDR:
19665dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
19675dfecf96Smrg			    next->code == XBC_SET) {
19685dfecf96Smrg			    if (next->data.signed_short ==
19695dfecf96Smrg				tree->data.signed_short)
19705dfecf96Smrg				next->code = XBC_LOAD_CDR_STORE;
19715dfecf96Smrg			    else {
19725dfecf96Smrg				next->code = XBC_LOAD_CDR_SET;
19735dfecf96Smrg				next->data.load_set.set =
19745dfecf96Smrg				    next->data.signed_short;
19755dfecf96Smrg				next->data.load_set.load =
19765dfecf96Smrg				    tree->data.signed_short;
19775dfecf96Smrg			    }
19785dfecf96Smrg			    goto remove_label;
19795dfecf96Smrg			}
19805dfecf96Smrg			break;
19815dfecf96Smrg		    case XBC_CALL:
19825dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
19835dfecf96Smrg			    switch (next->code) {
19845dfecf96Smrg				case XBC_SET:
19855dfecf96Smrg				    next->code = XBC_CALL_SET;
19865dfecf96Smrg				    next->data.builtin.offset =
19875dfecf96Smrg					next->data.signed_short;
19885dfecf96Smrg				    next->data.builtin.num_arguments =
19895dfecf96Smrg					tree->data.builtin.num_arguments;
19905dfecf96Smrg				    next->data.builtin.builtin =
19915dfecf96Smrg					tree->data.builtin.builtin;
19925dfecf96Smrg				    goto remove_label;
19935dfecf96Smrg				/* TODO add XBC_CALL_SETSYM */
19945dfecf96Smrg				default:
19955dfecf96Smrg				    break;
19965dfecf96Smrg			    }
19975dfecf96Smrg			}
19985dfecf96Smrg			break;
19995dfecf96Smrg		    case XBC_CAR:
20005dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20015dfecf96Smrg			    switch (next->code) {
20025dfecf96Smrg				case XBC_SET:
20035dfecf96Smrg				    next->code = XBC_CAR_SET;
20045dfecf96Smrg				    goto remove_label;
20055dfecf96Smrg				/* TODO add XBC_CAR_SETSYM */
20065dfecf96Smrg				case XBC_PUSH:
20075dfecf96Smrg				    next->code = XBC_CAR_PUSH;
20085dfecf96Smrg				    goto remove_label;
20095dfecf96Smrg				default:
20105dfecf96Smrg				    break;
20115dfecf96Smrg			    }
20125dfecf96Smrg			}
20135dfecf96Smrg			break;
20145dfecf96Smrg		    case XBC_CDR:
20155dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20165dfecf96Smrg			    switch (next->code) {
20175dfecf96Smrg				case XBC_SET:
20185dfecf96Smrg				    next->code = XBC_CDR_SET;
20195dfecf96Smrg				    goto remove_label;
20205dfecf96Smrg				/* TODO add XBC_CDR_SETSYM */
20215dfecf96Smrg				case XBC_PUSH:
20225dfecf96Smrg				    next->code = XBC_CDR_PUSH;
20235dfecf96Smrg				    goto remove_label;
20245dfecf96Smrg				default:
20255dfecf96Smrg				    break;
20265dfecf96Smrg			    }
20275dfecf96Smrg			}
20285dfecf96Smrg			break;
20295dfecf96Smrg		    case XBC_NIL:
20305dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20315dfecf96Smrg			    switch (next->code) {
20325dfecf96Smrg				case XBC_SET:
20335dfecf96Smrg				    next->code = XBC_SET_NIL;
20345dfecf96Smrg				    goto remove_label;
20355dfecf96Smrg				/* TODO add XBC_SETSYM_NIL */
20365dfecf96Smrg				default:
20375dfecf96Smrg				    break;
20385dfecf96Smrg			    }
20395dfecf96Smrg			}
20405dfecf96Smrg			break;
20415dfecf96Smrg		    case XBC_PUSH_NIL:
20425dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20435dfecf96Smrg			    next->code == XBC_PUSH_NIL) {
20445dfecf96Smrg			    next->code = XBC_PUSH_NIL_N;
20455dfecf96Smrg			    next->data.signed_char = 2;
20465dfecf96Smrg			    goto remove_label;
20475dfecf96Smrg			}
20485dfecf96Smrg			break;
20495dfecf96Smrg		    case XBC_PUSH_NIL_N:
20505dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20515dfecf96Smrg			    next->code == XBC_PUSH_NIL) {
20525dfecf96Smrg			    next->code = XBC_PUSH_NIL_N;
20535dfecf96Smrg			    next->data.signed_char = tree->data.signed_char + 1;
20545dfecf96Smrg			    goto remove_label;
20555dfecf96Smrg			}
20565dfecf96Smrg			break;
20575dfecf96Smrg		    case XBC_PUSH_UNSPEC:
20585dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20595dfecf96Smrg			    next->code == XBC_PUSH_UNSPEC) {
20605dfecf96Smrg			    next->code = XBC_PUSH_UNSPEC_N;
20615dfecf96Smrg			    next->data.signed_char = 2;
20625dfecf96Smrg			    goto remove_label;
20635dfecf96Smrg			}
20645dfecf96Smrg			break;
20655dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
20665dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20675dfecf96Smrg			    next->code == XBC_PUSH_UNSPEC) {
20685dfecf96Smrg			    next->code = XBC_PUSH_UNSPEC_N;
20695dfecf96Smrg			    next->data.signed_char = tree->data.signed_char + 1;
20705dfecf96Smrg			    goto remove_label;
20715dfecf96Smrg			}
20725dfecf96Smrg			break;
20735dfecf96Smrg		    default:
20745dfecf96Smrg			break;
20755dfecf96Smrg		}
20765dfecf96Smrg		break;
20775dfecf96Smrg	    case CodeTreeBlock:
20785dfecf96Smrg		LinkDoOptimize_0(com, tree->data.block);
20795dfecf96Smrg		break;
20805dfecf96Smrg	    default:
20815dfecf96Smrg		break;
20825dfecf96Smrg	}
20835dfecf96Smrg	goto update_label;
20845dfecf96Smrgremove_label:
20855dfecf96Smrg	if (tree == block->tree) {
20865dfecf96Smrg	    block->tree = prev = next;
20875dfecf96Smrg	    if (tree == block->tail)
20885dfecf96Smrg		block->tail = tree;
20895dfecf96Smrg	}
20905dfecf96Smrg	else
20915dfecf96Smrg	    prev->next = next;
20925dfecf96Smrg	CompileFreeTree(tree);
20935dfecf96Smrg	tree = next;
20945dfecf96Smrg	continue;
20955dfecf96Smrgremove_next_label:
20965dfecf96Smrg	tree->next = next->next;
20975dfecf96Smrg	CompileFreeTree(next);
20985dfecf96Smrg	continue;
20995dfecf96Smrgupdate_label:
21005dfecf96Smrg	prev = tree;
21015dfecf96Smrg	tree = tree->next;
21025dfecf96Smrg    }
21035dfecf96Smrg}
21045dfecf96Smrg
21055dfecf96Smrgstatic void
21065dfecf96SmrgLinkOptimize_0(LispCom *com)
21075dfecf96Smrg{
21085dfecf96Smrg    /* Recursive */
21095dfecf96Smrg    LinkDoOptimize_0(com, com->block);
21105dfecf96Smrg}
21115dfecf96Smrg
21125dfecf96Smrgstatic void
21135dfecf96SmrgLinkResolveLabels(LispCom *com, CodeBlock *block)
21145dfecf96Smrg{
21155dfecf96Smrg    int i;
21165dfecf96Smrg    CodeTree *tree = block->tree;
21175dfecf96Smrg
21185dfecf96Smrg    for (; tree; tree = tree->next) {
21195dfecf96Smrg	if (tree->type == CodeTreeBlock)
21205dfecf96Smrg	    LinkResolveLabels(com, tree->data.block);
21215dfecf96Smrg	else if (tree->type == CodeTreeLabel) {
21225dfecf96Smrg	    for (i = 0; i < block->tagbody.length; i++)
21235dfecf96Smrg		if (tree->data.object == block->tagbody.labels[i]) {
21245dfecf96Smrg		    block->tagbody.codes[i] = tree;
21255dfecf96Smrg		    break;
21265dfecf96Smrg		}
21275dfecf96Smrg	}
21285dfecf96Smrg    }
21295dfecf96Smrg}
21305dfecf96Smrg
21315dfecf96Smrgstatic void
21325dfecf96SmrgLinkResolveJumps(LispCom *com, CodeBlock *block)
21335dfecf96Smrg{
21345dfecf96Smrg    int i;
21355dfecf96Smrg    CodeBlock *body = block;
21365dfecf96Smrg    CodeTree *ptr, *tree = block->tree;
21375dfecf96Smrg
21385dfecf96Smrg    /* Check if there is a tagbody. Error checking already done */
21395dfecf96Smrg    while (body && body->type != LispBlockBody)
21405dfecf96Smrg	body = body->prev;
21415dfecf96Smrg
21425dfecf96Smrg    for (; tree; tree = tree->next) {
21435dfecf96Smrg	switch (tree->type) {
21445dfecf96Smrg	    case CodeTreeBytecode:
21455dfecf96Smrg	    case CodeTreeLabel:
21465dfecf96Smrg		break;
21475dfecf96Smrg
21485dfecf96Smrg	    case CodeTreeBlock:
21495dfecf96Smrg		LinkResolveJumps(com, tree->data.block);
21505dfecf96Smrg		break;
21515dfecf96Smrg
21525dfecf96Smrg	    case CodeTreeGo:
21535dfecf96Smrg		for (i = 0; i < body->tagbody.length; i++)
21545dfecf96Smrg		    if (tree->data.object == body->tagbody.labels[i])
21555dfecf96Smrg			break;
21565dfecf96Smrg		if (i == body->tagbody.length)
21575dfecf96Smrg		    LispDestroy("COMPILE: no visible tag %s to GO",
21585dfecf96Smrg				STROBJ(tree->data.object));
21595dfecf96Smrg		/* Now the jump code is known */
21605dfecf96Smrg		tree->data.tree = body->tagbody.codes[i];
21615dfecf96Smrg		break;
21625dfecf96Smrg
21635dfecf96Smrg	    case CodeTreeCond:
21645dfecf96Smrg		if (tree->code == XBC_JUMPNIL)
21655dfecf96Smrg		    /* If test is NIL, go to next test */
21665dfecf96Smrg		    tree->data.tree = tree->group->next;
21675dfecf96Smrg		else if (tree->code == XBC_JUMPT) {
21685dfecf96Smrg		    /* After executing code, test was T */
21695dfecf96Smrg		    for (ptr = tree->group;
21705dfecf96Smrg			 ptr->code != XBC_NOOP;
21715dfecf96Smrg			 ptr = ptr->group)
21725dfecf96Smrg			;
21735dfecf96Smrg		    tree->data.tree = ptr;
21745dfecf96Smrg		}
21755dfecf96Smrg		break;
21765dfecf96Smrg
21775dfecf96Smrg	    case CodeTreeJumpIf:
21785dfecf96Smrg		if (tree->code != XBC_NOOP) {
21795dfecf96Smrg		    for (ptr = tree->group;
21805dfecf96Smrg			 ptr->code != XBC_NOOP;
21815dfecf96Smrg			 ptr = ptr->group) {
21825dfecf96Smrg			if (ptr->type == CodeTreeJump) {
21835dfecf96Smrg			    /* ELSE code of IF */
21845dfecf96Smrg			    ptr = ptr->next;
21855dfecf96Smrg			    /* Skip inconditional jump node */
21865dfecf96Smrg			    break;
21875dfecf96Smrg			}
21885dfecf96Smrg		    }
21895dfecf96Smrg		    tree->data.tree = ptr;
21905dfecf96Smrg		}
21915dfecf96Smrg		break;
21925dfecf96Smrg
21935dfecf96Smrg	    case CodeTreeJump:
21945dfecf96Smrg		if (tree->code != XBC_NOOP)
21955dfecf96Smrg		    tree->data.tree = tree->group;
21965dfecf96Smrg		break;
21975dfecf96Smrg
21985dfecf96Smrg	    case CodeTreeReturn:
21995dfecf96Smrg		/* One bytecode is guaranteed to exist in the code tree */
22005dfecf96Smrg		if (tree->data.block->parent == NULL)
22015dfecf96Smrg		    /* Returning from the function or toplevel form */
22025dfecf96Smrg		    tree->data.tree = tree->data.block->tail;
22035dfecf96Smrg		else {
22045dfecf96Smrg		    for (;;) {
22055dfecf96Smrg			ptr = tree->data.block->parent->next;
22065dfecf96Smrg			if (ptr) {
22075dfecf96Smrg			    tree->data.tree = ptr;
22085dfecf96Smrg			    break;
22095dfecf96Smrg			}
22105dfecf96Smrg			else
22115dfecf96Smrg			    /* Move one BLOCK up */
22125dfecf96Smrg			    tree->data.block = tree->data.block->prev;
22135dfecf96Smrg		    }
22145dfecf96Smrg		}
22155dfecf96Smrg		break;
22165dfecf96Smrg	}
22175dfecf96Smrg    }
22185dfecf96Smrg}
22195dfecf96Smrg
22205dfecf96Smrgstatic long
22215dfecf96SmrgLinkPad(long offset, long adjust, int preffix, int datalen)
22225dfecf96Smrg{
22235dfecf96Smrg    /* If byte or aligned data */
22245dfecf96Smrg    if (datalen <= preffix || ((offset + adjust + preffix) % datalen) == 0)
22255dfecf96Smrg	return (adjust);
22265dfecf96Smrg
22275dfecf96Smrg    return (adjust + (datalen - ((offset + adjust + preffix) % datalen)));
22285dfecf96Smrg}
22295dfecf96Smrg
22305dfecf96Smrgstatic long
22315dfecf96SmrgLinkFixupOffsets(LispCom *com, CodeTree *tree, long adjust)
22325dfecf96Smrg{
22335dfecf96Smrg    for (; tree; tree = tree->next) {
22345dfecf96Smrg	switch (tree->type) {
22355dfecf96Smrg	    case CodeTreeBytecode:
22365dfecf96Smrg		switch (tree->code) {
22375dfecf96Smrg		    /* byte + short */
22385dfecf96Smrg		    case XBC_JUMP:
22395dfecf96Smrg		    case XBC_JUMPT:
22405dfecf96Smrg		    case XBC_JUMPNIL:
22415dfecf96Smrg			adjust = LinkPad(tree->offset, adjust, 1,
22425dfecf96Smrg					 sizeof(short));
22435dfecf96Smrg			/*FALLTROUGH*/
22445dfecf96Smrg		    default:
22455dfecf96Smrg			tree->offset += adjust;
22465dfecf96Smrg			break;
22475dfecf96Smrg		}
22485dfecf96Smrg		break;
22495dfecf96Smrg	    case CodeTreeLabel:
22505dfecf96Smrg		/* Labels are not loaded, just adjust offset */
22515dfecf96Smrg		tree->offset += adjust;
22525dfecf96Smrg		break;
22535dfecf96Smrg	    case CodeTreeJump:
22545dfecf96Smrg	    case CodeTreeCond:
22555dfecf96Smrg	    case CodeTreeJumpIf:
22565dfecf96Smrg		/* If an opcode will be generated. */
22575dfecf96Smrg		if (tree->code != XBC_NOOP)
22585dfecf96Smrg		    adjust = LinkPad(tree->offset, adjust, 1, sizeof(short));
22595dfecf96Smrg		tree->offset += adjust;
22605dfecf96Smrg		break;
22615dfecf96Smrg	    case CodeTreeGo:
22625dfecf96Smrg	    case CodeTreeReturn:
22635dfecf96Smrg		adjust = LinkPad(tree->offset, adjust, 1, sizeof(short));
22645dfecf96Smrg		tree->offset += adjust;
22655dfecf96Smrg		break;
22665dfecf96Smrg	    case CodeTreeBlock:
22675dfecf96Smrg		adjust = LinkFixupOffsets(com, tree->data.block->tree, adjust);
22685dfecf96Smrg		break;
22695dfecf96Smrg	}
22705dfecf96Smrg    }
22715dfecf96Smrg
22725dfecf96Smrg    return (adjust);
22735dfecf96Smrg}
22745dfecf96Smrg
22755dfecf96Smrgstatic void
22765dfecf96SmrgLinkSkipPadding(LispCom *com, CodeTree *tree)
22775dfecf96Smrg{
22785dfecf96Smrg    int found;
22795dfecf96Smrg    CodeTree *ptr;
22805dfecf96Smrg
22815dfecf96Smrg    /* Recurse to adjust forward jumps or jumps to the start of the block */
22825dfecf96Smrg    for (ptr = tree; ptr; ptr = ptr->next) {
22835dfecf96Smrg	if (ptr->type == CodeTreeBlock) {
22845dfecf96Smrg	    LinkSkipPadding(com, ptr->data.block->tree);
22855dfecf96Smrg	    ptr->offset = ptr->data.block->tree->offset;
22865dfecf96Smrg	}
22875dfecf96Smrg    }
22885dfecf96Smrg
22895dfecf96Smrg    /* Adjust the nodes offsets */
22905dfecf96Smrg    for (; tree; tree = tree->next) {
22915dfecf96Smrg	switch (tree->type) {
22925dfecf96Smrg	    case CodeTreeBytecode:
22935dfecf96Smrg	    case CodeTreeBlock:
22945dfecf96Smrg	    case CodeTreeGo:
22955dfecf96Smrg	    case CodeTreeReturn:
22965dfecf96Smrg		break;
22975dfecf96Smrg	    case CodeTreeJump:
22985dfecf96Smrg	    case CodeTreeCond:
22995dfecf96Smrg	    case CodeTreeJumpIf:
23005dfecf96Smrg		if (tree->code != XBC_NOOP)
23015dfecf96Smrg		    /* If code will be generated */
23025dfecf96Smrg		    break;
23035dfecf96Smrg	    case CodeTreeLabel:
23045dfecf96Smrg		/* This should be done in reversed order, but to avoid
23055dfecf96Smrg		 * the requirement of a prev pointer, do the job in a
23065dfecf96Smrg		 * harder way here. */
23075dfecf96Smrg		for (found = 0, ptr = tree->next; ptr; ptr = ptr->next) {
23085dfecf96Smrg		    switch (ptr->type) {
23095dfecf96Smrg			case CodeTreeBytecode:
23105dfecf96Smrg			case CodeTreeBlock:
23115dfecf96Smrg			case CodeTreeGo:
23125dfecf96Smrg			case CodeTreeReturn:
23135dfecf96Smrg			    found = 1;
23145dfecf96Smrg			    break;
23155dfecf96Smrg			case CodeTreeJump:
23165dfecf96Smrg			case CodeTreeCond:
23175dfecf96Smrg			case CodeTreeJumpIf:
23185dfecf96Smrg			    if (ptr->code != XBC_NOOP)
23195dfecf96Smrg				found = 1;
23205dfecf96Smrg			    break;
23215dfecf96Smrg			case CodeTreeLabel:
23225dfecf96Smrg			    break;
23235dfecf96Smrg		    }
23245dfecf96Smrg		    if (found)
23255dfecf96Smrg			break;
23265dfecf96Smrg		}
23275dfecf96Smrg		if (found)
23285dfecf96Smrg		    tree->offset = ptr->offset;
23295dfecf96Smrg		break;
23305dfecf96Smrg	}
23315dfecf96Smrg    }
23325dfecf96Smrg}
23335dfecf96Smrg
23345dfecf96Smrgstatic void
23355dfecf96SmrgLinkCalculateJump(LispCom *com, CodeTree *tree, LispByteOpcode code)
23365dfecf96Smrg{
23375dfecf96Smrg    long jumpto, offset, distance;
23385dfecf96Smrg
23395dfecf96Smrg    tree->type = CodeTreeBytecode;
23405dfecf96Smrg    /* After the opcode */
23415dfecf96Smrg    offset = tree->offset + 1;
23425dfecf96Smrg    jumpto = tree->data.tree->offset;
23435dfecf96Smrg    /* Effective distance */
23445dfecf96Smrg    distance = jumpto - offset;
23455dfecf96Smrg    tree->code = code;
23465dfecf96Smrg    if (distance < -32768 || distance > 32767) {
23475dfecf96Smrg	COMPILE_FAILURE("jump too long");
23485dfecf96Smrg    }
23495dfecf96Smrg    tree->data.signed_int = distance;
23505dfecf96Smrg}
23515dfecf96Smrg
23525dfecf96Smrgstatic void
23535dfecf96SmrgLinkFixupJumps(LispCom *com, CodeTree *tree)
23545dfecf96Smrg{
23555dfecf96Smrg    for (; tree; tree = tree->next) {
23565dfecf96Smrg	switch (tree->type) {
23575dfecf96Smrg	    case CodeTreeBytecode:
23585dfecf96Smrg	    case CodeTreeLabel:
23595dfecf96Smrg		break;
23605dfecf96Smrg	    case CodeTreeCond:
23615dfecf96Smrg		if (tree->code == XBC_JUMPNIL)
23625dfecf96Smrg		    /* Go to next test if NIL */
23635dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMPNIL);
23645dfecf96Smrg		else if (tree->code == XBC_JUMPT)
23655dfecf96Smrg		    /* After executing T code */
23665dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMP);
23675dfecf96Smrg		break;
23685dfecf96Smrg	    case CodeTreeJumpIf:
23695dfecf96Smrg		if (tree->code != XBC_NOOP)
23705dfecf96Smrg		    LinkCalculateJump(com, tree, tree->code);
23715dfecf96Smrg		break;
23725dfecf96Smrg	    case CodeTreeGo:
23735dfecf96Smrg		/* Inconditional jump */
23745dfecf96Smrg		LinkCalculateJump(com, tree, XBC_JUMP);
23755dfecf96Smrg		break;
23765dfecf96Smrg	    case CodeTreeReturn:
23775dfecf96Smrg		/* Inconditional jump */
23785dfecf96Smrg		if (tree->data.tree != tree)
23795dfecf96Smrg		    /* If need to skip something */
23805dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMP);
23815dfecf96Smrg		break;
23825dfecf96Smrg	    case CodeTreeBlock:
23835dfecf96Smrg		LinkFixupJumps(com, tree->data.block->tree);
23845dfecf96Smrg		break;
23855dfecf96Smrg	    case CodeTreeJump:
23865dfecf96Smrg		if (tree->code != XBC_NOOP)
23875dfecf96Smrg		    LinkCalculateJump(com, tree, tree->code);
23885dfecf96Smrg	}
23895dfecf96Smrg    }
23905dfecf96Smrg}
23915dfecf96Smrg
23925dfecf96Smrgstatic void
23935dfecf96SmrgLinkBuildTableSymbol(LispCom *com, LispAtom *symbol)
23945dfecf96Smrg{
23955dfecf96Smrg    if (BuildTablePointer(symbol, (void***)&com->table.symbols,
23965dfecf96Smrg			  &com->table.num_symbols) > 0xff) {
23975dfecf96Smrg	COMPILE_FAILURE("more than 256 symbols");
23985dfecf96Smrg    }
23995dfecf96Smrg}
24005dfecf96Smrg
24015dfecf96Smrgstatic void
24025dfecf96SmrgLinkBuildTableConstant(LispCom *com, LispObj *constant)
24035dfecf96Smrg{
24045dfecf96Smrg    if (BuildTablePointer(constant, (void***)&com->table.constants,
24055dfecf96Smrg			  &com->table.num_constants) > 0xff) {
24065dfecf96Smrg	COMPILE_FAILURE("more than 256 constants");
24075dfecf96Smrg    }
24085dfecf96Smrg}
24095dfecf96Smrg
24105dfecf96Smrgstatic void
24115dfecf96SmrgLinkBuildTableBuiltin(LispCom *com, LispBuiltin *builtin)
24125dfecf96Smrg{
24135dfecf96Smrg    if (BuildTablePointer(builtin, (void***)&com->table.builtins,
24145dfecf96Smrg			  &com->table.num_builtins) > 0xff) {
24155dfecf96Smrg	COMPILE_FAILURE("more than 256 functions");
24165dfecf96Smrg    }
24175dfecf96Smrg}
24185dfecf96Smrg
24195dfecf96Smrgstatic void
24205dfecf96SmrgLinkBuildTableBytecode(LispCom *com, LispObj *bytecode)
24215dfecf96Smrg{
24225dfecf96Smrg    if (BuildTablePointer(bytecode, (void***)&com->table.bytecodes,
24235dfecf96Smrg			  &com->table.num_bytecodes) > 0xff) {
24245dfecf96Smrg	COMPILE_FAILURE("more than 256 bytecode functions");
24255dfecf96Smrg    }
24265dfecf96Smrg}
24275dfecf96Smrg
24285dfecf96Smrgstatic void
24295dfecf96SmrgLinkBuildTables(LispCom *com, CodeBlock *block)
24305dfecf96Smrg{
24315dfecf96Smrg    CodeTree *tree;
24325dfecf96Smrg
24335dfecf96Smrg    for (tree = block->tree; tree; tree = tree->next) {
24345dfecf96Smrg	switch (tree->type) {
24355dfecf96Smrg	    case CodeTreeBytecode:
24365dfecf96Smrg		switch (tree->code) {
24375dfecf96Smrg		    case XBC_LET:
24385dfecf96Smrg		    case XBC_LETX:
24395dfecf96Smrg		    case XBC_LET_NIL:
24405dfecf96Smrg		    case XBC_LETX_NIL:
24415dfecf96Smrg		    case XBC_SETSYM:
24425dfecf96Smrg		    case XBC_LOADSYM:
24435dfecf96Smrg		    case XBC_LOADSYM_PUSH:
24445dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.atom);
24455dfecf96Smrg			break;
24465dfecf96Smrg		    case XBC_STRUCTP:
24475dfecf96Smrg		    case XBC_LOADCON:
24485dfecf96Smrg		    case XBC_LOADCON_PUSH:
24495dfecf96Smrg			LinkBuildTableConstant(com, tree->data.object);
24505dfecf96Smrg			break;
24515dfecf96Smrg		    case XBC_LOADCON_SET:
24525dfecf96Smrg			LinkBuildTableConstant(com, tree->data.load_con_set.object);
24535dfecf96Smrg			break;
24545dfecf96Smrg		    case XBC_CALL:
24555dfecf96Smrg		    case XBC_CALL_SET:
24565dfecf96Smrg			LinkBuildTableBuiltin(com, tree->data.builtin.builtin);
24575dfecf96Smrg			break;
24585dfecf96Smrg		    case XBC_BYTECALL:
24595dfecf96Smrg			LinkBuildTableBytecode(com, tree->data.bytecall.code);
24605dfecf96Smrg			break;
24615dfecf96Smrg		    case XBC_LOAD_LET:
24625dfecf96Smrg		    case XBC_LOAD_LETX:
24635dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let.name);
24645dfecf96Smrg			break;
24655dfecf96Smrg		    case XBC_STRUCT:
24665dfecf96Smrg			LinkBuildTableConstant(com, tree->data.struc.definition);
24675dfecf96Smrg			break;
24685dfecf96Smrg		    case XBC_LOADSYM_LET:
24695dfecf96Smrg		    case XBC_LOADSYM_LETX:
24705dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_sym.symbol);
24715dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_sym.name);
24725dfecf96Smrg			break;
24735dfecf96Smrg		    case XBC_LOADCON_LET:
24745dfecf96Smrg		    case XBC_LOADCON_LETX:
24755dfecf96Smrg			LinkBuildTableConstant(com, tree->data.let_con.object);
24765dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_con.name);
24775dfecf96Smrg			break;
24785dfecf96Smrg		    case XBC_CCONS:
24795dfecf96Smrg		    case XBC_FUNCALL:
24805dfecf96Smrg			LinkBuildTableConstant(com, tree->data.cons.car);
24815dfecf96Smrg			LinkBuildTableConstant(com, tree->data.cons.cdr);
24825dfecf96Smrg			break;
24835dfecf96Smrg		    default:
24845dfecf96Smrg			break;
24855dfecf96Smrg		}
24865dfecf96Smrg		break;
24875dfecf96Smrg	    case CodeTreeBlock:
24885dfecf96Smrg		LinkBuildTables(com, tree->data.block);
24895dfecf96Smrg		break;
24905dfecf96Smrg	    default:
24915dfecf96Smrg		break;
24925dfecf96Smrg	}
24935dfecf96Smrg    }
24945dfecf96Smrg}
24955dfecf96Smrg
24965dfecf96Smrgstatic long
24975dfecf96SmrgLinkEmmitBytecode(LispCom *com, CodeTree *tree,
24985dfecf96Smrg		  unsigned char *bytecode, long offset)
24995dfecf96Smrg{
25005dfecf96Smrg    short i;
25015dfecf96Smrg
25025dfecf96Smrg    for (; tree; tree = tree->next) {
25035dfecf96Smrg	/* Fill padding */
25045dfecf96Smrg	while (offset < tree->offset)
25055dfecf96Smrg	    bytecode[offset++] = XBC_NOOP;
25065dfecf96Smrg
25075dfecf96Smrg	switch (tree->type) {
25085dfecf96Smrg	    case CodeTreeBytecode:
25095dfecf96Smrg		bytecode[offset++] = tree->code;
25105dfecf96Smrg		switch (tree->code) {
25115dfecf96Smrg		    /* Noop should not enter the CodeTree */
25125dfecf96Smrg		    case XBC_NOOP:
25135dfecf96Smrg			INTERNAL_ERROR(__LINE__);
25145dfecf96Smrg			break;
25155dfecf96Smrg
25165dfecf96Smrg		    /* byte */
25175dfecf96Smrg		    case XBC_BCONS:
25185dfecf96Smrg		    case XBC_BCONS1:
25195dfecf96Smrg		    case XBC_BCONS2:
25205dfecf96Smrg		    case XBC_BCONS3:
25215dfecf96Smrg		    case XBC_BCONS4:
25225dfecf96Smrg		    case XBC_BCONS5:
25235dfecf96Smrg		    case XBC_BCONS6:
25245dfecf96Smrg		    case XBC_BCONS7:
25255dfecf96Smrg		    case XBC_INV:
25265dfecf96Smrg		    case XBC_NIL:
25275dfecf96Smrg		    case XBC_T:
25285dfecf96Smrg		    case XBC_PUSH_NIL:
25295dfecf96Smrg		    case XBC_PUSH_UNSPEC:
25305dfecf96Smrg		    case XBC_PUSH_T:
25315dfecf96Smrg		    case XBC_CAR_PUSH:
25325dfecf96Smrg		    case XBC_CDR_PUSH:
25335dfecf96Smrg		    case XBC_PUSH:
25345dfecf96Smrg		    case XBC_LSTAR:
25355dfecf96Smrg		    case XBC_LCONS:
25365dfecf96Smrg		    case XBC_LFINI:
25375dfecf96Smrg		    case XBC_RETURN:
25385dfecf96Smrg		    case XBC_CSTAR:
25395dfecf96Smrg		    case XBC_CFINI:
25405dfecf96Smrg		    case XBC_CAR:
25415dfecf96Smrg		    case XBC_CDR:
25425dfecf96Smrg		    case XBC_RPLACA:
25435dfecf96Smrg		    case XBC_RPLACD:
25445dfecf96Smrg		    case XBC_EQ:
25455dfecf96Smrg		    case XBC_EQL:
25465dfecf96Smrg		    case XBC_EQUAL:
25475dfecf96Smrg		    case XBC_EQUALP:
25485dfecf96Smrg		    case XBC_LENGTH:
25495dfecf96Smrg		    case XBC_LAST:
25505dfecf96Smrg		    case XBC_NTHCDR:
25515dfecf96Smrg			break;
25525dfecf96Smrg
25535dfecf96Smrg		    /* byte + byte */
25545dfecf96Smrg		    case XBC_LETREC:
25555dfecf96Smrg		    case XBC_PRED:
25565dfecf96Smrg		    case XBC_PUSH_NIL_N:
25575dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
25585dfecf96Smrg			bytecode[offset++] = tree->data.signed_char;
25595dfecf96Smrg			break;
25605dfecf96Smrg
25615dfecf96Smrg		    /* byte + byte */
25625dfecf96Smrg		    case XBC_CAR_SET:
25635dfecf96Smrg		    case XBC_CDR_SET:
25645dfecf96Smrg		    case XBC_SET:
25655dfecf96Smrg		    case XBC_SET_NIL:
25665dfecf96Smrg		    case XBC_LETBIND:
25675dfecf96Smrg		    case XBC_UNLET:
25685dfecf96Smrg		    case XBC_LOAD_PUSH:
25695dfecf96Smrg		    case XBC_LOAD:
25705dfecf96Smrg		    case XBC_LOAD_CAR:
25715dfecf96Smrg		    case XBC_LOAD_CDR:
25725dfecf96Smrg		    case XBC_LOAD_CAR_STORE:
25735dfecf96Smrg		    case XBC_LOAD_CDR_STORE:
25745dfecf96Smrg			bytecode[offset++] = tree->data.signed_short;
25755dfecf96Smrg			break;
25765dfecf96Smrg
25775dfecf96Smrg		    /* byte + byte + byte */
25785dfecf96Smrg		    case XBC_LOAD_SET:
25795dfecf96Smrg		    case XBC_LOAD_CAR_SET:
25805dfecf96Smrg		    case XBC_LOAD_CDR_SET:
25815dfecf96Smrg			bytecode[offset++] = tree->data.load_set.load;
25825dfecf96Smrg			bytecode[offset++] = tree->data.load_set.set;
25835dfecf96Smrg			break;
25845dfecf96Smrg
25855dfecf96Smrg		    /* byte + short */
25865dfecf96Smrg		    case XBC_JUMP:
25875dfecf96Smrg		    case XBC_JUMPT:
25885dfecf96Smrg		    case XBC_JUMPNIL:
25895dfecf96Smrg			*(short*)(bytecode + offset) = tree->data.signed_int;
25905dfecf96Smrg			offset += sizeof(short);
25915dfecf96Smrg			break;
25925dfecf96Smrg
25935dfecf96Smrg		    /* byte + byte */
25945dfecf96Smrg		    case XBC_LET:
25955dfecf96Smrg		    case XBC_LETX:
25965dfecf96Smrg		    case XBC_LET_NIL:
25975dfecf96Smrg		    case XBC_LETX_NIL:
25985dfecf96Smrg		    case XBC_SETSYM:
25995dfecf96Smrg		    case XBC_LOADSYM:
26005dfecf96Smrg		    case XBC_LOADSYM_PUSH:
26015dfecf96Smrg			i = FindIndex(tree->data.atom,
26025dfecf96Smrg				      (void**)com->table.symbols,
26035dfecf96Smrg				      com->table.num_symbols);
26045dfecf96Smrg			bytecode[offset++] = i;
26055dfecf96Smrg			break;
26065dfecf96Smrg
26075dfecf96Smrg		    /* byte + byte */
26085dfecf96Smrg		    case XBC_STRUCTP:
26095dfecf96Smrg		    case XBC_LOADCON:
26105dfecf96Smrg		    case XBC_LOADCON_PUSH:
26115dfecf96Smrg			i = FindIndex(tree->data.object,
26125dfecf96Smrg				      (void**)com->table.constants,
26135dfecf96Smrg				      com->table.num_constants);
26145dfecf96Smrg			bytecode[offset++] = i;
26155dfecf96Smrg			break;
26165dfecf96Smrg
26175dfecf96Smrg		    /* byte + byte + byte */
26185dfecf96Smrg		    case XBC_LOADCON_SET:
26195dfecf96Smrg			i = FindIndex(tree->data.load_con_set.object,
26205dfecf96Smrg				      (void**)com->table.constants,
26215dfecf96Smrg				      com->table.num_constants);
26225dfecf96Smrg			bytecode[offset++] = i;
26235dfecf96Smrg			bytecode[offset++] = tree->data.load_con_set.offset;
26245dfecf96Smrg			break;
26255dfecf96Smrg
26265dfecf96Smrg		    /* byte + byte + byte */
26275dfecf96Smrg		    case XBC_CALL:
26285dfecf96Smrg			bytecode[offset++] = tree->data.builtin.num_arguments;
26295dfecf96Smrg			i = FindIndex(tree->data.builtin.builtin,
26305dfecf96Smrg				      (void**)com->table.builtins,
26315dfecf96Smrg				      com->table.num_builtins);
26325dfecf96Smrg			bytecode[offset++] = i;
26335dfecf96Smrg			break;
26345dfecf96Smrg
26355dfecf96Smrg		    /* byte + byte + byte */
26365dfecf96Smrg		    case XBC_BYTECALL:
26375dfecf96Smrg			bytecode[offset++] = tree->data.bytecall.num_arguments;
26385dfecf96Smrg			i = FindIndex(tree->data.bytecall.code,
26395dfecf96Smrg				      (void**)com->table.bytecodes,
26405dfecf96Smrg				      com->table.num_bytecodes);
26415dfecf96Smrg			bytecode[offset++] = i;
26425dfecf96Smrg			break;
26435dfecf96Smrg
26445dfecf96Smrg		    /* byte + byte + byte + byte */
26455dfecf96Smrg		    case XBC_CALL_SET:
26465dfecf96Smrg			bytecode[offset++] = tree->data.builtin.num_arguments;
26475dfecf96Smrg			i = FindIndex(tree->data.builtin.builtin,
26485dfecf96Smrg				      (void**)com->table.builtins,
26495dfecf96Smrg				      com->table.num_builtins);
26505dfecf96Smrg			bytecode[offset++] = i;
26515dfecf96Smrg			bytecode[offset++] = tree->data.builtin.offset;
26525dfecf96Smrg			break;
26535dfecf96Smrg
26545dfecf96Smrg		    /* byte + byte + byte */
26555dfecf96Smrg		    case XBC_LOAD_LET:
26565dfecf96Smrg		    case XBC_LOAD_LETX:
26575dfecf96Smrg			bytecode[offset++] = tree->data.let.offset;
26585dfecf96Smrg			i = FindIndex(tree->data.let.name,
26595dfecf96Smrg				      (void**)com->table.symbols,
26605dfecf96Smrg				      com->table.num_symbols);
26615dfecf96Smrg			bytecode[offset++] = i;
26625dfecf96Smrg			break;
26635dfecf96Smrg
26645dfecf96Smrg		    /* byte + byte + byte */
26655dfecf96Smrg		    case XBC_STRUCT:
26665dfecf96Smrg			bytecode[offset++] = tree->data.struc.offset;
26675dfecf96Smrg			i = FindIndex(tree->data.struc.definition,
26685dfecf96Smrg				      (void**)com->table.constants,
26695dfecf96Smrg				      com->table.num_constants);
26705dfecf96Smrg			bytecode[offset++] = i;
26715dfecf96Smrg			break;
26725dfecf96Smrg
26735dfecf96Smrg		    /* byte + byte + byte */
26745dfecf96Smrg		    case XBC_LOADSYM_LET:
26755dfecf96Smrg		    case XBC_LOADSYM_LETX:
26765dfecf96Smrg			i = FindIndex(tree->data.let_sym.symbol,
26775dfecf96Smrg				      (void**)com->table.symbols,
26785dfecf96Smrg				      com->table.num_symbols);
26795dfecf96Smrg			bytecode[offset++] = i;
26805dfecf96Smrg			i = FindIndex(tree->data.let_sym.name,
26815dfecf96Smrg				      (void**)com->table.symbols,
26825dfecf96Smrg				      com->table.num_symbols);
26835dfecf96Smrg			bytecode[offset++] = i;
26845dfecf96Smrg			break;
26855dfecf96Smrg
26865dfecf96Smrg		    /* byte + byte + byte */
26875dfecf96Smrg		    case XBC_LOADCON_LET:
26885dfecf96Smrg		    case XBC_LOADCON_LETX:
26895dfecf96Smrg			i = FindIndex(tree->data.let_con.object,
26905dfecf96Smrg				      (void**)com->table.constants,
26915dfecf96Smrg				      com->table.num_constants);
26925dfecf96Smrg			bytecode[offset++] = i;
26935dfecf96Smrg			i = FindIndex(tree->data.let_con.name,
26945dfecf96Smrg				      (void**)com->table.symbols,
26955dfecf96Smrg				      com->table.num_symbols);
26965dfecf96Smrg			bytecode[offset++] = i;
26975dfecf96Smrg			break;
26985dfecf96Smrg
26995dfecf96Smrg		    /* byte + byte + byte */
27005dfecf96Smrg		    case XBC_CCONS:
27015dfecf96Smrg		    case XBC_FUNCALL:
27025dfecf96Smrg			i = FindIndex(tree->data.cons.car,
27035dfecf96Smrg				      (void**)com->table.constants,
27045dfecf96Smrg				      com->table.num_constants);
27055dfecf96Smrg			bytecode[offset++] = i;
27065dfecf96Smrg			i = FindIndex(tree->data.cons.cdr,
27075dfecf96Smrg				      (void**)com->table.constants,
27085dfecf96Smrg				      com->table.num_constants);
27095dfecf96Smrg			bytecode[offset++] = i;
27105dfecf96Smrg			break;
27115dfecf96Smrg		}
27125dfecf96Smrg		break;
27135dfecf96Smrg	    case CodeTreeLabel:
27145dfecf96Smrg		/* Labels are not loaded */
27155dfecf96Smrg		break;
27165dfecf96Smrg	    case CodeTreeCond:
27175dfecf96Smrg	    case CodeTreeJump:
27185dfecf96Smrg	    case CodeTreeJumpIf:
27195dfecf96Smrg		if (tree->code != XBC_NOOP)
27205dfecf96Smrg		    INTERNAL_ERROR(__LINE__);
27215dfecf96Smrg		break;
27225dfecf96Smrg	    case CodeTreeGo:
27235dfecf96Smrg		INTERNAL_ERROR(__LINE__);
27245dfecf96Smrg		break;
27255dfecf96Smrg	    case CodeTreeReturn:
27265dfecf96Smrg		if (tree->data.tree != tree)
27275dfecf96Smrg		    INTERNAL_ERROR(__LINE__);
27285dfecf96Smrg		break;
27295dfecf96Smrg	    case CodeTreeBlock:
27305dfecf96Smrg		offset = LinkEmmitBytecode(com, tree->data.block->tree,
27315dfecf96Smrg					   bytecode, offset);
27325dfecf96Smrg		break;
27335dfecf96Smrg	}
27345dfecf96Smrg    }
27355dfecf96Smrg
27365dfecf96Smrg    return (offset);
27375dfecf96Smrg}
27385dfecf96Smrg
27395dfecf96Smrgstatic void
27405dfecf96SmrgLinkBytecode(LispCom *com)
27415dfecf96Smrg{
27425dfecf96Smrg    long offset, count;
27435dfecf96Smrg    unsigned char **codes;
27445dfecf96Smrg    LispObj **names;
27455dfecf96Smrg
27465dfecf96Smrg    /* Close bytecode */
27475dfecf96Smrg    com_Bytecode(com, XBC_RETURN);
27485dfecf96Smrg
27495dfecf96Smrg    /* The only usage of this information for now, and still may generate
27505dfecf96Smrg     * false positives because arguments to unamed functions are not being
27515dfecf96Smrg     * parsed as well as arguments to yet undefined function/maros.
27525dfecf96Smrg     * XXX should also add declaim/declare to let the code specify that
27535dfecf96Smrg     * the argument is unused */
27545dfecf96Smrg    LinkWarnUnused(com, com->block);
27555dfecf96Smrg
27565dfecf96Smrg    /* First level optimization */
27575dfecf96Smrg    LinkOptimize_0(com);
27585dfecf96Smrg
27595dfecf96Smrg    /* Resolve tagbody labels */
27605dfecf96Smrg    LinkResolveLabels(com, com->block);
27615dfecf96Smrg
27625dfecf96Smrg    /* Resolve any pending jumps */
27635dfecf96Smrg    LinkResolveJumps(com, com->block);
27645dfecf96Smrg
27655dfecf96Smrg    /* Calculate unpadded offsets */
27665dfecf96Smrg    LinkBuildOffsets(com, com->block->tree, 0);
27675dfecf96Smrg
27685dfecf96Smrg    /* Do padding for aligned memory reads */
27695dfecf96Smrg    LinkFixupOffsets(com, com->block->tree, 0);
27705dfecf96Smrg
27715dfecf96Smrg    /* Jumps normally are to a node that does not generate code,
27725dfecf96Smrg     * and due to padding, the jump may go to a address with a
27735dfecf96Smrg     * XBC_NOOP, so adjust the jump to the next useful opcode. */
27745dfecf96Smrg    LinkSkipPadding(com, com->block->tree);
27755dfecf96Smrg
27765dfecf96Smrg    /* Now addresses are known */
27775dfecf96Smrg    LinkFixupJumps(com, com->block->tree);
27785dfecf96Smrg
27795dfecf96Smrg    /* Build symbol, constant and builtin tables */
27805dfecf96Smrg    LinkBuildTables(com, com->block);
27815dfecf96Smrg
27825dfecf96Smrg    /* Stack info */
27835dfecf96Smrg    com->length = sizeof(short) * 3;
27845dfecf96Smrg    /* Tables info */
27855dfecf96Smrg    com->length += sizeof(short) * 4;
27865dfecf96Smrg    com->length += com->table.num_constants * sizeof(LispObj*);
27875dfecf96Smrg    com->length += com->table.num_symbols * sizeof(LispAtom*);
27885dfecf96Smrg    com->length += com->table.num_builtins * sizeof(LispBuiltin*);
27895dfecf96Smrg    com->length += com->table.num_bytecodes * sizeof(unsigned char*);
27905dfecf96Smrg    com->length += com->table.num_bytecodes * sizeof(LispObj*);
27915dfecf96Smrg
27925dfecf96Smrg    /* Allocate space for the bytecode stream */
27935dfecf96Smrg    com->length += com->block->tail->offset + 1;
27945dfecf96Smrg    com->bytecode = LispMalloc(com->length);
27955dfecf96Smrg
27965dfecf96Smrg    /* Add header */
27975dfecf96Smrg    offset = 0;
27985dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.stack;
27995dfecf96Smrg    offset += sizeof(short);
28005dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.bstack;
28015dfecf96Smrg    offset += sizeof(short);
28025dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.pstack;
28035dfecf96Smrg    offset += sizeof(short);
28045dfecf96Smrg
28055dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_constants;
28065dfecf96Smrg    offset += sizeof(short);
28075dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_symbols;
28085dfecf96Smrg    offset += sizeof(short);
28095dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_builtins;
28105dfecf96Smrg    offset += sizeof(short);
28115dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_bytecodes;
28125dfecf96Smrg    offset += sizeof(short);
28135dfecf96Smrg
28145dfecf96Smrg    count = sizeof(LispObj*) * com->table.num_constants;
28155dfecf96Smrg    memcpy(com->bytecode + offset, com->table.constants, count);
28165dfecf96Smrg    offset += count;
28175dfecf96Smrg    count = sizeof(LispAtom*) * com->table.num_symbols;
28185dfecf96Smrg    memcpy(com->bytecode + offset, com->table.symbols, count);
28195dfecf96Smrg    offset += count;
28205dfecf96Smrg    count = sizeof(LispBuiltin*) * com->table.num_builtins;
28215dfecf96Smrg    memcpy(com->bytecode + offset, com->table.builtins, count);
28225dfecf96Smrg    offset += count;
28235dfecf96Smrg
28245dfecf96Smrg    /* Store bytecode information */
28255dfecf96Smrg    for (count = 0, codes = (unsigned char**)(com->bytecode + offset);
28265dfecf96Smrg	 count < com->table.num_bytecodes; count++, codes++)
28275dfecf96Smrg	*codes = com->table.bytecodes[count]->data.bytecode.bytecode->code;
28285dfecf96Smrg    offset += com->table.num_bytecodes * sizeof(unsigned char*);
28295dfecf96Smrg    /* Store names, only useful for disassemble but may also be used
28305dfecf96Smrg     * to check if a function was redefined, and the bytecode is referencing
28315dfecf96Smrg     * the older version, the current version can be checked looking at
28325dfecf96Smrg     * <name>->data.atom */
28335dfecf96Smrg    for (count = 0, names = (LispObj**)(com->bytecode + offset);
28345dfecf96Smrg	 count < com->table.num_bytecodes; count++, names++)
28355dfecf96Smrg	*names = com->table.bytecodes[count]->data.bytecode.name;
28365dfecf96Smrg    offset += com->table.num_bytecodes * sizeof(LispObj*);
28375dfecf96Smrg
28385dfecf96Smrg    /* Generate it */
28395dfecf96Smrg    LinkEmmitBytecode(com, com->block->tree, com->bytecode + offset, 0);
28405dfecf96Smrg}
28415dfecf96Smrg
28425dfecf96Smrgstatic LispObj *
28435dfecf96SmrgExecuteBytecode(register unsigned char *stream)
28445dfecf96Smrg{
28455dfecf96Smrg    register LispObj *reg0;
28465dfecf96Smrg    register LispAtom *atom;
28475dfecf96Smrg    register short offset;
28485dfecf96Smrg    LispObj *reg1;
28495dfecf96Smrg    LispBuiltin *builtin;
28505dfecf96Smrg    LispObj *lambda;
28515dfecf96Smrg    LispObj *arguments;
28525dfecf96Smrg    unsigned char *bytecode;
28535dfecf96Smrg
28545dfecf96Smrg    LispObj **constants;
28555dfecf96Smrg    LispAtom **symbols;
28565dfecf96Smrg    LispBuiltin **builtins;
28575dfecf96Smrg    unsigned char **codes;
28585dfecf96Smrg    short num_constants, num_symbols, num_builtins, num_codes;
28595dfecf96Smrg
28605dfecf96Smrg    int lex, len;
28615dfecf96Smrg
28625dfecf96Smrg    /* To control gc protected slots */
28635dfecf96Smrg    int phead, pbase;
28645dfecf96Smrg
28655dfecf96Smrg    long fixnum = 0;
28665dfecf96Smrg
28675dfecf96Smrg#if defined(__GNUC__) && !defined(ANSI_SOURCE)
28685dfecf96Smrg#define ALLOW_GOTO_ADDRESS
28695dfecf96Smrg#endif
28705dfecf96Smrg
28715dfecf96Smrg#ifdef ALLOW_GOTO_ADDRESS
28725dfecf96Smrg#define JUMP_ADDRESS(label)	&&label
28735dfecf96Smrg    static const void *opcode_labels[] = {
28745dfecf96Smrg	JUMP_ADDRESS(XBC_NOOP),
28755dfecf96Smrg	JUMP_ADDRESS(XBC_INV),
28765dfecf96Smrg	JUMP_ADDRESS(XBC_NIL),
28775dfecf96Smrg	JUMP_ADDRESS(XBC_T),
28785dfecf96Smrg	JUMP_ADDRESS(XBC_PRED),
28795dfecf96Smrg	JUMP_ADDRESS(XBC_CAR),
28805dfecf96Smrg	JUMP_ADDRESS(XBC_CDR),
28815dfecf96Smrg	JUMP_ADDRESS(XBC_CAR_SET),
28825dfecf96Smrg	JUMP_ADDRESS(XBC_CDR_SET),
28835dfecf96Smrg	JUMP_ADDRESS(XBC_RPLACA),
28845dfecf96Smrg	JUMP_ADDRESS(XBC_RPLACD),
28855dfecf96Smrg	JUMP_ADDRESS(XBC_EQ),
28865dfecf96Smrg	JUMP_ADDRESS(XBC_EQL),
28875dfecf96Smrg	JUMP_ADDRESS(XBC_EQUAL),
28885dfecf96Smrg	JUMP_ADDRESS(XBC_EQUALP),
28895dfecf96Smrg	JUMP_ADDRESS(XBC_LENGTH),
28905dfecf96Smrg	JUMP_ADDRESS(XBC_LAST),
28915dfecf96Smrg	JUMP_ADDRESS(XBC_NTHCDR),
28925dfecf96Smrg	JUMP_ADDRESS(XBC_CAR_PUSH),
28935dfecf96Smrg	JUMP_ADDRESS(XBC_CDR_PUSH),
28945dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH),
28955dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_NIL),
28965dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_UNSPEC),
28975dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_T),
28985dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_NIL_N),
28995dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_UNSPEC_N),
29005dfecf96Smrg	JUMP_ADDRESS(XBC_LET),
29015dfecf96Smrg	JUMP_ADDRESS(XBC_LETX),
29025dfecf96Smrg	JUMP_ADDRESS(XBC_LET_NIL),
29035dfecf96Smrg	JUMP_ADDRESS(XBC_LETX_NIL),
29045dfecf96Smrg	JUMP_ADDRESS(XBC_LETBIND),
29055dfecf96Smrg	JUMP_ADDRESS(XBC_UNLET),
29065dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD),
29075dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_LET),
29085dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_LETX),
29095dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_PUSH),
29105dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON),
29115dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_LET),
29125dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_LETX),
29135dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_PUSH),
29145dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR),
29155dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR),
29165dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR_STORE),
29175dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR_STORE),
29185dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_SET),
29195dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM),
29205dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_LET),
29215dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_LETX),
29225dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_PUSH),
29235dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_SET),
29245dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR_SET),
29255dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR_SET),
29265dfecf96Smrg	JUMP_ADDRESS(XBC_SET),
29275dfecf96Smrg	JUMP_ADDRESS(XBC_SETSYM),
29285dfecf96Smrg	JUMP_ADDRESS(XBC_SET_NIL),
29295dfecf96Smrg	JUMP_ADDRESS(XBC_CALL),
29305dfecf96Smrg	JUMP_ADDRESS(XBC_CALL_SET),
29315dfecf96Smrg	JUMP_ADDRESS(XBC_BYTECALL),
29325dfecf96Smrg	JUMP_ADDRESS(XBC_FUNCALL),
29335dfecf96Smrg	JUMP_ADDRESS(XBC_LETREC),
29345dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS),
29355dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS1),
29365dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS2),
29375dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS3),
29385dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS4),
29395dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS5),
29405dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS6),
29415dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS7),
29425dfecf96Smrg	JUMP_ADDRESS(XBC_CCONS),
29435dfecf96Smrg	JUMP_ADDRESS(XBC_CSTAR),
29445dfecf96Smrg	JUMP_ADDRESS(XBC_CFINI),
29455dfecf96Smrg	JUMP_ADDRESS(XBC_LSTAR),
29465dfecf96Smrg	JUMP_ADDRESS(XBC_LCONS),
29475dfecf96Smrg	JUMP_ADDRESS(XBC_LFINI),
29485dfecf96Smrg	JUMP_ADDRESS(XBC_JUMP),
29495dfecf96Smrg	JUMP_ADDRESS(XBC_JUMPT),
29505dfecf96Smrg	JUMP_ADDRESS(XBC_JUMPNIL),
29515dfecf96Smrg	JUMP_ADDRESS(XBC_STRUCT),
29525dfecf96Smrg	JUMP_ADDRESS(XBC_STRUCTP),
29535dfecf96Smrg	JUMP_ADDRESS(XBC_RETURN)
29545dfecf96Smrg    };
29555dfecf96Smrg    static const void *predicate_opcode_labels[] = {
29565dfecf96Smrg	JUMP_ADDRESS(XBP_CONSP),
29575dfecf96Smrg	JUMP_ADDRESS(XBP_LISTP),
29585dfecf96Smrg	JUMP_ADDRESS(XBP_NUMBERP)
29595dfecf96Smrg    };
29605dfecf96Smrg#endif
29615dfecf96Smrg
29625dfecf96Smrg    reg0 = NIL;
29635dfecf96Smrg
29645dfecf96Smrg    bytecode = stream;
29655dfecf96Smrg    pbase = lisp__data.protect.length;
29665dfecf96Smrg
29675dfecf96Smrg    /* stack */
29685dfecf96Smrg    offset = *(short*)stream;
29695dfecf96Smrg    stream += sizeof(short);
29705dfecf96Smrg    if (lisp__data.env.length + offset > lisp__data.env.space) {
29715dfecf96Smrg	do
29725dfecf96Smrg	    LispMoreEnvironment();
29735dfecf96Smrg	while (lisp__data.env.length + offset >= lisp__data.env.space);
29745dfecf96Smrg    }
29755dfecf96Smrg    /* builtin stack */
29765dfecf96Smrg    offset = *(short*)stream;
29775dfecf96Smrg    stream += sizeof(short);
29785dfecf96Smrg    if (lisp__data.stack.length + offset >= lisp__data.stack.space) {
29795dfecf96Smrg	do
29805dfecf96Smrg	    LispMoreStack();
29815dfecf96Smrg	while (lisp__data.stack.length + offset >= lisp__data.stack.space);
29825dfecf96Smrg    }
29835dfecf96Smrg    /* protect stack */
29845dfecf96Smrg    phead = *(short*)stream;
29855dfecf96Smrg    stream += sizeof(short);
29865dfecf96Smrg    if (lisp__data.protect.length + phead > lisp__data.protect.space) {
29875dfecf96Smrg	do
29885dfecf96Smrg	    LispMoreProtects();
29895dfecf96Smrg	while (lisp__data.protect.length + phead >= lisp__data.protect.space);
29905dfecf96Smrg    }
29915dfecf96Smrg
29925dfecf96Smrg    num_constants = *(short*)stream;
29935dfecf96Smrg    stream += sizeof(short);
29945dfecf96Smrg    num_symbols = *(short*)stream;
29955dfecf96Smrg    stream += sizeof(short);
29965dfecf96Smrg    num_builtins = *(short*)stream;
29975dfecf96Smrg    stream += sizeof(short);
29985dfecf96Smrg    num_codes = *(short*)stream;
29995dfecf96Smrg    stream += sizeof(short);
30005dfecf96Smrg
30015dfecf96Smrg    constants = (LispObj**)stream;
30025dfecf96Smrg    stream += num_constants * sizeof(LispObj*);
30035dfecf96Smrg    symbols = (LispAtom**)stream;
30045dfecf96Smrg    stream += num_symbols * sizeof(LispAtom*);
30055dfecf96Smrg    builtins = (LispBuiltin**)stream;
30065dfecf96Smrg    stream += num_builtins * sizeof(LispBuiltin*);
30075dfecf96Smrg    codes = (unsigned char**)stream;
30085dfecf96Smrg    stream += num_codes * (sizeof(unsigned char*) + sizeof(LispObj*));
30095dfecf96Smrg
30105dfecf96Smrg    for (; phead > 0; phead--)
30115dfecf96Smrg	lisp__data.protect.objects[lisp__data.protect.length++] = NIL;
30125dfecf96Smrg    phead = pbase;
30135dfecf96Smrg
30145dfecf96Smrg#ifdef ALLOW_GOTO_ADDRESS
30155dfecf96Smrg#define OPCODE_LABEL(label)	label
30165dfecf96Smrg#define NEXT_OPCODE()		goto *opcode_labels[*stream++]
30175dfecf96Smrg#define GOTO_PREDICATE()	goto *predicate_opcode_labels[*stream++]
30185dfecf96Smrg#else
30195dfecf96Smrg#define OPCODE_LABEL(label)	case label
30205dfecf96Smrg#define NEXT_OPCODE()		goto next_opcode
30215dfecf96Smrg#define GOTO_PREDICATE()	goto predicate_label
30225dfecf96Smrg    for (;;) {
30235dfecf96Smrgnext_opcode:
30245dfecf96Smrg	switch (*stream++) {
30255dfecf96Smrg#endif	/* ALLOW_GOTO_ADDRESS */
30265dfecf96Smrg
30275dfecf96SmrgOPCODE_LABEL(XBC_NOOP):
30285dfecf96Smrg	NEXT_OPCODE();
30295dfecf96Smrg
30305dfecf96SmrgOPCODE_LABEL(XBC_PRED):
30315dfecf96Smrg	GOTO_PREDICATE();
30325dfecf96Smrg
30335dfecf96SmrgOPCODE_LABEL(XBC_INV):
30345dfecf96Smrg	reg0 = reg0 == NIL ? T : NIL;
30355dfecf96Smrg	NEXT_OPCODE();
30365dfecf96Smrg
30375dfecf96SmrgOPCODE_LABEL(XBC_NIL):
30385dfecf96Smrg	reg0 = NIL;
30395dfecf96Smrg	NEXT_OPCODE();
30405dfecf96Smrg
30415dfecf96SmrgOPCODE_LABEL(XBC_T):
30425dfecf96Smrg	reg0 = T;
30435dfecf96Smrg	NEXT_OPCODE();
30445dfecf96Smrg
30455dfecf96SmrgOPCODE_LABEL(XBC_CAR):
30465dfecf96Smrgcar:
30475dfecf96Smrg	if (reg0 != NIL) {
30485dfecf96Smrg	    if (!CONSP(reg0))
30495dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
30505dfecf96Smrg	    reg0 = CAR(reg0);
30515dfecf96Smrg	}
30525dfecf96Smrg	NEXT_OPCODE();
30535dfecf96Smrg
30545dfecf96SmrgOPCODE_LABEL(XBC_CDR):
30555dfecf96Smrgcdr:
30565dfecf96Smrg	if (reg0 != NIL) {
30575dfecf96Smrg	    if (!CONSP(reg0))
30585dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
30595dfecf96Smrg	    reg0 = CDR(reg0);
30605dfecf96Smrg	}
30615dfecf96Smrg	NEXT_OPCODE();
30625dfecf96Smrg
30635dfecf96SmrgOPCODE_LABEL(XBC_RPLACA):
30645dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
30655dfecf96Smrg	if (!CONSP(reg1))
30665dfecf96Smrg	    LispDestroy("RPLACA: %s is not a cons", STROBJ(reg1));
30675dfecf96Smrg	RPLACA(reg1, reg0);
30685dfecf96Smrg	reg0 = reg1;
30695dfecf96Smrg	NEXT_OPCODE();
30705dfecf96Smrg
30715dfecf96SmrgOPCODE_LABEL(XBC_RPLACD):
30725dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
30735dfecf96Smrg	if (!CONSP(reg1))
30745dfecf96Smrg	    LispDestroy("RPLACD: %s is not a cons", STROBJ(reg1));
30755dfecf96Smrg	RPLACD(reg1, reg0);
30765dfecf96Smrg	reg0 = reg1;
30775dfecf96Smrg	NEXT_OPCODE();
30785dfecf96Smrg
30795dfecf96SmrgOPCODE_LABEL(XBC_BCONS):
30805dfecf96Smrg	CAR(cons) = reg0;
30815dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = cons;
30825dfecf96Smrg	NEXT_OPCODE();
30835dfecf96Smrg
30845dfecf96SmrgOPCODE_LABEL(XBC_BCONS1):
30855dfecf96Smrg	offset = lisp__data.stack.length - 1;
30865dfecf96Smrg	CAR(cons) = reg0;
30875dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[offset];
30885dfecf96Smrg	lisp__data.stack.values[offset] = cons1;
30895dfecf96Smrg	NEXT_OPCODE();
30905dfecf96Smrg
30915dfecf96SmrgOPCODE_LABEL(XBC_BCONS2):
30925dfecf96Smrg	offset = lisp__data.stack.length;
30935dfecf96Smrg	CAR(cons) = reg0;
30945dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
30955dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
30965dfecf96Smrg	lisp__data.stack.values[offset] = cons2;
30975dfecf96Smrg	lisp__data.stack.length = offset + 1;
30985dfecf96Smrg	NEXT_OPCODE();
30995dfecf96Smrg
31005dfecf96SmrgOPCODE_LABEL(XBC_BCONS3):
31015dfecf96Smrg	offset = lisp__data.stack.length;
31025dfecf96Smrg	CAR(cons) = reg0;
31035dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31045dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31055dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31065dfecf96Smrg	lisp__data.stack.values[offset] = cons3;
31075dfecf96Smrg	lisp__data.stack.length = offset + 1;
31085dfecf96Smrg	NEXT_OPCODE();
31095dfecf96Smrg
31105dfecf96SmrgOPCODE_LABEL(XBC_BCONS4):
31115dfecf96Smrg	offset = lisp__data.stack.length;
31125dfecf96Smrg	CAR(cons) = reg0;
31135dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31145dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31155dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31165dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31175dfecf96Smrg	lisp__data.stack.values[offset] = cons4;
31185dfecf96Smrg	lisp__data.stack.length = offset + 1;
31195dfecf96Smrg	NEXT_OPCODE();
31205dfecf96Smrg
31215dfecf96SmrgOPCODE_LABEL(XBC_BCONS5):
31225dfecf96Smrg	offset = lisp__data.stack.length;
31235dfecf96Smrg	CAR(cons) = reg0;
31245dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31255dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31265dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31275dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31285dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31295dfecf96Smrg	lisp__data.stack.values[offset] = cons5;
31305dfecf96Smrg	lisp__data.stack.length = offset + 1;
31315dfecf96Smrg	NEXT_OPCODE();
31325dfecf96Smrg
31335dfecf96SmrgOPCODE_LABEL(XBC_BCONS6):
31345dfecf96Smrg	offset = lisp__data.stack.length;
31355dfecf96Smrg	CAR(cons) = reg0;
31365dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31375dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31385dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31395dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31405dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31415dfecf96Smrg	CAR(cons6) = lisp__data.stack.values[--offset];
31425dfecf96Smrg	lisp__data.stack.values[offset] = cons6;
31435dfecf96Smrg	lisp__data.stack.length = offset + 1;
31445dfecf96Smrg	NEXT_OPCODE();
31455dfecf96Smrg
31465dfecf96SmrgOPCODE_LABEL(XBC_BCONS7):
31475dfecf96Smrg	offset = lisp__data.stack.length;
31485dfecf96Smrg	CAR(cons) = reg0;
31495dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31505dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31515dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31525dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31535dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31545dfecf96Smrg	CAR(cons6) = lisp__data.stack.values[--offset];
31555dfecf96Smrg	CAR(cons7) = lisp__data.stack.values[--offset];
31565dfecf96Smrg	lisp__data.stack.values[offset] = cons7;
31575dfecf96Smrg	lisp__data.stack.length = offset + 1;
31585dfecf96Smrg	NEXT_OPCODE();
31595dfecf96Smrg
31605dfecf96SmrgOPCODE_LABEL(XBC_EQ):
31615dfecf96Smrg	reg0 = reg0 == lisp__data.stack.values[--lisp__data.stack.length] ? T : NIL;
31625dfecf96Smrg	NEXT_OPCODE();
31635dfecf96Smrg
31645dfecf96SmrgOPCODE_LABEL(XBC_EQL):
31655dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31665dfecf96Smrg	reg0 = XEQL(reg1, reg0);
31675dfecf96Smrg	NEXT_OPCODE();
31685dfecf96Smrg
31695dfecf96SmrgOPCODE_LABEL(XBC_EQUAL):
31705dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31715dfecf96Smrg	reg0 = XEQUAL(reg1, reg0);
31725dfecf96Smrg	NEXT_OPCODE();
31735dfecf96Smrg
31745dfecf96SmrgOPCODE_LABEL(XBC_EQUALP):
31755dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31765dfecf96Smrg	reg0 = XEQUALP(reg1, reg0);
31775dfecf96Smrg	NEXT_OPCODE();
31785dfecf96Smrg
31795dfecf96SmrgOPCODE_LABEL(XBC_LENGTH):
31805dfecf96Smrg	reg0 = FIXNUM(LispLength(reg0));
31815dfecf96Smrg	NEXT_OPCODE();
31825dfecf96Smrg
31835dfecf96SmrgOPCODE_LABEL(XBC_LAST):
31845dfecf96Smrg    {
31855dfecf96Smrg	long length;
31865dfecf96Smrg
31875dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31885dfecf96Smrg	if (CONSP(reg1)) {
31895dfecf96Smrg	    if (reg0 != NIL) {
31905dfecf96Smrg		if (!FIXNUMP(reg0) || (fixnum = FIXNUM_VALUE(reg0)) < 0)
31915dfecf96Smrg		    LispDestroy("LAST: %s is not a positive fixnum",
31925dfecf96Smrg				STROBJ(reg0));
31935dfecf96Smrg	    }
31945dfecf96Smrg	    else
31955dfecf96Smrg		fixnum = 1;
31965dfecf96Smrg	    reg0 = reg1;
31975dfecf96Smrg	    for (reg0 = reg1, length = 0;
31985dfecf96Smrg		 CONSP(reg0);
31995dfecf96Smrg		 reg0 = CDR(reg0), length++)
32005dfecf96Smrg		;
32015dfecf96Smrg	    for (length -= fixnum, reg0 = reg1; length > 0; length--)
32025dfecf96Smrg		reg0 = CDR(reg0);
32035dfecf96Smrg	}
32045dfecf96Smrg	else
32055dfecf96Smrg	    reg0 = reg1;
32065dfecf96Smrg    }	NEXT_OPCODE();
32075dfecf96Smrg
32085dfecf96SmrgOPCODE_LABEL(XBC_NTHCDR):
32095dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
32105dfecf96Smrg	if (!FIXNUMP(reg1) || (fixnum = FIXNUM_VALUE(reg1)) < 0)
32115dfecf96Smrg	    LispDestroy("NTHCDR: %s is not a positive fixnum",
32125dfecf96Smrg			STROBJ(reg1));
32135dfecf96Smrg	if (reg0 != NIL) {
32145dfecf96Smrg	    if (!CONSP(reg0))
32155dfecf96Smrg		LispDestroy("NTHCDR: %s is not a list", STROBJ(reg0));
32165dfecf96Smrg	    for (; fixnum > 0; fixnum--) {
32175dfecf96Smrg		if (!CONSP(reg0))
32185dfecf96Smrg		    break;
32195dfecf96Smrg		reg0 = CDR(reg0);
32205dfecf96Smrg	    }
32215dfecf96Smrg	}
32225dfecf96Smrg	NEXT_OPCODE();
32235dfecf96Smrg
32245dfecf96Smrg	/* Push to builtin stack */
32255dfecf96SmrgOPCODE_LABEL(XBC_CAR_PUSH):
32265dfecf96Smrg	if (reg0 != NIL) {
32275dfecf96Smrg	    if (!CONSP(reg0))
32285dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
32295dfecf96Smrg	    reg0 = CAR(reg0);
32305dfecf96Smrg	}
32315dfecf96Smrg	goto push_builtin;
32325dfecf96Smrg
32335dfecf96SmrgOPCODE_LABEL(XBC_CDR_PUSH):
32345dfecf96Smrg	if (reg0 != NIL) {
32355dfecf96Smrg	    if (!CONSP(reg0))
32365dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
32375dfecf96Smrg	    reg0 = CDR(reg0);
32385dfecf96Smrg	}
32395dfecf96Smrg	/*FALLTROUGH*/
32405dfecf96Smrg
32415dfecf96SmrgOPCODE_LABEL(XBC_PUSH):
32425dfecf96Smrgpush_builtin:
32435dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
32445dfecf96Smrg	NEXT_OPCODE();
32455dfecf96Smrg
32465dfecf96SmrgOPCODE_LABEL(XBC_PUSH_NIL):
32475dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = NIL;
32485dfecf96Smrg	NEXT_OPCODE();
32495dfecf96Smrg
32505dfecf96SmrgOPCODE_LABEL(XBC_PUSH_UNSPEC):
32515dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC;
32525dfecf96Smrg	NEXT_OPCODE();
32535dfecf96Smrg
32545dfecf96SmrgOPCODE_LABEL(XBC_PUSH_T):
32555dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = T;
32565dfecf96Smrg	NEXT_OPCODE();
32575dfecf96Smrg
32585dfecf96SmrgOPCODE_LABEL(XBC_PUSH_NIL_N):
32595dfecf96Smrg	for (offset = *stream++; offset > 0; offset--)
32605dfecf96Smrg	    lisp__data.stack.values[lisp__data.stack.length++] = NIL;
32615dfecf96Smrg	NEXT_OPCODE();
32625dfecf96Smrg
32635dfecf96SmrgOPCODE_LABEL(XBC_PUSH_UNSPEC_N):
32645dfecf96Smrg	for (offset = *stream++; offset > 0; offset--)
32655dfecf96Smrg	    lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC;
32665dfecf96Smrg	NEXT_OPCODE();
32675dfecf96Smrg
32685dfecf96SmrgOPCODE_LABEL(XBC_LET):
32695dfecf96Smrglet_argument:
32705dfecf96Smrg	/*  The global object value is not changed, so it does not
32715dfecf96Smrg	 * matter if it is a constant symbol. An error would be
32725dfecf96Smrg	 * generated if it was declared as constant at the time of
32735dfecf96Smrg	 * bytecode generation. Check can be done looking at the
32745dfecf96Smrg	 * atom->constant field. */
32755dfecf96Smrg	atom = symbols[*stream++];
32765dfecf96Smrg	atom->offset = lisp__data.env.length;
32775dfecf96Smrg	lisp__data.env.names[lisp__data.env.length] = atom->string;
32785dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = reg0;
32795dfecf96Smrg	NEXT_OPCODE();
32805dfecf96Smrg
32815dfecf96SmrgOPCODE_LABEL(XBC_LETX):
32825dfecf96Smrgletx_argument:
32835dfecf96Smrg	atom = symbols[*stream++];
32845dfecf96Smrg	atom->offset = lisp__data.env.length;
32855dfecf96Smrg	lisp__data.env.names[lisp__data.env.length] = atom->string;
32865dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = reg0;
32875dfecf96Smrg	lisp__data.env.head++;
32885dfecf96Smrg	NEXT_OPCODE();
32895dfecf96Smrg
32905dfecf96SmrgOPCODE_LABEL(XBC_LET_NIL):
32915dfecf96Smrg	atom = symbols[*stream++];
32925dfecf96Smrg	atom->offset = lisp__data.env.length;
32935dfecf96Smrg	lisp__data.env.names[lisp__data.env.length] = atom->string;
32945dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = NIL;
32955dfecf96Smrg	NEXT_OPCODE();
32965dfecf96Smrg
32975dfecf96SmrgOPCODE_LABEL(XBC_LETX_NIL):
32985dfecf96Smrg	atom = symbols[*stream++];
32995dfecf96Smrg	atom->offset = lisp__data.env.length;
33005dfecf96Smrg	lisp__data.env.names[lisp__data.env.length] = atom->string;
33015dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = NIL;
33025dfecf96Smrg	lisp__data.env.head++;
33035dfecf96Smrg	NEXT_OPCODE();
33045dfecf96Smrg
33055dfecf96Smrg	/* Bind locally added variables to a block */
33065dfecf96SmrgOPCODE_LABEL(XBC_LETBIND):
33075dfecf96Smrg	offset = *stream++;
33085dfecf96Smrg	lisp__data.env.head += offset;
33095dfecf96Smrg	NEXT_OPCODE();
33105dfecf96Smrg
33115dfecf96Smrg	/* Unbind locally added variables to a block */
33125dfecf96SmrgOPCODE_LABEL(XBC_UNLET):
33135dfecf96Smrg	offset = *stream++;
33145dfecf96Smrg	lisp__data.env.head -= offset;
33155dfecf96Smrg	lisp__data.env.length -= offset;
33165dfecf96Smrg	NEXT_OPCODE();
33175dfecf96Smrg
33185dfecf96Smrg	/* Load value from stack */
33195dfecf96SmrgOPCODE_LABEL(XBC_LOAD):
33205dfecf96Smrg	offset = *stream++;
33215dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33225dfecf96Smrg	NEXT_OPCODE();
33235dfecf96Smrg
33245dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR):
33255dfecf96Smrg	offset = *stream++;
33265dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33275dfecf96Smrg	goto car;
33285dfecf96Smrg
33295dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR):
33305dfecf96Smrg	offset = *stream++;
33315dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33325dfecf96Smrg	goto cdr;
33335dfecf96Smrg
33345dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR_STORE):
33355dfecf96Smrg	offset = *stream++;
33365dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33375dfecf96Smrg	if (reg0 != NIL) {
33385dfecf96Smrg	    if (!CONSP(reg0))
33395dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
33405dfecf96Smrg	    reg0 = CAR(reg0);
33415dfecf96Smrg	    lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33425dfecf96Smrg	}
33435dfecf96Smrg	NEXT_OPCODE();
33445dfecf96Smrg
33455dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR_STORE):
33465dfecf96Smrg	offset = *stream++;
33475dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33485dfecf96Smrg	if (reg0 != NIL) {
33495dfecf96Smrg	    if (!CONSP(reg0))
33505dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
33515dfecf96Smrg	    reg0 = CDR(reg0);
33525dfecf96Smrg	    lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33535dfecf96Smrg	}
33545dfecf96Smrg	NEXT_OPCODE();
33555dfecf96Smrg
33565dfecf96SmrgOPCODE_LABEL(XBC_LOAD_LET):
33575dfecf96Smrg	offset = *stream++;
33585dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33595dfecf96Smrg	goto let_argument;
33605dfecf96Smrg
33615dfecf96SmrgOPCODE_LABEL(XBC_LOAD_LETX):
33625dfecf96Smrg	offset = *stream++;
33635dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33645dfecf96Smrg	goto letx_argument;
33655dfecf96Smrg
33665dfecf96SmrgOPCODE_LABEL(XBC_LOAD_PUSH):
33675dfecf96Smrg	offset = *stream++;
33685dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33695dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
33705dfecf96Smrg	NEXT_OPCODE();
33715dfecf96Smrg
33725dfecf96Smrg	/* Load pointer to constant */
33735dfecf96SmrgOPCODE_LABEL(XBC_LOADCON):
33745dfecf96Smrg	reg0 = constants[*stream++];
33755dfecf96Smrg	NEXT_OPCODE();
33765dfecf96Smrg
33775dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_LET):
33785dfecf96Smrg	reg0 = constants[*stream++];
33795dfecf96Smrg	goto let_argument;
33805dfecf96Smrg
33815dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_LETX):
33825dfecf96Smrg	reg0 = constants[*stream++];
33835dfecf96Smrg	goto letx_argument;
33845dfecf96Smrg
33855dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_PUSH):
33865dfecf96Smrg	reg0 = constants[*stream++];
33875dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
33885dfecf96Smrg	NEXT_OPCODE();
33895dfecf96Smrg
33905dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_SET):
33915dfecf96Smrg	reg0 = constants[*stream++];
33925dfecf96Smrg	offset = *stream++;
33935dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33945dfecf96Smrg	NEXT_OPCODE();
33955dfecf96Smrg
33965dfecf96Smrg	/* Change value of local variable */
33975dfecf96SmrgOPCODE_LABEL(XBC_CAR_SET):
33985dfecf96Smrgcar_set:
33995dfecf96Smrg	if (reg0 != NIL) {
34005dfecf96Smrg	    if (!CONSP(reg0))
34015dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
34025dfecf96Smrg	    reg0 = CAR(reg0);
34035dfecf96Smrg	}
34045dfecf96Smrg	goto set_local_variable;
34055dfecf96Smrg
34065dfecf96SmrgOPCODE_LABEL(XBC_CDR_SET):
34075dfecf96Smrgcdr_set:
34085dfecf96Smrg	if (reg0 != NIL) {
34095dfecf96Smrg	    if (!CONSP(reg0))
34105dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
34115dfecf96Smrg	    reg0 = CDR(reg0);
34125dfecf96Smrg	}
34135dfecf96Smrg	goto set_local_variable;
34145dfecf96Smrg
34155dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR_SET):
34165dfecf96Smrg	offset = *stream++;
34175dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34185dfecf96Smrg	goto car_set;
34195dfecf96Smrg
34205dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR_SET):
34215dfecf96Smrg	offset = *stream++;
34225dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34235dfecf96Smrg	goto cdr_set;
34245dfecf96Smrg
34255dfecf96SmrgOPCODE_LABEL(XBC_LOAD_SET):
34265dfecf96Smrg	offset = *stream++;
34275dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34285dfecf96Smrg	/*FALLTROUGH*/
34295dfecf96Smrg
34305dfecf96SmrgOPCODE_LABEL(XBC_SET):
34315dfecf96Smrgset_local_variable:
34325dfecf96Smrg	offset = *stream++;
34335dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
34345dfecf96Smrg	NEXT_OPCODE();
34355dfecf96Smrg
34365dfecf96SmrgOPCODE_LABEL(XBC_SET_NIL):
34375dfecf96Smrg	offset = *stream++;
34385dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = NIL;
34395dfecf96Smrg	NEXT_OPCODE();
34405dfecf96Smrg
34415dfecf96Smrg	/* Change value of a global/special variable */
34425dfecf96SmrgOPCODE_LABEL(XBC_SETSYM):
34435dfecf96Smrg	    atom = symbols[*stream++];
34445dfecf96Smrg	    if (atom->dyn) {
34455dfecf96Smrg		/*  atom->dyn and atom->constant are exclusive, no
34465dfecf96Smrg		 * need to check if variable declared as constant. */
34475dfecf96Smrg		if (atom->offset < lisp__data.env.head &&
34485dfecf96Smrg		    lisp__data.env.names[atom->offset] == atom->string)
34495dfecf96Smrg		    lisp__data.env.values[atom->offset] = reg0;
34505dfecf96Smrg		else {
34515dfecf96Smrg		    if (atom->watch)
34525dfecf96Smrg			LispSetAtomObjectProperty(atom, reg0);
34535dfecf96Smrg		    else
34545dfecf96Smrg			SETVALUE(atom, reg0);
34555dfecf96Smrg		}
34565dfecf96Smrg	    }
34575dfecf96Smrg	    else if (atom->a_object) {
34585dfecf96Smrg		if (atom->constant)
34595dfecf96Smrg		    LispDestroy("EVAL: %s is a constant",
34605dfecf96Smrg				STROBJ(atom->object));
34615dfecf96Smrg		else if (atom->watch)
34625dfecf96Smrg		    LispSetAtomObjectProperty(atom, reg0);
34635dfecf96Smrg		else
34645dfecf96Smrg		    SETVALUE(atom, reg0);
34655dfecf96Smrg	    }
34665dfecf96Smrg	    else {
34675dfecf96Smrg		/* Create new global variable */
34685dfecf96Smrg		LispPackage *pack;
34695dfecf96Smrg
34705dfecf96Smrg		LispWarning("the variable %s was not declared",
34715dfecf96Smrg			    atom->string);
34725dfecf96Smrg		LispSetAtomObjectProperty(atom, reg0);
34735dfecf96Smrg		pack = atom->package->data.package.package;
34745dfecf96Smrg		if (pack->glb.length >= pack->glb.space)
34755dfecf96Smrg		    LispMoreGlobals(pack);
34765dfecf96Smrg		pack->glb.pairs[pack->glb.length++] = atom->object;
34775dfecf96Smrg	    }
34785dfecf96Smrg	    NEXT_OPCODE();
34795dfecf96Smrg
34805dfecf96Smrg/* Resolve symbol value at runtime */
34815dfecf96Smrg#define LOAD_SYMBOL_VALUE()					    \
34825dfecf96Smrg    atom = symbols[*stream++];					    \
34835dfecf96Smrg    if (atom->dyn) {						    \
34845dfecf96Smrg	if (atom->offset < lisp__data.env.head &&		    \
34855dfecf96Smrg	    lisp__data.env.names[atom->offset] == atom->string)	    \
34865dfecf96Smrg	    reg0 = lisp__data.env.values[atom->offset];		    \
34875dfecf96Smrg	else {							    \
34885dfecf96Smrg	    reg0 = atom->property->value;			    \
34895dfecf96Smrg	    if (reg0 == UNBOUND)				    \
34905dfecf96Smrg		LispDestroy("EVAL: the symbol %s is unbound",  \
34915dfecf96Smrg			    STROBJ(atom->object));		    \
34925dfecf96Smrg	}							    \
34935dfecf96Smrg    }								    \
34945dfecf96Smrg    else {							    \
34955dfecf96Smrg	if (atom->a_object)					    \
34965dfecf96Smrg	    reg0 = atom->property->value;			    \
34975dfecf96Smrg	else							    \
34985dfecf96Smrg	    LispDestroy("EVAL: the symbol %s is unbound",	    \
34995dfecf96Smrg			STROBJ(atom->object));			    \
35005dfecf96Smrg    }
35015dfecf96Smrg
35025dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM):
35035dfecf96Smrg	LOAD_SYMBOL_VALUE();
35045dfecf96Smrg	NEXT_OPCODE();
35055dfecf96Smrg
35065dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_LET):
35075dfecf96Smrg	LOAD_SYMBOL_VALUE();
35085dfecf96Smrg	goto let_argument;
35095dfecf96Smrg
35105dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_LETX):
35115dfecf96Smrg	LOAD_SYMBOL_VALUE();
35125dfecf96Smrg	goto letx_argument;
35135dfecf96Smrg
35145dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_PUSH):
35155dfecf96Smrg	LOAD_SYMBOL_VALUE();
35165dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
35175dfecf96Smrg	NEXT_OPCODE();
35185dfecf96Smrg
35195dfecf96Smrg	    /* Builtin function */
35205dfecf96SmrgOPCODE_LABEL(XBC_CALL):
35215dfecf96Smrg	offset = *stream++;
35225dfecf96Smrg	lisp__data.stack.base = lisp__data.stack.length - offset;
35235dfecf96Smrg	builtin = builtins[*stream++];
35245dfecf96Smrg	if (builtin->multiple_values) {
35255dfecf96Smrg	    RETURN_COUNT = 0;
35265dfecf96Smrg	    reg0 = builtin->function(builtin);
35275dfecf96Smrg	}
35285dfecf96Smrg	else {
35295dfecf96Smrg	    reg0 = builtin->function(builtin);
35305dfecf96Smrg	    RETURN_COUNT = 0;
35315dfecf96Smrg	}
35325dfecf96Smrg	lisp__data.stack.length -= offset;
35335dfecf96Smrg	NEXT_OPCODE();
35345dfecf96Smrg
35355dfecf96SmrgOPCODE_LABEL(XBC_CALL_SET):
35365dfecf96Smrg	offset = *stream++;
35375dfecf96Smrg	lisp__data.stack.base = lisp__data.stack.length - offset;
35385dfecf96Smrg	builtin = builtins[*stream++];
35395dfecf96Smrg	if (builtin->multiple_values) {
35405dfecf96Smrg	    RETURN_COUNT = 0;
35415dfecf96Smrg	    reg0 = builtin->function(builtin);
35425dfecf96Smrg	}
35435dfecf96Smrg	else {
35445dfecf96Smrg	    reg0 = builtin->function(builtin);
35455dfecf96Smrg	    RETURN_COUNT = 0;
35465dfecf96Smrg	}
35475dfecf96Smrg	lisp__data.stack.length -= offset;
35485dfecf96Smrg	offset = *stream++;
35495dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
35505dfecf96Smrg	NEXT_OPCODE();
35515dfecf96Smrg
35525dfecf96Smrg	/* Bytecode call */
35535dfecf96SmrgOPCODE_LABEL(XBC_BYTECALL):
35545dfecf96Smrg	lex = lisp__data.env.lex;
35555dfecf96Smrg	offset = *stream++;
35565dfecf96Smrg	lisp__data.env.head = lisp__data.env.length;
35575dfecf96Smrg	len = lisp__data.env.lex = lisp__data.env.length - offset;
35585dfecf96Smrg	reg0 = ExecuteBytecode(codes[*stream++]);
35595dfecf96Smrg	lisp__data.env.length = lisp__data.env.head = len;
35605dfecf96Smrg	lisp__data.env.lex = lex;
35615dfecf96Smrg	NEXT_OPCODE();
35625dfecf96Smrg
35635dfecf96Smrg	/* Unimplemented function/macro call */
35645dfecf96SmrgOPCODE_LABEL(XBC_FUNCALL):
35655dfecf96Smrg	lambda = constants[*stream++];
35665dfecf96Smrg	arguments = constants[*stream++];
35675dfecf96Smrg	reg0 = LispFuncall(lambda, arguments, 1);
35685dfecf96Smrg	NEXT_OPCODE();
35695dfecf96Smrg
35705dfecf96SmrgOPCODE_LABEL(XBC_JUMP):
35715dfecf96Smrg	stream += *(signed short*)stream;
35725dfecf96Smrg	NEXT_OPCODE();
35735dfecf96Smrg
35745dfecf96SmrgOPCODE_LABEL(XBC_JUMPT):
35755dfecf96Smrg	if (reg0 != NIL)
35765dfecf96Smrg	    stream += *(signed short*)stream;
35775dfecf96Smrg	else
35785dfecf96Smrg	    /* skip jump relative offset */
35795dfecf96Smrg	    stream += sizeof(signed short);
35805dfecf96Smrg	NEXT_OPCODE();
35815dfecf96Smrg
35825dfecf96SmrgOPCODE_LABEL(XBC_JUMPNIL):
35835dfecf96Smrg	if (reg0 == NIL)
35845dfecf96Smrg	    stream += *(signed short*)stream;
35855dfecf96Smrg	else
35865dfecf96Smrg	    /* skip jump relative offset */
35875dfecf96Smrg	    stream += sizeof(signed short);
35885dfecf96Smrg	NEXT_OPCODE();
35895dfecf96Smrg
35905dfecf96Smrg	/* Build CONS of two constant arguments */
35915dfecf96SmrgOPCODE_LABEL(XBC_CCONS):
35925dfecf96Smrg	reg0 = constants[*stream++];
35935dfecf96Smrg	reg1 = constants[*stream++];
35945dfecf96Smrg	reg0 = CONS(reg0, reg1);
35955dfecf96Smrg	NEXT_OPCODE();
35965dfecf96Smrg
35975dfecf96Smrg	/* Start CONS */
35985dfecf96SmrgOPCODE_LABEL(XBC_CSTAR):
35995dfecf96Smrg	/* This the CAR of the CONS */
36005dfecf96Smrg	lisp__data.protect.objects[phead++] = reg0;
36015dfecf96Smrg	NEXT_OPCODE();
36025dfecf96Smrg
36035dfecf96Smrg	/* Finish CONS */
36045dfecf96SmrgOPCODE_LABEL(XBC_CFINI):
36055dfecf96Smrg	reg0 = CONS(lisp__data.protect.objects[--phead], reg0);
36065dfecf96Smrg	NEXT_OPCODE();
36075dfecf96Smrg
36085dfecf96Smrg	/* Start building list */
36095dfecf96SmrgOPCODE_LABEL(XBC_LSTAR):
36105dfecf96Smrg	reg1 = CONS(reg0, NIL);
36115dfecf96Smrg	/* Start of list stored here */
36125dfecf96Smrg	lisp__data.protect.objects[phead++] = reg1;
36135dfecf96Smrg	/* Tail of list stored here */
36145dfecf96Smrg	lisp__data.protect.objects[phead++] = reg1;
36155dfecf96Smrg	NEXT_OPCODE();
36165dfecf96Smrg
36175dfecf96Smrg	/* Add to list */
36185dfecf96SmrgOPCODE_LABEL(XBC_LCONS):
36195dfecf96Smrg	reg1 = lisp__data.protect.objects[phead - 2];
36205dfecf96Smrg	RPLACD(reg1, CONS(reg0, NIL));
36215dfecf96Smrg	 lisp__data.protect.objects[phead - 2] = CDR(reg1);
36225dfecf96Smrg	NEXT_OPCODE();
36235dfecf96Smrg
36245dfecf96Smrg	/* Finish list */
36255dfecf96SmrgOPCODE_LABEL(XBC_LFINI):
36265dfecf96Smrg	phead -= 2;
36275dfecf96Smrg	reg0 = lisp__data.protect.objects[phead + 1];
36285dfecf96Smrg	NEXT_OPCODE();
36295dfecf96Smrg
36305dfecf96SmrgOPCODE_LABEL(XBC_STRUCT):
36315dfecf96Smrg	offset = *stream++;
36325dfecf96Smrg	reg1 = constants[*stream++];
36335dfecf96Smrg	if (!STRUCTP(reg0) || reg0->data.struc.def != reg1) {
36345dfecf96Smrg	    char *name = ATOMID(CAR(reg1));
36355dfecf96Smrg
36365dfecf96Smrg	    for (reg1 = CDR(reg1); offset; offset--)
36375dfecf96Smrg		reg1 = CDR(reg1);
36385dfecf96Smrg	    LispDestroy("%s-%s: %s is not a %s",
36395dfecf96Smrg			name, ATOMID(CAR(reg1)), STROBJ(reg0), name);
36405dfecf96Smrg	}
36415dfecf96Smrg	for (reg0 = reg0->data.struc.fields; offset; offset--)
36425dfecf96Smrg	    reg0 = CDR(reg0);
36435dfecf96Smrg	reg0 = CAR(reg0);
36445dfecf96Smrg	NEXT_OPCODE();
36455dfecf96Smrg
36465dfecf96SmrgOPCODE_LABEL(XBC_STRUCTP):
36475dfecf96Smrg	reg1 = constants[*stream++];
36485dfecf96Smrg	reg0 = STRUCTP(reg0) && reg0->data.struc.def == reg1 ? T : NIL;
36495dfecf96Smrg	NEXT_OPCODE();
36505dfecf96Smrg
36515dfecf96SmrgOPCODE_LABEL(XBC_LETREC):
36525dfecf96Smrg	/* XXX could/should optimize, shouldn't need to parse
36535dfecf96Smrg	 * the bytecode header again */
36545dfecf96Smrg	lex = lisp__data.env.lex;
36555dfecf96Smrg	offset = *stream++;
36565dfecf96Smrg	lisp__data.env.head = lisp__data.env.length;
36575dfecf96Smrg	len = lisp__data.env.lex = lisp__data.env.length - offset;
36585dfecf96Smrg	reg0 = ExecuteBytecode(bytecode);
36595dfecf96Smrg	lisp__data.env.length = lisp__data.env.head = len;
36605dfecf96Smrg	lisp__data.env.lex = lex;
36615dfecf96Smrg	NEXT_OPCODE();
36625dfecf96Smrg
36635dfecf96SmrgOPCODE_LABEL(XBC_RETURN):
36645dfecf96Smrg	lisp__data.protect.length = pbase;
36655dfecf96Smrg	return (reg0);
36665dfecf96Smrg
36675dfecf96Smrg#ifndef ALLOW_GOTO_ADDRESS
36685dfecf96Smrg	}	/* end of switch */
36695dfecf96Smrg
36705dfecf96Smrgpredicate_label:
36715dfecf96Smrg	switch (*stream++) {
36725dfecf96Smrg#endif
36735dfecf96Smrg
36745dfecf96SmrgOPCODE_LABEL(XBP_CONSP):
36755dfecf96Smrg	reg0 = CONSP(reg0) ? T : NIL;
36765dfecf96Smrg	NEXT_OPCODE();
36775dfecf96Smrg
36785dfecf96SmrgOPCODE_LABEL(XBP_LISTP):
36795dfecf96Smrg	reg0 = LISTP(reg0) ? T : NIL;
36805dfecf96Smrg	NEXT_OPCODE();
36815dfecf96Smrg
36825dfecf96SmrgOPCODE_LABEL(XBP_NUMBERP):
36835dfecf96Smrg	reg0 = NUMBERP(reg0) ? T : NIL;
36845dfecf96Smrg	NEXT_OPCODE();
36855dfecf96Smrg
36865dfecf96Smrg#ifndef ALLOW_GOTO_ADDRESS
36875dfecf96Smrg	}	/* end of switch */
36885dfecf96Smrg    }
36895dfecf96Smrg#endif
36905dfecf96Smrg
36915dfecf96Smrg    /*NOTREACHED*/
36925dfecf96Smrg    return (reg0);
36935dfecf96Smrg}
3694