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)) {
554f14f4646Smrg	case LispFunction_t:
555f14f4646Smrg	    function = function->data.atom->object;
5565dfecf96Smrg	case LispAtom_t:
5575dfecf96Smrg	    name = function;
5585dfecf96Smrg	    atom = function->data.atom;
5595dfecf96Smrg	    alist = atom->property->alist;
5605dfecf96Smrg	    if (atom->a_builtin) {
5615dfecf96Smrg		xbuiltin = atom->property->fun.builtin;
5625dfecf96Smrg		macro = xbuiltin->type == LispMacro;
5635dfecf96Smrg	    }
5645dfecf96Smrg	    else if (atom->a_compiled)
5655dfecf96Smrg		bytecode = atom->property->fun.function;
5665dfecf96Smrg	    else if (atom->a_function) {
5675dfecf96Smrg		lambda = atom->property->fun.function;
5685dfecf96Smrg		macro = lambda->funtype == LispMacro;
5695dfecf96Smrg	    }
5705dfecf96Smrg	    else if (atom->a_defstruct &&
5715dfecf96Smrg		     atom->property->structure.function != STRUCT_NAME) {
5725dfecf96Smrg		if (atom->property->structure.function == STRUCT_CONSTRUCTOR)
5735dfecf96Smrg		    atom = Omake_struct->data.atom;
5745dfecf96Smrg		else if (atom->property->structure.function == STRUCT_CHECK)
5755dfecf96Smrg		    atom = Ostruct_type->data.atom;
5765dfecf96Smrg		else
5775dfecf96Smrg		    atom = Ostruct_access->data.atom;
5785dfecf96Smrg		xbuiltin = atom->property->fun.builtin;
5795dfecf96Smrg	    }
5805dfecf96Smrg	    else
5815dfecf96Smrg		LispDestroy("%s: the function %s is not defined",
5825dfecf96Smrg			    STRFUN(builtin), STROBJ(function));
5835dfecf96Smrg	    break;
5845dfecf96Smrg	case LispBytecode_t:
5855dfecf96Smrg	    name = Olambda;
5865dfecf96Smrg	    bytecode = function;
5875dfecf96Smrg	    break;
5885dfecf96Smrg	case LispLambda_t:
5895dfecf96Smrg	    name = Olambda;
5905dfecf96Smrg	    alist = (LispArgList*)function->data.lambda.name->data.opaque.data;
5915dfecf96Smrg	    break;
5925dfecf96Smrg	case LispCons_t:
5935dfecf96Smrg	    if (CAR(function) == Olambda) {
5945dfecf96Smrg		function = EVAL(function);
5955dfecf96Smrg		if (OBJECT_TYPE(function) == LispLambda_t) {
5965dfecf96Smrg		    name = Olambda;
5975dfecf96Smrg		    alist = (LispArgList*)
5985dfecf96Smrg			function->data.lambda.name->data.opaque.data;
5995dfecf96Smrg		    break;
6005dfecf96Smrg		}
6015dfecf96Smrg	    }
6025dfecf96Smrg	default:
6035dfecf96Smrg	    LispDestroy("%s: %s is not a function",
6045dfecf96Smrg			STRFUN(builtin), STROBJ(function));
6055dfecf96Smrg	    break;
6065dfecf96Smrg    }
6075dfecf96Smrg
6085dfecf96Smrg    if (xbuiltin) {
6095dfecf96Smrg	LispWriteStr(NIL, "Builtin ", 8);
6105dfecf96Smrg	if (macro)
6115dfecf96Smrg	    LispWriteStr(NIL, "macro ", 6);
6125dfecf96Smrg	else
6135dfecf96Smrg	    LispWriteStr(NIL, "function ", 9);
6145dfecf96Smrg    }
6155dfecf96Smrg    else if (macro)
6165dfecf96Smrg	LispWriteStr(NIL, "Macro ", 6);
6175dfecf96Smrg    else
6185dfecf96Smrg	LispWriteStr(NIL, "Function ", 9);
6195dfecf96Smrg    LispWriteObject(NIL, name);
6205dfecf96Smrg    LispWriteStr(NIL, ":\n", 2);
6215dfecf96Smrg
6225dfecf96Smrg    if (alist) {
6235dfecf96Smrg	int i;
6245dfecf96Smrg
6255dfecf96Smrg	sprintf(buffer, "%d required argument%s",
6265dfecf96Smrg		alist->normals.num_symbols,
6275dfecf96Smrg		alist->normals.num_symbols != 1 ? "s" : "");
6285dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6295dfecf96Smrg	for (i = 0; i < alist->normals.num_symbols; i++) {
6305dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6315dfecf96Smrg	    LispWriteChar(NIL, ' ');
632f14f4646Smrg	    LispWriteStr(NIL, ATOMID(alist->normals.symbols[i])->value,
633f14f4646Smrg			 ATOMID(alist->normals.symbols[i])->length);
6345dfecf96Smrg	}
6355dfecf96Smrg	LispWriteChar(NIL, '\n');
6365dfecf96Smrg
6375dfecf96Smrg	sprintf(buffer, "%d optional argument%s",
6385dfecf96Smrg		alist->optionals.num_symbols,
6395dfecf96Smrg		alist->optionals.num_symbols != 1 ? "s" : "");
6405dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6415dfecf96Smrg	for (i = 0; i < alist->optionals.num_symbols; i++) {
6425dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6435dfecf96Smrg	    LispWriteChar(NIL, ' ');
644f14f4646Smrg	    LispWriteStr(NIL, ATOMID(alist->optionals.symbols[i])->value,
645f14f4646Smrg			 ATOMID(alist->optionals.symbols[i])->length);
6465dfecf96Smrg	}
6475dfecf96Smrg	LispWriteChar(NIL, '\n');
6485dfecf96Smrg
6495dfecf96Smrg	sprintf(buffer, "%d keyword parameter%s",
6505dfecf96Smrg		alist->keys.num_symbols,
6515dfecf96Smrg		alist->keys.num_symbols != 1 ? "s" : "");
6525dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6535dfecf96Smrg	for (i = 0; i < alist->keys.num_symbols; i++) {
6545dfecf96Smrg	    LispWriteChar(NIL, i ? ',' : ':');
6555dfecf96Smrg	    LispWriteChar(NIL, ' ');
6565dfecf96Smrg	    LispWriteObject(NIL, alist->keys.symbols[i]);
6575dfecf96Smrg	}
6585dfecf96Smrg	LispWriteChar(NIL, '\n');
6595dfecf96Smrg
6605dfecf96Smrg	if (alist->rest) {
6615dfecf96Smrg	    LispWriteStr(NIL, "Rest argument: ", 15);
662f14f4646Smrg	    LispWriteStr(NIL, ATOMID(alist->rest)->value,
663f14f4646Smrg			 ATOMID(alist->rest)->length);
6645dfecf96Smrg	    LispWriteChar(NIL, '\n');
6655dfecf96Smrg	}
6665dfecf96Smrg	else
6675dfecf96Smrg	    LispWriteStr(NIL, "No rest argument\n", 17);
6685dfecf96Smrg    }
6695dfecf96Smrg
6705dfecf96Smrg    if (bytecode) {
671f14f4646Smrg	Atom_id id;
6725dfecf96Smrg	char *ptr;
6735dfecf96Smrg	int *offsets[4];
6745dfecf96Smrg	int i, done, j, sym0, sym1, con0, con1, bui0, byt0, strd, strf;
6755dfecf96Smrg	LispObj **constants;
6765dfecf96Smrg	LispAtom **symbols;
6775dfecf96Smrg	LispBuiltin **builtins;
6785dfecf96Smrg	LispObj **names;
6795dfecf96Smrg	short stack, num_constants, num_symbols, num_builtins, num_bytecodes;
6805dfecf96Smrg	unsigned char *base, *stream = bytecode->data.bytecode.bytecode->code;
6815dfecf96Smrg
6825dfecf96Smrg	LispWriteStr(NIL, "\nBytecode header:\n", 18);
6835dfecf96Smrg
6845dfecf96Smrg	/* Header information */
6855dfecf96Smrg	stack = *(short*)stream;
6865dfecf96Smrg	stream += sizeof(short);
6875dfecf96Smrg	sprintf(buffer, "%d element%s used in the stack\n",
6885dfecf96Smrg		stack, stack != 1 ? "s" : "");
6895dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6905dfecf96Smrg	stack = *(short*)stream;
6915dfecf96Smrg	stream += sizeof(short);
6925dfecf96Smrg	sprintf(buffer, "%d element%s used in the builtin stack\n",
6935dfecf96Smrg		stack, stack != 1 ? "s" : "");
6945dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
6955dfecf96Smrg	stack = *(short*)stream;
6965dfecf96Smrg	stream += sizeof(short);
6975dfecf96Smrg	sprintf(buffer, "%d element%s used in the protected stack\n",
6985dfecf96Smrg		stack, stack != 1 ? "s" : "");
6995dfecf96Smrg	LispWriteStr(NIL, buffer, strlen(buffer));
7005dfecf96Smrg
7015dfecf96Smrg	num_constants = *(short*)stream;
7025dfecf96Smrg	stream += sizeof(short);
7035dfecf96Smrg	num_symbols = *(short*)stream;
7045dfecf96Smrg	stream += sizeof(short);
7055dfecf96Smrg	num_builtins = *(short*)stream;
7065dfecf96Smrg	stream += sizeof(short);
7075dfecf96Smrg	num_bytecodes = *(short*)stream;
7085dfecf96Smrg	stream += sizeof(short);
7095dfecf96Smrg
7105dfecf96Smrg	constants = (LispObj**)stream;
7115dfecf96Smrg	stream += num_constants * sizeof(LispObj*);
7125dfecf96Smrg	symbols = (LispAtom**)stream;
7135dfecf96Smrg	stream += num_symbols * sizeof(LispAtom*);
7145dfecf96Smrg	builtins = (LispBuiltin**)stream;
7155dfecf96Smrg	stream += num_builtins * sizeof(LispBuiltin*);
7165dfecf96Smrg	stream += num_bytecodes * sizeof(unsigned char*);
7175dfecf96Smrg	names = (LispObj**)stream;
7185dfecf96Smrg	stream += num_bytecodes * sizeof(LispObj*);
7195dfecf96Smrg
7205dfecf96Smrg	for (i = 0; i < num_constants; i++) {
7215dfecf96Smrg	    sprintf(buffer, "Constant %d = %s\n", i, STROBJ(constants[i]));
7225dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7235dfecf96Smrg	}
7245dfecf96Smrg
7255dfecf96Smrg/* Macro XSTRING avoids some noisy in the output, if it were defined as
7265dfecf96Smrg * #define XSTRING(object) object ? STROBJ(object) : #<UNBOUND>
7275dfecf96Smrg *	and called as XSTRING(atom->object)
7285dfecf96Smrg * it would also print the package name were the symbol was first defined,
7295dfecf96Smrg * but for local variables, only the symbol string is important. */
730f14f4646Smrg#define XSTRING(key)		key ? key->value : "#<UNBOUND>"
7315dfecf96Smrg
7325dfecf96Smrg	for (i = 0; i < num_symbols; i++) {
7335dfecf96Smrg	    sprintf(buffer, "Symbol %d = %s\n",
734f14f4646Smrg		    i, XSTRING(symbols[i]->key));
7355dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7365dfecf96Smrg	}
7375dfecf96Smrg	for (i = 0; i < num_builtins; i++) {
7385dfecf96Smrg	    sprintf(buffer, "Builtin %d = %s\n",
7395dfecf96Smrg		    i, STROBJ(builtins[i]->symbol));
7405dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7415dfecf96Smrg	}
7425dfecf96Smrg	for (i = 0; i < num_bytecodes; i++) {
7435dfecf96Smrg	    sprintf(buffer, "Bytecode %d = %s\n",
7445dfecf96Smrg		    i, STROBJ(names[i]));
7455dfecf96Smrg	    LispWriteStr(NIL, buffer, strlen(buffer));
7465dfecf96Smrg	}
7475dfecf96Smrg
7485dfecf96Smrg	/*  Make readability slightly easier printing the names of local
7495dfecf96Smrg	 * variables where it's offset is known, i.e. function arguments. */
7505dfecf96Smrg	if (alist) {
7515dfecf96Smrg	    if (alist->num_arguments == 0)
7525dfecf96Smrg		LispWriteStr(NIL, "\nNo initial stack\n", 18);
7535dfecf96Smrg	    else {
7545dfecf96Smrg		int len1, len2;
7555dfecf96Smrg
7565dfecf96Smrg		j = 0;
7575dfecf96Smrg		LispWriteStr(NIL, "\nInitial stack:\n", 16);
7585dfecf96Smrg
7595dfecf96Smrg		for (i = 0; i < alist->normals.num_symbols; i++, j++) {
7605dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7615dfecf96Smrg		    LispWriteStr(NIL, buffer, strlen(buffer));
762f14f4646Smrg		    id = alist->normals.symbols[i]->data.atom->key;
763f14f4646Smrg		    LispWriteStr(NIL, id->value, id->length);
7645dfecf96Smrg		    LispWriteChar(NIL, '\n');
7655dfecf96Smrg		}
7665dfecf96Smrg
7675dfecf96Smrg		for (i = 0; i < alist->optionals.num_symbols; i++, j++) {
7685dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7695dfecf96Smrg		    LispWriteStr(NIL, buffer, strlen(buffer));
770f14f4646Smrg		    id = alist->optionals.symbols[i]->data.atom->key;
771f14f4646Smrg		    LispWriteStr(NIL, id->value, id->length);
7725dfecf96Smrg		    LispWriteChar(NIL, '\n');
7735dfecf96Smrg		    if (alist->optionals.sforms[i]) {
7745dfecf96Smrg			sprintf(buffer, "%d = ", j);
7755dfecf96Smrg			len1 = strlen(buffer);
7765dfecf96Smrg			LispWriteStr(NIL, buffer, len1);
777f14f4646Smrg			id = alist->optionals.sforms[i]->data.atom->key;
778f14f4646Smrg			len2 = id->length;
779f14f4646Smrg			LispWriteStr(NIL, id->value, len2);
7805dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
7815dfecf96Smrg			LispWriteStr(NIL, ";  sform\n", 9);
7825dfecf96Smrg			j++;
7835dfecf96Smrg		    }
7845dfecf96Smrg		}
7855dfecf96Smrg
7865dfecf96Smrg		for (i = 0; i < alist->keys.num_symbols; i++, j++) {
7875dfecf96Smrg		    sprintf(buffer, "%d = ", j);
7885dfecf96Smrg		    len1 = strlen(buffer);
7895dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
7905dfecf96Smrg		    if (alist->keys.keys[i]) {
791f14f4646Smrg			id = alist->keys.keys[i]->data.atom->key;
792f14f4646Smrg			len2 = id->length;
793f14f4646Smrg			LispWriteStr(NIL, id->value, id->length);
7945dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
7955dfecf96Smrg			LispWriteStr(NIL, ";  special key", 14);
7965dfecf96Smrg		    }
7975dfecf96Smrg		    else {
798f14f4646Smrg			id = alist->keys.symbols[i]->data.atom->key;
799f14f4646Smrg			LispWriteStr(NIL, id->value, id->length);
8005dfecf96Smrg		    }
8015dfecf96Smrg		    LispWriteChar(NIL, '\n');
8025dfecf96Smrg		    if (alist->keys.sforms[i]) {
8035dfecf96Smrg			sprintf(buffer, "%d = ", j);
8045dfecf96Smrg			len1 = strlen(buffer);
8055dfecf96Smrg			LispWriteStr(NIL, buffer, len1);
806f14f4646Smrg			id = alist->keys.sforms[i]->data.atom->key;
807f14f4646Smrg			len2 = id->length;
808f14f4646Smrg			LispWriteStr(NIL, id->value, len2);
8095dfecf96Smrg			LispWriteChars(NIL, ' ', 28 - (len1 + len2));
8105dfecf96Smrg			LispWriteStr(NIL, ";  sform\n", 9);
8115dfecf96Smrg			j++;
8125dfecf96Smrg		    }
8135dfecf96Smrg		}
8145dfecf96Smrg
8155dfecf96Smrg		if (alist->rest) {
8165dfecf96Smrg		    sprintf(buffer, "%d = ", j);
8175dfecf96Smrg		    len1 = strlen(buffer);
8185dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
819f14f4646Smrg		    id = alist->rest->data.atom->key;
820f14f4646Smrg		    len2 = id->length;
821f14f4646Smrg		    LispWriteStr(NIL, id->value, len2);
8225dfecf96Smrg		    LispWriteChar(NIL, '\n');
8235dfecf96Smrg		    j++;
8245dfecf96Smrg		}
8255dfecf96Smrg
8265dfecf96Smrg		for (i = 0; i < alist->auxs.num_symbols; i++, j++) {
8275dfecf96Smrg		    sprintf(buffer, "%d = ", j);
8285dfecf96Smrg		    len1 = strlen(buffer);
8295dfecf96Smrg		    LispWriteStr(NIL, buffer, len1);
830f14f4646Smrg		    id = alist->auxs.symbols[i]->data.atom->key;
831f14f4646Smrg		    len2 = id->length;
832f14f4646Smrg		    LispWriteStr(NIL, id->value, len2);
8335dfecf96Smrg		    LispWriteChars(NIL, ' ', 28 - (len1 + len2));
8345dfecf96Smrg		    LispWriteStr(NIL, ";  aux\n", 7);
8355dfecf96Smrg		}
8365dfecf96Smrg	    }
8375dfecf96Smrg	}
8385dfecf96Smrg
8395dfecf96Smrg	LispWriteStr(NIL, "\nBytecode stream:\n", 18);
8405dfecf96Smrg
8415dfecf96Smrg	base = stream;
8425dfecf96Smrg	for (done = j = 0; !done; j = 0) {
8435dfecf96Smrg	    sym0 = sym1 = con0 = con1 = bui0 = byt0 = strd = strf = -1;
8445dfecf96Smrg	    sprintf(buffer, "%4ld  ", (long)(stream - base));
8455dfecf96Smrg	    ptr = buffer + strlen(buffer);
8465dfecf96Smrg	    switch (*stream++) {
8475dfecf96Smrg		case XBC_NOOP:	strcpy(ptr, "NOOP");	break;
8485dfecf96Smrg		case XBC_PRED:
8495dfecf96Smrg		    strcpy(ptr, "PRED:");
8505dfecf96Smrg		    ptr += strlen(ptr);
8515dfecf96Smrg		    goto predicate;
8525dfecf96Smrg		case XBC_INV:	strcpy(ptr, "INV");	break;
8535dfecf96Smrg		case XBC_NIL:	strcpy(ptr, "NIL");	break;
8545dfecf96Smrg		case XBC_T:	strcpy(ptr, "T");	break;
8555dfecf96Smrg		case XBC_CAR:	strcpy(ptr, "CAR");	break;
8565dfecf96Smrg		case XBC_CDR:	strcpy(ptr, "CDR");	break;
8575dfecf96Smrg		case XBC_RPLACA:strcpy(ptr, "RPLACA");	break;
8585dfecf96Smrg		case XBC_RPLACD:strcpy(ptr, "RPLACD");	break;
8595dfecf96Smrg		case XBC_EQ:	strcpy(ptr, "EQ");	break;
8605dfecf96Smrg		case XBC_EQL:	strcpy(ptr, "EQL");	break;
8615dfecf96Smrg		case XBC_EQUAL:	strcpy(ptr, "EQUAL");	break;
8625dfecf96Smrg		case XBC_EQUALP:strcpy(ptr, "EQUALP");	break;
8635dfecf96Smrg		case XBC_LENGTH:strcpy(ptr, "LENGTH");	break;
8645dfecf96Smrg		case XBC_LAST:	strcpy(ptr, "LAST");	break;
8655dfecf96Smrg		case XBC_NTHCDR:strcpy(ptr, "NTHCDR");	break;
8665dfecf96Smrg		case XBC_PUSH:	strcpy(ptr, "PUSH");	break;
8675dfecf96Smrg		case XBC_CAR_PUSH:
8685dfecf96Smrg		    strcpy(ptr, "CAR&PUSH");
8695dfecf96Smrg		    break;
8705dfecf96Smrg		case XBC_CDR_PUSH:
8715dfecf96Smrg		    strcpy(ptr, "CDR&PUSH");
8725dfecf96Smrg		    break;
8735dfecf96Smrg		case XBC_PUSH_NIL:
8745dfecf96Smrg		    strcpy(ptr, "PUSH NIL");
8755dfecf96Smrg		    break;
8765dfecf96Smrg		case XBC_PUSH_UNSPEC:
8775dfecf96Smrg		    strcpy(ptr, "PUSH #<UNSPEC>");
8785dfecf96Smrg		    break;
8795dfecf96Smrg		case XBC_PUSH_T:
8805dfecf96Smrg		    strcpy(ptr, "PUSH T");
8815dfecf96Smrg		    break;
8825dfecf96Smrg		case XBC_PUSH_NIL_N:
8835dfecf96Smrg		    strcpy(ptr, "PUSH NIL ");
8845dfecf96Smrg		    ptr += strlen(ptr);
8855dfecf96Smrg		    sprintf(ptr, "%d", (int)(*stream++));
8865dfecf96Smrg		    break;
8875dfecf96Smrg		case XBC_PUSH_UNSPEC_N:
8885dfecf96Smrg		    strcpy(ptr, "PUSH #<UNSPEC> ");
8895dfecf96Smrg		    ptr += strlen(ptr);
8905dfecf96Smrg		    sprintf(ptr, "%d", (int)(*stream++));
8915dfecf96Smrg		    break;
8925dfecf96Smrg		case XBC_LET:
8935dfecf96Smrg		    strcpy(ptr, "LET");
8945dfecf96Smrg/* update sym0 */
8955dfecf96Smrgsymbol:
8965dfecf96Smrg		    offsets[j++] = &sym0;
8975dfecf96Smrg/* update <offsets> - print [byte] */
8985dfecf96Smrgoffset:
8995dfecf96Smrg		    ptr += strlen(ptr);
9005dfecf96Smrg		    i = *stream++;
9015dfecf96Smrg		    *(offsets[j - 1]) = i;
9025dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9035dfecf96Smrg		    break;
9045dfecf96Smrg		case XBC_LETX:
9055dfecf96Smrg		    strcpy(ptr, "LET*");
9065dfecf96Smrg		    goto symbol;
9075dfecf96Smrg		case XBC_LET_NIL:
9085dfecf96Smrg		    strcpy(ptr, "LET NIL");
9095dfecf96Smrg		    goto symbol;
9105dfecf96Smrg		case XBC_LETX_NIL:
9115dfecf96Smrg		    strcpy(ptr, "LET* NIL");
9125dfecf96Smrg		    goto symbol;
9135dfecf96Smrg		case XBC_LETBIND:
9145dfecf96Smrg		    strcpy(ptr, "LETBIND");
9155dfecf96Smrg/* print byte */
9165dfecf96Smrgvalue:
9175dfecf96Smrg		    ptr += strlen(ptr);
9185dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
9195dfecf96Smrg		    break;
9205dfecf96Smrg		case XBC_UNLET:strcpy(ptr, "UNLET");	goto value;
9215dfecf96Smrg		case XBC_LOAD:
9225dfecf96Smrg		    strcpy(ptr, "LOAD");
9235dfecf96Smrg/* print (byte) */
9245dfecf96Smrgreference:
9255dfecf96Smrg		    ptr += strlen(ptr);
9265dfecf96Smrg		    i = *stream++;
9275dfecf96Smrg		    sprintf(ptr, " (%d)", i);
9285dfecf96Smrg		    break;
9295dfecf96Smrg		case XBC_LOAD_CAR:
9305dfecf96Smrg		    strcpy(ptr, "LOAD&CAR");
9315dfecf96Smrg		    goto reference;
9325dfecf96Smrg		case XBC_LOAD_CDR:
9335dfecf96Smrg		    strcpy(ptr, "LOAD&CDR");
9345dfecf96Smrg		    goto reference;
9355dfecf96Smrg		case XBC_LOAD_CAR_STORE:
9365dfecf96Smrg		    strcpy(ptr, "LOAD&CAR&STORE");
9375dfecf96Smrg		    goto reference;
9385dfecf96Smrg		case XBC_LOAD_CDR_STORE:
9395dfecf96Smrg		    strcpy(ptr, "LOAD&CDR&STORE");
9405dfecf96Smrg		    goto reference;
9415dfecf96Smrg		case XBC_LOAD_LET:
9425dfecf96Smrg		    strcpy(ptr, "LOAD&LET");
9435dfecf96Smrgload_let:
9445dfecf96Smrg		    offsets[j++] = &sym0;
9455dfecf96Smrg		    i = *stream++;
9465dfecf96Smrg		    ptr += strlen(ptr);
9475dfecf96Smrg		    sprintf(ptr, " (%d)", i);
9485dfecf96Smrg		    goto offset;
9495dfecf96Smrg		case XBC_LOAD_LETX:
9505dfecf96Smrg		    strcpy(ptr, "LOAD&LET*");
9515dfecf96Smrg		    goto load_let;
9525dfecf96Smrg		case XBC_STRUCT:
9535dfecf96Smrg		    strcpy(ptr, "STRUCT");
9545dfecf96Smrg		    offsets[j++] = &strf;
9555dfecf96Smrg		    offsets[j++] = &strd;
9565dfecf96Smrg/* update <offsets> - print [byte] - update <offsets> - print [byte] */
9575dfecf96Smrgoffset_offset:
9585dfecf96Smrg		    ptr += strlen(ptr);
9595dfecf96Smrg		    i = *stream++;
9605dfecf96Smrg		    *(offsets[j - 2]) = i;
9615dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9625dfecf96Smrg		    goto offset;
9635dfecf96Smrg		case XBC_LOAD_PUSH:
9645dfecf96Smrg		    strcpy(ptr, "LOAD&PUSH");
9655dfecf96Smrg		    goto reference;
9665dfecf96Smrg		case XBC_LOADCON:
9675dfecf96Smrg		    strcpy(ptr, "LOADCON");
9685dfecf96Smrgconstant:
9695dfecf96Smrg		    offsets[j++] = &con0;
9705dfecf96Smrg		    goto offset;
9715dfecf96Smrg		case XBC_LOADCON_SET:
9725dfecf96Smrg		    strcpy(ptr, "LOADCON&SET");
9735dfecf96Smrg		    offsets[j++] = &con0;
9745dfecf96Smrg/* update <offsets> - print [byte] - print (byte) */
9755dfecf96Smrgoffset_reference:
9765dfecf96Smrg		    i = *stream++;
9775dfecf96Smrg		    *(offsets[j - 1]) = i;
9785dfecf96Smrg		    ptr += strlen(ptr);
9795dfecf96Smrg		    sprintf(ptr, " [%d]", i);
9805dfecf96Smrg		    goto reference;
9815dfecf96Smrg		case XBC_STRUCTP:
9825dfecf96Smrg		    strcpy(ptr, "STRUCTP");
9835dfecf96Smrg		    offsets[j++] = &strd;
9845dfecf96Smrg		    goto offset;
9855dfecf96Smrg		case XBC_LOADCON_LET:
9865dfecf96Smrg		    strcpy(ptr, "LOADCON&LET");
9875dfecf96Smrgloadcon_let:
9885dfecf96Smrg		    offsets[j++] = &con0;
9895dfecf96Smrg		    offsets[j++] = &sym0;
9905dfecf96Smrg		    goto offset_offset;
9915dfecf96Smrg		case XBC_LOADCON_LETX:
9925dfecf96Smrg		    strcpy(ptr, "LOADCON&LET*");
9935dfecf96Smrg		    goto loadcon_let;
9945dfecf96Smrg		case XBC_LOADCON_PUSH:
9955dfecf96Smrg		    strcpy(ptr, "LOADCON&PUSH");
9965dfecf96Smrg		    goto constant;
9975dfecf96Smrg		case XBC_LOADSYM:
9985dfecf96Smrg		    strcpy(ptr, "LOADSYM");
9995dfecf96Smrg		    goto symbol;
10005dfecf96Smrg		case XBC_LOADSYM_LET:
10015dfecf96Smrg		    strcpy(ptr, "LOADSYM&LET");
10025dfecf96Smrgloadsym_let:
10035dfecf96Smrg		    offsets[j++] = &sym0;
10045dfecf96Smrg		    offsets[j++] = &sym1;
10055dfecf96Smrg		    goto offset_offset;
10065dfecf96Smrg		case XBC_LOADSYM_LETX:
10075dfecf96Smrg		    strcpy(ptr, "LOADSYM&LET*");
10085dfecf96Smrg		    goto loadsym_let;
10095dfecf96Smrg		case XBC_LOADSYM_PUSH:
10105dfecf96Smrg		    strcpy(ptr, "LOADSYM&PUSH");
10115dfecf96Smrg		    goto symbol;
10125dfecf96Smrg		case XBC_LOAD_SET:
10135dfecf96Smrg		    strcpy(ptr, "LOAD&SET");
10145dfecf96Smrg/* print (byte) - print (byte) */
10155dfecf96Smrgreference_reference:
10165dfecf96Smrg		    ptr += strlen(ptr);
10175dfecf96Smrg		    i = *stream++;
10185dfecf96Smrg		    sprintf(ptr, " (%d)", i);
10195dfecf96Smrg		    goto reference;
10205dfecf96Smrg		case XBC_LOAD_CAR_SET:
10215dfecf96Smrg		    strcpy(ptr, "LOAD&CAR&SET");
10225dfecf96Smrg		    goto reference_reference;
10235dfecf96Smrg		case XBC_LOAD_CDR_SET:
10245dfecf96Smrg		    strcpy(ptr, "LOAD&CDR&SET");
10255dfecf96Smrg		    goto reference_reference;
10265dfecf96Smrg		case XBC_CAR_SET:
10275dfecf96Smrg		    strcpy(ptr, "CAR&SET");
10285dfecf96Smrg		    goto reference;
10295dfecf96Smrg		case XBC_CDR_SET:
10305dfecf96Smrg		    strcpy(ptr, "CDR&SET");
10315dfecf96Smrg		    goto reference;
10325dfecf96Smrg		case XBC_SET:
10335dfecf96Smrg		    strcpy(ptr, "SET");
10345dfecf96Smrg		    goto reference;
10355dfecf96Smrg		case XBC_SETSYM:
10365dfecf96Smrg		    strcpy(ptr, "SETSYM");
10375dfecf96Smrg		    goto symbol;
10385dfecf96Smrg		case XBC_SET_NIL:
10395dfecf96Smrg		    strcpy(ptr, "SET NIL");
10405dfecf96Smrg		    goto reference;
10415dfecf96Smrg		case XBC_CALL:
10425dfecf96Smrg		    strcpy(ptr, "CALL");
10435dfecf96Smrg		    ptr += strlen(ptr);
10445dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10455dfecf96Smrg		    offsets[j++] = &bui0;
10465dfecf96Smrg		    goto offset;
10475dfecf96Smrg		case XBC_CALL_SET:
10485dfecf96Smrg		    strcpy(ptr, "CALL&SET");
10495dfecf96Smrg		    ptr += strlen(ptr);
10505dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10515dfecf96Smrg		    offsets[j++] = &bui0;
10525dfecf96Smrg		    goto offset_reference;
10535dfecf96Smrg		case XBC_BYTECALL:
10545dfecf96Smrg		    strcpy(ptr, "BYTECALL");
10555dfecf96Smrg		    ptr += strlen(ptr);
10565dfecf96Smrg		    sprintf(ptr, " %d", (int)(*stream++));
10575dfecf96Smrg		    offsets[j++] = &byt0;
10585dfecf96Smrg		    goto offset;
10595dfecf96Smrg		case XBC_FUNCALL:
10605dfecf96Smrg		    strcpy(ptr, "FUNCALL");
10615dfecf96Smrgconstant_constant:
10625dfecf96Smrg		    offsets[j++] = &con0;
10635dfecf96Smrg		    offsets[j++] = &con1;
10645dfecf96Smrg		    goto offset_offset;
10655dfecf96Smrg		case XBC_CCONS:
10665dfecf96Smrg		    strcpy(ptr, "CCONS");
10675dfecf96Smrg		    goto constant_constant;
10685dfecf96Smrg		case XBC_CSTAR:	strcpy(ptr, "CSTAR");	break;
10695dfecf96Smrg		case XBC_CFINI:	strcpy(ptr, "CFINI");	break;
10705dfecf96Smrg		case XBC_LSTAR:	strcpy(ptr, "LSTAR");	break;
10715dfecf96Smrg		case XBC_LCONS:	strcpy(ptr, "LCONS");	break;
10725dfecf96Smrg		case XBC_LFINI:	strcpy(ptr, "LFINI");	break;
10735dfecf96Smrg		case XBC_BCONS:	strcpy(ptr, "BCONS");	break;
10745dfecf96Smrg		case XBC_BCONS1:	case XBC_BCONS2:	case XBC_BCONS3:
10755dfecf96Smrg		case XBC_BCONS4:	case XBC_BCONS5:	case XBC_BCONS6:
10765dfecf96Smrg		case XBC_BCONS7:
10775dfecf96Smrg		    strcpy(ptr, "BCONS");
10785dfecf96Smrg		    ptr += strlen(ptr);
10795dfecf96Smrg		    sprintf(ptr, "%d", (int)(stream[-1] - XBC_BCONS));
10805dfecf96Smrg		    break;
10815dfecf96Smrg		case XBC_JUMP:
10825dfecf96Smrg		    strcpy(ptr, "JUMP");
10835dfecf96Smrginteger:
10845dfecf96Smrg		    ptr += strlen(ptr);
10855dfecf96Smrg		    sprintf(ptr, " %d", *(signed short*)stream);
10865dfecf96Smrg		    stream += sizeof(short);
10875dfecf96Smrg		    break;
10885dfecf96Smrg		case XBC_JUMPT:
10895dfecf96Smrg		    strcpy(ptr, "JUMPT");
10905dfecf96Smrg		    goto integer;
10915dfecf96Smrg		case XBC_JUMPNIL:
10925dfecf96Smrg		    strcpy(ptr, "JUMPNIL");
10935dfecf96Smrg		    goto integer;
10945dfecf96Smrg		case XBC_LETREC:
10955dfecf96Smrg		    strcpy(ptr, "LETREC");
10965dfecf96Smrg		    ptr += strlen(ptr);
10975dfecf96Smrg		    sprintf(ptr, " %d", (int)*stream++);
10985dfecf96Smrg		    break;
10995dfecf96Smrg		case XBC_RETURN:
11005dfecf96Smrg		    strcpy(ptr, "RETURN");
11015dfecf96Smrg		    done = 1;
11025dfecf96Smrg		    break;
11035dfecf96Smrg	    }
11045dfecf96Smrg	    i = ptr - buffer + strlen(ptr);
11055dfecf96Smrg	    LispWriteStr(NIL, buffer, i);
11065dfecf96Smrg	    if (j) {
11075dfecf96Smrg
11085dfecf96Smrg		/* Pad */
11095dfecf96Smrg		LispWriteChars(NIL, ' ', 28 - i);
11105dfecf96Smrg		LispWriteChar(NIL, ';');
11115dfecf96Smrg
11125dfecf96Smrg		ptr = buffer;
11135dfecf96Smrg
11145dfecf96Smrg		/* Structure */
11155dfecf96Smrg		if (strf >= 0) {
11165dfecf96Smrg		    /* strd is valid if strf set */
11175dfecf96Smrg		    LispObj *fields = constants[strd];
11185dfecf96Smrg
11195dfecf96Smrg		    for (; strf >= 0; strf--)
11205dfecf96Smrg			fields = CDR(fields);
11215dfecf96Smrg		    strcpy(ptr, "  ");	    ptr += 2;
1122f14f4646Smrg		    strcpy(ptr, CAR(fields)->data.atom->key->value);
11235dfecf96Smrg		    ptr += strlen(ptr);
11245dfecf96Smrg		}
11255dfecf96Smrg		if (strd >= 0) {
11265dfecf96Smrg		    strcpy(ptr, "  ");		ptr += 2;
11275dfecf96Smrg		    strcpy(ptr, STROBJ(CAR(constants[strd])));
11285dfecf96Smrg		    ptr += strlen(ptr);
11295dfecf96Smrg		}
11305dfecf96Smrg
11315dfecf96Smrg		/* Constants */
11325dfecf96Smrg		if (con0 >= 0) {
11335dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11345dfecf96Smrg		    strcpy(ptr, STROBJ(constants[con0]));
11355dfecf96Smrg		    ptr += strlen(ptr);
11365dfecf96Smrg		    if (con1 >= 0) {
11375dfecf96Smrg			strcpy(ptr, "  ");	ptr += 2;
11385dfecf96Smrg			strcpy(ptr, STROBJ(constants[con1]));
11395dfecf96Smrg			ptr += strlen(ptr);
11405dfecf96Smrg		    }
11415dfecf96Smrg		}
11425dfecf96Smrg
11435dfecf96Smrg		/* Builtin */
11445dfecf96Smrg		if (bui0 >= 0) {
11455dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11465dfecf96Smrg		    strcpy(ptr, STROBJ(builtins[bui0]->symbol));
11475dfecf96Smrg		    ptr += strlen(ptr);
11485dfecf96Smrg		}
11495dfecf96Smrg
11505dfecf96Smrg		/* Bytecode */
11515dfecf96Smrg		if (byt0 >= 0) {
11525dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
11535dfecf96Smrg		    strcpy(ptr, STROBJ(names[byt0]));
11545dfecf96Smrg		    ptr += strlen(ptr);
11555dfecf96Smrg		}
11565dfecf96Smrg
11575dfecf96Smrg		/* Symbols */
11585dfecf96Smrg		if (sym0 >= 0) {
11595dfecf96Smrg		    strcpy(ptr, "  ");	ptr += 2;
1160f14f4646Smrg		    strcpy(ptr, XSTRING(symbols[sym0]->key));
11615dfecf96Smrg		    ptr += strlen(ptr);
11625dfecf96Smrg		    if (sym1 >= 0) {
11635dfecf96Smrg			strcpy(ptr, "  ");	ptr += 2;
1164f14f4646Smrg			strcpy(ptr, XSTRING(symbols[sym1]->key));
11655dfecf96Smrg			ptr += strlen(ptr);
11665dfecf96Smrg		    }
11675dfecf96Smrg		}
11685dfecf96Smrg
11695dfecf96Smrg		i = ptr - buffer;
11705dfecf96Smrg		LispWriteStr(NIL, buffer, i);
11715dfecf96Smrg	    }
11725dfecf96Smrg	    LispWriteChar(NIL, '\n');
11735dfecf96Smrg	    continue;
11745dfecf96Smrgpredicate:
11755dfecf96Smrg	    switch (*stream++) {
11765dfecf96Smrg		case XBP_CONSP:     strcpy(ptr, "CONSP");   break;
11775dfecf96Smrg		case XBP_LISTP:     strcpy(ptr, "LISTP");   break;
11785dfecf96Smrg		case XBP_NUMBERP:   strcpy(ptr, "NUMBERP"); break;
11795dfecf96Smrg	    }
11805dfecf96Smrg	    LispWriteStr(NIL, buffer, ptr - buffer + strlen(ptr));
11815dfecf96Smrg	    LispWriteChar(NIL, '\n');
11825dfecf96Smrg	}
11835dfecf96Smrg#undef XSTRING
11845dfecf96Smrg    }
11855dfecf96Smrg
11865dfecf96Smrg    return (function);
11875dfecf96Smrg}
11885dfecf96Smrg
11895dfecf96Smrg
11905dfecf96Smrg
11915dfecf96SmrgLispObj *
11925dfecf96SmrgLispCompileForm(LispObj *form)
11935dfecf96Smrg{
11945dfecf96Smrg    GC_ENTER();
11955dfecf96Smrg    int failed;
11965dfecf96Smrg    LispCom com;
11975dfecf96Smrg
11985dfecf96Smrg    if (!CONSP(form))
11995dfecf96Smrg	/* Incorrect call or NIL */
12005dfecf96Smrg	return (form);
12015dfecf96Smrg
12025dfecf96Smrg    memset(&com, 0, sizeof(LispCom));
12035dfecf96Smrg
12045dfecf96Smrg    com.toplevel = com.block = LispCalloc(1, sizeof(CodeBlock));
12055dfecf96Smrg    com.block->type = LispBlockNone;
12065dfecf96Smrg    com.lex = lisp__data.env.lex;
12075dfecf96Smrg
12085dfecf96Smrg    com.plist = CONS(NIL, NIL);
12095dfecf96Smrg    GC_PROTECT(com.plist);
12105dfecf96Smrg
12115dfecf96Smrg    failed = 1;
12125dfecf96Smrg    if (setjmp(com.jmp) == 0) {
12135dfecf96Smrg	for (; CONSP(form); form = CDR(form)) {
12145dfecf96Smrg	    com.form = form;
12155dfecf96Smrg	    ComEval(&com, CAR(form));
12165dfecf96Smrg	}
12175dfecf96Smrg	failed = 0;
12185dfecf96Smrg    }
12195dfecf96Smrg    GC_LEAVE();
12205dfecf96Smrg
12215dfecf96Smrg    return (failed ? NIL : MakeBytecodeObject(&com, NIL, NIL));
12225dfecf96Smrg}
12235dfecf96Smrg
12245dfecf96SmrgLispObj *
12255dfecf96SmrgLispExecuteBytecode(LispObj *object)
12265dfecf96Smrg{
12275dfecf96Smrg    if (!BYTECODEP(object))
12285dfecf96Smrg	return (EVAL(object));
12295dfecf96Smrg
12305dfecf96Smrg    return (ExecuteBytecode(object->data.bytecode.bytecode->code));
12315dfecf96Smrg}
12325dfecf96Smrg
12335dfecf96Smrgstatic LispObj *
12345dfecf96SmrgMakeBytecodeObject(LispCom *com, LispObj *name, LispObj *plist)
12355dfecf96Smrg{
12365dfecf96Smrg    LispObj *object;
12375dfecf96Smrg    LispBytecode *bytecode;
12385dfecf96Smrg
12395dfecf96Smrg    GC_ENTER();
12405dfecf96Smrg    unsigned char *stream;
12415dfecf96Smrg    short i, num_constants;
12425dfecf96Smrg    LispObj **constants, *code, *cons, *prev;
12435dfecf96Smrg
12445dfecf96Smrg    /* Resolve dependencies, optimize and create byte stream */
12455dfecf96Smrg    LinkBytecode(com);
12465dfecf96Smrg
12475dfecf96Smrg    object = LispNew(NIL, NIL);
12485dfecf96Smrg    GC_PROTECT(object);
12495dfecf96Smrg    bytecode = LispMalloc(sizeof(LispBytecode));
12505dfecf96Smrg    bytecode->code = com->bytecode;
12515dfecf96Smrg    bytecode->length = com->length;
12525dfecf96Smrg
12535dfecf96Smrg
12545dfecf96Smrg    stream = bytecode->code;
12555dfecf96Smrg
12565dfecf96Smrg    /* Skip stack information */
12575dfecf96Smrg    stream += sizeof(short) * 3;
12585dfecf96Smrg
12595dfecf96Smrg    /* Get information */
12605dfecf96Smrg    num_constants = *(short*)stream;
12615dfecf96Smrg    stream += sizeof(short) * 4;
12625dfecf96Smrg    constants = (LispObj**)stream;
12635dfecf96Smrg
12645dfecf96Smrg    GC_PROTECT(plist);
12655dfecf96Smrg    code = cons = prev = NIL;
12665dfecf96Smrg    for (i = 0; i < num_constants; i++) {
12675dfecf96Smrg	if (POINTERP(constants[i]) && !XSYMBOLP(constants[i])) {
12685dfecf96Smrg	    if (code == NIL) {
12695dfecf96Smrg		code = cons = prev = CONS(constants[i], NIL);
12705dfecf96Smrg		GC_PROTECT(code);
12715dfecf96Smrg	    }
12725dfecf96Smrg	    else {
12735dfecf96Smrg		RPLACD(cons, CONS(constants[i], NIL));
12745dfecf96Smrg		prev = cons;
12755dfecf96Smrg		cons = CDR(cons);
12765dfecf96Smrg	    }
12775dfecf96Smrg	}
12785dfecf96Smrg    }
12795dfecf96Smrg
12805dfecf96Smrg    /* Protect this in case the function is redefined */
12815dfecf96Smrg    for (i = 0; i < com->table.num_bytecodes; i++) {
12825dfecf96Smrg	if (code == NIL) {
12835dfecf96Smrg	    code = cons = prev = CONS(com->table.bytecodes[i], NIL);
12845dfecf96Smrg	    GC_PROTECT(code);
12855dfecf96Smrg	}
12865dfecf96Smrg	else {
12875dfecf96Smrg	    RPLACD(cons, CONS(com->table.bytecodes[i], NIL));
12885dfecf96Smrg	    prev = cons;
12895dfecf96Smrg	    cons = CDR(cons);
12905dfecf96Smrg	}
12915dfecf96Smrg    }
12925dfecf96Smrg
12935dfecf96Smrg    /* Free everything, but the LispCom structure and the generated bytecode */
12945dfecf96Smrg    CompileFreeState(com);
12955dfecf96Smrg
12965dfecf96Smrg    /* Allocate the minimum required number of cons cells to protect objects */
12975dfecf96Smrg    if (!CONSP(code))
12985dfecf96Smrg	code = plist;
12995dfecf96Smrg    else if (CONSP(plist)) {
13005dfecf96Smrg	if (code == cons)
13015dfecf96Smrg	    RPLACD(code, plist);
13025dfecf96Smrg	else
13035dfecf96Smrg	    RPLACD(cons, plist);
13045dfecf96Smrg    }
13055dfecf96Smrg    else {
13065dfecf96Smrg	if (code == cons)
13075dfecf96Smrg	    code = CAR(code);
13085dfecf96Smrg	else
13095dfecf96Smrg	    CDR(prev) = CAR(cons);
13105dfecf96Smrg    }
13115dfecf96Smrg
13125dfecf96Smrg    object->data.bytecode.bytecode = bytecode;
13135dfecf96Smrg    /* Byte code references this object, so it cannot be garbage collected */
13145dfecf96Smrg    object->data.bytecode.code = code;
13155dfecf96Smrg    object->data.bytecode.name = name;
13165dfecf96Smrg    object->type = LispBytecode_t;
13175dfecf96Smrg
13185dfecf96Smrg    LispMused(bytecode);
13195dfecf96Smrg    LispMused(bytecode->code);
13205dfecf96Smrg    GC_LEAVE();
13215dfecf96Smrg
13225dfecf96Smrg    return (object);
13235dfecf96Smrg}
13245dfecf96Smrg
13255dfecf96Smrgstatic void
13265dfecf96SmrgCompileFreeTree(CodeTree *tree)
13275dfecf96Smrg{
13285dfecf96Smrg    if (tree->type == CodeTreeBlock)
13295dfecf96Smrg	CompileFreeBlock(tree->data.block);
13305dfecf96Smrg    LispFree(tree);
13315dfecf96Smrg}
13325dfecf96Smrg
13335dfecf96Smrgstatic void
13345dfecf96SmrgCompileFreeBlock(CodeBlock *block)
13355dfecf96Smrg{
13365dfecf96Smrg    CodeTree *tree = block->tree, *next;
13375dfecf96Smrg
13385dfecf96Smrg    while (tree) {
13395dfecf96Smrg	next = tree->next;
13405dfecf96Smrg	CompileFreeTree(tree);
13415dfecf96Smrg	tree = next;
13425dfecf96Smrg    }
13435dfecf96Smrg    if (block->type == LispBlockBody) {
13445dfecf96Smrg	LispFree(block->tagbody.labels);
13455dfecf96Smrg	LispFree(block->tagbody.codes);
13465dfecf96Smrg    }
13475dfecf96Smrg    LispFree(block->variables.symbols);
13485dfecf96Smrg    LispFree(block->variables.flags);
13495dfecf96Smrg    LispFree(block);
13505dfecf96Smrg}
13515dfecf96Smrg
13525dfecf96Smrgstatic void
13535dfecf96SmrgCompileFreeState(LispCom *com)
13545dfecf96Smrg{
13555dfecf96Smrg    CompileFreeBlock(com->block);
13565dfecf96Smrg    LispFree(com->table.constants);
13575dfecf96Smrg    LispFree(com->table.symbols);
13585dfecf96Smrg    LispFree(com->table.builtins);
13595dfecf96Smrg    LispFree(com->table.bytecodes);
13605dfecf96Smrg}
13615dfecf96Smrg
13625dfecf96Smrg/* XXX Put a breakpoint here when changing the macro expansion code.
13635dfecf96Smrg *     No opcodes should be generated during macro expansion. */
13645dfecf96Smrgstatic CodeTree *
13655dfecf96SmrgCompileNewTree(LispCom *com, CodeTreeType type)
13665dfecf96Smrg{
13675dfecf96Smrg    CodeTree *tree = LispMalloc(sizeof(CodeTree));
13685dfecf96Smrg
13695dfecf96Smrg    tree->type = type;
13705dfecf96Smrg    tree->next = NULL;
13715dfecf96Smrg    tree->block = com->block;
13725dfecf96Smrg    if (com->block->tree == NULL)
13735dfecf96Smrg	com->block->tree = tree;
13745dfecf96Smrg    else
13755dfecf96Smrg	com->block->tail->next = tree;
13765dfecf96Smrg    com->block->tail = tree;
13775dfecf96Smrg
13785dfecf96Smrg    return (tree);
13795dfecf96Smrg}
13805dfecf96Smrg
13815dfecf96Smrgstatic void
13825dfecf96SmrgCompileIniBlock(LispCom *com, LispBlockType type, LispObj *tag)
13835dfecf96Smrg{
13845dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBlock);
13855dfecf96Smrg    CodeBlock *block = LispCalloc(1, sizeof(CodeBlock));
13865dfecf96Smrg
13875dfecf96Smrg    tree->data.block = block;
13885dfecf96Smrg
13895dfecf96Smrg    block->type = type;
13905dfecf96Smrg    block->tag = tag;
13915dfecf96Smrg    block->prev = com->block;
13925dfecf96Smrg    block->parent = tree;
13935dfecf96Smrg    block->level = com->level;
13945dfecf96Smrg    com->block = block;
13955dfecf96Smrg
13965dfecf96Smrg    if (type == LispBlockBody)
13975dfecf96Smrg	com->tagbody = com->level;
13985dfecf96Smrg}
13995dfecf96Smrg
14005dfecf96Smrgstatic void
14015dfecf96SmrgCompileFiniBlock(LispCom *com)
14025dfecf96Smrg{
14035dfecf96Smrg    com->block = com->block->prev;
14045dfecf96Smrg    if (com->block && com->block->type == LispBlockBody)
14055dfecf96Smrg	com->tagbody = com->block->level;
14065dfecf96Smrg}
14075dfecf96Smrg
14085dfecf96Smrgstatic void
14095dfecf96Smrgcom_BytecodeChar(LispCom *com, LispByteOpcode code, char value)
14105dfecf96Smrg{
14115dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14125dfecf96Smrg
14135dfecf96Smrg    tree->code = code;
14145dfecf96Smrg    tree->data.signed_char = value;
14155dfecf96Smrg}
14165dfecf96Smrg
14175dfecf96Smrgstatic void
14185dfecf96Smrgcom_BytecodeShort(LispCom *com, LispByteOpcode code, short value)
14195dfecf96Smrg{
14205dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14215dfecf96Smrg
14225dfecf96Smrg    tree->code = code;
14235dfecf96Smrg    tree->data.signed_short = value;
14245dfecf96Smrg}
14255dfecf96Smrg
14265dfecf96Smrgstatic void
14275dfecf96Smrgcom_BytecodeAtom(LispCom *com, LispByteOpcode code, LispAtom *atom)
14285dfecf96Smrg{
14295dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14305dfecf96Smrg
14315dfecf96Smrg    tree->code = code;
14325dfecf96Smrg    tree->data.atom = atom;
14335dfecf96Smrg}
14345dfecf96Smrg
14355dfecf96Smrgstatic void
14365dfecf96Smrgcom_BytecodeObject(LispCom *com, LispByteOpcode code, LispObj *object)
14375dfecf96Smrg{
14385dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14395dfecf96Smrg
14405dfecf96Smrg    tree->code = code;
14415dfecf96Smrg    tree->data.object = object;
14425dfecf96Smrg}
14435dfecf96Smrg
14445dfecf96Smrgstatic void
14455dfecf96Smrgcom_BytecodeCons(LispCom *com, LispByteOpcode code, LispObj *car, LispObj *cdr)
14465dfecf96Smrg{
14475dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14485dfecf96Smrg
14495dfecf96Smrg    tree->code = code;
14505dfecf96Smrg    tree->data.cons.car = car;
14515dfecf96Smrg    tree->data.cons.cdr = cdr;
14525dfecf96Smrg}
14535dfecf96Smrg
14545dfecf96Smrgstatic void
14555dfecf96Smrgcom_Bytecode(LispCom *com, LispByteOpcode code)
14565dfecf96Smrg{
14575dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14585dfecf96Smrg
14595dfecf96Smrg    tree->code = code;
14605dfecf96Smrg}
14615dfecf96Smrg
14625dfecf96Smrgstatic void
14635dfecf96Smrgcom_Load(LispCom *com, short offset)
14645dfecf96Smrg{
14655dfecf96Smrg    com_BytecodeShort(com, XBC_LOAD, offset);
14665dfecf96Smrg}
14675dfecf96Smrg
14685dfecf96Smrgstatic void
14695dfecf96Smrgcom_LoadLet(LispCom *com, short offset, LispAtom *name)
14705dfecf96Smrg{
14715dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
14725dfecf96Smrg
14735dfecf96Smrg    tree->code = XBC_LOAD_LET;
14745dfecf96Smrg    tree->data.let.offset = offset;
14755dfecf96Smrg    tree->data.let.name = name;
14765dfecf96Smrg}
14775dfecf96Smrg
14785dfecf96Smrgstatic void
14795dfecf96Smrgcom_LoadPush(LispCom *com, short offset)
14805dfecf96Smrg{
14815dfecf96Smrg    com_BytecodeShort(com, XBC_LOAD_PUSH, offset);
14825dfecf96Smrg}
14835dfecf96Smrg
14845dfecf96Smrgstatic void
14855dfecf96Smrgcom_Let(LispCom *com, LispAtom *name)
14865dfecf96Smrg{
14875dfecf96Smrg    com_BytecodeAtom(com, XBC_LET, name);
14885dfecf96Smrg}
14895dfecf96Smrg
14905dfecf96Smrgstatic void
14915dfecf96Smrgcom_Bind(LispCom *com, short count)
14925dfecf96Smrg{
14935dfecf96Smrg    if (count)
14945dfecf96Smrg	com_BytecodeShort(com, XBC_LETBIND, count);
14955dfecf96Smrg}
14965dfecf96Smrg
14975dfecf96Smrgstatic void
14985dfecf96Smrgcom_Unbind(LispCom *com, short count)
14995dfecf96Smrg{
15005dfecf96Smrg    if (count)
15015dfecf96Smrg	com_BytecodeShort(com, XBC_UNLET, count);
15025dfecf96Smrg}
15035dfecf96Smrg
15045dfecf96Smrgstatic void
15055dfecf96Smrgcom_LoadSym(LispCom *com, LispAtom *atom)
15065dfecf96Smrg{
15075dfecf96Smrg    com_BytecodeAtom(com, XBC_LOADSYM, atom);
15085dfecf96Smrg}
15095dfecf96Smrg
15105dfecf96Smrgstatic void
15115dfecf96Smrgcom_LoadSymLet(LispCom *com, LispAtom *symbol, LispAtom *name)
15125dfecf96Smrg{
15135dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15145dfecf96Smrg
15155dfecf96Smrg    tree->code = XBC_LOADSYM_LET;
15165dfecf96Smrg    tree->data.let_sym.symbol = symbol;
15175dfecf96Smrg    tree->data.let_sym.name = name;
15185dfecf96Smrg}
15195dfecf96Smrg
15205dfecf96Smrgstatic void
15215dfecf96Smrgcom_LoadSymPush(LispCom *com, LispAtom *name)
15225dfecf96Smrg{
15235dfecf96Smrg    com_BytecodeAtom(com, XBC_LOADSYM_PUSH, name);
15245dfecf96Smrg}
15255dfecf96Smrg
15265dfecf96Smrgstatic void
15275dfecf96Smrgcom_LoadCon(LispCom *com, LispObj *constant)
15285dfecf96Smrg{
15295dfecf96Smrg    if (constant == NIL)
15305dfecf96Smrg	com_Bytecode(com, XBC_NIL);
15315dfecf96Smrg    else if (constant == T)
15325dfecf96Smrg	com_Bytecode(com, XBC_T);
15335dfecf96Smrg    else if (constant == UNSPEC) {
15345dfecf96Smrg	COMPILE_FAILURE("internal error: loading #<UNSPEC>");
15355dfecf96Smrg    }
15365dfecf96Smrg    else
15375dfecf96Smrg	com_BytecodeObject(com, XBC_LOADCON, constant);
15385dfecf96Smrg}
15395dfecf96Smrg
15405dfecf96Smrgstatic void
15415dfecf96Smrgcom_LoadConLet(LispCom *com, LispObj *constant, LispAtom *name)
15425dfecf96Smrg{
15435dfecf96Smrg    if (constant == NIL)
15445dfecf96Smrg	com_BytecodeAtom(com, XBC_LET_NIL, name);
15455dfecf96Smrg    else {
15465dfecf96Smrg	CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15475dfecf96Smrg
15485dfecf96Smrg	tree->code = XBC_LOADCON_LET;
15495dfecf96Smrg	tree->data.let_con.object = constant;
15505dfecf96Smrg	tree->data.let_con.name = name;
15515dfecf96Smrg    }
15525dfecf96Smrg}
15535dfecf96Smrg
15545dfecf96Smrgstatic void
15555dfecf96Smrgcom_LoadConPush(LispCom *com, LispObj *constant)
15565dfecf96Smrg{
15575dfecf96Smrg    if (constant == NIL)
15585dfecf96Smrg	com_Bytecode(com, XBC_PUSH_NIL);
15595dfecf96Smrg    else if (constant == T)
15605dfecf96Smrg	com_Bytecode(com, XBC_PUSH_T);
15615dfecf96Smrg    else if (constant == UNSPEC)
15625dfecf96Smrg	com_Bytecode(com, XBC_PUSH_UNSPEC);
15635dfecf96Smrg    else
15645dfecf96Smrg	com_BytecodeObject(com, XBC_LOADCON_PUSH, constant);
15655dfecf96Smrg}
15665dfecf96Smrg
15675dfecf96Smrgstatic void
15685dfecf96Smrgcom_Set(LispCom *com, short offset)
15695dfecf96Smrg{
15705dfecf96Smrg    com_BytecodeShort(com, XBC_SET, offset);
15715dfecf96Smrg}
15725dfecf96Smrg
15735dfecf96Smrgstatic void
15745dfecf96Smrgcom_SetSym(LispCom *com, LispAtom *symbol)
15755dfecf96Smrg{
15765dfecf96Smrg    com_BytecodeAtom(com, XBC_SETSYM, symbol);
15775dfecf96Smrg}
15785dfecf96Smrg
15795dfecf96Smrgstatic void
15805dfecf96Smrgcom_Struct(LispCom *com, short offset, LispObj *definition)
15815dfecf96Smrg{
15825dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15835dfecf96Smrg
15845dfecf96Smrg    tree->code = XBC_STRUCT;
15855dfecf96Smrg    tree->data.struc.offset = offset;
15865dfecf96Smrg    tree->data.struc.definition = definition;
15875dfecf96Smrg}
15885dfecf96Smrg
15895dfecf96Smrgstatic void
15905dfecf96Smrgcom_Structp(LispCom *com, LispObj *definition)
15915dfecf96Smrg{
15925dfecf96Smrg    com_BytecodeObject(com, XBC_STRUCTP, definition);
15935dfecf96Smrg}
15945dfecf96Smrg
15955dfecf96Smrgstatic void
15965dfecf96Smrgcom_Call(LispCom *com, unsigned char num_arguments, LispBuiltin *builtin)
15975dfecf96Smrg{
15985dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
15995dfecf96Smrg
16005dfecf96Smrg    tree->code = XBC_CALL;
16015dfecf96Smrg    tree->data.builtin.num_arguments = num_arguments;
16025dfecf96Smrg    tree->data.builtin.builtin = builtin;
16035dfecf96Smrg}
16045dfecf96Smrg
16055dfecf96Smrgstatic void
16065dfecf96Smrgcom_Bytecall(LispCom *com, unsigned char num_arguments, LispObj *code)
16075dfecf96Smrg{
16085dfecf96Smrg    CodeTree *tree = NEW_TREE(CodeTreeBytecode);
16095dfecf96Smrg
16105dfecf96Smrg    tree->code = XBC_BYTECALL;
16115dfecf96Smrg    tree->data.bytecall.num_arguments = num_arguments;
16125dfecf96Smrg    tree->data.bytecall.code = code;
16135dfecf96Smrg}
16145dfecf96Smrg
16155dfecf96Smrgstatic void
16165dfecf96Smrgcom_Funcall(LispCom *com, LispObj *function, LispObj *arguments)
16175dfecf96Smrg{
16185dfecf96Smrg    com_BytecodeCons(com, XBC_FUNCALL, function, arguments);
16195dfecf96Smrg}
16205dfecf96Smrg
16215dfecf96Smrgstatic void
16225dfecf96SmrgCompileStackEnter(LispCom *com, int count, int builtin)
16235dfecf96Smrg{
16245dfecf96Smrg    if (!com->macro) {
16255dfecf96Smrg	if (builtin) {
16265dfecf96Smrg	    com->stack.cbstack += count;
16275dfecf96Smrg	    if (com->stack.bstack < com->stack.cbstack)
16285dfecf96Smrg		com->stack.bstack = com->stack.cbstack;
16295dfecf96Smrg	}
16305dfecf96Smrg	else {
16315dfecf96Smrg	    com->stack.cstack += count;
16325dfecf96Smrg	    if (com->stack.stack < com->stack.cstack)
16335dfecf96Smrg		com->stack.stack = com->stack.cstack;
16345dfecf96Smrg	}
16355dfecf96Smrg    }
16365dfecf96Smrg}
16375dfecf96Smrg
16385dfecf96Smrgstatic void
16395dfecf96SmrgCompileStackLeave(LispCom *com, int count, int builtin)
16405dfecf96Smrg{
16415dfecf96Smrg    if (!com->macro) {
16425dfecf96Smrg	if (builtin)
16435dfecf96Smrg	    com->stack.cbstack -= count;
16445dfecf96Smrg	else
16455dfecf96Smrg	    com->stack.cstack -= count;
16465dfecf96Smrg    }
16475dfecf96Smrg}
16485dfecf96Smrg
16495dfecf96Smrgstatic void
16505dfecf96SmrgLinkWarnUnused(LispCom *com, CodeBlock *block)
16515dfecf96Smrg{
16525dfecf96Smrg    int i;
16535dfecf96Smrg    CodeTree *tree;
16545dfecf96Smrg
16555dfecf96Smrg    for (tree = block->tree; tree; tree = tree->next) {
16565dfecf96Smrg	if (tree->type == CodeTreeBlock)
16575dfecf96Smrg	    LinkWarnUnused(com, tree->data.block);
16585dfecf96Smrg    }
16595dfecf96Smrg
16605dfecf96Smrg    for (i = 0; i < block->variables.length; i++)
16615dfecf96Smrg	if (!(block->variables.flags[i] & (VARIABLE_USED | VARIABLE_ARGUMENT))) {
16625dfecf96Smrg	    ++com->warnings;
16635dfecf96Smrg	    LispWarning("the variable %s is unused",
1664f14f4646Smrg			block->variables.symbols[i]->key->value);
16655dfecf96Smrg	}
16665dfecf96Smrg}
16675dfecf96Smrg
16685dfecf96Smrg#define	INTERNAL_ERROR_STRING "COMPILE: internal error #%d"
16695dfecf96Smrg#define	INTERNAL_ERROR(value) LispDestroy(INTERNAL_ERROR_STRING, value)
16705dfecf96Smrgstatic long
16715dfecf96SmrgLinkBuildOffsets(LispCom *com, CodeTree *tree, long offset)
16725dfecf96Smrg{
16735dfecf96Smrg    for (; tree; tree = tree->next) {
16745dfecf96Smrg	tree->offset = offset;
16755dfecf96Smrg	switch (tree->type) {
16765dfecf96Smrg	    case CodeTreeBytecode:
16775dfecf96Smrg		switch (tree->code) {
16785dfecf96Smrg		    case XBC_NOOP:
16795dfecf96Smrg			INTERNAL_ERROR(__LINE__);
16805dfecf96Smrg			break;
16815dfecf96Smrg
16825dfecf96Smrg		    /* byte */
16835dfecf96Smrg		    case XBC_BCONS:
16845dfecf96Smrg		    case XBC_BCONS1:
16855dfecf96Smrg		    case XBC_BCONS2:
16865dfecf96Smrg		    case XBC_BCONS3:
16875dfecf96Smrg		    case XBC_BCONS4:
16885dfecf96Smrg		    case XBC_BCONS5:
16895dfecf96Smrg		    case XBC_BCONS6:
16905dfecf96Smrg		    case XBC_BCONS7:
16915dfecf96Smrg		    case XBC_INV:
16925dfecf96Smrg		    case XBC_NIL:
16935dfecf96Smrg		    case XBC_T:
16945dfecf96Smrg		    case XBC_PUSH:
16955dfecf96Smrg		    case XBC_CAR_PUSH:
16965dfecf96Smrg		    case XBC_CDR_PUSH:
16975dfecf96Smrg		    case XBC_PUSH_NIL:
16985dfecf96Smrg		    case XBC_PUSH_UNSPEC:
16995dfecf96Smrg		    case XBC_PUSH_T:
17005dfecf96Smrg		    case XBC_LSTAR:
17015dfecf96Smrg		    case XBC_LCONS:
17025dfecf96Smrg		    case XBC_LFINI:
17035dfecf96Smrg		    case XBC_RETURN:
17045dfecf96Smrg		    case XBC_CSTAR:
17055dfecf96Smrg		    case XBC_CFINI:
17065dfecf96Smrg		    case XBC_CAR:
17075dfecf96Smrg		    case XBC_CDR:
17085dfecf96Smrg		    case XBC_RPLACA:
17095dfecf96Smrg		    case XBC_RPLACD:
17105dfecf96Smrg		    case XBC_EQ:
17115dfecf96Smrg		    case XBC_EQL:
17125dfecf96Smrg		    case XBC_EQUAL:
17135dfecf96Smrg		    case XBC_EQUALP:
17145dfecf96Smrg		    case XBC_LENGTH:
17155dfecf96Smrg		    case XBC_LAST:
17165dfecf96Smrg		    case XBC_NTHCDR:
17175dfecf96Smrg			++offset;
17185dfecf96Smrg			break;
17195dfecf96Smrg
17205dfecf96Smrg		    /* byte + byte */
17215dfecf96Smrg		    case XBC_PUSH_NIL_N:
17225dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
17235dfecf96Smrg		    case XBC_PRED:
17245dfecf96Smrg		    case XBC_LETREC:
17255dfecf96Smrg		    case XBC_LOAD_PUSH:
17265dfecf96Smrg		    case XBC_CAR_SET:
17275dfecf96Smrg		    case XBC_CDR_SET:
17285dfecf96Smrg		    case XBC_SET:
17295dfecf96Smrg		    case XBC_SET_NIL:
17305dfecf96Smrg		    case XBC_LETBIND:
17315dfecf96Smrg		    case XBC_UNLET:
17325dfecf96Smrg		    case XBC_LOAD:
17335dfecf96Smrg		    case XBC_LOAD_CAR:
17345dfecf96Smrg		    case XBC_LOAD_CDR:
17355dfecf96Smrg		    case XBC_LOAD_CAR_STORE:
17365dfecf96Smrg		    case XBC_LOAD_CDR_STORE:
17375dfecf96Smrg		    case XBC_LET:
17385dfecf96Smrg		    case XBC_LETX:
17395dfecf96Smrg		    case XBC_LET_NIL:
17405dfecf96Smrg		    case XBC_LETX_NIL:
17415dfecf96Smrg		    case XBC_STRUCTP:
17425dfecf96Smrg		    case XBC_SETSYM:
17435dfecf96Smrg		    case XBC_LOADCON_PUSH:
17445dfecf96Smrg		    case XBC_LOADSYM_PUSH:
17455dfecf96Smrg		    case XBC_LOADCON:
17465dfecf96Smrg		    case XBC_LOADSYM:
17475dfecf96Smrg			offset += 2;
17485dfecf96Smrg			break;
17495dfecf96Smrg
17505dfecf96Smrg		    /* byte + byte + byte */
17515dfecf96Smrg		    case XBC_CALL:
17525dfecf96Smrg		    case XBC_BYTECALL:
17535dfecf96Smrg		    case XBC_LOAD_SET:
17545dfecf96Smrg		    case XBC_LOAD_CAR_SET:
17555dfecf96Smrg		    case XBC_LOAD_CDR_SET:
17565dfecf96Smrg		    case XBC_LOADCON_SET:
17575dfecf96Smrg		    case XBC_LOAD_LET:
17585dfecf96Smrg		    case XBC_LOAD_LETX:
17595dfecf96Smrg		    case XBC_STRUCT:
17605dfecf96Smrg		    case XBC_LOADCON_LET:
17615dfecf96Smrg		    case XBC_LOADCON_LETX:
17625dfecf96Smrg		    case XBC_LOADSYM_LET:
17635dfecf96Smrg		    case XBC_LOADSYM_LETX:
17645dfecf96Smrg		    case XBC_CCONS:
17655dfecf96Smrg		    case XBC_FUNCALL:
17665dfecf96Smrg			offset += 3;
17675dfecf96Smrg			break;
17685dfecf96Smrg
17695dfecf96Smrg		    /* byte + short */
17705dfecf96Smrg		    case XBC_JUMP:
17715dfecf96Smrg		    case XBC_JUMPT:
17725dfecf96Smrg		    case XBC_JUMPNIL:
17735dfecf96Smrg			/* XXX this is likely a jump to random address here */
17745dfecf96Smrg			INTERNAL_ERROR(__LINE__);
17755dfecf96Smrg			offset += sizeof(short) + 1;
17765dfecf96Smrg			break;
17775dfecf96Smrg
17785dfecf96Smrg		    /* byte + byte + byte + byte */
17795dfecf96Smrg		    case XBC_CALL_SET:
17805dfecf96Smrg			offset += 4;
17815dfecf96Smrg			break;
17825dfecf96Smrg		}
17835dfecf96Smrg		break;
17845dfecf96Smrg	    case CodeTreeLabel:
17855dfecf96Smrg		/* Labels are not loaded */
17865dfecf96Smrg		break;
17875dfecf96Smrg	    case CodeTreeJump:
17885dfecf96Smrg	    case CodeTreeJumpIf:
17895dfecf96Smrg	    case CodeTreeCond:
17905dfecf96Smrg		/* If not the point where the conditional block finishes */
17915dfecf96Smrg		if (tree->code != XBC_NOOP)
17925dfecf96Smrg		    /* Reserve space for the jump opcode */
17935dfecf96Smrg		    offset += sizeof(short) + 1;
17945dfecf96Smrg		break;
17955dfecf96Smrg	    case CodeTreeGo:
17965dfecf96Smrg	    case CodeTreeReturn:
17975dfecf96Smrg		/* Reserve space for the jump opcode */
17985dfecf96Smrg		offset += sizeof(short) + 1;
17995dfecf96Smrg		break;
18005dfecf96Smrg	    case CodeTreeBlock:
18015dfecf96Smrg		offset = LinkBuildOffsets(com, tree->data.block->tree, offset);
18025dfecf96Smrg		break;
18035dfecf96Smrg	}
18045dfecf96Smrg    }
18055dfecf96Smrg
18065dfecf96Smrg    return (offset);
18075dfecf96Smrg}
18085dfecf96Smrg
18095dfecf96Smrgstatic void
18105dfecf96SmrgLinkDoOptimize_0(LispCom *com, CodeBlock *block)
18115dfecf96Smrg{
18125dfecf96Smrg    CodeTree *tree, *prev, *next;
18135dfecf96Smrg
18145dfecf96Smrg    /*  Remove redundant or join opcodes that can be joined. Do it here
18155dfecf96Smrg     * because some of these are hard to detect earlier, and/or would
18165dfecf96Smrg     * require a lot of duplicated code or more time. */
18175dfecf96Smrg    tree = prev = block->tree;
18185dfecf96Smrg    while (tree) {
18195dfecf96Smrg	next = tree->next;
18205dfecf96Smrg
18215dfecf96Smrg	/* LET -> LET* */
18225dfecf96Smrg	if (next &&
18235dfecf96Smrg	    next->type == CodeTreeBytecode &&
18245dfecf96Smrg	    next->code == XBC_LETBIND &&
18255dfecf96Smrg	    next->data.signed_short == 1) {
18265dfecf96Smrg	    switch (tree->code) {
18275dfecf96Smrg		case XBC_LET:
18285dfecf96Smrg		    tree->code = XBC_LETX;
18295dfecf96Smrg		    goto remove_next_label;
18305dfecf96Smrg		case XBC_LET_NIL:
18315dfecf96Smrg		    tree->code = XBC_LETX_NIL;
18325dfecf96Smrg		    goto remove_next_label;
18335dfecf96Smrg		case XBC_LOAD_LET:
18345dfecf96Smrg		    tree->code = XBC_LOAD_LETX;
18355dfecf96Smrg		    goto remove_next_label;
18365dfecf96Smrg		case XBC_LOADCON_LET:
18375dfecf96Smrg		    tree->code = XBC_LOADCON_LETX;
18385dfecf96Smrg		    goto remove_next_label;
18395dfecf96Smrg		case XBC_LOADSYM_LET:
18405dfecf96Smrg		    tree->code = XBC_LOADSYM_LETX;
18415dfecf96Smrg		    goto remove_next_label;
18425dfecf96Smrg		default:
18435dfecf96Smrg		    break;
18445dfecf96Smrg	    }
18455dfecf96Smrg	}
18465dfecf96Smrg
18475dfecf96Smrg	switch (tree->type) {
18485dfecf96Smrg	    case CodeTreeBytecode:
18495dfecf96Smrg		switch (tree->code) {
18505dfecf96Smrg		    case XBC_LOADCON:
18515dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
18525dfecf96Smrg			    switch (next->code) {
18535dfecf96Smrg				case XBC_LET:
18545dfecf96Smrg				    next->code = XBC_LOADCON_LET;
18555dfecf96Smrg				    next->data.let_con.name =
18565dfecf96Smrg					next->data.atom;
18575dfecf96Smrg				    next->data.let_con.object =
18585dfecf96Smrg					tree->data.object;
18595dfecf96Smrg				    goto remove_label;
18605dfecf96Smrg				case XBC_PUSH:
18615dfecf96Smrg				    next->code = XBC_LOADCON_PUSH;
18625dfecf96Smrg				    next->data.object = tree->data.object;
18635dfecf96Smrg				    goto remove_label;
18645dfecf96Smrg				case XBC_CAR:
18655dfecf96Smrg				    if (tree->data.object != NIL) {
18665dfecf96Smrg					if (!CONSP(tree->data.object))
18675dfecf96Smrg					    LispDestroy("CAR: %s is not a list",
18685dfecf96Smrg						        STROBJ(
18695dfecf96Smrg							tree->data.object));
18705dfecf96Smrg					next->code = XBC_LOADCON;
18715dfecf96Smrg					next->data.object =
18725dfecf96Smrg					    CAR(tree->data.object);
18735dfecf96Smrg				    }
18745dfecf96Smrg				    goto remove_label;
18755dfecf96Smrg				case XBC_CDR:
18765dfecf96Smrg				    if (tree->data.object != NIL) {
18775dfecf96Smrg					if (!CONSP(tree->data.object))
18785dfecf96Smrg					    LispDestroy("CAR: %s is not a list",
18795dfecf96Smrg						        STROBJ(
18805dfecf96Smrg							tree->data.object));
18815dfecf96Smrg					next->code = XBC_LOADCON;
18825dfecf96Smrg					next->data.object =
18835dfecf96Smrg					    CDR(tree->data.object);
18845dfecf96Smrg				    }
18855dfecf96Smrg				    goto remove_label;
18865dfecf96Smrg				case XBC_SET:
18875dfecf96Smrg				    next->code = XBC_LOADCON_SET;
18885dfecf96Smrg				    next->data.load_con_set.offset =
18895dfecf96Smrg					next->data.signed_short;
18905dfecf96Smrg				    next->data.load_con_set.object =
18915dfecf96Smrg					tree->data.object;
18925dfecf96Smrg				    goto remove_label;
18935dfecf96Smrg				default:
18945dfecf96Smrg				    break;
18955dfecf96Smrg			    }
18965dfecf96Smrg			}
18975dfecf96Smrg			break;
18985dfecf96Smrg		    case XBC_LOADSYM:
18995dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
19005dfecf96Smrg			    switch (next->code) {
19015dfecf96Smrg				case XBC_LET:
19025dfecf96Smrg				    next->code = XBC_LOADSYM_LET;
19035dfecf96Smrg				    next->data.let_sym.name =
19045dfecf96Smrg					next->data.atom;
19055dfecf96Smrg				    next->data.let_sym.symbol =
19065dfecf96Smrg					tree->data.atom;
19075dfecf96Smrg				    goto remove_label;
19085dfecf96Smrg				case XBC_PUSH:
19095dfecf96Smrg				    next->code = XBC_LOADSYM_PUSH;
19105dfecf96Smrg				    next->data.atom = tree->data.atom;
19115dfecf96Smrg				    goto remove_label;
19125dfecf96Smrg				default:
19135dfecf96Smrg				    break;
19145dfecf96Smrg			    }
19155dfecf96Smrg			}
19165dfecf96Smrg			break;
19175dfecf96Smrg		    case XBC_LOAD:
19185dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
19195dfecf96Smrg			    switch (next->code) {
19205dfecf96Smrg				case XBC_SET:
19215dfecf96Smrg				    next->code = XBC_LOAD_SET;
19225dfecf96Smrg				    next->data.load_set.set =
19235dfecf96Smrg					next->data.signed_short;
19245dfecf96Smrg				    next->data.load_set.load =
19255dfecf96Smrg					tree->data.signed_short;
19265dfecf96Smrg				    goto remove_label;
19275dfecf96Smrg				/* TODO add XBC_LOAD_SETSYM */
19285dfecf96Smrg				case XBC_CAR:
19295dfecf96Smrg				    next->code = XBC_LOAD_CAR;
19305dfecf96Smrg				    next->data.signed_short =
19315dfecf96Smrg					tree->data.signed_short;
19325dfecf96Smrg				    goto remove_label;
19335dfecf96Smrg				case XBC_CDR:
19345dfecf96Smrg				    next->code = XBC_LOAD_CDR;
19355dfecf96Smrg				    next->data.signed_short =
19365dfecf96Smrg					tree->data.signed_short;
19375dfecf96Smrg				    goto remove_label;
19385dfecf96Smrg				case XBC_PUSH:
19395dfecf96Smrg				    tree->code = XBC_LOAD_PUSH;
19405dfecf96Smrg				    goto remove_next_label;
19415dfecf96Smrg				case XBC_LET:
19425dfecf96Smrg				    next->code = XBC_LOAD_LET;
19435dfecf96Smrg				    next->data.let.name = next->data.atom;
19445dfecf96Smrg				    next->data.let.offset =
19455dfecf96Smrg					tree->data.signed_short;
19465dfecf96Smrg				    goto remove_label;
19475dfecf96Smrg				default:
19485dfecf96Smrg				    break;
19495dfecf96Smrg			    }
19505dfecf96Smrg			}
19515dfecf96Smrg			break;
19525dfecf96Smrg		    case XBC_LOAD_CAR:
19535dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
19545dfecf96Smrg			    next->code == XBC_SET) {
19555dfecf96Smrg			    if (next->data.signed_short ==
19565dfecf96Smrg				tree->data.signed_short)
19575dfecf96Smrg				next->code = XBC_LOAD_CAR_STORE;
19585dfecf96Smrg			    else {
19595dfecf96Smrg				next->code = XBC_LOAD_CAR_SET;
19605dfecf96Smrg				next->data.load_set.set =
19615dfecf96Smrg				    next->data.signed_short;
19625dfecf96Smrg				next->data.load_set.load =
19635dfecf96Smrg				    tree->data.signed_short;
19645dfecf96Smrg			    }
19655dfecf96Smrg			    goto remove_label;
19665dfecf96Smrg			}
19675dfecf96Smrg			break;
19685dfecf96Smrg		    case XBC_LOAD_CDR:
19695dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
19705dfecf96Smrg			    next->code == XBC_SET) {
19715dfecf96Smrg			    if (next->data.signed_short ==
19725dfecf96Smrg				tree->data.signed_short)
19735dfecf96Smrg				next->code = XBC_LOAD_CDR_STORE;
19745dfecf96Smrg			    else {
19755dfecf96Smrg				next->code = XBC_LOAD_CDR_SET;
19765dfecf96Smrg				next->data.load_set.set =
19775dfecf96Smrg				    next->data.signed_short;
19785dfecf96Smrg				next->data.load_set.load =
19795dfecf96Smrg				    tree->data.signed_short;
19805dfecf96Smrg			    }
19815dfecf96Smrg			    goto remove_label;
19825dfecf96Smrg			}
19835dfecf96Smrg			break;
19845dfecf96Smrg		    case XBC_CALL:
19855dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
19865dfecf96Smrg			    switch (next->code) {
19875dfecf96Smrg				case XBC_SET:
19885dfecf96Smrg				    next->code = XBC_CALL_SET;
19895dfecf96Smrg				    next->data.builtin.offset =
19905dfecf96Smrg					next->data.signed_short;
19915dfecf96Smrg				    next->data.builtin.num_arguments =
19925dfecf96Smrg					tree->data.builtin.num_arguments;
19935dfecf96Smrg				    next->data.builtin.builtin =
19945dfecf96Smrg					tree->data.builtin.builtin;
19955dfecf96Smrg				    goto remove_label;
19965dfecf96Smrg				/* TODO add XBC_CALL_SETSYM */
19975dfecf96Smrg				default:
19985dfecf96Smrg				    break;
19995dfecf96Smrg			    }
20005dfecf96Smrg			}
20015dfecf96Smrg			break;
20025dfecf96Smrg		    case XBC_CAR:
20035dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20045dfecf96Smrg			    switch (next->code) {
20055dfecf96Smrg				case XBC_SET:
20065dfecf96Smrg				    next->code = XBC_CAR_SET;
20075dfecf96Smrg				    goto remove_label;
20085dfecf96Smrg				/* TODO add XBC_CAR_SETSYM */
20095dfecf96Smrg				case XBC_PUSH:
20105dfecf96Smrg				    next->code = XBC_CAR_PUSH;
20115dfecf96Smrg				    goto remove_label;
20125dfecf96Smrg				default:
20135dfecf96Smrg				    break;
20145dfecf96Smrg			    }
20155dfecf96Smrg			}
20165dfecf96Smrg			break;
20175dfecf96Smrg		    case XBC_CDR:
20185dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20195dfecf96Smrg			    switch (next->code) {
20205dfecf96Smrg				case XBC_SET:
20215dfecf96Smrg				    next->code = XBC_CDR_SET;
20225dfecf96Smrg				    goto remove_label;
20235dfecf96Smrg				/* TODO add XBC_CDR_SETSYM */
20245dfecf96Smrg				case XBC_PUSH:
20255dfecf96Smrg				    next->code = XBC_CDR_PUSH;
20265dfecf96Smrg				    goto remove_label;
20275dfecf96Smrg				default:
20285dfecf96Smrg				    break;
20295dfecf96Smrg			    }
20305dfecf96Smrg			}
20315dfecf96Smrg			break;
20325dfecf96Smrg		    case XBC_NIL:
20335dfecf96Smrg			if (next && next->type == CodeTreeBytecode) {
20345dfecf96Smrg			    switch (next->code) {
20355dfecf96Smrg				case XBC_SET:
20365dfecf96Smrg				    next->code = XBC_SET_NIL;
20375dfecf96Smrg				    goto remove_label;
20385dfecf96Smrg				/* TODO add XBC_SETSYM_NIL */
20395dfecf96Smrg				default:
20405dfecf96Smrg				    break;
20415dfecf96Smrg			    }
20425dfecf96Smrg			}
20435dfecf96Smrg			break;
20445dfecf96Smrg		    case XBC_PUSH_NIL:
20455dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20465dfecf96Smrg			    next->code == XBC_PUSH_NIL) {
20475dfecf96Smrg			    next->code = XBC_PUSH_NIL_N;
20485dfecf96Smrg			    next->data.signed_char = 2;
20495dfecf96Smrg			    goto remove_label;
20505dfecf96Smrg			}
20515dfecf96Smrg			break;
20525dfecf96Smrg		    case XBC_PUSH_NIL_N:
20535dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20545dfecf96Smrg			    next->code == XBC_PUSH_NIL) {
20555dfecf96Smrg			    next->code = XBC_PUSH_NIL_N;
20565dfecf96Smrg			    next->data.signed_char = tree->data.signed_char + 1;
20575dfecf96Smrg			    goto remove_label;
20585dfecf96Smrg			}
20595dfecf96Smrg			break;
20605dfecf96Smrg		    case XBC_PUSH_UNSPEC:
20615dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20625dfecf96Smrg			    next->code == XBC_PUSH_UNSPEC) {
20635dfecf96Smrg			    next->code = XBC_PUSH_UNSPEC_N;
20645dfecf96Smrg			    next->data.signed_char = 2;
20655dfecf96Smrg			    goto remove_label;
20665dfecf96Smrg			}
20675dfecf96Smrg			break;
20685dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
20695dfecf96Smrg			if (next && next->type == CodeTreeBytecode &&
20705dfecf96Smrg			    next->code == XBC_PUSH_UNSPEC) {
20715dfecf96Smrg			    next->code = XBC_PUSH_UNSPEC_N;
20725dfecf96Smrg			    next->data.signed_char = tree->data.signed_char + 1;
20735dfecf96Smrg			    goto remove_label;
20745dfecf96Smrg			}
20755dfecf96Smrg			break;
20765dfecf96Smrg		    default:
20775dfecf96Smrg			break;
20785dfecf96Smrg		}
20795dfecf96Smrg		break;
20805dfecf96Smrg	    case CodeTreeBlock:
20815dfecf96Smrg		LinkDoOptimize_0(com, tree->data.block);
20825dfecf96Smrg		break;
20835dfecf96Smrg	    default:
20845dfecf96Smrg		break;
20855dfecf96Smrg	}
20865dfecf96Smrg	goto update_label;
20875dfecf96Smrgremove_label:
20885dfecf96Smrg	if (tree == block->tree) {
20895dfecf96Smrg	    block->tree = prev = next;
20905dfecf96Smrg	    if (tree == block->tail)
20915dfecf96Smrg		block->tail = tree;
20925dfecf96Smrg	}
20935dfecf96Smrg	else
20945dfecf96Smrg	    prev->next = next;
20955dfecf96Smrg	CompileFreeTree(tree);
20965dfecf96Smrg	tree = next;
20975dfecf96Smrg	continue;
20985dfecf96Smrgremove_next_label:
20995dfecf96Smrg	tree->next = next->next;
21005dfecf96Smrg	CompileFreeTree(next);
21015dfecf96Smrg	continue;
21025dfecf96Smrgupdate_label:
21035dfecf96Smrg	prev = tree;
21045dfecf96Smrg	tree = tree->next;
21055dfecf96Smrg    }
21065dfecf96Smrg}
21075dfecf96Smrg
21085dfecf96Smrgstatic void
21095dfecf96SmrgLinkOptimize_0(LispCom *com)
21105dfecf96Smrg{
21115dfecf96Smrg    /* Recursive */
21125dfecf96Smrg    LinkDoOptimize_0(com, com->block);
21135dfecf96Smrg}
21145dfecf96Smrg
21155dfecf96Smrgstatic void
21165dfecf96SmrgLinkResolveLabels(LispCom *com, CodeBlock *block)
21175dfecf96Smrg{
21185dfecf96Smrg    int i;
21195dfecf96Smrg    CodeTree *tree = block->tree;
21205dfecf96Smrg
21215dfecf96Smrg    for (; tree; tree = tree->next) {
21225dfecf96Smrg	if (tree->type == CodeTreeBlock)
21235dfecf96Smrg	    LinkResolveLabels(com, tree->data.block);
21245dfecf96Smrg	else if (tree->type == CodeTreeLabel) {
21255dfecf96Smrg	    for (i = 0; i < block->tagbody.length; i++)
21265dfecf96Smrg		if (tree->data.object == block->tagbody.labels[i]) {
21275dfecf96Smrg		    block->tagbody.codes[i] = tree;
21285dfecf96Smrg		    break;
21295dfecf96Smrg		}
21305dfecf96Smrg	}
21315dfecf96Smrg    }
21325dfecf96Smrg}
21335dfecf96Smrg
21345dfecf96Smrgstatic void
21355dfecf96SmrgLinkResolveJumps(LispCom *com, CodeBlock *block)
21365dfecf96Smrg{
21375dfecf96Smrg    int i;
21385dfecf96Smrg    CodeBlock *body = block;
21395dfecf96Smrg    CodeTree *ptr, *tree = block->tree;
21405dfecf96Smrg
21415dfecf96Smrg    /* Check if there is a tagbody. Error checking already done */
21425dfecf96Smrg    while (body && body->type != LispBlockBody)
21435dfecf96Smrg	body = body->prev;
21445dfecf96Smrg
21455dfecf96Smrg    for (; tree; tree = tree->next) {
21465dfecf96Smrg	switch (tree->type) {
21475dfecf96Smrg	    case CodeTreeBytecode:
21485dfecf96Smrg	    case CodeTreeLabel:
21495dfecf96Smrg		break;
21505dfecf96Smrg
21515dfecf96Smrg	    case CodeTreeBlock:
21525dfecf96Smrg		LinkResolveJumps(com, tree->data.block);
21535dfecf96Smrg		break;
21545dfecf96Smrg
21555dfecf96Smrg	    case CodeTreeGo:
21565dfecf96Smrg		for (i = 0; i < body->tagbody.length; i++)
21575dfecf96Smrg		    if (tree->data.object == body->tagbody.labels[i])
21585dfecf96Smrg			break;
21595dfecf96Smrg		if (i == body->tagbody.length)
21605dfecf96Smrg		    LispDestroy("COMPILE: no visible tag %s to GO",
21615dfecf96Smrg				STROBJ(tree->data.object));
21625dfecf96Smrg		/* Now the jump code is known */
21635dfecf96Smrg		tree->data.tree = body->tagbody.codes[i];
21645dfecf96Smrg		break;
21655dfecf96Smrg
21665dfecf96Smrg	    case CodeTreeCond:
21675dfecf96Smrg		if (tree->code == XBC_JUMPNIL)
21685dfecf96Smrg		    /* If test is NIL, go to next test */
21695dfecf96Smrg		    tree->data.tree = tree->group->next;
21705dfecf96Smrg		else if (tree->code == XBC_JUMPT) {
21715dfecf96Smrg		    /* After executing code, test was T */
21725dfecf96Smrg		    for (ptr = tree->group;
21735dfecf96Smrg			 ptr->code != XBC_NOOP;
21745dfecf96Smrg			 ptr = ptr->group)
21755dfecf96Smrg			;
21765dfecf96Smrg		    tree->data.tree = ptr;
21775dfecf96Smrg		}
21785dfecf96Smrg		break;
21795dfecf96Smrg
21805dfecf96Smrg	    case CodeTreeJumpIf:
21815dfecf96Smrg		if (tree->code != XBC_NOOP) {
21825dfecf96Smrg		    for (ptr = tree->group;
21835dfecf96Smrg			 ptr->code != XBC_NOOP;
21845dfecf96Smrg			 ptr = ptr->group) {
21855dfecf96Smrg			if (ptr->type == CodeTreeJump) {
21865dfecf96Smrg			    /* ELSE code of IF */
21875dfecf96Smrg			    ptr = ptr->next;
21885dfecf96Smrg			    /* Skip inconditional jump node */
21895dfecf96Smrg			    break;
21905dfecf96Smrg			}
21915dfecf96Smrg		    }
21925dfecf96Smrg		    tree->data.tree = ptr;
21935dfecf96Smrg		}
21945dfecf96Smrg		break;
21955dfecf96Smrg
21965dfecf96Smrg	    case CodeTreeJump:
21975dfecf96Smrg		if (tree->code != XBC_NOOP)
21985dfecf96Smrg		    tree->data.tree = tree->group;
21995dfecf96Smrg		break;
22005dfecf96Smrg
22015dfecf96Smrg	    case CodeTreeReturn:
22025dfecf96Smrg		/* One bytecode is guaranteed to exist in the code tree */
22035dfecf96Smrg		if (tree->data.block->parent == NULL)
22045dfecf96Smrg		    /* Returning from the function or toplevel form */
22055dfecf96Smrg		    tree->data.tree = tree->data.block->tail;
22065dfecf96Smrg		else {
22075dfecf96Smrg		    for (;;) {
22085dfecf96Smrg			ptr = tree->data.block->parent->next;
22095dfecf96Smrg			if (ptr) {
22105dfecf96Smrg			    tree->data.tree = ptr;
22115dfecf96Smrg			    break;
22125dfecf96Smrg			}
22135dfecf96Smrg			else
22145dfecf96Smrg			    /* Move one BLOCK up */
22155dfecf96Smrg			    tree->data.block = tree->data.block->prev;
22165dfecf96Smrg		    }
22175dfecf96Smrg		}
22185dfecf96Smrg		break;
22195dfecf96Smrg	}
22205dfecf96Smrg    }
22215dfecf96Smrg}
22225dfecf96Smrg
22235dfecf96Smrgstatic long
22245dfecf96SmrgLinkPad(long offset, long adjust, int preffix, int datalen)
22255dfecf96Smrg{
22265dfecf96Smrg    /* If byte or aligned data */
22275dfecf96Smrg    if (datalen <= preffix || ((offset + adjust + preffix) % datalen) == 0)
22285dfecf96Smrg	return (adjust);
22295dfecf96Smrg
22305dfecf96Smrg    return (adjust + (datalen - ((offset + adjust + preffix) % datalen)));
22315dfecf96Smrg}
22325dfecf96Smrg
22335dfecf96Smrgstatic long
22345dfecf96SmrgLinkFixupOffsets(LispCom *com, CodeTree *tree, long adjust)
22355dfecf96Smrg{
22365dfecf96Smrg    for (; tree; tree = tree->next) {
22375dfecf96Smrg	switch (tree->type) {
22385dfecf96Smrg	    case CodeTreeBytecode:
22395dfecf96Smrg		switch (tree->code) {
22405dfecf96Smrg		    /* byte + short */
22415dfecf96Smrg		    case XBC_JUMP:
22425dfecf96Smrg		    case XBC_JUMPT:
22435dfecf96Smrg		    case XBC_JUMPNIL:
22445dfecf96Smrg			adjust = LinkPad(tree->offset, adjust, 1,
22455dfecf96Smrg					 sizeof(short));
22465dfecf96Smrg			/*FALLTROUGH*/
22475dfecf96Smrg		    default:
22485dfecf96Smrg			tree->offset += adjust;
22495dfecf96Smrg			break;
22505dfecf96Smrg		}
22515dfecf96Smrg		break;
22525dfecf96Smrg	    case CodeTreeLabel:
22535dfecf96Smrg		/* Labels are not loaded, just adjust offset */
22545dfecf96Smrg		tree->offset += adjust;
22555dfecf96Smrg		break;
22565dfecf96Smrg	    case CodeTreeJump:
22575dfecf96Smrg	    case CodeTreeCond:
22585dfecf96Smrg	    case CodeTreeJumpIf:
22595dfecf96Smrg		/* If an opcode will be generated. */
22605dfecf96Smrg		if (tree->code != XBC_NOOP)
22615dfecf96Smrg		    adjust = LinkPad(tree->offset, adjust, 1, sizeof(short));
22625dfecf96Smrg		tree->offset += adjust;
22635dfecf96Smrg		break;
22645dfecf96Smrg	    case CodeTreeGo:
22655dfecf96Smrg	    case CodeTreeReturn:
22665dfecf96Smrg		adjust = LinkPad(tree->offset, adjust, 1, sizeof(short));
22675dfecf96Smrg		tree->offset += adjust;
22685dfecf96Smrg		break;
22695dfecf96Smrg	    case CodeTreeBlock:
22705dfecf96Smrg		adjust = LinkFixupOffsets(com, tree->data.block->tree, adjust);
22715dfecf96Smrg		break;
22725dfecf96Smrg	}
22735dfecf96Smrg    }
22745dfecf96Smrg
22755dfecf96Smrg    return (adjust);
22765dfecf96Smrg}
22775dfecf96Smrg
22785dfecf96Smrgstatic void
22795dfecf96SmrgLinkSkipPadding(LispCom *com, CodeTree *tree)
22805dfecf96Smrg{
22815dfecf96Smrg    int found;
22825dfecf96Smrg    CodeTree *ptr;
22835dfecf96Smrg
22845dfecf96Smrg    /* Recurse to adjust forward jumps or jumps to the start of the block */
22855dfecf96Smrg    for (ptr = tree; ptr; ptr = ptr->next) {
22865dfecf96Smrg	if (ptr->type == CodeTreeBlock) {
22875dfecf96Smrg	    LinkSkipPadding(com, ptr->data.block->tree);
22885dfecf96Smrg	    ptr->offset = ptr->data.block->tree->offset;
22895dfecf96Smrg	}
22905dfecf96Smrg    }
22915dfecf96Smrg
22925dfecf96Smrg    /* Adjust the nodes offsets */
22935dfecf96Smrg    for (; tree; tree = tree->next) {
22945dfecf96Smrg	switch (tree->type) {
22955dfecf96Smrg	    case CodeTreeBytecode:
22965dfecf96Smrg	    case CodeTreeBlock:
22975dfecf96Smrg	    case CodeTreeGo:
22985dfecf96Smrg	    case CodeTreeReturn:
22995dfecf96Smrg		break;
23005dfecf96Smrg	    case CodeTreeJump:
23015dfecf96Smrg	    case CodeTreeCond:
23025dfecf96Smrg	    case CodeTreeJumpIf:
23035dfecf96Smrg		if (tree->code != XBC_NOOP)
23045dfecf96Smrg		    /* If code will be generated */
23055dfecf96Smrg		    break;
23065dfecf96Smrg	    case CodeTreeLabel:
23075dfecf96Smrg		/* This should be done in reversed order, but to avoid
23085dfecf96Smrg		 * the requirement of a prev pointer, do the job in a
23095dfecf96Smrg		 * harder way here. */
23105dfecf96Smrg		for (found = 0, ptr = tree->next; ptr; ptr = ptr->next) {
23115dfecf96Smrg		    switch (ptr->type) {
23125dfecf96Smrg			case CodeTreeBytecode:
23135dfecf96Smrg			case CodeTreeBlock:
23145dfecf96Smrg			case CodeTreeGo:
23155dfecf96Smrg			case CodeTreeReturn:
23165dfecf96Smrg			    found = 1;
23175dfecf96Smrg			    break;
23185dfecf96Smrg			case CodeTreeJump:
23195dfecf96Smrg			case CodeTreeCond:
23205dfecf96Smrg			case CodeTreeJumpIf:
23215dfecf96Smrg			    if (ptr->code != XBC_NOOP)
23225dfecf96Smrg				found = 1;
23235dfecf96Smrg			    break;
23245dfecf96Smrg			case CodeTreeLabel:
23255dfecf96Smrg			    break;
23265dfecf96Smrg		    }
23275dfecf96Smrg		    if (found)
23285dfecf96Smrg			break;
23295dfecf96Smrg		}
23305dfecf96Smrg		if (found)
23315dfecf96Smrg		    tree->offset = ptr->offset;
23325dfecf96Smrg		break;
23335dfecf96Smrg	}
23345dfecf96Smrg    }
23355dfecf96Smrg}
23365dfecf96Smrg
23375dfecf96Smrgstatic void
23385dfecf96SmrgLinkCalculateJump(LispCom *com, CodeTree *tree, LispByteOpcode code)
23395dfecf96Smrg{
23405dfecf96Smrg    long jumpto, offset, distance;
23415dfecf96Smrg
23425dfecf96Smrg    tree->type = CodeTreeBytecode;
23435dfecf96Smrg    /* After the opcode */
23445dfecf96Smrg    offset = tree->offset + 1;
23455dfecf96Smrg    jumpto = tree->data.tree->offset;
23465dfecf96Smrg    /* Effective distance */
23475dfecf96Smrg    distance = jumpto - offset;
23485dfecf96Smrg    tree->code = code;
23495dfecf96Smrg    if (distance < -32768 || distance > 32767) {
23505dfecf96Smrg	COMPILE_FAILURE("jump too long");
23515dfecf96Smrg    }
23525dfecf96Smrg    tree->data.signed_int = distance;
23535dfecf96Smrg}
23545dfecf96Smrg
23555dfecf96Smrgstatic void
23565dfecf96SmrgLinkFixupJumps(LispCom *com, CodeTree *tree)
23575dfecf96Smrg{
23585dfecf96Smrg    for (; tree; tree = tree->next) {
23595dfecf96Smrg	switch (tree->type) {
23605dfecf96Smrg	    case CodeTreeBytecode:
23615dfecf96Smrg	    case CodeTreeLabel:
23625dfecf96Smrg		break;
23635dfecf96Smrg	    case CodeTreeCond:
23645dfecf96Smrg		if (tree->code == XBC_JUMPNIL)
23655dfecf96Smrg		    /* Go to next test if NIL */
23665dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMPNIL);
23675dfecf96Smrg		else if (tree->code == XBC_JUMPT)
23685dfecf96Smrg		    /* After executing T code */
23695dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMP);
23705dfecf96Smrg		break;
23715dfecf96Smrg	    case CodeTreeJumpIf:
23725dfecf96Smrg		if (tree->code != XBC_NOOP)
23735dfecf96Smrg		    LinkCalculateJump(com, tree, tree->code);
23745dfecf96Smrg		break;
23755dfecf96Smrg	    case CodeTreeGo:
23765dfecf96Smrg		/* Inconditional jump */
23775dfecf96Smrg		LinkCalculateJump(com, tree, XBC_JUMP);
23785dfecf96Smrg		break;
23795dfecf96Smrg	    case CodeTreeReturn:
23805dfecf96Smrg		/* Inconditional jump */
23815dfecf96Smrg		if (tree->data.tree != tree)
23825dfecf96Smrg		    /* If need to skip something */
23835dfecf96Smrg		    LinkCalculateJump(com, tree, XBC_JUMP);
23845dfecf96Smrg		break;
23855dfecf96Smrg	    case CodeTreeBlock:
23865dfecf96Smrg		LinkFixupJumps(com, tree->data.block->tree);
23875dfecf96Smrg		break;
23885dfecf96Smrg	    case CodeTreeJump:
23895dfecf96Smrg		if (tree->code != XBC_NOOP)
23905dfecf96Smrg		    LinkCalculateJump(com, tree, tree->code);
23915dfecf96Smrg	}
23925dfecf96Smrg    }
23935dfecf96Smrg}
23945dfecf96Smrg
23955dfecf96Smrgstatic void
23965dfecf96SmrgLinkBuildTableSymbol(LispCom *com, LispAtom *symbol)
23975dfecf96Smrg{
23985dfecf96Smrg    if (BuildTablePointer(symbol, (void***)&com->table.symbols,
23995dfecf96Smrg			  &com->table.num_symbols) > 0xff) {
24005dfecf96Smrg	COMPILE_FAILURE("more than 256 symbols");
24015dfecf96Smrg    }
24025dfecf96Smrg}
24035dfecf96Smrg
24045dfecf96Smrgstatic void
24055dfecf96SmrgLinkBuildTableConstant(LispCom *com, LispObj *constant)
24065dfecf96Smrg{
24075dfecf96Smrg    if (BuildTablePointer(constant, (void***)&com->table.constants,
24085dfecf96Smrg			  &com->table.num_constants) > 0xff) {
24095dfecf96Smrg	COMPILE_FAILURE("more than 256 constants");
24105dfecf96Smrg    }
24115dfecf96Smrg}
24125dfecf96Smrg
24135dfecf96Smrgstatic void
24145dfecf96SmrgLinkBuildTableBuiltin(LispCom *com, LispBuiltin *builtin)
24155dfecf96Smrg{
24165dfecf96Smrg    if (BuildTablePointer(builtin, (void***)&com->table.builtins,
24175dfecf96Smrg			  &com->table.num_builtins) > 0xff) {
24185dfecf96Smrg	COMPILE_FAILURE("more than 256 functions");
24195dfecf96Smrg    }
24205dfecf96Smrg}
24215dfecf96Smrg
24225dfecf96Smrgstatic void
24235dfecf96SmrgLinkBuildTableBytecode(LispCom *com, LispObj *bytecode)
24245dfecf96Smrg{
24255dfecf96Smrg    if (BuildTablePointer(bytecode, (void***)&com->table.bytecodes,
24265dfecf96Smrg			  &com->table.num_bytecodes) > 0xff) {
24275dfecf96Smrg	COMPILE_FAILURE("more than 256 bytecode functions");
24285dfecf96Smrg    }
24295dfecf96Smrg}
24305dfecf96Smrg
24315dfecf96Smrgstatic void
24325dfecf96SmrgLinkBuildTables(LispCom *com, CodeBlock *block)
24335dfecf96Smrg{
24345dfecf96Smrg    CodeTree *tree;
24355dfecf96Smrg
24365dfecf96Smrg    for (tree = block->tree; tree; tree = tree->next) {
24375dfecf96Smrg	switch (tree->type) {
24385dfecf96Smrg	    case CodeTreeBytecode:
24395dfecf96Smrg		switch (tree->code) {
24405dfecf96Smrg		    case XBC_LET:
24415dfecf96Smrg		    case XBC_LETX:
24425dfecf96Smrg		    case XBC_LET_NIL:
24435dfecf96Smrg		    case XBC_LETX_NIL:
24445dfecf96Smrg		    case XBC_SETSYM:
24455dfecf96Smrg		    case XBC_LOADSYM:
24465dfecf96Smrg		    case XBC_LOADSYM_PUSH:
24475dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.atom);
24485dfecf96Smrg			break;
24495dfecf96Smrg		    case XBC_STRUCTP:
24505dfecf96Smrg		    case XBC_LOADCON:
24515dfecf96Smrg		    case XBC_LOADCON_PUSH:
24525dfecf96Smrg			LinkBuildTableConstant(com, tree->data.object);
24535dfecf96Smrg			break;
24545dfecf96Smrg		    case XBC_LOADCON_SET:
24555dfecf96Smrg			LinkBuildTableConstant(com, tree->data.load_con_set.object);
24565dfecf96Smrg			break;
24575dfecf96Smrg		    case XBC_CALL:
24585dfecf96Smrg		    case XBC_CALL_SET:
24595dfecf96Smrg			LinkBuildTableBuiltin(com, tree->data.builtin.builtin);
24605dfecf96Smrg			break;
24615dfecf96Smrg		    case XBC_BYTECALL:
24625dfecf96Smrg			LinkBuildTableBytecode(com, tree->data.bytecall.code);
24635dfecf96Smrg			break;
24645dfecf96Smrg		    case XBC_LOAD_LET:
24655dfecf96Smrg		    case XBC_LOAD_LETX:
24665dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let.name);
24675dfecf96Smrg			break;
24685dfecf96Smrg		    case XBC_STRUCT:
24695dfecf96Smrg			LinkBuildTableConstant(com, tree->data.struc.definition);
24705dfecf96Smrg			break;
24715dfecf96Smrg		    case XBC_LOADSYM_LET:
24725dfecf96Smrg		    case XBC_LOADSYM_LETX:
24735dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_sym.symbol);
24745dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_sym.name);
24755dfecf96Smrg			break;
24765dfecf96Smrg		    case XBC_LOADCON_LET:
24775dfecf96Smrg		    case XBC_LOADCON_LETX:
24785dfecf96Smrg			LinkBuildTableConstant(com, tree->data.let_con.object);
24795dfecf96Smrg			LinkBuildTableSymbol(com, tree->data.let_con.name);
24805dfecf96Smrg			break;
24815dfecf96Smrg		    case XBC_CCONS:
24825dfecf96Smrg		    case XBC_FUNCALL:
24835dfecf96Smrg			LinkBuildTableConstant(com, tree->data.cons.car);
24845dfecf96Smrg			LinkBuildTableConstant(com, tree->data.cons.cdr);
24855dfecf96Smrg			break;
24865dfecf96Smrg		    default:
24875dfecf96Smrg			break;
24885dfecf96Smrg		}
24895dfecf96Smrg		break;
24905dfecf96Smrg	    case CodeTreeBlock:
24915dfecf96Smrg		LinkBuildTables(com, tree->data.block);
24925dfecf96Smrg		break;
24935dfecf96Smrg	    default:
24945dfecf96Smrg		break;
24955dfecf96Smrg	}
24965dfecf96Smrg    }
24975dfecf96Smrg}
24985dfecf96Smrg
24995dfecf96Smrgstatic long
25005dfecf96SmrgLinkEmmitBytecode(LispCom *com, CodeTree *tree,
25015dfecf96Smrg		  unsigned char *bytecode, long offset)
25025dfecf96Smrg{
25035dfecf96Smrg    short i;
25045dfecf96Smrg
25055dfecf96Smrg    for (; tree; tree = tree->next) {
25065dfecf96Smrg	/* Fill padding */
25075dfecf96Smrg	while (offset < tree->offset)
25085dfecf96Smrg	    bytecode[offset++] = XBC_NOOP;
25095dfecf96Smrg
25105dfecf96Smrg	switch (tree->type) {
25115dfecf96Smrg	    case CodeTreeBytecode:
25125dfecf96Smrg		bytecode[offset++] = tree->code;
25135dfecf96Smrg		switch (tree->code) {
25145dfecf96Smrg		    /* Noop should not enter the CodeTree */
25155dfecf96Smrg		    case XBC_NOOP:
25165dfecf96Smrg			INTERNAL_ERROR(__LINE__);
25175dfecf96Smrg			break;
25185dfecf96Smrg
25195dfecf96Smrg		    /* byte */
25205dfecf96Smrg		    case XBC_BCONS:
25215dfecf96Smrg		    case XBC_BCONS1:
25225dfecf96Smrg		    case XBC_BCONS2:
25235dfecf96Smrg		    case XBC_BCONS3:
25245dfecf96Smrg		    case XBC_BCONS4:
25255dfecf96Smrg		    case XBC_BCONS5:
25265dfecf96Smrg		    case XBC_BCONS6:
25275dfecf96Smrg		    case XBC_BCONS7:
25285dfecf96Smrg		    case XBC_INV:
25295dfecf96Smrg		    case XBC_NIL:
25305dfecf96Smrg		    case XBC_T:
25315dfecf96Smrg		    case XBC_PUSH_NIL:
25325dfecf96Smrg		    case XBC_PUSH_UNSPEC:
25335dfecf96Smrg		    case XBC_PUSH_T:
25345dfecf96Smrg		    case XBC_CAR_PUSH:
25355dfecf96Smrg		    case XBC_CDR_PUSH:
25365dfecf96Smrg		    case XBC_PUSH:
25375dfecf96Smrg		    case XBC_LSTAR:
25385dfecf96Smrg		    case XBC_LCONS:
25395dfecf96Smrg		    case XBC_LFINI:
25405dfecf96Smrg		    case XBC_RETURN:
25415dfecf96Smrg		    case XBC_CSTAR:
25425dfecf96Smrg		    case XBC_CFINI:
25435dfecf96Smrg		    case XBC_CAR:
25445dfecf96Smrg		    case XBC_CDR:
25455dfecf96Smrg		    case XBC_RPLACA:
25465dfecf96Smrg		    case XBC_RPLACD:
25475dfecf96Smrg		    case XBC_EQ:
25485dfecf96Smrg		    case XBC_EQL:
25495dfecf96Smrg		    case XBC_EQUAL:
25505dfecf96Smrg		    case XBC_EQUALP:
25515dfecf96Smrg		    case XBC_LENGTH:
25525dfecf96Smrg		    case XBC_LAST:
25535dfecf96Smrg		    case XBC_NTHCDR:
25545dfecf96Smrg			break;
25555dfecf96Smrg
25565dfecf96Smrg		    /* byte + byte */
25575dfecf96Smrg		    case XBC_LETREC:
25585dfecf96Smrg		    case XBC_PRED:
25595dfecf96Smrg		    case XBC_PUSH_NIL_N:
25605dfecf96Smrg		    case XBC_PUSH_UNSPEC_N:
25615dfecf96Smrg			bytecode[offset++] = tree->data.signed_char;
25625dfecf96Smrg			break;
25635dfecf96Smrg
25645dfecf96Smrg		    /* byte + byte */
25655dfecf96Smrg		    case XBC_CAR_SET:
25665dfecf96Smrg		    case XBC_CDR_SET:
25675dfecf96Smrg		    case XBC_SET:
25685dfecf96Smrg		    case XBC_SET_NIL:
25695dfecf96Smrg		    case XBC_LETBIND:
25705dfecf96Smrg		    case XBC_UNLET:
25715dfecf96Smrg		    case XBC_LOAD_PUSH:
25725dfecf96Smrg		    case XBC_LOAD:
25735dfecf96Smrg		    case XBC_LOAD_CAR:
25745dfecf96Smrg		    case XBC_LOAD_CDR:
25755dfecf96Smrg		    case XBC_LOAD_CAR_STORE:
25765dfecf96Smrg		    case XBC_LOAD_CDR_STORE:
25775dfecf96Smrg			bytecode[offset++] = tree->data.signed_short;
25785dfecf96Smrg			break;
25795dfecf96Smrg
25805dfecf96Smrg		    /* byte + byte + byte */
25815dfecf96Smrg		    case XBC_LOAD_SET:
25825dfecf96Smrg		    case XBC_LOAD_CAR_SET:
25835dfecf96Smrg		    case XBC_LOAD_CDR_SET:
25845dfecf96Smrg			bytecode[offset++] = tree->data.load_set.load;
25855dfecf96Smrg			bytecode[offset++] = tree->data.load_set.set;
25865dfecf96Smrg			break;
25875dfecf96Smrg
25885dfecf96Smrg		    /* byte + short */
25895dfecf96Smrg		    case XBC_JUMP:
25905dfecf96Smrg		    case XBC_JUMPT:
25915dfecf96Smrg		    case XBC_JUMPNIL:
25925dfecf96Smrg			*(short*)(bytecode + offset) = tree->data.signed_int;
25935dfecf96Smrg			offset += sizeof(short);
25945dfecf96Smrg			break;
25955dfecf96Smrg
25965dfecf96Smrg		    /* byte + byte */
25975dfecf96Smrg		    case XBC_LET:
25985dfecf96Smrg		    case XBC_LETX:
25995dfecf96Smrg		    case XBC_LET_NIL:
26005dfecf96Smrg		    case XBC_LETX_NIL:
26015dfecf96Smrg		    case XBC_SETSYM:
26025dfecf96Smrg		    case XBC_LOADSYM:
26035dfecf96Smrg		    case XBC_LOADSYM_PUSH:
26045dfecf96Smrg			i = FindIndex(tree->data.atom,
26055dfecf96Smrg				      (void**)com->table.symbols,
26065dfecf96Smrg				      com->table.num_symbols);
26075dfecf96Smrg			bytecode[offset++] = i;
26085dfecf96Smrg			break;
26095dfecf96Smrg
26105dfecf96Smrg		    /* byte + byte */
26115dfecf96Smrg		    case XBC_STRUCTP:
26125dfecf96Smrg		    case XBC_LOADCON:
26135dfecf96Smrg		    case XBC_LOADCON_PUSH:
26145dfecf96Smrg			i = FindIndex(tree->data.object,
26155dfecf96Smrg				      (void**)com->table.constants,
26165dfecf96Smrg				      com->table.num_constants);
26175dfecf96Smrg			bytecode[offset++] = i;
26185dfecf96Smrg			break;
26195dfecf96Smrg
26205dfecf96Smrg		    /* byte + byte + byte */
26215dfecf96Smrg		    case XBC_LOADCON_SET:
26225dfecf96Smrg			i = FindIndex(tree->data.load_con_set.object,
26235dfecf96Smrg				      (void**)com->table.constants,
26245dfecf96Smrg				      com->table.num_constants);
26255dfecf96Smrg			bytecode[offset++] = i;
26265dfecf96Smrg			bytecode[offset++] = tree->data.load_con_set.offset;
26275dfecf96Smrg			break;
26285dfecf96Smrg
26295dfecf96Smrg		    /* byte + byte + byte */
26305dfecf96Smrg		    case XBC_CALL:
26315dfecf96Smrg			bytecode[offset++] = tree->data.builtin.num_arguments;
26325dfecf96Smrg			i = FindIndex(tree->data.builtin.builtin,
26335dfecf96Smrg				      (void**)com->table.builtins,
26345dfecf96Smrg				      com->table.num_builtins);
26355dfecf96Smrg			bytecode[offset++] = i;
26365dfecf96Smrg			break;
26375dfecf96Smrg
26385dfecf96Smrg		    /* byte + byte + byte */
26395dfecf96Smrg		    case XBC_BYTECALL:
26405dfecf96Smrg			bytecode[offset++] = tree->data.bytecall.num_arguments;
26415dfecf96Smrg			i = FindIndex(tree->data.bytecall.code,
26425dfecf96Smrg				      (void**)com->table.bytecodes,
26435dfecf96Smrg				      com->table.num_bytecodes);
26445dfecf96Smrg			bytecode[offset++] = i;
26455dfecf96Smrg			break;
26465dfecf96Smrg
26475dfecf96Smrg		    /* byte + byte + byte + byte */
26485dfecf96Smrg		    case XBC_CALL_SET:
26495dfecf96Smrg			bytecode[offset++] = tree->data.builtin.num_arguments;
26505dfecf96Smrg			i = FindIndex(tree->data.builtin.builtin,
26515dfecf96Smrg				      (void**)com->table.builtins,
26525dfecf96Smrg				      com->table.num_builtins);
26535dfecf96Smrg			bytecode[offset++] = i;
26545dfecf96Smrg			bytecode[offset++] = tree->data.builtin.offset;
26555dfecf96Smrg			break;
26565dfecf96Smrg
26575dfecf96Smrg		    /* byte + byte + byte */
26585dfecf96Smrg		    case XBC_LOAD_LET:
26595dfecf96Smrg		    case XBC_LOAD_LETX:
26605dfecf96Smrg			bytecode[offset++] = tree->data.let.offset;
26615dfecf96Smrg			i = FindIndex(tree->data.let.name,
26625dfecf96Smrg				      (void**)com->table.symbols,
26635dfecf96Smrg				      com->table.num_symbols);
26645dfecf96Smrg			bytecode[offset++] = i;
26655dfecf96Smrg			break;
26665dfecf96Smrg
26675dfecf96Smrg		    /* byte + byte + byte */
26685dfecf96Smrg		    case XBC_STRUCT:
26695dfecf96Smrg			bytecode[offset++] = tree->data.struc.offset;
26705dfecf96Smrg			i = FindIndex(tree->data.struc.definition,
26715dfecf96Smrg				      (void**)com->table.constants,
26725dfecf96Smrg				      com->table.num_constants);
26735dfecf96Smrg			bytecode[offset++] = i;
26745dfecf96Smrg			break;
26755dfecf96Smrg
26765dfecf96Smrg		    /* byte + byte + byte */
26775dfecf96Smrg		    case XBC_LOADSYM_LET:
26785dfecf96Smrg		    case XBC_LOADSYM_LETX:
26795dfecf96Smrg			i = FindIndex(tree->data.let_sym.symbol,
26805dfecf96Smrg				      (void**)com->table.symbols,
26815dfecf96Smrg				      com->table.num_symbols);
26825dfecf96Smrg			bytecode[offset++] = i;
26835dfecf96Smrg			i = FindIndex(tree->data.let_sym.name,
26845dfecf96Smrg				      (void**)com->table.symbols,
26855dfecf96Smrg				      com->table.num_symbols);
26865dfecf96Smrg			bytecode[offset++] = i;
26875dfecf96Smrg			break;
26885dfecf96Smrg
26895dfecf96Smrg		    /* byte + byte + byte */
26905dfecf96Smrg		    case XBC_LOADCON_LET:
26915dfecf96Smrg		    case XBC_LOADCON_LETX:
26925dfecf96Smrg			i = FindIndex(tree->data.let_con.object,
26935dfecf96Smrg				      (void**)com->table.constants,
26945dfecf96Smrg				      com->table.num_constants);
26955dfecf96Smrg			bytecode[offset++] = i;
26965dfecf96Smrg			i = FindIndex(tree->data.let_con.name,
26975dfecf96Smrg				      (void**)com->table.symbols,
26985dfecf96Smrg				      com->table.num_symbols);
26995dfecf96Smrg			bytecode[offset++] = i;
27005dfecf96Smrg			break;
27015dfecf96Smrg
27025dfecf96Smrg		    /* byte + byte + byte */
27035dfecf96Smrg		    case XBC_CCONS:
27045dfecf96Smrg		    case XBC_FUNCALL:
27055dfecf96Smrg			i = FindIndex(tree->data.cons.car,
27065dfecf96Smrg				      (void**)com->table.constants,
27075dfecf96Smrg				      com->table.num_constants);
27085dfecf96Smrg			bytecode[offset++] = i;
27095dfecf96Smrg			i = FindIndex(tree->data.cons.cdr,
27105dfecf96Smrg				      (void**)com->table.constants,
27115dfecf96Smrg				      com->table.num_constants);
27125dfecf96Smrg			bytecode[offset++] = i;
27135dfecf96Smrg			break;
27145dfecf96Smrg		}
27155dfecf96Smrg		break;
27165dfecf96Smrg	    case CodeTreeLabel:
27175dfecf96Smrg		/* Labels are not loaded */
27185dfecf96Smrg		break;
27195dfecf96Smrg	    case CodeTreeCond:
27205dfecf96Smrg	    case CodeTreeJump:
27215dfecf96Smrg	    case CodeTreeJumpIf:
27225dfecf96Smrg		if (tree->code != XBC_NOOP)
27235dfecf96Smrg		    INTERNAL_ERROR(__LINE__);
27245dfecf96Smrg		break;
27255dfecf96Smrg	    case CodeTreeGo:
27265dfecf96Smrg		INTERNAL_ERROR(__LINE__);
27275dfecf96Smrg		break;
27285dfecf96Smrg	    case CodeTreeReturn:
27295dfecf96Smrg		if (tree->data.tree != tree)
27305dfecf96Smrg		    INTERNAL_ERROR(__LINE__);
27315dfecf96Smrg		break;
27325dfecf96Smrg	    case CodeTreeBlock:
27335dfecf96Smrg		offset = LinkEmmitBytecode(com, tree->data.block->tree,
27345dfecf96Smrg					   bytecode, offset);
27355dfecf96Smrg		break;
27365dfecf96Smrg	}
27375dfecf96Smrg    }
27385dfecf96Smrg
27395dfecf96Smrg    return (offset);
27405dfecf96Smrg}
27415dfecf96Smrg
27425dfecf96Smrgstatic void
27435dfecf96SmrgLinkBytecode(LispCom *com)
27445dfecf96Smrg{
27455dfecf96Smrg    long offset, count;
27465dfecf96Smrg    unsigned char **codes;
27475dfecf96Smrg    LispObj **names;
27485dfecf96Smrg
27495dfecf96Smrg    /* Close bytecode */
27505dfecf96Smrg    com_Bytecode(com, XBC_RETURN);
27515dfecf96Smrg
27525dfecf96Smrg    /* The only usage of this information for now, and still may generate
27535dfecf96Smrg     * false positives because arguments to unamed functions are not being
27545dfecf96Smrg     * parsed as well as arguments to yet undefined function/maros.
27555dfecf96Smrg     * XXX should also add declaim/declare to let the code specify that
27565dfecf96Smrg     * the argument is unused */
27575dfecf96Smrg    LinkWarnUnused(com, com->block);
27585dfecf96Smrg
27595dfecf96Smrg    /* First level optimization */
27605dfecf96Smrg    LinkOptimize_0(com);
27615dfecf96Smrg
27625dfecf96Smrg    /* Resolve tagbody labels */
27635dfecf96Smrg    LinkResolveLabels(com, com->block);
27645dfecf96Smrg
27655dfecf96Smrg    /* Resolve any pending jumps */
27665dfecf96Smrg    LinkResolveJumps(com, com->block);
27675dfecf96Smrg
27685dfecf96Smrg    /* Calculate unpadded offsets */
27695dfecf96Smrg    LinkBuildOffsets(com, com->block->tree, 0);
27705dfecf96Smrg
27715dfecf96Smrg    /* Do padding for aligned memory reads */
27725dfecf96Smrg    LinkFixupOffsets(com, com->block->tree, 0);
27735dfecf96Smrg
27745dfecf96Smrg    /* Jumps normally are to a node that does not generate code,
27755dfecf96Smrg     * and due to padding, the jump may go to a address with a
27765dfecf96Smrg     * XBC_NOOP, so adjust the jump to the next useful opcode. */
27775dfecf96Smrg    LinkSkipPadding(com, com->block->tree);
27785dfecf96Smrg
27795dfecf96Smrg    /* Now addresses are known */
27805dfecf96Smrg    LinkFixupJumps(com, com->block->tree);
27815dfecf96Smrg
27825dfecf96Smrg    /* Build symbol, constant and builtin tables */
27835dfecf96Smrg    LinkBuildTables(com, com->block);
27845dfecf96Smrg
27855dfecf96Smrg    /* Stack info */
27865dfecf96Smrg    com->length = sizeof(short) * 3;
27875dfecf96Smrg    /* Tables info */
27885dfecf96Smrg    com->length += sizeof(short) * 4;
27895dfecf96Smrg    com->length += com->table.num_constants * sizeof(LispObj*);
27905dfecf96Smrg    com->length += com->table.num_symbols * sizeof(LispAtom*);
27915dfecf96Smrg    com->length += com->table.num_builtins * sizeof(LispBuiltin*);
27925dfecf96Smrg    com->length += com->table.num_bytecodes * sizeof(unsigned char*);
27935dfecf96Smrg    com->length += com->table.num_bytecodes * sizeof(LispObj*);
27945dfecf96Smrg
27955dfecf96Smrg    /* Allocate space for the bytecode stream */
27965dfecf96Smrg    com->length += com->block->tail->offset + 1;
27975dfecf96Smrg    com->bytecode = LispMalloc(com->length);
27985dfecf96Smrg
27995dfecf96Smrg    /* Add header */
28005dfecf96Smrg    offset = 0;
28015dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.stack;
28025dfecf96Smrg    offset += sizeof(short);
28035dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.bstack;
28045dfecf96Smrg    offset += sizeof(short);
28055dfecf96Smrg    *(short*)(com->bytecode + offset) = com->stack.pstack;
28065dfecf96Smrg    offset += sizeof(short);
28075dfecf96Smrg
28085dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_constants;
28095dfecf96Smrg    offset += sizeof(short);
28105dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_symbols;
28115dfecf96Smrg    offset += sizeof(short);
28125dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_builtins;
28135dfecf96Smrg    offset += sizeof(short);
28145dfecf96Smrg    *(short*)(com->bytecode + offset) = com->table.num_bytecodes;
28155dfecf96Smrg    offset += sizeof(short);
28165dfecf96Smrg
28175dfecf96Smrg    count = sizeof(LispObj*) * com->table.num_constants;
28185dfecf96Smrg    memcpy(com->bytecode + offset, com->table.constants, count);
28195dfecf96Smrg    offset += count;
28205dfecf96Smrg    count = sizeof(LispAtom*) * com->table.num_symbols;
28215dfecf96Smrg    memcpy(com->bytecode + offset, com->table.symbols, count);
28225dfecf96Smrg    offset += count;
28235dfecf96Smrg    count = sizeof(LispBuiltin*) * com->table.num_builtins;
28245dfecf96Smrg    memcpy(com->bytecode + offset, com->table.builtins, count);
28255dfecf96Smrg    offset += count;
28265dfecf96Smrg
28275dfecf96Smrg    /* Store bytecode information */
28285dfecf96Smrg    for (count = 0, codes = (unsigned char**)(com->bytecode + offset);
28295dfecf96Smrg	 count < com->table.num_bytecodes; count++, codes++)
28305dfecf96Smrg	*codes = com->table.bytecodes[count]->data.bytecode.bytecode->code;
28315dfecf96Smrg    offset += com->table.num_bytecodes * sizeof(unsigned char*);
28325dfecf96Smrg    /* Store names, only useful for disassemble but may also be used
28335dfecf96Smrg     * to check if a function was redefined, and the bytecode is referencing
28345dfecf96Smrg     * the older version, the current version can be checked looking at
28355dfecf96Smrg     * <name>->data.atom */
28365dfecf96Smrg    for (count = 0, names = (LispObj**)(com->bytecode + offset);
28375dfecf96Smrg	 count < com->table.num_bytecodes; count++, names++)
28385dfecf96Smrg	*names = com->table.bytecodes[count]->data.bytecode.name;
28395dfecf96Smrg    offset += com->table.num_bytecodes * sizeof(LispObj*);
28405dfecf96Smrg
28415dfecf96Smrg    /* Generate it */
28425dfecf96Smrg    LinkEmmitBytecode(com, com->block->tree, com->bytecode + offset, 0);
28435dfecf96Smrg}
28445dfecf96Smrg
28455dfecf96Smrgstatic LispObj *
28465dfecf96SmrgExecuteBytecode(register unsigned char *stream)
28475dfecf96Smrg{
28485dfecf96Smrg    register LispObj *reg0;
28495dfecf96Smrg    register LispAtom *atom;
28505dfecf96Smrg    register short offset;
28515dfecf96Smrg    LispObj *reg1;
28525dfecf96Smrg    LispBuiltin *builtin;
28535dfecf96Smrg    LispObj *lambda;
28545dfecf96Smrg    LispObj *arguments;
28555dfecf96Smrg    unsigned char *bytecode;
28565dfecf96Smrg
28575dfecf96Smrg    LispObj **constants;
28585dfecf96Smrg    LispAtom **symbols;
28595dfecf96Smrg    LispBuiltin **builtins;
28605dfecf96Smrg    unsigned char **codes;
28615dfecf96Smrg    short num_constants, num_symbols, num_builtins, num_codes;
28625dfecf96Smrg
28635dfecf96Smrg    int lex, len;
28645dfecf96Smrg
28655dfecf96Smrg    /* To control gc protected slots */
28665dfecf96Smrg    int phead, pbase;
28675dfecf96Smrg
28685dfecf96Smrg    long fixnum = 0;
28695dfecf96Smrg
28705dfecf96Smrg#if defined(__GNUC__) && !defined(ANSI_SOURCE)
28715dfecf96Smrg#define ALLOW_GOTO_ADDRESS
28725dfecf96Smrg#endif
28735dfecf96Smrg
28745dfecf96Smrg#ifdef ALLOW_GOTO_ADDRESS
28755dfecf96Smrg#define JUMP_ADDRESS(label)	&&label
28765dfecf96Smrg    static const void *opcode_labels[] = {
28775dfecf96Smrg	JUMP_ADDRESS(XBC_NOOP),
28785dfecf96Smrg	JUMP_ADDRESS(XBC_INV),
28795dfecf96Smrg	JUMP_ADDRESS(XBC_NIL),
28805dfecf96Smrg	JUMP_ADDRESS(XBC_T),
28815dfecf96Smrg	JUMP_ADDRESS(XBC_PRED),
28825dfecf96Smrg	JUMP_ADDRESS(XBC_CAR),
28835dfecf96Smrg	JUMP_ADDRESS(XBC_CDR),
28845dfecf96Smrg	JUMP_ADDRESS(XBC_CAR_SET),
28855dfecf96Smrg	JUMP_ADDRESS(XBC_CDR_SET),
28865dfecf96Smrg	JUMP_ADDRESS(XBC_RPLACA),
28875dfecf96Smrg	JUMP_ADDRESS(XBC_RPLACD),
28885dfecf96Smrg	JUMP_ADDRESS(XBC_EQ),
28895dfecf96Smrg	JUMP_ADDRESS(XBC_EQL),
28905dfecf96Smrg	JUMP_ADDRESS(XBC_EQUAL),
28915dfecf96Smrg	JUMP_ADDRESS(XBC_EQUALP),
28925dfecf96Smrg	JUMP_ADDRESS(XBC_LENGTH),
28935dfecf96Smrg	JUMP_ADDRESS(XBC_LAST),
28945dfecf96Smrg	JUMP_ADDRESS(XBC_NTHCDR),
28955dfecf96Smrg	JUMP_ADDRESS(XBC_CAR_PUSH),
28965dfecf96Smrg	JUMP_ADDRESS(XBC_CDR_PUSH),
28975dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH),
28985dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_NIL),
28995dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_UNSPEC),
29005dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_T),
29015dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_NIL_N),
29025dfecf96Smrg	JUMP_ADDRESS(XBC_PUSH_UNSPEC_N),
29035dfecf96Smrg	JUMP_ADDRESS(XBC_LET),
29045dfecf96Smrg	JUMP_ADDRESS(XBC_LETX),
29055dfecf96Smrg	JUMP_ADDRESS(XBC_LET_NIL),
29065dfecf96Smrg	JUMP_ADDRESS(XBC_LETX_NIL),
29075dfecf96Smrg	JUMP_ADDRESS(XBC_LETBIND),
29085dfecf96Smrg	JUMP_ADDRESS(XBC_UNLET),
29095dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD),
29105dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_LET),
29115dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_LETX),
29125dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_PUSH),
29135dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON),
29145dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_LET),
29155dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_LETX),
29165dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_PUSH),
29175dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR),
29185dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR),
29195dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR_STORE),
29205dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR_STORE),
29215dfecf96Smrg	JUMP_ADDRESS(XBC_LOADCON_SET),
29225dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM),
29235dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_LET),
29245dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_LETX),
29255dfecf96Smrg	JUMP_ADDRESS(XBC_LOADSYM_PUSH),
29265dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_SET),
29275dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CAR_SET),
29285dfecf96Smrg	JUMP_ADDRESS(XBC_LOAD_CDR_SET),
29295dfecf96Smrg	JUMP_ADDRESS(XBC_SET),
29305dfecf96Smrg	JUMP_ADDRESS(XBC_SETSYM),
29315dfecf96Smrg	JUMP_ADDRESS(XBC_SET_NIL),
29325dfecf96Smrg	JUMP_ADDRESS(XBC_CALL),
29335dfecf96Smrg	JUMP_ADDRESS(XBC_CALL_SET),
29345dfecf96Smrg	JUMP_ADDRESS(XBC_BYTECALL),
29355dfecf96Smrg	JUMP_ADDRESS(XBC_FUNCALL),
29365dfecf96Smrg	JUMP_ADDRESS(XBC_LETREC),
29375dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS),
29385dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS1),
29395dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS2),
29405dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS3),
29415dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS4),
29425dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS5),
29435dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS6),
29445dfecf96Smrg	JUMP_ADDRESS(XBC_BCONS7),
29455dfecf96Smrg	JUMP_ADDRESS(XBC_CCONS),
29465dfecf96Smrg	JUMP_ADDRESS(XBC_CSTAR),
29475dfecf96Smrg	JUMP_ADDRESS(XBC_CFINI),
29485dfecf96Smrg	JUMP_ADDRESS(XBC_LSTAR),
29495dfecf96Smrg	JUMP_ADDRESS(XBC_LCONS),
29505dfecf96Smrg	JUMP_ADDRESS(XBC_LFINI),
29515dfecf96Smrg	JUMP_ADDRESS(XBC_JUMP),
29525dfecf96Smrg	JUMP_ADDRESS(XBC_JUMPT),
29535dfecf96Smrg	JUMP_ADDRESS(XBC_JUMPNIL),
29545dfecf96Smrg	JUMP_ADDRESS(XBC_STRUCT),
29555dfecf96Smrg	JUMP_ADDRESS(XBC_STRUCTP),
29565dfecf96Smrg	JUMP_ADDRESS(XBC_RETURN)
29575dfecf96Smrg    };
29585dfecf96Smrg    static const void *predicate_opcode_labels[] = {
29595dfecf96Smrg	JUMP_ADDRESS(XBP_CONSP),
29605dfecf96Smrg	JUMP_ADDRESS(XBP_LISTP),
29615dfecf96Smrg	JUMP_ADDRESS(XBP_NUMBERP)
29625dfecf96Smrg    };
29635dfecf96Smrg#endif
29645dfecf96Smrg
29655dfecf96Smrg    reg0 = NIL;
29665dfecf96Smrg
29675dfecf96Smrg    bytecode = stream;
29685dfecf96Smrg    pbase = lisp__data.protect.length;
29695dfecf96Smrg
29705dfecf96Smrg    /* stack */
29715dfecf96Smrg    offset = *(short*)stream;
29725dfecf96Smrg    stream += sizeof(short);
29735dfecf96Smrg    if (lisp__data.env.length + offset > lisp__data.env.space) {
29745dfecf96Smrg	do
29755dfecf96Smrg	    LispMoreEnvironment();
29765dfecf96Smrg	while (lisp__data.env.length + offset >= lisp__data.env.space);
29775dfecf96Smrg    }
29785dfecf96Smrg    /* builtin stack */
29795dfecf96Smrg    offset = *(short*)stream;
29805dfecf96Smrg    stream += sizeof(short);
29815dfecf96Smrg    if (lisp__data.stack.length + offset >= lisp__data.stack.space) {
29825dfecf96Smrg	do
29835dfecf96Smrg	    LispMoreStack();
29845dfecf96Smrg	while (lisp__data.stack.length + offset >= lisp__data.stack.space);
29855dfecf96Smrg    }
29865dfecf96Smrg    /* protect stack */
29875dfecf96Smrg    phead = *(short*)stream;
29885dfecf96Smrg    stream += sizeof(short);
29895dfecf96Smrg    if (lisp__data.protect.length + phead > lisp__data.protect.space) {
29905dfecf96Smrg	do
29915dfecf96Smrg	    LispMoreProtects();
29925dfecf96Smrg	while (lisp__data.protect.length + phead >= lisp__data.protect.space);
29935dfecf96Smrg    }
29945dfecf96Smrg
29955dfecf96Smrg    num_constants = *(short*)stream;
29965dfecf96Smrg    stream += sizeof(short);
29975dfecf96Smrg    num_symbols = *(short*)stream;
29985dfecf96Smrg    stream += sizeof(short);
29995dfecf96Smrg    num_builtins = *(short*)stream;
30005dfecf96Smrg    stream += sizeof(short);
30015dfecf96Smrg    num_codes = *(short*)stream;
30025dfecf96Smrg    stream += sizeof(short);
30035dfecf96Smrg
30045dfecf96Smrg    constants = (LispObj**)stream;
30055dfecf96Smrg    stream += num_constants * sizeof(LispObj*);
30065dfecf96Smrg    symbols = (LispAtom**)stream;
30075dfecf96Smrg    stream += num_symbols * sizeof(LispAtom*);
30085dfecf96Smrg    builtins = (LispBuiltin**)stream;
30095dfecf96Smrg    stream += num_builtins * sizeof(LispBuiltin*);
30105dfecf96Smrg    codes = (unsigned char**)stream;
30115dfecf96Smrg    stream += num_codes * (sizeof(unsigned char*) + sizeof(LispObj*));
30125dfecf96Smrg
30135dfecf96Smrg    for (; phead > 0; phead--)
30145dfecf96Smrg	lisp__data.protect.objects[lisp__data.protect.length++] = NIL;
30155dfecf96Smrg    phead = pbase;
30165dfecf96Smrg
30175dfecf96Smrg#ifdef ALLOW_GOTO_ADDRESS
30185dfecf96Smrg#define OPCODE_LABEL(label)	label
30195dfecf96Smrg#define NEXT_OPCODE()		goto *opcode_labels[*stream++]
30205dfecf96Smrg#define GOTO_PREDICATE()	goto *predicate_opcode_labels[*stream++]
30215dfecf96Smrg#else
30225dfecf96Smrg#define OPCODE_LABEL(label)	case label
30235dfecf96Smrg#define NEXT_OPCODE()		goto next_opcode
30245dfecf96Smrg#define GOTO_PREDICATE()	goto predicate_label
30255dfecf96Smrg    for (;;) {
30265dfecf96Smrgnext_opcode:
30275dfecf96Smrg	switch (*stream++) {
30285dfecf96Smrg#endif	/* ALLOW_GOTO_ADDRESS */
30295dfecf96Smrg
30305dfecf96SmrgOPCODE_LABEL(XBC_NOOP):
30315dfecf96Smrg	NEXT_OPCODE();
30325dfecf96Smrg
30335dfecf96SmrgOPCODE_LABEL(XBC_PRED):
30345dfecf96Smrg	GOTO_PREDICATE();
30355dfecf96Smrg
30365dfecf96SmrgOPCODE_LABEL(XBC_INV):
30375dfecf96Smrg	reg0 = reg0 == NIL ? T : NIL;
30385dfecf96Smrg	NEXT_OPCODE();
30395dfecf96Smrg
30405dfecf96SmrgOPCODE_LABEL(XBC_NIL):
30415dfecf96Smrg	reg0 = NIL;
30425dfecf96Smrg	NEXT_OPCODE();
30435dfecf96Smrg
30445dfecf96SmrgOPCODE_LABEL(XBC_T):
30455dfecf96Smrg	reg0 = T;
30465dfecf96Smrg	NEXT_OPCODE();
30475dfecf96Smrg
30485dfecf96SmrgOPCODE_LABEL(XBC_CAR):
30495dfecf96Smrgcar:
30505dfecf96Smrg	if (reg0 != NIL) {
30515dfecf96Smrg	    if (!CONSP(reg0))
30525dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
30535dfecf96Smrg	    reg0 = CAR(reg0);
30545dfecf96Smrg	}
30555dfecf96Smrg	NEXT_OPCODE();
30565dfecf96Smrg
30575dfecf96SmrgOPCODE_LABEL(XBC_CDR):
30585dfecf96Smrgcdr:
30595dfecf96Smrg	if (reg0 != NIL) {
30605dfecf96Smrg	    if (!CONSP(reg0))
30615dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
30625dfecf96Smrg	    reg0 = CDR(reg0);
30635dfecf96Smrg	}
30645dfecf96Smrg	NEXT_OPCODE();
30655dfecf96Smrg
30665dfecf96SmrgOPCODE_LABEL(XBC_RPLACA):
30675dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
30685dfecf96Smrg	if (!CONSP(reg1))
30695dfecf96Smrg	    LispDestroy("RPLACA: %s is not a cons", STROBJ(reg1));
30705dfecf96Smrg	RPLACA(reg1, reg0);
30715dfecf96Smrg	reg0 = reg1;
30725dfecf96Smrg	NEXT_OPCODE();
30735dfecf96Smrg
30745dfecf96SmrgOPCODE_LABEL(XBC_RPLACD):
30755dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
30765dfecf96Smrg	if (!CONSP(reg1))
30775dfecf96Smrg	    LispDestroy("RPLACD: %s is not a cons", STROBJ(reg1));
30785dfecf96Smrg	RPLACD(reg1, reg0);
30795dfecf96Smrg	reg0 = reg1;
30805dfecf96Smrg	NEXT_OPCODE();
30815dfecf96Smrg
30825dfecf96SmrgOPCODE_LABEL(XBC_BCONS):
30835dfecf96Smrg	CAR(cons) = reg0;
30845dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = cons;
30855dfecf96Smrg	NEXT_OPCODE();
30865dfecf96Smrg
30875dfecf96SmrgOPCODE_LABEL(XBC_BCONS1):
30885dfecf96Smrg	offset = lisp__data.stack.length - 1;
30895dfecf96Smrg	CAR(cons) = reg0;
30905dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[offset];
30915dfecf96Smrg	lisp__data.stack.values[offset] = cons1;
30925dfecf96Smrg	NEXT_OPCODE();
30935dfecf96Smrg
30945dfecf96SmrgOPCODE_LABEL(XBC_BCONS2):
30955dfecf96Smrg	offset = lisp__data.stack.length;
30965dfecf96Smrg	CAR(cons) = reg0;
30975dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
30985dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
30995dfecf96Smrg	lisp__data.stack.values[offset] = cons2;
31005dfecf96Smrg	lisp__data.stack.length = offset + 1;
31015dfecf96Smrg	NEXT_OPCODE();
31025dfecf96Smrg
31035dfecf96SmrgOPCODE_LABEL(XBC_BCONS3):
31045dfecf96Smrg	offset = lisp__data.stack.length;
31055dfecf96Smrg	CAR(cons) = reg0;
31065dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31075dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31085dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31095dfecf96Smrg	lisp__data.stack.values[offset] = cons3;
31105dfecf96Smrg	lisp__data.stack.length = offset + 1;
31115dfecf96Smrg	NEXT_OPCODE();
31125dfecf96Smrg
31135dfecf96SmrgOPCODE_LABEL(XBC_BCONS4):
31145dfecf96Smrg	offset = lisp__data.stack.length;
31155dfecf96Smrg	CAR(cons) = reg0;
31165dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31175dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31185dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31195dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31205dfecf96Smrg	lisp__data.stack.values[offset] = cons4;
31215dfecf96Smrg	lisp__data.stack.length = offset + 1;
31225dfecf96Smrg	NEXT_OPCODE();
31235dfecf96Smrg
31245dfecf96SmrgOPCODE_LABEL(XBC_BCONS5):
31255dfecf96Smrg	offset = lisp__data.stack.length;
31265dfecf96Smrg	CAR(cons) = reg0;
31275dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31285dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31295dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31305dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31315dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31325dfecf96Smrg	lisp__data.stack.values[offset] = cons5;
31335dfecf96Smrg	lisp__data.stack.length = offset + 1;
31345dfecf96Smrg	NEXT_OPCODE();
31355dfecf96Smrg
31365dfecf96SmrgOPCODE_LABEL(XBC_BCONS6):
31375dfecf96Smrg	offset = lisp__data.stack.length;
31385dfecf96Smrg	CAR(cons) = reg0;
31395dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31405dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31415dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31425dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31435dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31445dfecf96Smrg	CAR(cons6) = lisp__data.stack.values[--offset];
31455dfecf96Smrg	lisp__data.stack.values[offset] = cons6;
31465dfecf96Smrg	lisp__data.stack.length = offset + 1;
31475dfecf96Smrg	NEXT_OPCODE();
31485dfecf96Smrg
31495dfecf96SmrgOPCODE_LABEL(XBC_BCONS7):
31505dfecf96Smrg	offset = lisp__data.stack.length;
31515dfecf96Smrg	CAR(cons) = reg0;
31525dfecf96Smrg	CAR(cons1) = lisp__data.stack.values[--offset];
31535dfecf96Smrg	CAR(cons2) = lisp__data.stack.values[--offset];
31545dfecf96Smrg	CAR(cons3) = lisp__data.stack.values[--offset];
31555dfecf96Smrg	CAR(cons4) = lisp__data.stack.values[--offset];
31565dfecf96Smrg	CAR(cons5) = lisp__data.stack.values[--offset];
31575dfecf96Smrg	CAR(cons6) = lisp__data.stack.values[--offset];
31585dfecf96Smrg	CAR(cons7) = lisp__data.stack.values[--offset];
31595dfecf96Smrg	lisp__data.stack.values[offset] = cons7;
31605dfecf96Smrg	lisp__data.stack.length = offset + 1;
31615dfecf96Smrg	NEXT_OPCODE();
31625dfecf96Smrg
31635dfecf96SmrgOPCODE_LABEL(XBC_EQ):
31645dfecf96Smrg	reg0 = reg0 == lisp__data.stack.values[--lisp__data.stack.length] ? T : NIL;
31655dfecf96Smrg	NEXT_OPCODE();
31665dfecf96Smrg
31675dfecf96SmrgOPCODE_LABEL(XBC_EQL):
31685dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31695dfecf96Smrg	reg0 = XEQL(reg1, reg0);
31705dfecf96Smrg	NEXT_OPCODE();
31715dfecf96Smrg
31725dfecf96SmrgOPCODE_LABEL(XBC_EQUAL):
31735dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31745dfecf96Smrg	reg0 = XEQUAL(reg1, reg0);
31755dfecf96Smrg	NEXT_OPCODE();
31765dfecf96Smrg
31775dfecf96SmrgOPCODE_LABEL(XBC_EQUALP):
31785dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31795dfecf96Smrg	reg0 = XEQUALP(reg1, reg0);
31805dfecf96Smrg	NEXT_OPCODE();
31815dfecf96Smrg
31825dfecf96SmrgOPCODE_LABEL(XBC_LENGTH):
31835dfecf96Smrg	reg0 = FIXNUM(LispLength(reg0));
31845dfecf96Smrg	NEXT_OPCODE();
31855dfecf96Smrg
31865dfecf96SmrgOPCODE_LABEL(XBC_LAST):
31875dfecf96Smrg    {
31885dfecf96Smrg	long length;
31895dfecf96Smrg
31905dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
31915dfecf96Smrg	if (CONSP(reg1)) {
31925dfecf96Smrg	    if (reg0 != NIL) {
31935dfecf96Smrg		if (!FIXNUMP(reg0) || (fixnum = FIXNUM_VALUE(reg0)) < 0)
31945dfecf96Smrg		    LispDestroy("LAST: %s is not a positive fixnum",
31955dfecf96Smrg				STROBJ(reg0));
31965dfecf96Smrg	    }
31975dfecf96Smrg	    else
31985dfecf96Smrg		fixnum = 1;
31995dfecf96Smrg	    reg0 = reg1;
32005dfecf96Smrg	    for (reg0 = reg1, length = 0;
32015dfecf96Smrg		 CONSP(reg0);
32025dfecf96Smrg		 reg0 = CDR(reg0), length++)
32035dfecf96Smrg		;
32045dfecf96Smrg	    for (length -= fixnum, reg0 = reg1; length > 0; length--)
32055dfecf96Smrg		reg0 = CDR(reg0);
32065dfecf96Smrg	}
32075dfecf96Smrg	else
32085dfecf96Smrg	    reg0 = reg1;
32095dfecf96Smrg    }	NEXT_OPCODE();
32105dfecf96Smrg
32115dfecf96SmrgOPCODE_LABEL(XBC_NTHCDR):
32125dfecf96Smrg	reg1 = lisp__data.stack.values[--lisp__data.stack.length];
32135dfecf96Smrg	if (!FIXNUMP(reg1) || (fixnum = FIXNUM_VALUE(reg1)) < 0)
32145dfecf96Smrg	    LispDestroy("NTHCDR: %s is not a positive fixnum",
32155dfecf96Smrg			STROBJ(reg1));
32165dfecf96Smrg	if (reg0 != NIL) {
32175dfecf96Smrg	    if (!CONSP(reg0))
32185dfecf96Smrg		LispDestroy("NTHCDR: %s is not a list", STROBJ(reg0));
32195dfecf96Smrg	    for (; fixnum > 0; fixnum--) {
32205dfecf96Smrg		if (!CONSP(reg0))
32215dfecf96Smrg		    break;
32225dfecf96Smrg		reg0 = CDR(reg0);
32235dfecf96Smrg	    }
32245dfecf96Smrg	}
32255dfecf96Smrg	NEXT_OPCODE();
32265dfecf96Smrg
32275dfecf96Smrg	/* Push to builtin stack */
32285dfecf96SmrgOPCODE_LABEL(XBC_CAR_PUSH):
32295dfecf96Smrg	if (reg0 != NIL) {
32305dfecf96Smrg	    if (!CONSP(reg0))
32315dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
32325dfecf96Smrg	    reg0 = CAR(reg0);
32335dfecf96Smrg	}
32345dfecf96Smrg	goto push_builtin;
32355dfecf96Smrg
32365dfecf96SmrgOPCODE_LABEL(XBC_CDR_PUSH):
32375dfecf96Smrg	if (reg0 != NIL) {
32385dfecf96Smrg	    if (!CONSP(reg0))
32395dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
32405dfecf96Smrg	    reg0 = CDR(reg0);
32415dfecf96Smrg	}
32425dfecf96Smrg	/*FALLTROUGH*/
32435dfecf96Smrg
32445dfecf96SmrgOPCODE_LABEL(XBC_PUSH):
32455dfecf96Smrgpush_builtin:
32465dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
32475dfecf96Smrg	NEXT_OPCODE();
32485dfecf96Smrg
32495dfecf96SmrgOPCODE_LABEL(XBC_PUSH_NIL):
32505dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = NIL;
32515dfecf96Smrg	NEXT_OPCODE();
32525dfecf96Smrg
32535dfecf96SmrgOPCODE_LABEL(XBC_PUSH_UNSPEC):
32545dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC;
32555dfecf96Smrg	NEXT_OPCODE();
32565dfecf96Smrg
32575dfecf96SmrgOPCODE_LABEL(XBC_PUSH_T):
32585dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = T;
32595dfecf96Smrg	NEXT_OPCODE();
32605dfecf96Smrg
32615dfecf96SmrgOPCODE_LABEL(XBC_PUSH_NIL_N):
32625dfecf96Smrg	for (offset = *stream++; offset > 0; offset--)
32635dfecf96Smrg	    lisp__data.stack.values[lisp__data.stack.length++] = NIL;
32645dfecf96Smrg	NEXT_OPCODE();
32655dfecf96Smrg
32665dfecf96SmrgOPCODE_LABEL(XBC_PUSH_UNSPEC_N):
32675dfecf96Smrg	for (offset = *stream++; offset > 0; offset--)
32685dfecf96Smrg	    lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC;
32695dfecf96Smrg	NEXT_OPCODE();
32705dfecf96Smrg
32715dfecf96SmrgOPCODE_LABEL(XBC_LET):
32725dfecf96Smrglet_argument:
32735dfecf96Smrg	/*  The global object value is not changed, so it does not
32745dfecf96Smrg	 * matter if it is a constant symbol. An error would be
32755dfecf96Smrg	 * generated if it was declared as constant at the time of
32765dfecf96Smrg	 * bytecode generation. Check can be done looking at the
32775dfecf96Smrg	 * atom->constant field. */
32785dfecf96Smrg	atom = symbols[*stream++];
32795dfecf96Smrg	atom->offset = lisp__data.env.length;
3280f14f4646Smrg	lisp__data.env.names[lisp__data.env.length] = atom->key;
32815dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = reg0;
32825dfecf96Smrg	NEXT_OPCODE();
32835dfecf96Smrg
32845dfecf96SmrgOPCODE_LABEL(XBC_LETX):
32855dfecf96Smrgletx_argument:
32865dfecf96Smrg	atom = symbols[*stream++];
32875dfecf96Smrg	atom->offset = lisp__data.env.length;
3288f14f4646Smrg	lisp__data.env.names[lisp__data.env.length] = atom->key;
32895dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = reg0;
32905dfecf96Smrg	lisp__data.env.head++;
32915dfecf96Smrg	NEXT_OPCODE();
32925dfecf96Smrg
32935dfecf96SmrgOPCODE_LABEL(XBC_LET_NIL):
32945dfecf96Smrg	atom = symbols[*stream++];
32955dfecf96Smrg	atom->offset = lisp__data.env.length;
3296f14f4646Smrg	lisp__data.env.names[lisp__data.env.length] = atom->key;
32975dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = NIL;
32985dfecf96Smrg	NEXT_OPCODE();
32995dfecf96Smrg
33005dfecf96SmrgOPCODE_LABEL(XBC_LETX_NIL):
33015dfecf96Smrg	atom = symbols[*stream++];
33025dfecf96Smrg	atom->offset = lisp__data.env.length;
3303f14f4646Smrg	lisp__data.env.names[lisp__data.env.length] = atom->key;
33045dfecf96Smrg	lisp__data.env.values[lisp__data.env.length++] = NIL;
33055dfecf96Smrg	lisp__data.env.head++;
33065dfecf96Smrg	NEXT_OPCODE();
33075dfecf96Smrg
33085dfecf96Smrg	/* Bind locally added variables to a block */
33095dfecf96SmrgOPCODE_LABEL(XBC_LETBIND):
33105dfecf96Smrg	offset = *stream++;
33115dfecf96Smrg	lisp__data.env.head += offset;
33125dfecf96Smrg	NEXT_OPCODE();
33135dfecf96Smrg
33145dfecf96Smrg	/* Unbind locally added variables to a block */
33155dfecf96SmrgOPCODE_LABEL(XBC_UNLET):
33165dfecf96Smrg	offset = *stream++;
33175dfecf96Smrg	lisp__data.env.head -= offset;
33185dfecf96Smrg	lisp__data.env.length -= offset;
33195dfecf96Smrg	NEXT_OPCODE();
33205dfecf96Smrg
33215dfecf96Smrg	/* Load value from stack */
33225dfecf96SmrgOPCODE_LABEL(XBC_LOAD):
33235dfecf96Smrg	offset = *stream++;
33245dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33255dfecf96Smrg	NEXT_OPCODE();
33265dfecf96Smrg
33275dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR):
33285dfecf96Smrg	offset = *stream++;
33295dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33305dfecf96Smrg	goto car;
33315dfecf96Smrg
33325dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR):
33335dfecf96Smrg	offset = *stream++;
33345dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33355dfecf96Smrg	goto cdr;
33365dfecf96Smrg
33375dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR_STORE):
33385dfecf96Smrg	offset = *stream++;
33395dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33405dfecf96Smrg	if (reg0 != NIL) {
33415dfecf96Smrg	    if (!CONSP(reg0))
33425dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
33435dfecf96Smrg	    reg0 = CAR(reg0);
33445dfecf96Smrg	    lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33455dfecf96Smrg	}
33465dfecf96Smrg	NEXT_OPCODE();
33475dfecf96Smrg
33485dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR_STORE):
33495dfecf96Smrg	offset = *stream++;
33505dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33515dfecf96Smrg	if (reg0 != NIL) {
33525dfecf96Smrg	    if (!CONSP(reg0))
33535dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
33545dfecf96Smrg	    reg0 = CDR(reg0);
33555dfecf96Smrg	    lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33565dfecf96Smrg	}
33575dfecf96Smrg	NEXT_OPCODE();
33585dfecf96Smrg
33595dfecf96SmrgOPCODE_LABEL(XBC_LOAD_LET):
33605dfecf96Smrg	offset = *stream++;
33615dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33625dfecf96Smrg	goto let_argument;
33635dfecf96Smrg
33645dfecf96SmrgOPCODE_LABEL(XBC_LOAD_LETX):
33655dfecf96Smrg	offset = *stream++;
33665dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33675dfecf96Smrg	goto letx_argument;
33685dfecf96Smrg
33695dfecf96SmrgOPCODE_LABEL(XBC_LOAD_PUSH):
33705dfecf96Smrg	offset = *stream++;
33715dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
33725dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
33735dfecf96Smrg	NEXT_OPCODE();
33745dfecf96Smrg
33755dfecf96Smrg	/* Load pointer to constant */
33765dfecf96SmrgOPCODE_LABEL(XBC_LOADCON):
33775dfecf96Smrg	reg0 = constants[*stream++];
33785dfecf96Smrg	NEXT_OPCODE();
33795dfecf96Smrg
33805dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_LET):
33815dfecf96Smrg	reg0 = constants[*stream++];
33825dfecf96Smrg	goto let_argument;
33835dfecf96Smrg
33845dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_LETX):
33855dfecf96Smrg	reg0 = constants[*stream++];
33865dfecf96Smrg	goto letx_argument;
33875dfecf96Smrg
33885dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_PUSH):
33895dfecf96Smrg	reg0 = constants[*stream++];
33905dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
33915dfecf96Smrg	NEXT_OPCODE();
33925dfecf96Smrg
33935dfecf96SmrgOPCODE_LABEL(XBC_LOADCON_SET):
33945dfecf96Smrg	reg0 = constants[*stream++];
33955dfecf96Smrg	offset = *stream++;
33965dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
33975dfecf96Smrg	NEXT_OPCODE();
33985dfecf96Smrg
33995dfecf96Smrg	/* Change value of local variable */
34005dfecf96SmrgOPCODE_LABEL(XBC_CAR_SET):
34015dfecf96Smrgcar_set:
34025dfecf96Smrg	if (reg0 != NIL) {
34035dfecf96Smrg	    if (!CONSP(reg0))
34045dfecf96Smrg		LispDestroy("CAR: %s is not a list", STROBJ(reg0));
34055dfecf96Smrg	    reg0 = CAR(reg0);
34065dfecf96Smrg	}
34075dfecf96Smrg	goto set_local_variable;
34085dfecf96Smrg
34095dfecf96SmrgOPCODE_LABEL(XBC_CDR_SET):
34105dfecf96Smrgcdr_set:
34115dfecf96Smrg	if (reg0 != NIL) {
34125dfecf96Smrg	    if (!CONSP(reg0))
34135dfecf96Smrg		LispDestroy("CDR: %s is not a list", STROBJ(reg0));
34145dfecf96Smrg	    reg0 = CDR(reg0);
34155dfecf96Smrg	}
34165dfecf96Smrg	goto set_local_variable;
34175dfecf96Smrg
34185dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CAR_SET):
34195dfecf96Smrg	offset = *stream++;
34205dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34215dfecf96Smrg	goto car_set;
34225dfecf96Smrg
34235dfecf96SmrgOPCODE_LABEL(XBC_LOAD_CDR_SET):
34245dfecf96Smrg	offset = *stream++;
34255dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34265dfecf96Smrg	goto cdr_set;
34275dfecf96Smrg
34285dfecf96SmrgOPCODE_LABEL(XBC_LOAD_SET):
34295dfecf96Smrg	offset = *stream++;
34305dfecf96Smrg	reg0 = lisp__data.env.values[lisp__data.env.lex + offset];
34315dfecf96Smrg	/*FALLTROUGH*/
34325dfecf96Smrg
34335dfecf96SmrgOPCODE_LABEL(XBC_SET):
34345dfecf96Smrgset_local_variable:
34355dfecf96Smrg	offset = *stream++;
34365dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
34375dfecf96Smrg	NEXT_OPCODE();
34385dfecf96Smrg
34395dfecf96SmrgOPCODE_LABEL(XBC_SET_NIL):
34405dfecf96Smrg	offset = *stream++;
34415dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = NIL;
34425dfecf96Smrg	NEXT_OPCODE();
34435dfecf96Smrg
34445dfecf96Smrg	/* Change value of a global/special variable */
34455dfecf96SmrgOPCODE_LABEL(XBC_SETSYM):
34465dfecf96Smrg	    atom = symbols[*stream++];
34475dfecf96Smrg	    if (atom->dyn) {
34485dfecf96Smrg		/*  atom->dyn and atom->constant are exclusive, no
34495dfecf96Smrg		 * need to check if variable declared as constant. */
34505dfecf96Smrg		if (atom->offset < lisp__data.env.head &&
3451f14f4646Smrg		    lisp__data.env.names[atom->offset] == atom->key)
34525dfecf96Smrg		    lisp__data.env.values[atom->offset] = reg0;
34535dfecf96Smrg		else {
34545dfecf96Smrg		    if (atom->watch)
34555dfecf96Smrg			LispSetAtomObjectProperty(atom, reg0);
34565dfecf96Smrg		    else
34575dfecf96Smrg			SETVALUE(atom, reg0);
34585dfecf96Smrg		}
34595dfecf96Smrg	    }
34605dfecf96Smrg	    else if (atom->a_object) {
34615dfecf96Smrg		if (atom->constant)
34625dfecf96Smrg		    LispDestroy("EVAL: %s is a constant",
34635dfecf96Smrg				STROBJ(atom->object));
34645dfecf96Smrg		else if (atom->watch)
34655dfecf96Smrg		    LispSetAtomObjectProperty(atom, reg0);
34665dfecf96Smrg		else
34675dfecf96Smrg		    SETVALUE(atom, reg0);
34685dfecf96Smrg	    }
34695dfecf96Smrg	    else {
34705dfecf96Smrg		/* Create new global variable */
34715dfecf96Smrg		LispPackage *pack;
34725dfecf96Smrg
34735dfecf96Smrg		LispWarning("the variable %s was not declared",
3474f14f4646Smrg			    atom->key->value);
34755dfecf96Smrg		LispSetAtomObjectProperty(atom, reg0);
34765dfecf96Smrg		pack = atom->package->data.package.package;
34775dfecf96Smrg		if (pack->glb.length >= pack->glb.space)
34785dfecf96Smrg		    LispMoreGlobals(pack);
34795dfecf96Smrg		pack->glb.pairs[pack->glb.length++] = atom->object;
34805dfecf96Smrg	    }
34815dfecf96Smrg	    NEXT_OPCODE();
34825dfecf96Smrg
34835dfecf96Smrg/* Resolve symbol value at runtime */
34845dfecf96Smrg#define LOAD_SYMBOL_VALUE()					    \
34855dfecf96Smrg    atom = symbols[*stream++];					    \
34865dfecf96Smrg    if (atom->dyn) {						    \
34875dfecf96Smrg	if (atom->offset < lisp__data.env.head &&		    \
3488f14f4646Smrg	    lisp__data.env.names[atom->offset] == atom->key)	    \
34895dfecf96Smrg	    reg0 = lisp__data.env.values[atom->offset];		    \
34905dfecf96Smrg	else {							    \
34915dfecf96Smrg	    reg0 = atom->property->value;			    \
34925dfecf96Smrg	    if (reg0 == UNBOUND)				    \
34935dfecf96Smrg		LispDestroy("EVAL: the symbol %s is unbound",  \
34945dfecf96Smrg			    STROBJ(atom->object));		    \
34955dfecf96Smrg	}							    \
34965dfecf96Smrg    }								    \
34975dfecf96Smrg    else {							    \
34985dfecf96Smrg	if (atom->a_object)					    \
34995dfecf96Smrg	    reg0 = atom->property->value;			    \
35005dfecf96Smrg	else							    \
35015dfecf96Smrg	    LispDestroy("EVAL: the symbol %s is unbound",	    \
35025dfecf96Smrg			STROBJ(atom->object));			    \
35035dfecf96Smrg    }
35045dfecf96Smrg
35055dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM):
35065dfecf96Smrg	LOAD_SYMBOL_VALUE();
35075dfecf96Smrg	NEXT_OPCODE();
35085dfecf96Smrg
35095dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_LET):
35105dfecf96Smrg	LOAD_SYMBOL_VALUE();
35115dfecf96Smrg	goto let_argument;
35125dfecf96Smrg
35135dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_LETX):
35145dfecf96Smrg	LOAD_SYMBOL_VALUE();
35155dfecf96Smrg	goto letx_argument;
35165dfecf96Smrg
35175dfecf96SmrgOPCODE_LABEL(XBC_LOADSYM_PUSH):
35185dfecf96Smrg	LOAD_SYMBOL_VALUE();
35195dfecf96Smrg	lisp__data.stack.values[lisp__data.stack.length++] = reg0;
35205dfecf96Smrg	NEXT_OPCODE();
35215dfecf96Smrg
35225dfecf96Smrg	    /* Builtin function */
35235dfecf96SmrgOPCODE_LABEL(XBC_CALL):
35245dfecf96Smrg	offset = *stream++;
35255dfecf96Smrg	lisp__data.stack.base = lisp__data.stack.length - offset;
35265dfecf96Smrg	builtin = builtins[*stream++];
35275dfecf96Smrg	if (builtin->multiple_values) {
35285dfecf96Smrg	    RETURN_COUNT = 0;
35295dfecf96Smrg	    reg0 = builtin->function(builtin);
35305dfecf96Smrg	}
35315dfecf96Smrg	else {
35325dfecf96Smrg	    reg0 = builtin->function(builtin);
35335dfecf96Smrg	    RETURN_COUNT = 0;
35345dfecf96Smrg	}
35355dfecf96Smrg	lisp__data.stack.length -= offset;
35365dfecf96Smrg	NEXT_OPCODE();
35375dfecf96Smrg
35385dfecf96SmrgOPCODE_LABEL(XBC_CALL_SET):
35395dfecf96Smrg	offset = *stream++;
35405dfecf96Smrg	lisp__data.stack.base = lisp__data.stack.length - offset;
35415dfecf96Smrg	builtin = builtins[*stream++];
35425dfecf96Smrg	if (builtin->multiple_values) {
35435dfecf96Smrg	    RETURN_COUNT = 0;
35445dfecf96Smrg	    reg0 = builtin->function(builtin);
35455dfecf96Smrg	}
35465dfecf96Smrg	else {
35475dfecf96Smrg	    reg0 = builtin->function(builtin);
35485dfecf96Smrg	    RETURN_COUNT = 0;
35495dfecf96Smrg	}
35505dfecf96Smrg	lisp__data.stack.length -= offset;
35515dfecf96Smrg	offset = *stream++;
35525dfecf96Smrg	lisp__data.env.values[lisp__data.env.lex + offset] = reg0;
35535dfecf96Smrg	NEXT_OPCODE();
35545dfecf96Smrg
35555dfecf96Smrg	/* Bytecode call */
35565dfecf96SmrgOPCODE_LABEL(XBC_BYTECALL):
35575dfecf96Smrg	lex = lisp__data.env.lex;
35585dfecf96Smrg	offset = *stream++;
35595dfecf96Smrg	lisp__data.env.head = lisp__data.env.length;
35605dfecf96Smrg	len = lisp__data.env.lex = lisp__data.env.length - offset;
35615dfecf96Smrg	reg0 = ExecuteBytecode(codes[*stream++]);
35625dfecf96Smrg	lisp__data.env.length = lisp__data.env.head = len;
35635dfecf96Smrg	lisp__data.env.lex = lex;
35645dfecf96Smrg	NEXT_OPCODE();
35655dfecf96Smrg
35665dfecf96Smrg	/* Unimplemented function/macro call */
35675dfecf96SmrgOPCODE_LABEL(XBC_FUNCALL):
35685dfecf96Smrg	lambda = constants[*stream++];
35695dfecf96Smrg	arguments = constants[*stream++];
35705dfecf96Smrg	reg0 = LispFuncall(lambda, arguments, 1);
35715dfecf96Smrg	NEXT_OPCODE();
35725dfecf96Smrg
35735dfecf96SmrgOPCODE_LABEL(XBC_JUMP):
35745dfecf96Smrg	stream += *(signed short*)stream;
35755dfecf96Smrg	NEXT_OPCODE();
35765dfecf96Smrg
35775dfecf96SmrgOPCODE_LABEL(XBC_JUMPT):
35785dfecf96Smrg	if (reg0 != NIL)
35795dfecf96Smrg	    stream += *(signed short*)stream;
35805dfecf96Smrg	else
35815dfecf96Smrg	    /* skip jump relative offset */
35825dfecf96Smrg	    stream += sizeof(signed short);
35835dfecf96Smrg	NEXT_OPCODE();
35845dfecf96Smrg
35855dfecf96SmrgOPCODE_LABEL(XBC_JUMPNIL):
35865dfecf96Smrg	if (reg0 == NIL)
35875dfecf96Smrg	    stream += *(signed short*)stream;
35885dfecf96Smrg	else
35895dfecf96Smrg	    /* skip jump relative offset */
35905dfecf96Smrg	    stream += sizeof(signed short);
35915dfecf96Smrg	NEXT_OPCODE();
35925dfecf96Smrg
35935dfecf96Smrg	/* Build CONS of two constant arguments */
35945dfecf96SmrgOPCODE_LABEL(XBC_CCONS):
35955dfecf96Smrg	reg0 = constants[*stream++];
35965dfecf96Smrg	reg1 = constants[*stream++];
35975dfecf96Smrg	reg0 = CONS(reg0, reg1);
35985dfecf96Smrg	NEXT_OPCODE();
35995dfecf96Smrg
36005dfecf96Smrg	/* Start CONS */
36015dfecf96SmrgOPCODE_LABEL(XBC_CSTAR):
36025dfecf96Smrg	/* This the CAR of the CONS */
36035dfecf96Smrg	lisp__data.protect.objects[phead++] = reg0;
36045dfecf96Smrg	NEXT_OPCODE();
36055dfecf96Smrg
36065dfecf96Smrg	/* Finish CONS */
36075dfecf96SmrgOPCODE_LABEL(XBC_CFINI):
36085dfecf96Smrg	reg0 = CONS(lisp__data.protect.objects[--phead], reg0);
36095dfecf96Smrg	NEXT_OPCODE();
36105dfecf96Smrg
36115dfecf96Smrg	/* Start building list */
36125dfecf96SmrgOPCODE_LABEL(XBC_LSTAR):
36135dfecf96Smrg	reg1 = CONS(reg0, NIL);
36145dfecf96Smrg	/* Start of list stored here */
36155dfecf96Smrg	lisp__data.protect.objects[phead++] = reg1;
36165dfecf96Smrg	/* Tail of list stored here */
36175dfecf96Smrg	lisp__data.protect.objects[phead++] = reg1;
36185dfecf96Smrg	NEXT_OPCODE();
36195dfecf96Smrg
36205dfecf96Smrg	/* Add to list */
36215dfecf96SmrgOPCODE_LABEL(XBC_LCONS):
36225dfecf96Smrg	reg1 = lisp__data.protect.objects[phead - 2];
36235dfecf96Smrg	RPLACD(reg1, CONS(reg0, NIL));
36245dfecf96Smrg	 lisp__data.protect.objects[phead - 2] = CDR(reg1);
36255dfecf96Smrg	NEXT_OPCODE();
36265dfecf96Smrg
36275dfecf96Smrg	/* Finish list */
36285dfecf96SmrgOPCODE_LABEL(XBC_LFINI):
36295dfecf96Smrg	phead -= 2;
36305dfecf96Smrg	reg0 = lisp__data.protect.objects[phead + 1];
36315dfecf96Smrg	NEXT_OPCODE();
36325dfecf96Smrg
36335dfecf96SmrgOPCODE_LABEL(XBC_STRUCT):
36345dfecf96Smrg	offset = *stream++;
36355dfecf96Smrg	reg1 = constants[*stream++];
36365dfecf96Smrg	if (!STRUCTP(reg0) || reg0->data.struc.def != reg1) {
3637f14f4646Smrg	    char *name = ATOMID(CAR(reg1))->value;
36385dfecf96Smrg
36395dfecf96Smrg	    for (reg1 = CDR(reg1); offset; offset--)
36405dfecf96Smrg		reg1 = CDR(reg1);
36415dfecf96Smrg	    LispDestroy("%s-%s: %s is not a %s",
3642f14f4646Smrg			name, ATOMID(CAR(reg1))->value, STROBJ(reg0), name);
36435dfecf96Smrg	}
36445dfecf96Smrg	for (reg0 = reg0->data.struc.fields; offset; offset--)
36455dfecf96Smrg	    reg0 = CDR(reg0);
36465dfecf96Smrg	reg0 = CAR(reg0);
36475dfecf96Smrg	NEXT_OPCODE();
36485dfecf96Smrg
36495dfecf96SmrgOPCODE_LABEL(XBC_STRUCTP):
36505dfecf96Smrg	reg1 = constants[*stream++];
36515dfecf96Smrg	reg0 = STRUCTP(reg0) && reg0->data.struc.def == reg1 ? T : NIL;
36525dfecf96Smrg	NEXT_OPCODE();
36535dfecf96Smrg
36545dfecf96SmrgOPCODE_LABEL(XBC_LETREC):
36555dfecf96Smrg	/* XXX could/should optimize, shouldn't need to parse
36565dfecf96Smrg	 * the bytecode header again */
36575dfecf96Smrg	lex = lisp__data.env.lex;
36585dfecf96Smrg	offset = *stream++;
36595dfecf96Smrg	lisp__data.env.head = lisp__data.env.length;
36605dfecf96Smrg	len = lisp__data.env.lex = lisp__data.env.length - offset;
36615dfecf96Smrg	reg0 = ExecuteBytecode(bytecode);
36625dfecf96Smrg	lisp__data.env.length = lisp__data.env.head = len;
36635dfecf96Smrg	lisp__data.env.lex = lex;
36645dfecf96Smrg	NEXT_OPCODE();
36655dfecf96Smrg
36665dfecf96SmrgOPCODE_LABEL(XBC_RETURN):
36675dfecf96Smrg	lisp__data.protect.length = pbase;
36685dfecf96Smrg	return (reg0);
36695dfecf96Smrg
36705dfecf96Smrg#ifndef ALLOW_GOTO_ADDRESS
36715dfecf96Smrg	}	/* end of switch */
36725dfecf96Smrg
36735dfecf96Smrgpredicate_label:
36745dfecf96Smrg	switch (*stream++) {
36755dfecf96Smrg#endif
36765dfecf96Smrg
36775dfecf96SmrgOPCODE_LABEL(XBP_CONSP):
36785dfecf96Smrg	reg0 = CONSP(reg0) ? T : NIL;
36795dfecf96Smrg	NEXT_OPCODE();
36805dfecf96Smrg
36815dfecf96SmrgOPCODE_LABEL(XBP_LISTP):
36825dfecf96Smrg	reg0 = LISTP(reg0) ? T : NIL;
36835dfecf96Smrg	NEXT_OPCODE();
36845dfecf96Smrg
36855dfecf96SmrgOPCODE_LABEL(XBP_NUMBERP):
36865dfecf96Smrg	reg0 = NUMBERP(reg0) ? T : NIL;
36875dfecf96Smrg	NEXT_OPCODE();
36885dfecf96Smrg
36895dfecf96Smrg#ifndef ALLOW_GOTO_ADDRESS
36905dfecf96Smrg	}	/* end of switch */
36915dfecf96Smrg    }
36925dfecf96Smrg#endif
36935dfecf96Smrg
36945dfecf96Smrg    /*NOTREACHED*/
36955dfecf96Smrg    return (reg0);
36965dfecf96Smrg}
3697