bytecode.c revision 5dfecf96
1/* 2 * Copyright (c) 2002 by The XFree86 Project, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 * Except as contained in this notice, the name of the XFree86 Project shall 23 * not be used in advertising or otherwise to promote the sale, use or other 24 * dealings in this Software without prior written authorization from the 25 * XFree86 Project. 26 * 27 * Author: Paulo César Pereira de Andrade 28 */ 29 30/* $XFree86: xc/programs/xedit/lisp/bytecode.c,v 1.17 2003/05/27 22:27:01 tsi Exp $ */ 31 32 33/* 34somethings TODO: 35 36 o Write code for allowing storing the bytecode on disk. Basically 37 write a section of the bytecode with the package name of the symbol 38 pointers, and after that, the symbols used. At load time just put 39 the pointers in the bytecode. Constants can be stored as the string 40 representation. Probably just storing the gc protected code as a 41 string is enough to rebuild it. 42 43 o Write code to store tags of BLOCK/CATCH and setjump buffer stacks, 44 and, only keep track of this if non byte-compiled code is called, 45 as after byte-compilation RETURN and THROW are just jumps. 46 47 o Remove not reliable "optmization code" code from Com_XXX functions 48 and do it later, removing dead code, tests with a constant argument, 49 etc, in the "link time". Frequently joining sequential opcodes to a 50 compound version. 51 52 o Write an optimizer to do code transformation. 53 54 o Write code to know when variables can be changed in place, this 55 can save a huge time in loop counters. 56 57 o Write code for fast garbage collection of objects that can be 58 safely collected. 59 60 o Cleanup of interpreted code. Having bytecode mean that the interpreter 61 now is better having a clean and small code. If speed is important, 62 it should be byte compiled. 63 64 o Limit the stacks length. So that instead of using an index, use the 65 pointer where an object value should be read/stored as the stack address 66 would not change during the program execution. 67 68 o Optimize jump to jump. Common in code like: 69 (IF test 70 (GO somewhere) 71 (GO elsewhere) 72 ) 73 (GO there) 74 that generates a bytecode like: 75 <code to evaluate test> 76 JUMPNIL :NIL-RESULT 77 :T-RESULT 78 JUMP :SOMEWHERE 79 JUMP :END-OF-IF ;; <- this is not required, or even 80 :NIL-RESULT ;; better, notice the jump after 81 JUMP :ELSEWHERE ;; the if and transform it into 82 :END-OF-IF ;; a JUMP :THERE (assuming there 83 JUMP :THERE ;; (was no jump in the T code). 84 85 o Optimize variables that are known to not change it's value, i.e. pseudo 86 constants. Loading the value of a constant should be faster than loading 87 the current value of a variable; the constant table could fit in the 88 processor cache line and needs less calculation to find the object address. 89 90 o Fix some known problems, like when calling return or return-from while 91 building the argument list to a builtin function, or inline of recursive 92 functions. 93 */ 94 95 96#include "lisp/bytecode.h" 97#include "lisp/write.h" 98 99#define SYMBOL_KEYWORD -1 /* A keyword, load as constant */ 100#define SYMBOL_CONSTANT -2 /* Defined as constant at compile time */ 101#define SYMBOL_UNBOUND -3 /* Not a local variable */ 102 103#define NEW_TREE(type) CompileNewTree(com, type) 104 105/* If in tagbody, ignore anything that is not code */ 106#define IN_TAGBODY() (com->block->type == LispBlockBody && \ 107 com->level == com->tagbody) 108#define FORM_ENTER() ++com->level 109#define FORM_LEAVE() --com->level 110 111#define COMPILE_FAILURE(message) \ 112 LispMessage("COMPILE: %s", message); \ 113 longjmp(com->jmp, 1) 114 115/* 116 * Types 117 */ 118typedef struct _CodeTree CodeTree; 119typedef struct _CodeBlock CodeBlock; 120 121typedef enum { 122 CodeTreeBytecode, 123 CodeTreeLabel, 124 CodeTreeGo, 125 CodeTreeJump, 126 CodeTreeJumpIf, 127 CodeTreeCond, 128 CodeTreeBlock, 129 CodeTreeReturn 130} CodeTreeType; 131 132struct _CodeTree { 133 CodeTreeType type; 134 135 /* Resolved when linking, may be adjusted while optimizing */ 136 long offset; 137 138 LispByteOpcode code; 139 140 union { 141 signed char signed_char; 142 signed short signed_short; 143 signed int signed_int; 144 LispAtom *atom; 145 LispObj *object; 146 CodeTree *tree; 147 CodeBlock *block; 148 struct { 149 unsigned char num_arguments; 150 LispBuiltin *builtin; 151 signed short offset; /* Used if opcode is XBC_CALL_SET */ 152 } builtin; 153 struct { 154 unsigned char num_arguments; 155 LispObj *name; 156 LispObj *lambda; 157 } call; 158 struct { 159 unsigned char num_arguments; 160 LispObj *code; 161 } bytecall; 162 struct { 163 short offset; 164 LispAtom *name; 165 } let; 166 struct { 167 LispAtom *symbol; 168 LispAtom *name; 169 } let_sym; 170 struct { 171 LispObj *object; 172 LispAtom *name; 173 } let_con; 174 struct { 175 signed short load; 176 signed short set; 177 } load_set; 178 struct { 179 LispObj *object; 180 signed short offset; 181 } load_con_set; 182 struct { 183 LispObj *car; 184 LispObj *cdr; 185 } cons; 186 struct { 187 short offset; 188 LispObj *definition; 189 } struc; 190 } data; 191 192 CodeTree *next; 193 CodeTree *group; 194 CodeBlock *block; 195}; 196 197struct _CodeBlock { 198 LispBlockType type; 199 LispObj *tag; 200 201 struct { 202 LispObj **labels; 203 CodeTree **codes; /* Filled at link time */ 204 int length; 205 int space; 206 } tagbody; 207 208 struct { 209 LispAtom **symbols; /* Identifiers of variables in a block */ 210 int *flags; /* Information about usage of the variable */ 211 int length; 212 } variables; 213 214 int bind; /* Used in case of RETURN from LET */ 215 int level; /* Nesting level block was created */ 216 217 CodeTree *tree, *tail; 218 CodeBlock *prev; /* Linked list as a stack */ 219 CodeTree *parent; /* Back reference */ 220}; 221 222struct _LispCom { 223 unsigned char *bytecode; /* Bytecode generated so far */ 224 long length; 225 226 CodeBlock *block, *toplevel; 227 228 int tagbody; /* Inside a tagbody block? */ 229 int level; /* Nesting level */ 230 int macro; /* Expanding a macro? */ 231 232 int lex; 233 234 int warnings; 235 236 LispObj *form, *plist; 237 238 jmp_buf jmp; /* Used if compilation cannot be finished */ 239 240 struct { 241 int cstack; /* Current number of objects in forms evaluation */ 242 int cbstack; 243 int cpstack; 244 int stack; /* max number of objects will be loaded in stack */ 245 int bstack; 246 int pstack; 247 } stack; 248 249 struct { 250 /* Constant table */ 251 LispObj **constants; 252 int num_constants; 253 /* Symbol table */ 254 LispAtom **symbols; 255 int num_symbols; 256 /* Builtin table */ 257 LispBuiltin **builtins; 258 int num_builtins; 259 /* Bytecode table */ 260 LispObj **bytecodes; 261 int num_bytecodes; 262 } table; 263}; 264 265/* 266 * Prototypes 267 */ 268static LispObj *MakeBytecodeObject(LispCom*, LispObj*, LispObj*); 269 270static CodeTree *CompileNewTree(LispCom*, CodeTreeType); 271static void CompileFreeState(LispCom*); 272static void CompileFreeBlock(CodeBlock*); 273static void CompileFreeTree(CodeTree*); 274 275static void CompileIniBlock(LispCom*, LispBlockType, LispObj*); 276static void CompileFiniBlock(LispCom*); 277 278static void com_BytecodeChar(LispCom*, LispByteOpcode, char); 279static void com_BytecodeShort(LispCom*, LispByteOpcode, short); 280static void com_BytecodeObject(LispCom*, LispByteOpcode, LispObj*); 281static void com_BytecodeCons(LispCom*, LispByteOpcode, LispObj*, LispObj*); 282 283static void com_BytecodeAtom(LispCom*, LispByteOpcode, LispAtom*); 284 285static void com_Bytecode(LispCom*, LispByteOpcode); 286 287static void com_Load(LispCom*, short); 288static void com_LoadLet(LispCom*, short, LispAtom*); 289static void com_LoadPush(LispCom*, short); 290 291static void com_Let(LispCom*, LispAtom*); 292 293static void com_Bind(LispCom*, short); 294static void com_Unbind(LispCom*, short); 295 296static void com_LoadSym(LispCom*, LispAtom*); 297static void com_LoadSymLet(LispCom*, LispAtom*, LispAtom*); 298static void com_LoadSymPush(LispCom*, LispAtom*); 299 300static void com_LoadCon(LispCom*, LispObj*); 301static void com_LoadConLet(LispCom*, LispObj*, LispAtom*); 302static void com_LoadConPush(LispCom*, LispObj*); 303 304static void com_Set(LispCom*, short); 305static void com_SetSym(LispCom*, LispAtom*); 306 307static void com_Struct(LispCom*, short, LispObj*); 308static void com_Structp(LispCom*, LispObj*); 309 310static void com_Call(LispCom*, unsigned char, LispBuiltin*); 311static void com_Bytecall(LispCom*, unsigned char, LispObj*); 312static void com_Funcall(LispCom*, LispObj*, LispObj*); 313 314static void CompileStackEnter(LispCom*, int, int); 315static void CompileStackLeave(LispCom*, int, int); 316 317static void LinkBytecode(LispCom*); 318 319static LispObj *ExecuteBytecode(unsigned char*); 320 321 322/* Defined in lisp.c */ 323void LispMoreStack(void); 324void LispMoreEnvironment(void); 325void LispMoreGlobals(LispPackage*); 326LispObj *LispEvalBackquote(LispObj*, int); 327void LispSetAtomObjectProperty(LispAtom*, LispObj*); 328 329/* 330 * Initialization 331 */ 332extern int pagesize; 333 334LispObj x_cons[8]; 335static LispObj *cons, *cons1, *cons2, *cons3, *cons4, *cons5, *cons6, *cons7; 336 337/* 338 * Implementation 339 */ 340#include "lisp/compile.c" 341 342void 343LispBytecodeInit(void) 344{ 345 cons = &x_cons[7]; 346 cons->type = LispCons_t; 347 CDR(cons) = NIL; 348 cons1 = &x_cons[6]; 349 cons1->type = LispCons_t; 350 CDR(cons1) = cons; 351 cons2 = &x_cons[5]; 352 cons2->type = LispCons_t; 353 CDR(cons2) = cons1; 354 cons3 = &x_cons[4]; 355 cons3->type = LispCons_t; 356 CDR(cons3) = cons2; 357 cons4 = &x_cons[3]; 358 cons4->type = LispCons_t; 359 CDR(cons4) = cons3; 360 cons5 = &x_cons[2]; 361 cons5->type = LispCons_t; 362 CDR(cons5) = cons4; 363 cons6 = &x_cons[1]; 364 cons6->type = LispCons_t; 365 CDR(cons6) = cons5; 366 cons7 = &x_cons[0]; 367 cons7->type = LispCons_t; 368 CDR(cons7) = cons6; 369} 370 371LispObj * 372Lisp_Compile(LispBuiltin *builtin) 373/* 374 compile name &optional definition 375 */ 376{ 377 GC_ENTER(); 378 LispObj *result, *warnings_p, *failure_p; 379 380 LispObj *name, *definition; 381 382 definition = ARGUMENT(1); 383 name = ARGUMENT(0); 384 385 result = name; 386 warnings_p = NIL; 387 failure_p = T; 388 389 if (name != NIL) { 390 LispAtom *atom; 391 392 CHECK_SYMBOL(name); 393 atom = name->data.atom; 394 if (atom->a_builtin || atom->a_compiled) 395 goto finished_compilation; 396 else if (atom->a_function) { 397 LispCom com; 398 int failed; 399 int lex = 0, base; 400 LispArgList *alist; 401 LispObj *lambda, *form, *arguments; 402 403 lambda = atom->property->fun.function; 404 if (definition != UNSPEC || lambda->funtype != LispFunction) 405 /* XXX TODO replace definition etc. */ 406 goto finished_compilation; 407 alist = atom->property->alist; 408 409 memset(&com, 0, sizeof(LispCom)); 410 com.toplevel = com.block = LispCalloc(1, sizeof(CodeBlock)); 411 com.block->type = LispBlockClosure; 412 com.block->tag = name; 413 414 /* Create a fake argument list to avoid yet another flag 415 * for ComCall. The value does not matter, just the fact 416 * that the symbol will be bound or not in the implicit 417 * PROGN of the function body. */ 418 base = alist->num_arguments - alist->auxs.num_symbols; 419 if (base) { 420 LispObj *argument; 421 int i, sforms; 422 423 for (i = sforms = 0; i < alist->optionals.num_symbols; i++) 424 if (alist->optionals.sforms[i]) 425 ++sforms; 426 427 arguments = form = NIL; 428 i = sforms + 429 alist->normals.num_symbols + alist->optionals.num_symbols; 430 431 if (i) { 432 arguments = form = CONS(NIL, NIL); 433 GC_PROTECT(arguments); 434 for (--i; i > 0; i--) { 435 RPLACD(form, CONS(NIL, NIL)); 436 form = CDR(form); 437 } 438 } 439 440 for (i = 0; i < alist->keys.num_symbols; i++) { 441 /* key symbol */ 442 if (alist->keys.keys[i]) 443 argument = QUOTE(alist->keys.keys[i]); 444 else 445 argument = alist->keys.symbols[i]; 446 447 /* add key */ 448 if (arguments == NIL) { 449 arguments = form = CONS(argument, NIL); 450 GC_PROTECT(arguments); 451 } 452 else { 453 RPLACD(form, CONS(argument, NIL)); 454 form = CDR(form); 455 } 456 457 /* add value */ 458 RPLACD(form, CONS(NIL, NIL)); 459 form = CDR(form); 460 461 if (alist->keys.sforms[i]) { 462 RPLACD(form, CONS(NIL, NIL)); 463 form = CDR(form); 464 } 465 } 466 467 if (alist->rest) { 468 if (arguments == NIL) { 469 arguments = form = CONS(NIL, NIL); 470 GC_PROTECT(arguments); 471 } 472 else { 473 RPLACD(form, CONS(NIL, NIL)); 474 form = CDR(form); 475 } 476 } 477 } 478 else 479 arguments = NIL; 480 481 form = CONS(lambda->data.lambda.code, NIL); 482 GC_PROTECT(form); 483 com.form = form; 484 com.plist = CONS(NIL, NIL); 485 GC_PROTECT(com.plist); 486 487 failed = 1; 488 if (setjmp(com.jmp) == 0) { 489 /* Save interpreter state */ 490 lex = com.lex = lisp__data.env.lex; 491 base = ComCall(&com, alist, name, arguments, 1, 0, 1); 492 493 /* Generate code tree */ 494 lisp__data.env.lex = base; 495 ComProgn(&com, CAR(form)); 496 failed = 0; 497 } 498 499 /* Restore interpreter state */ 500 lisp__data.env.lex = lex; 501 lisp__data.env.head = lisp__data.env.length = base; 502 503 if (!failed) { 504 failure_p = NIL; 505 result = MakeBytecodeObject(&com, name, 506 lambda->data.lambda.data); 507 LispSetAtomCompiledProperty(atom, result); 508 result = name; 509 } 510 if (com.warnings) 511 warnings_p = FIXNUM(com.warnings); 512 goto finished_compilation; 513 } 514 else 515 goto undefined_function; 516 } 517 518undefined_function: 519 LispDestroy("%s: the function %s is undefined", 520 STRFUN(builtin), STROBJ(name)); 521 522finished_compilation: 523 RETURN(0) = warnings_p; 524 RETURN(1) = failure_p; 525 RETURN_COUNT = 2; 526 GC_LEAVE(); 527 528 return (result); 529} 530 531LispObj * 532Lisp_Disassemble(LispBuiltin *builtin) 533/* 534 disassemble function 535 */ 536{ 537 int macro; 538 char buffer[128]; 539 LispAtom *atom; 540 LispArgList *alist; 541 LispBuiltin *xbuiltin; 542 LispObj *name, *lambda, *bytecode; 543 544 LispObj *function; 545 546 function = ARGUMENT(0); 547 548 macro = 0; 549 alist = NULL; 550 xbuiltin = NULL; 551 name = bytecode = NULL; 552 553 switch (OBJECT_TYPE(function)) { 554 case LispAtom_t: 555 name = function; 556 atom = function->data.atom; 557 alist = atom->property->alist; 558 if (atom->a_builtin) { 559 xbuiltin = atom->property->fun.builtin; 560 macro = xbuiltin->type == LispMacro; 561 } 562 else if (atom->a_compiled) 563 bytecode = atom->property->fun.function; 564 else if (atom->a_function) { 565 lambda = atom->property->fun.function; 566 macro = lambda->funtype == LispMacro; 567 } 568 else if (atom->a_defstruct && 569 atom->property->structure.function != STRUCT_NAME) { 570 if (atom->property->structure.function == STRUCT_CONSTRUCTOR) 571 atom = Omake_struct->data.atom; 572 else if (atom->property->structure.function == STRUCT_CHECK) 573 atom = Ostruct_type->data.atom; 574 else 575 atom = Ostruct_access->data.atom; 576 xbuiltin = atom->property->fun.builtin; 577 } 578 else 579 LispDestroy("%s: the function %s is not defined", 580 STRFUN(builtin), STROBJ(function)); 581 break; 582 case LispBytecode_t: 583 name = Olambda; 584 bytecode = function; 585 break; 586 case LispLambda_t: 587 name = Olambda; 588 alist = (LispArgList*)function->data.lambda.name->data.opaque.data; 589 break; 590 case LispCons_t: 591 if (CAR(function) == Olambda) { 592 function = EVAL(function); 593 if (OBJECT_TYPE(function) == LispLambda_t) { 594 name = Olambda; 595 alist = (LispArgList*) 596 function->data.lambda.name->data.opaque.data; 597 break; 598 } 599 } 600 default: 601 LispDestroy("%s: %s is not a function", 602 STRFUN(builtin), STROBJ(function)); 603 break; 604 } 605 606 if (xbuiltin) { 607 LispWriteStr(NIL, "Builtin ", 8); 608 if (macro) 609 LispWriteStr(NIL, "macro ", 6); 610 else 611 LispWriteStr(NIL, "function ", 9); 612 } 613 else if (macro) 614 LispWriteStr(NIL, "Macro ", 6); 615 else 616 LispWriteStr(NIL, "Function ", 9); 617 LispWriteObject(NIL, name); 618 LispWriteStr(NIL, ":\n", 2); 619 620 if (alist) { 621 int i; 622 623 sprintf(buffer, "%d required argument%s", 624 alist->normals.num_symbols, 625 alist->normals.num_symbols != 1 ? "s" : ""); 626 LispWriteStr(NIL, buffer, strlen(buffer)); 627 for (i = 0; i < alist->normals.num_symbols; i++) { 628 LispWriteChar(NIL, i ? ',' : ':'); 629 LispWriteChar(NIL, ' '); 630 LispWriteStr(NIL, ATOMID(alist->normals.symbols[i]), 631 strlen(ATOMID(alist->normals.symbols[i]))); 632 } 633 LispWriteChar(NIL, '\n'); 634 635 sprintf(buffer, "%d optional argument%s", 636 alist->optionals.num_symbols, 637 alist->optionals.num_symbols != 1 ? "s" : ""); 638 LispWriteStr(NIL, buffer, strlen(buffer)); 639 for (i = 0; i < alist->optionals.num_symbols; i++) { 640 LispWriteChar(NIL, i ? ',' : ':'); 641 LispWriteChar(NIL, ' '); 642 LispWriteStr(NIL, ATOMID(alist->optionals.symbols[i]), 643 strlen(ATOMID(alist->optionals.symbols[i]))); 644 } 645 LispWriteChar(NIL, '\n'); 646 647 sprintf(buffer, "%d keyword parameter%s", 648 alist->keys.num_symbols, 649 alist->keys.num_symbols != 1 ? "s" : ""); 650 LispWriteStr(NIL, buffer, strlen(buffer)); 651 for (i = 0; i < alist->keys.num_symbols; i++) { 652 LispWriteChar(NIL, i ? ',' : ':'); 653 LispWriteChar(NIL, ' '); 654 LispWriteObject(NIL, alist->keys.symbols[i]); 655 } 656 LispWriteChar(NIL, '\n'); 657 658 if (alist->rest) { 659 LispWriteStr(NIL, "Rest argument: ", 15); 660 LispWriteStr(NIL, ATOMID(alist->rest), 661 strlen(ATOMID(alist->rest))); 662 LispWriteChar(NIL, '\n'); 663 } 664 else 665 LispWriteStr(NIL, "No rest argument\n", 17); 666 } 667 668 if (bytecode) { 669 char *ptr; 670 int *offsets[4]; 671 int i, done, j, sym0, sym1, con0, con1, bui0, byt0, strd, strf; 672 LispObj **constants; 673 LispAtom **symbols; 674 LispBuiltin **builtins; 675 LispObj **names; 676 short stack, num_constants, num_symbols, num_builtins, num_bytecodes; 677 unsigned char *base, *stream = bytecode->data.bytecode.bytecode->code; 678 679 LispWriteStr(NIL, "\nBytecode header:\n", 18); 680 681 /* Header information */ 682 stack = *(short*)stream; 683 stream += sizeof(short); 684 sprintf(buffer, "%d element%s used in the stack\n", 685 stack, stack != 1 ? "s" : ""); 686 LispWriteStr(NIL, buffer, strlen(buffer)); 687 stack = *(short*)stream; 688 stream += sizeof(short); 689 sprintf(buffer, "%d element%s used in the builtin stack\n", 690 stack, stack != 1 ? "s" : ""); 691 LispWriteStr(NIL, buffer, strlen(buffer)); 692 stack = *(short*)stream; 693 stream += sizeof(short); 694 sprintf(buffer, "%d element%s used in the protected stack\n", 695 stack, stack != 1 ? "s" : ""); 696 LispWriteStr(NIL, buffer, strlen(buffer)); 697 698 num_constants = *(short*)stream; 699 stream += sizeof(short); 700 num_symbols = *(short*)stream; 701 stream += sizeof(short); 702 num_builtins = *(short*)stream; 703 stream += sizeof(short); 704 num_bytecodes = *(short*)stream; 705 stream += sizeof(short); 706 707 constants = (LispObj**)stream; 708 stream += num_constants * sizeof(LispObj*); 709 symbols = (LispAtom**)stream; 710 stream += num_symbols * sizeof(LispAtom*); 711 builtins = (LispBuiltin**)stream; 712 stream += num_builtins * sizeof(LispBuiltin*); 713 stream += num_bytecodes * sizeof(unsigned char*); 714 names = (LispObj**)stream; 715 stream += num_bytecodes * sizeof(LispObj*); 716 717 for (i = 0; i < num_constants; i++) { 718 sprintf(buffer, "Constant %d = %s\n", i, STROBJ(constants[i])); 719 LispWriteStr(NIL, buffer, strlen(buffer)); 720 } 721 722/* Macro XSTRING avoids some noisy in the output, if it were defined as 723 * #define XSTRING(object) object ? STROBJ(object) : #<UNBOUND> 724 * and called as XSTRING(atom->object) 725 * it would also print the package name were the symbol was first defined, 726 * but for local variables, only the symbol string is important. */ 727#define XSTRING(string) string ? string : "#<UNBOUND>" 728 729 for (i = 0; i < num_symbols; i++) { 730 sprintf(buffer, "Symbol %d = %s\n", 731 i, XSTRING(symbols[i]->string)); 732 LispWriteStr(NIL, buffer, strlen(buffer)); 733 } 734 for (i = 0; i < num_builtins; i++) { 735 sprintf(buffer, "Builtin %d = %s\n", 736 i, STROBJ(builtins[i]->symbol)); 737 LispWriteStr(NIL, buffer, strlen(buffer)); 738 } 739 for (i = 0; i < num_bytecodes; i++) { 740 sprintf(buffer, "Bytecode %d = %s\n", 741 i, STROBJ(names[i])); 742 LispWriteStr(NIL, buffer, strlen(buffer)); 743 } 744 745 /* Make readability slightly easier printing the names of local 746 * variables where it's offset is known, i.e. function arguments. */ 747 if (alist) { 748 if (alist->num_arguments == 0) 749 LispWriteStr(NIL, "\nNo initial stack\n", 18); 750 else { 751 int len1, len2; 752 753 j = 0; 754 LispWriteStr(NIL, "\nInitial stack:\n", 16); 755 756 for (i = 0; i < alist->normals.num_symbols; i++, j++) { 757 sprintf(buffer, "%d = ", j); 758 LispWriteStr(NIL, buffer, strlen(buffer)); 759 ptr = alist->normals.symbols[i]->data.atom->string; 760 LispWriteStr(NIL, ptr, strlen(ptr)); 761 LispWriteChar(NIL, '\n'); 762 } 763 764 for (i = 0; i < alist->optionals.num_symbols; i++, j++) { 765 sprintf(buffer, "%d = ", j); 766 LispWriteStr(NIL, buffer, strlen(buffer)); 767 ptr = alist->optionals.symbols[i]->data.atom->string; 768 LispWriteStr(NIL, ptr, strlen(ptr)); 769 LispWriteChar(NIL, '\n'); 770 if (alist->optionals.sforms[i]) { 771 sprintf(buffer, "%d = ", j); 772 len1 = strlen(buffer); 773 LispWriteStr(NIL, buffer, len1); 774 ptr = alist->optionals.sforms[i]->data.atom->string; 775 len2 = strlen(ptr); 776 LispWriteStr(NIL, ptr, len2); 777 LispWriteChars(NIL, ' ', 28 - (len1 + len2)); 778 LispWriteStr(NIL, "; sform\n", 9); 779 j++; 780 } 781 } 782 783 for (i = 0; i < alist->keys.num_symbols; i++, j++) { 784 sprintf(buffer, "%d = ", j); 785 len1 = strlen(buffer); 786 LispWriteStr(NIL, buffer, len1); 787 if (alist->keys.keys[i]) { 788 ptr = alist->keys.keys[i]->data.atom->string; 789 len2 = strlen(ptr); 790 LispWriteStr(NIL, ptr, strlen(ptr)); 791 LispWriteChars(NIL, ' ', 28 - (len1 + len2)); 792 LispWriteStr(NIL, "; special key", 14); 793 } 794 else { 795 ptr = alist->keys.symbols[i]->data.atom->string; 796 LispWriteStr(NIL, ptr, strlen(ptr)); 797 } 798 LispWriteChar(NIL, '\n'); 799 if (alist->keys.sforms[i]) { 800 sprintf(buffer, "%d = ", j); 801 len1 = strlen(buffer); 802 LispWriteStr(NIL, buffer, len1); 803 ptr = alist->keys.sforms[i]->data.atom->string; 804 len2 = strlen(ptr); 805 LispWriteStr(NIL, ptr, len2); 806 LispWriteChars(NIL, ' ', 28 - (len1 + len2)); 807 LispWriteStr(NIL, "; sform\n", 9); 808 j++; 809 } 810 } 811 812 if (alist->rest) { 813 sprintf(buffer, "%d = ", j); 814 len1 = strlen(buffer); 815 LispWriteStr(NIL, buffer, len1); 816 ptr = alist->rest->data.atom->string; 817 len2 = strlen(ptr); 818 LispWriteStr(NIL, ptr, len2); 819 LispWriteChar(NIL, '\n'); 820 j++; 821 } 822 823 for (i = 0; i < alist->auxs.num_symbols; i++, j++) { 824 sprintf(buffer, "%d = ", j); 825 len1 = strlen(buffer); 826 LispWriteStr(NIL, buffer, len1); 827 ptr = alist->auxs.symbols[i]->data.atom->string; 828 len2 = strlen(ptr); 829 LispWriteStr(NIL, ptr, len2); 830 LispWriteChars(NIL, ' ', 28 - (len1 + len2)); 831 LispWriteStr(NIL, "; aux\n", 7); 832 } 833 } 834 } 835 836 LispWriteStr(NIL, "\nBytecode stream:\n", 18); 837 838 base = stream; 839 for (done = j = 0; !done; j = 0) { 840 sym0 = sym1 = con0 = con1 = bui0 = byt0 = strd = strf = -1; 841 sprintf(buffer, "%4ld ", (long)(stream - base)); 842 ptr = buffer + strlen(buffer); 843 switch (*stream++) { 844 case XBC_NOOP: strcpy(ptr, "NOOP"); break; 845 case XBC_PRED: 846 strcpy(ptr, "PRED:"); 847 ptr += strlen(ptr); 848 goto predicate; 849 case XBC_INV: strcpy(ptr, "INV"); break; 850 case XBC_NIL: strcpy(ptr, "NIL"); break; 851 case XBC_T: strcpy(ptr, "T"); break; 852 case XBC_CAR: strcpy(ptr, "CAR"); break; 853 case XBC_CDR: strcpy(ptr, "CDR"); break; 854 case XBC_RPLACA:strcpy(ptr, "RPLACA"); break; 855 case XBC_RPLACD:strcpy(ptr, "RPLACD"); break; 856 case XBC_EQ: strcpy(ptr, "EQ"); break; 857 case XBC_EQL: strcpy(ptr, "EQL"); break; 858 case XBC_EQUAL: strcpy(ptr, "EQUAL"); break; 859 case XBC_EQUALP:strcpy(ptr, "EQUALP"); break; 860 case XBC_LENGTH:strcpy(ptr, "LENGTH"); break; 861 case XBC_LAST: strcpy(ptr, "LAST"); break; 862 case XBC_NTHCDR:strcpy(ptr, "NTHCDR"); break; 863 case XBC_PUSH: strcpy(ptr, "PUSH"); break; 864 case XBC_CAR_PUSH: 865 strcpy(ptr, "CAR&PUSH"); 866 break; 867 case XBC_CDR_PUSH: 868 strcpy(ptr, "CDR&PUSH"); 869 break; 870 case XBC_PUSH_NIL: 871 strcpy(ptr, "PUSH NIL"); 872 break; 873 case XBC_PUSH_UNSPEC: 874 strcpy(ptr, "PUSH #<UNSPEC>"); 875 break; 876 case XBC_PUSH_T: 877 strcpy(ptr, "PUSH T"); 878 break; 879 case XBC_PUSH_NIL_N: 880 strcpy(ptr, "PUSH NIL "); 881 ptr += strlen(ptr); 882 sprintf(ptr, "%d", (int)(*stream++)); 883 break; 884 case XBC_PUSH_UNSPEC_N: 885 strcpy(ptr, "PUSH #<UNSPEC> "); 886 ptr += strlen(ptr); 887 sprintf(ptr, "%d", (int)(*stream++)); 888 break; 889 case XBC_LET: 890 strcpy(ptr, "LET"); 891/* update sym0 */ 892symbol: 893 offsets[j++] = &sym0; 894/* update <offsets> - print [byte] */ 895offset: 896 ptr += strlen(ptr); 897 i = *stream++; 898 *(offsets[j - 1]) = i; 899 sprintf(ptr, " [%d]", i); 900 break; 901 case XBC_LETX: 902 strcpy(ptr, "LET*"); 903 goto symbol; 904 case XBC_LET_NIL: 905 strcpy(ptr, "LET NIL"); 906 goto symbol; 907 case XBC_LETX_NIL: 908 strcpy(ptr, "LET* NIL"); 909 goto symbol; 910 case XBC_LETBIND: 911 strcpy(ptr, "LETBIND"); 912/* print byte */ 913value: 914 ptr += strlen(ptr); 915 sprintf(ptr, " %d", (int)(*stream++)); 916 break; 917 case XBC_UNLET:strcpy(ptr, "UNLET"); goto value; 918 case XBC_LOAD: 919 strcpy(ptr, "LOAD"); 920/* print (byte) */ 921reference: 922 ptr += strlen(ptr); 923 i = *stream++; 924 sprintf(ptr, " (%d)", i); 925 break; 926 case XBC_LOAD_CAR: 927 strcpy(ptr, "LOAD&CAR"); 928 goto reference; 929 case XBC_LOAD_CDR: 930 strcpy(ptr, "LOAD&CDR"); 931 goto reference; 932 case XBC_LOAD_CAR_STORE: 933 strcpy(ptr, "LOAD&CAR&STORE"); 934 goto reference; 935 case XBC_LOAD_CDR_STORE: 936 strcpy(ptr, "LOAD&CDR&STORE"); 937 goto reference; 938 case XBC_LOAD_LET: 939 strcpy(ptr, "LOAD&LET"); 940load_let: 941 offsets[j++] = &sym0; 942 i = *stream++; 943 ptr += strlen(ptr); 944 sprintf(ptr, " (%d)", i); 945 goto offset; 946 case XBC_LOAD_LETX: 947 strcpy(ptr, "LOAD&LET*"); 948 goto load_let; 949 case XBC_STRUCT: 950 strcpy(ptr, "STRUCT"); 951 offsets[j++] = &strf; 952 offsets[j++] = &strd; 953/* update <offsets> - print [byte] - update <offsets> - print [byte] */ 954offset_offset: 955 ptr += strlen(ptr); 956 i = *stream++; 957 *(offsets[j - 2]) = i; 958 sprintf(ptr, " [%d]", i); 959 goto offset; 960 case XBC_LOAD_PUSH: 961 strcpy(ptr, "LOAD&PUSH"); 962 goto reference; 963 case XBC_LOADCON: 964 strcpy(ptr, "LOADCON"); 965constant: 966 offsets[j++] = &con0; 967 goto offset; 968 case XBC_LOADCON_SET: 969 strcpy(ptr, "LOADCON&SET"); 970 offsets[j++] = &con0; 971/* update <offsets> - print [byte] - print (byte) */ 972offset_reference: 973 i = *stream++; 974 *(offsets[j - 1]) = i; 975 ptr += strlen(ptr); 976 sprintf(ptr, " [%d]", i); 977 goto reference; 978 case XBC_STRUCTP: 979 strcpy(ptr, "STRUCTP"); 980 offsets[j++] = &strd; 981 goto offset; 982 case XBC_LOADCON_LET: 983 strcpy(ptr, "LOADCON&LET"); 984loadcon_let: 985 offsets[j++] = &con0; 986 offsets[j++] = &sym0; 987 goto offset_offset; 988 case XBC_LOADCON_LETX: 989 strcpy(ptr, "LOADCON&LET*"); 990 goto loadcon_let; 991 case XBC_LOADCON_PUSH: 992 strcpy(ptr, "LOADCON&PUSH"); 993 goto constant; 994 case XBC_LOADSYM: 995 strcpy(ptr, "LOADSYM"); 996 goto symbol; 997 case XBC_LOADSYM_LET: 998 strcpy(ptr, "LOADSYM&LET"); 999loadsym_let: 1000 offsets[j++] = &sym0; 1001 offsets[j++] = &sym1; 1002 goto offset_offset; 1003 case XBC_LOADSYM_LETX: 1004 strcpy(ptr, "LOADSYM&LET*"); 1005 goto loadsym_let; 1006 case XBC_LOADSYM_PUSH: 1007 strcpy(ptr, "LOADSYM&PUSH"); 1008 goto symbol; 1009 case XBC_LOAD_SET: 1010 strcpy(ptr, "LOAD&SET"); 1011/* print (byte) - print (byte) */ 1012reference_reference: 1013 ptr += strlen(ptr); 1014 i = *stream++; 1015 sprintf(ptr, " (%d)", i); 1016 goto reference; 1017 case XBC_LOAD_CAR_SET: 1018 strcpy(ptr, "LOAD&CAR&SET"); 1019 goto reference_reference; 1020 case XBC_LOAD_CDR_SET: 1021 strcpy(ptr, "LOAD&CDR&SET"); 1022 goto reference_reference; 1023 case XBC_CAR_SET: 1024 strcpy(ptr, "CAR&SET"); 1025 goto reference; 1026 case XBC_CDR_SET: 1027 strcpy(ptr, "CDR&SET"); 1028 goto reference; 1029 case XBC_SET: 1030 strcpy(ptr, "SET"); 1031 goto reference; 1032 case XBC_SETSYM: 1033 strcpy(ptr, "SETSYM"); 1034 goto symbol; 1035 case XBC_SET_NIL: 1036 strcpy(ptr, "SET NIL"); 1037 goto reference; 1038 case XBC_CALL: 1039 strcpy(ptr, "CALL"); 1040 ptr += strlen(ptr); 1041 sprintf(ptr, " %d", (int)(*stream++)); 1042 offsets[j++] = &bui0; 1043 goto offset; 1044 case XBC_CALL_SET: 1045 strcpy(ptr, "CALL&SET"); 1046 ptr += strlen(ptr); 1047 sprintf(ptr, " %d", (int)(*stream++)); 1048 offsets[j++] = &bui0; 1049 goto offset_reference; 1050 case XBC_BYTECALL: 1051 strcpy(ptr, "BYTECALL"); 1052 ptr += strlen(ptr); 1053 sprintf(ptr, " %d", (int)(*stream++)); 1054 offsets[j++] = &byt0; 1055 goto offset; 1056 case XBC_FUNCALL: 1057 strcpy(ptr, "FUNCALL"); 1058constant_constant: 1059 offsets[j++] = &con0; 1060 offsets[j++] = &con1; 1061 goto offset_offset; 1062 case XBC_CCONS: 1063 strcpy(ptr, "CCONS"); 1064 goto constant_constant; 1065 case XBC_CSTAR: strcpy(ptr, "CSTAR"); break; 1066 case XBC_CFINI: strcpy(ptr, "CFINI"); break; 1067 case XBC_LSTAR: strcpy(ptr, "LSTAR"); break; 1068 case XBC_LCONS: strcpy(ptr, "LCONS"); break; 1069 case XBC_LFINI: strcpy(ptr, "LFINI"); break; 1070 case XBC_BCONS: strcpy(ptr, "BCONS"); break; 1071 case XBC_BCONS1: case XBC_BCONS2: case XBC_BCONS3: 1072 case XBC_BCONS4: case XBC_BCONS5: case XBC_BCONS6: 1073 case XBC_BCONS7: 1074 strcpy(ptr, "BCONS"); 1075 ptr += strlen(ptr); 1076 sprintf(ptr, "%d", (int)(stream[-1] - XBC_BCONS)); 1077 break; 1078 case XBC_JUMP: 1079 strcpy(ptr, "JUMP"); 1080integer: 1081 ptr += strlen(ptr); 1082 sprintf(ptr, " %d", *(signed short*)stream); 1083 stream += sizeof(short); 1084 break; 1085 case XBC_JUMPT: 1086 strcpy(ptr, "JUMPT"); 1087 goto integer; 1088 case XBC_JUMPNIL: 1089 strcpy(ptr, "JUMPNIL"); 1090 goto integer; 1091 case XBC_LETREC: 1092 strcpy(ptr, "LETREC"); 1093 ptr += strlen(ptr); 1094 sprintf(ptr, " %d", (int)*stream++); 1095 break; 1096 case XBC_RETURN: 1097 strcpy(ptr, "RETURN"); 1098 done = 1; 1099 break; 1100 } 1101 i = ptr - buffer + strlen(ptr); 1102 LispWriteStr(NIL, buffer, i); 1103 if (j) { 1104 1105 /* Pad */ 1106 LispWriteChars(NIL, ' ', 28 - i); 1107 LispWriteChar(NIL, ';'); 1108 1109 ptr = buffer; 1110 1111 /* Structure */ 1112 if (strf >= 0) { 1113 /* strd is valid if strf set */ 1114 LispObj *fields = constants[strd]; 1115 1116 for (; strf >= 0; strf--) 1117 fields = CDR(fields); 1118 strcpy(ptr, " "); ptr += 2; 1119 strcpy(ptr, CAR(fields)->data.atom->string); 1120 ptr += strlen(ptr); 1121 } 1122 if (strd >= 0) { 1123 strcpy(ptr, " "); ptr += 2; 1124 strcpy(ptr, STROBJ(CAR(constants[strd]))); 1125 ptr += strlen(ptr); 1126 } 1127 1128 /* Constants */ 1129 if (con0 >= 0) { 1130 strcpy(ptr, " "); ptr += 2; 1131 strcpy(ptr, STROBJ(constants[con0])); 1132 ptr += strlen(ptr); 1133 if (con1 >= 0) { 1134 strcpy(ptr, " "); ptr += 2; 1135 strcpy(ptr, STROBJ(constants[con1])); 1136 ptr += strlen(ptr); 1137 } 1138 } 1139 1140 /* Builtin */ 1141 if (bui0 >= 0) { 1142 strcpy(ptr, " "); ptr += 2; 1143 strcpy(ptr, STROBJ(builtins[bui0]->symbol)); 1144 ptr += strlen(ptr); 1145 } 1146 1147 /* Bytecode */ 1148 if (byt0 >= 0) { 1149 strcpy(ptr, " "); ptr += 2; 1150 strcpy(ptr, STROBJ(names[byt0])); 1151 ptr += strlen(ptr); 1152 } 1153 1154 /* Symbols */ 1155 if (sym0 >= 0) { 1156 strcpy(ptr, " "); ptr += 2; 1157 strcpy(ptr, XSTRING(symbols[sym0]->string)); 1158 ptr += strlen(ptr); 1159 if (sym1 >= 0) { 1160 strcpy(ptr, " "); ptr += 2; 1161 strcpy(ptr, XSTRING(symbols[sym1]->string)); 1162 ptr += strlen(ptr); 1163 } 1164 } 1165 1166 i = ptr - buffer; 1167 LispWriteStr(NIL, buffer, i); 1168 } 1169 LispWriteChar(NIL, '\n'); 1170 continue; 1171predicate: 1172 switch (*stream++) { 1173 case XBP_CONSP: strcpy(ptr, "CONSP"); break; 1174 case XBP_LISTP: strcpy(ptr, "LISTP"); break; 1175 case XBP_NUMBERP: strcpy(ptr, "NUMBERP"); break; 1176 } 1177 LispWriteStr(NIL, buffer, ptr - buffer + strlen(ptr)); 1178 LispWriteChar(NIL, '\n'); 1179 } 1180#undef XSTRING 1181 } 1182 1183 return (function); 1184} 1185 1186 1187 1188LispObj * 1189LispCompileForm(LispObj *form) 1190{ 1191 GC_ENTER(); 1192 int failed; 1193 LispCom com; 1194 1195 if (!CONSP(form)) 1196 /* Incorrect call or NIL */ 1197 return (form); 1198 1199 memset(&com, 0, sizeof(LispCom)); 1200 1201 com.toplevel = com.block = LispCalloc(1, sizeof(CodeBlock)); 1202 com.block->type = LispBlockNone; 1203 com.lex = lisp__data.env.lex; 1204 1205 com.plist = CONS(NIL, NIL); 1206 GC_PROTECT(com.plist); 1207 1208 failed = 1; 1209 if (setjmp(com.jmp) == 0) { 1210 for (; CONSP(form); form = CDR(form)) { 1211 com.form = form; 1212 ComEval(&com, CAR(form)); 1213 } 1214 failed = 0; 1215 } 1216 GC_LEAVE(); 1217 1218 return (failed ? NIL : MakeBytecodeObject(&com, NIL, NIL)); 1219} 1220 1221LispObj * 1222LispExecuteBytecode(LispObj *object) 1223{ 1224 if (!BYTECODEP(object)) 1225 return (EVAL(object)); 1226 1227 return (ExecuteBytecode(object->data.bytecode.bytecode->code)); 1228} 1229 1230static LispObj * 1231MakeBytecodeObject(LispCom *com, LispObj *name, LispObj *plist) 1232{ 1233 LispObj *object; 1234 LispBytecode *bytecode; 1235 1236 GC_ENTER(); 1237 unsigned char *stream; 1238 short i, num_constants; 1239 LispObj **constants, *code, *cons, *prev; 1240 1241 /* Resolve dependencies, optimize and create byte stream */ 1242 LinkBytecode(com); 1243 1244 object = LispNew(NIL, NIL); 1245 GC_PROTECT(object); 1246 bytecode = LispMalloc(sizeof(LispBytecode)); 1247 bytecode->code = com->bytecode; 1248 bytecode->length = com->length; 1249 1250 1251 stream = bytecode->code; 1252 1253 /* Skip stack information */ 1254 stream += sizeof(short) * 3; 1255 1256 /* Get information */ 1257 num_constants = *(short*)stream; 1258 stream += sizeof(short) * 4; 1259 constants = (LispObj**)stream; 1260 1261 GC_PROTECT(plist); 1262 code = cons = prev = NIL; 1263 for (i = 0; i < num_constants; i++) { 1264 if (POINTERP(constants[i]) && !XSYMBOLP(constants[i])) { 1265 if (code == NIL) { 1266 code = cons = prev = CONS(constants[i], NIL); 1267 GC_PROTECT(code); 1268 } 1269 else { 1270 RPLACD(cons, CONS(constants[i], NIL)); 1271 prev = cons; 1272 cons = CDR(cons); 1273 } 1274 } 1275 } 1276 1277 /* Protect this in case the function is redefined */ 1278 for (i = 0; i < com->table.num_bytecodes; i++) { 1279 if (code == NIL) { 1280 code = cons = prev = CONS(com->table.bytecodes[i], NIL); 1281 GC_PROTECT(code); 1282 } 1283 else { 1284 RPLACD(cons, CONS(com->table.bytecodes[i], NIL)); 1285 prev = cons; 1286 cons = CDR(cons); 1287 } 1288 } 1289 1290 /* Free everything, but the LispCom structure and the generated bytecode */ 1291 CompileFreeState(com); 1292 1293 /* Allocate the minimum required number of cons cells to protect objects */ 1294 if (!CONSP(code)) 1295 code = plist; 1296 else if (CONSP(plist)) { 1297 if (code == cons) 1298 RPLACD(code, plist); 1299 else 1300 RPLACD(cons, plist); 1301 } 1302 else { 1303 if (code == cons) 1304 code = CAR(code); 1305 else 1306 CDR(prev) = CAR(cons); 1307 } 1308 1309 object->data.bytecode.bytecode = bytecode; 1310 /* Byte code references this object, so it cannot be garbage collected */ 1311 object->data.bytecode.code = code; 1312 object->data.bytecode.name = name; 1313 object->type = LispBytecode_t; 1314 1315 LispMused(bytecode); 1316 LispMused(bytecode->code); 1317 GC_LEAVE(); 1318 1319 return (object); 1320} 1321 1322static void 1323CompileFreeTree(CodeTree *tree) 1324{ 1325 if (tree->type == CodeTreeBlock) 1326 CompileFreeBlock(tree->data.block); 1327 LispFree(tree); 1328} 1329 1330static void 1331CompileFreeBlock(CodeBlock *block) 1332{ 1333 CodeTree *tree = block->tree, *next; 1334 1335 while (tree) { 1336 next = tree->next; 1337 CompileFreeTree(tree); 1338 tree = next; 1339 } 1340 if (block->type == LispBlockBody) { 1341 LispFree(block->tagbody.labels); 1342 LispFree(block->tagbody.codes); 1343 } 1344 LispFree(block->variables.symbols); 1345 LispFree(block->variables.flags); 1346 LispFree(block); 1347} 1348 1349static void 1350CompileFreeState(LispCom *com) 1351{ 1352 CompileFreeBlock(com->block); 1353 LispFree(com->table.constants); 1354 LispFree(com->table.symbols); 1355 LispFree(com->table.builtins); 1356 LispFree(com->table.bytecodes); 1357} 1358 1359/* XXX Put a breakpoint here when changing the macro expansion code. 1360 * No opcodes should be generated during macro expansion. */ 1361static CodeTree * 1362CompileNewTree(LispCom *com, CodeTreeType type) 1363{ 1364 CodeTree *tree = LispMalloc(sizeof(CodeTree)); 1365 1366 tree->type = type; 1367 tree->next = NULL; 1368 tree->block = com->block; 1369 if (com->block->tree == NULL) 1370 com->block->tree = tree; 1371 else 1372 com->block->tail->next = tree; 1373 com->block->tail = tree; 1374 1375 return (tree); 1376} 1377 1378static void 1379CompileIniBlock(LispCom *com, LispBlockType type, LispObj *tag) 1380{ 1381 CodeTree *tree = NEW_TREE(CodeTreeBlock); 1382 CodeBlock *block = LispCalloc(1, sizeof(CodeBlock)); 1383 1384 tree->data.block = block; 1385 1386 block->type = type; 1387 block->tag = tag; 1388 block->prev = com->block; 1389 block->parent = tree; 1390 block->level = com->level; 1391 com->block = block; 1392 1393 if (type == LispBlockBody) 1394 com->tagbody = com->level; 1395} 1396 1397static void 1398CompileFiniBlock(LispCom *com) 1399{ 1400 com->block = com->block->prev; 1401 if (com->block && com->block->type == LispBlockBody) 1402 com->tagbody = com->block->level; 1403} 1404 1405static void 1406com_BytecodeChar(LispCom *com, LispByteOpcode code, char value) 1407{ 1408 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1409 1410 tree->code = code; 1411 tree->data.signed_char = value; 1412} 1413 1414static void 1415com_BytecodeShort(LispCom *com, LispByteOpcode code, short value) 1416{ 1417 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1418 1419 tree->code = code; 1420 tree->data.signed_short = value; 1421} 1422 1423static void 1424com_BytecodeAtom(LispCom *com, LispByteOpcode code, LispAtom *atom) 1425{ 1426 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1427 1428 tree->code = code; 1429 tree->data.atom = atom; 1430} 1431 1432static void 1433com_BytecodeObject(LispCom *com, LispByteOpcode code, LispObj *object) 1434{ 1435 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1436 1437 tree->code = code; 1438 tree->data.object = object; 1439} 1440 1441static void 1442com_BytecodeCons(LispCom *com, LispByteOpcode code, LispObj *car, LispObj *cdr) 1443{ 1444 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1445 1446 tree->code = code; 1447 tree->data.cons.car = car; 1448 tree->data.cons.cdr = cdr; 1449} 1450 1451static void 1452com_Bytecode(LispCom *com, LispByteOpcode code) 1453{ 1454 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1455 1456 tree->code = code; 1457} 1458 1459static void 1460com_Load(LispCom *com, short offset) 1461{ 1462 com_BytecodeShort(com, XBC_LOAD, offset); 1463} 1464 1465static void 1466com_LoadLet(LispCom *com, short offset, LispAtom *name) 1467{ 1468 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1469 1470 tree->code = XBC_LOAD_LET; 1471 tree->data.let.offset = offset; 1472 tree->data.let.name = name; 1473} 1474 1475static void 1476com_LoadPush(LispCom *com, short offset) 1477{ 1478 com_BytecodeShort(com, XBC_LOAD_PUSH, offset); 1479} 1480 1481static void 1482com_Let(LispCom *com, LispAtom *name) 1483{ 1484 com_BytecodeAtom(com, XBC_LET, name); 1485} 1486 1487static void 1488com_Bind(LispCom *com, short count) 1489{ 1490 if (count) 1491 com_BytecodeShort(com, XBC_LETBIND, count); 1492} 1493 1494static void 1495com_Unbind(LispCom *com, short count) 1496{ 1497 if (count) 1498 com_BytecodeShort(com, XBC_UNLET, count); 1499} 1500 1501static void 1502com_LoadSym(LispCom *com, LispAtom *atom) 1503{ 1504 com_BytecodeAtom(com, XBC_LOADSYM, atom); 1505} 1506 1507static void 1508com_LoadSymLet(LispCom *com, LispAtom *symbol, LispAtom *name) 1509{ 1510 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1511 1512 tree->code = XBC_LOADSYM_LET; 1513 tree->data.let_sym.symbol = symbol; 1514 tree->data.let_sym.name = name; 1515} 1516 1517static void 1518com_LoadSymPush(LispCom *com, LispAtom *name) 1519{ 1520 com_BytecodeAtom(com, XBC_LOADSYM_PUSH, name); 1521} 1522 1523static void 1524com_LoadCon(LispCom *com, LispObj *constant) 1525{ 1526 if (constant == NIL) 1527 com_Bytecode(com, XBC_NIL); 1528 else if (constant == T) 1529 com_Bytecode(com, XBC_T); 1530 else if (constant == UNSPEC) { 1531 COMPILE_FAILURE("internal error: loading #<UNSPEC>"); 1532 } 1533 else 1534 com_BytecodeObject(com, XBC_LOADCON, constant); 1535} 1536 1537static void 1538com_LoadConLet(LispCom *com, LispObj *constant, LispAtom *name) 1539{ 1540 if (constant == NIL) 1541 com_BytecodeAtom(com, XBC_LET_NIL, name); 1542 else { 1543 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1544 1545 tree->code = XBC_LOADCON_LET; 1546 tree->data.let_con.object = constant; 1547 tree->data.let_con.name = name; 1548 } 1549} 1550 1551static void 1552com_LoadConPush(LispCom *com, LispObj *constant) 1553{ 1554 if (constant == NIL) 1555 com_Bytecode(com, XBC_PUSH_NIL); 1556 else if (constant == T) 1557 com_Bytecode(com, XBC_PUSH_T); 1558 else if (constant == UNSPEC) 1559 com_Bytecode(com, XBC_PUSH_UNSPEC); 1560 else 1561 com_BytecodeObject(com, XBC_LOADCON_PUSH, constant); 1562} 1563 1564static void 1565com_Set(LispCom *com, short offset) 1566{ 1567 com_BytecodeShort(com, XBC_SET, offset); 1568} 1569 1570static void 1571com_SetSym(LispCom *com, LispAtom *symbol) 1572{ 1573 com_BytecodeAtom(com, XBC_SETSYM, symbol); 1574} 1575 1576static void 1577com_Struct(LispCom *com, short offset, LispObj *definition) 1578{ 1579 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1580 1581 tree->code = XBC_STRUCT; 1582 tree->data.struc.offset = offset; 1583 tree->data.struc.definition = definition; 1584} 1585 1586static void 1587com_Structp(LispCom *com, LispObj *definition) 1588{ 1589 com_BytecodeObject(com, XBC_STRUCTP, definition); 1590} 1591 1592static void 1593com_Call(LispCom *com, unsigned char num_arguments, LispBuiltin *builtin) 1594{ 1595 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1596 1597 tree->code = XBC_CALL; 1598 tree->data.builtin.num_arguments = num_arguments; 1599 tree->data.builtin.builtin = builtin; 1600} 1601 1602static void 1603com_Bytecall(LispCom *com, unsigned char num_arguments, LispObj *code) 1604{ 1605 CodeTree *tree = NEW_TREE(CodeTreeBytecode); 1606 1607 tree->code = XBC_BYTECALL; 1608 tree->data.bytecall.num_arguments = num_arguments; 1609 tree->data.bytecall.code = code; 1610} 1611 1612static void 1613com_Funcall(LispCom *com, LispObj *function, LispObj *arguments) 1614{ 1615 com_BytecodeCons(com, XBC_FUNCALL, function, arguments); 1616} 1617 1618static void 1619CompileStackEnter(LispCom *com, int count, int builtin) 1620{ 1621 if (!com->macro) { 1622 if (builtin) { 1623 com->stack.cbstack += count; 1624 if (com->stack.bstack < com->stack.cbstack) 1625 com->stack.bstack = com->stack.cbstack; 1626 } 1627 else { 1628 com->stack.cstack += count; 1629 if (com->stack.stack < com->stack.cstack) 1630 com->stack.stack = com->stack.cstack; 1631 } 1632 } 1633} 1634 1635static void 1636CompileStackLeave(LispCom *com, int count, int builtin) 1637{ 1638 if (!com->macro) { 1639 if (builtin) 1640 com->stack.cbstack -= count; 1641 else 1642 com->stack.cstack -= count; 1643 } 1644} 1645 1646static void 1647LinkWarnUnused(LispCom *com, CodeBlock *block) 1648{ 1649 int i; 1650 CodeTree *tree; 1651 1652 for (tree = block->tree; tree; tree = tree->next) { 1653 if (tree->type == CodeTreeBlock) 1654 LinkWarnUnused(com, tree->data.block); 1655 } 1656 1657 for (i = 0; i < block->variables.length; i++) 1658 if (!(block->variables.flags[i] & (VARIABLE_USED | VARIABLE_ARGUMENT))) { 1659 ++com->warnings; 1660 LispWarning("the variable %s is unused", 1661 block->variables.symbols[i]->string); 1662 } 1663} 1664 1665#define INTERNAL_ERROR_STRING "COMPILE: internal error #%d" 1666#define INTERNAL_ERROR(value) LispDestroy(INTERNAL_ERROR_STRING, value) 1667static long 1668LinkBuildOffsets(LispCom *com, CodeTree *tree, long offset) 1669{ 1670 for (; tree; tree = tree->next) { 1671 tree->offset = offset; 1672 switch (tree->type) { 1673 case CodeTreeBytecode: 1674 switch (tree->code) { 1675 case XBC_NOOP: 1676 INTERNAL_ERROR(__LINE__); 1677 break; 1678 1679 /* byte */ 1680 case XBC_BCONS: 1681 case XBC_BCONS1: 1682 case XBC_BCONS2: 1683 case XBC_BCONS3: 1684 case XBC_BCONS4: 1685 case XBC_BCONS5: 1686 case XBC_BCONS6: 1687 case XBC_BCONS7: 1688 case XBC_INV: 1689 case XBC_NIL: 1690 case XBC_T: 1691 case XBC_PUSH: 1692 case XBC_CAR_PUSH: 1693 case XBC_CDR_PUSH: 1694 case XBC_PUSH_NIL: 1695 case XBC_PUSH_UNSPEC: 1696 case XBC_PUSH_T: 1697 case XBC_LSTAR: 1698 case XBC_LCONS: 1699 case XBC_LFINI: 1700 case XBC_RETURN: 1701 case XBC_CSTAR: 1702 case XBC_CFINI: 1703 case XBC_CAR: 1704 case XBC_CDR: 1705 case XBC_RPLACA: 1706 case XBC_RPLACD: 1707 case XBC_EQ: 1708 case XBC_EQL: 1709 case XBC_EQUAL: 1710 case XBC_EQUALP: 1711 case XBC_LENGTH: 1712 case XBC_LAST: 1713 case XBC_NTHCDR: 1714 ++offset; 1715 break; 1716 1717 /* byte + byte */ 1718 case XBC_PUSH_NIL_N: 1719 case XBC_PUSH_UNSPEC_N: 1720 case XBC_PRED: 1721 case XBC_LETREC: 1722 case XBC_LOAD_PUSH: 1723 case XBC_CAR_SET: 1724 case XBC_CDR_SET: 1725 case XBC_SET: 1726 case XBC_SET_NIL: 1727 case XBC_LETBIND: 1728 case XBC_UNLET: 1729 case XBC_LOAD: 1730 case XBC_LOAD_CAR: 1731 case XBC_LOAD_CDR: 1732 case XBC_LOAD_CAR_STORE: 1733 case XBC_LOAD_CDR_STORE: 1734 case XBC_LET: 1735 case XBC_LETX: 1736 case XBC_LET_NIL: 1737 case XBC_LETX_NIL: 1738 case XBC_STRUCTP: 1739 case XBC_SETSYM: 1740 case XBC_LOADCON_PUSH: 1741 case XBC_LOADSYM_PUSH: 1742 case XBC_LOADCON: 1743 case XBC_LOADSYM: 1744 offset += 2; 1745 break; 1746 1747 /* byte + byte + byte */ 1748 case XBC_CALL: 1749 case XBC_BYTECALL: 1750 case XBC_LOAD_SET: 1751 case XBC_LOAD_CAR_SET: 1752 case XBC_LOAD_CDR_SET: 1753 case XBC_LOADCON_SET: 1754 case XBC_LOAD_LET: 1755 case XBC_LOAD_LETX: 1756 case XBC_STRUCT: 1757 case XBC_LOADCON_LET: 1758 case XBC_LOADCON_LETX: 1759 case XBC_LOADSYM_LET: 1760 case XBC_LOADSYM_LETX: 1761 case XBC_CCONS: 1762 case XBC_FUNCALL: 1763 offset += 3; 1764 break; 1765 1766 /* byte + short */ 1767 case XBC_JUMP: 1768 case XBC_JUMPT: 1769 case XBC_JUMPNIL: 1770 /* XXX this is likely a jump to random address here */ 1771 INTERNAL_ERROR(__LINE__); 1772 offset += sizeof(short) + 1; 1773 break; 1774 1775 /* byte + byte + byte + byte */ 1776 case XBC_CALL_SET: 1777 offset += 4; 1778 break; 1779 } 1780 break; 1781 case CodeTreeLabel: 1782 /* Labels are not loaded */ 1783 break; 1784 case CodeTreeJump: 1785 case CodeTreeJumpIf: 1786 case CodeTreeCond: 1787 /* If not the point where the conditional block finishes */ 1788 if (tree->code != XBC_NOOP) 1789 /* Reserve space for the jump opcode */ 1790 offset += sizeof(short) + 1; 1791 break; 1792 case CodeTreeGo: 1793 case CodeTreeReturn: 1794 /* Reserve space for the jump opcode */ 1795 offset += sizeof(short) + 1; 1796 break; 1797 case CodeTreeBlock: 1798 offset = LinkBuildOffsets(com, tree->data.block->tree, offset); 1799 break; 1800 } 1801 } 1802 1803 return (offset); 1804} 1805 1806static void 1807LinkDoOptimize_0(LispCom *com, CodeBlock *block) 1808{ 1809 CodeTree *tree, *prev, *next; 1810 1811 /* Remove redundant or join opcodes that can be joined. Do it here 1812 * because some of these are hard to detect earlier, and/or would 1813 * require a lot of duplicated code or more time. */ 1814 tree = prev = block->tree; 1815 while (tree) { 1816 next = tree->next; 1817 1818 /* LET -> LET* */ 1819 if (next && 1820 next->type == CodeTreeBytecode && 1821 next->code == XBC_LETBIND && 1822 next->data.signed_short == 1) { 1823 switch (tree->code) { 1824 case XBC_LET: 1825 tree->code = XBC_LETX; 1826 goto remove_next_label; 1827 case XBC_LET_NIL: 1828 tree->code = XBC_LETX_NIL; 1829 goto remove_next_label; 1830 case XBC_LOAD_LET: 1831 tree->code = XBC_LOAD_LETX; 1832 goto remove_next_label; 1833 case XBC_LOADCON_LET: 1834 tree->code = XBC_LOADCON_LETX; 1835 goto remove_next_label; 1836 case XBC_LOADSYM_LET: 1837 tree->code = XBC_LOADSYM_LETX; 1838 goto remove_next_label; 1839 default: 1840 break; 1841 } 1842 } 1843 1844 switch (tree->type) { 1845 case CodeTreeBytecode: 1846 switch (tree->code) { 1847 case XBC_LOADCON: 1848 if (next && next->type == CodeTreeBytecode) { 1849 switch (next->code) { 1850 case XBC_LET: 1851 next->code = XBC_LOADCON_LET; 1852 next->data.let_con.name = 1853 next->data.atom; 1854 next->data.let_con.object = 1855 tree->data.object; 1856 goto remove_label; 1857 case XBC_PUSH: 1858 next->code = XBC_LOADCON_PUSH; 1859 next->data.object = tree->data.object; 1860 goto remove_label; 1861 case XBC_CAR: 1862 if (tree->data.object != NIL) { 1863 if (!CONSP(tree->data.object)) 1864 LispDestroy("CAR: %s is not a list", 1865 STROBJ( 1866 tree->data.object)); 1867 next->code = XBC_LOADCON; 1868 next->data.object = 1869 CAR(tree->data.object); 1870 } 1871 goto remove_label; 1872 case XBC_CDR: 1873 if (tree->data.object != NIL) { 1874 if (!CONSP(tree->data.object)) 1875 LispDestroy("CAR: %s is not a list", 1876 STROBJ( 1877 tree->data.object)); 1878 next->code = XBC_LOADCON; 1879 next->data.object = 1880 CDR(tree->data.object); 1881 } 1882 goto remove_label; 1883 case XBC_SET: 1884 next->code = XBC_LOADCON_SET; 1885 next->data.load_con_set.offset = 1886 next->data.signed_short; 1887 next->data.load_con_set.object = 1888 tree->data.object; 1889 goto remove_label; 1890 default: 1891 break; 1892 } 1893 } 1894 break; 1895 case XBC_LOADSYM: 1896 if (next && next->type == CodeTreeBytecode) { 1897 switch (next->code) { 1898 case XBC_LET: 1899 next->code = XBC_LOADSYM_LET; 1900 next->data.let_sym.name = 1901 next->data.atom; 1902 next->data.let_sym.symbol = 1903 tree->data.atom; 1904 goto remove_label; 1905 case XBC_PUSH: 1906 next->code = XBC_LOADSYM_PUSH; 1907 next->data.atom = tree->data.atom; 1908 goto remove_label; 1909 default: 1910 break; 1911 } 1912 } 1913 break; 1914 case XBC_LOAD: 1915 if (next && next->type == CodeTreeBytecode) { 1916 switch (next->code) { 1917 case XBC_SET: 1918 next->code = XBC_LOAD_SET; 1919 next->data.load_set.set = 1920 next->data.signed_short; 1921 next->data.load_set.load = 1922 tree->data.signed_short; 1923 goto remove_label; 1924 /* TODO add XBC_LOAD_SETSYM */ 1925 case XBC_CAR: 1926 next->code = XBC_LOAD_CAR; 1927 next->data.signed_short = 1928 tree->data.signed_short; 1929 goto remove_label; 1930 case XBC_CDR: 1931 next->code = XBC_LOAD_CDR; 1932 next->data.signed_short = 1933 tree->data.signed_short; 1934 goto remove_label; 1935 case XBC_PUSH: 1936 tree->code = XBC_LOAD_PUSH; 1937 goto remove_next_label; 1938 case XBC_LET: 1939 next->code = XBC_LOAD_LET; 1940 next->data.let.name = next->data.atom; 1941 next->data.let.offset = 1942 tree->data.signed_short; 1943 goto remove_label; 1944 default: 1945 break; 1946 } 1947 } 1948 break; 1949 case XBC_LOAD_CAR: 1950 if (next && next->type == CodeTreeBytecode && 1951 next->code == XBC_SET) { 1952 if (next->data.signed_short == 1953 tree->data.signed_short) 1954 next->code = XBC_LOAD_CAR_STORE; 1955 else { 1956 next->code = XBC_LOAD_CAR_SET; 1957 next->data.load_set.set = 1958 next->data.signed_short; 1959 next->data.load_set.load = 1960 tree->data.signed_short; 1961 } 1962 goto remove_label; 1963 } 1964 break; 1965 case XBC_LOAD_CDR: 1966 if (next && next->type == CodeTreeBytecode && 1967 next->code == XBC_SET) { 1968 if (next->data.signed_short == 1969 tree->data.signed_short) 1970 next->code = XBC_LOAD_CDR_STORE; 1971 else { 1972 next->code = XBC_LOAD_CDR_SET; 1973 next->data.load_set.set = 1974 next->data.signed_short; 1975 next->data.load_set.load = 1976 tree->data.signed_short; 1977 } 1978 goto remove_label; 1979 } 1980 break; 1981 case XBC_CALL: 1982 if (next && next->type == CodeTreeBytecode) { 1983 switch (next->code) { 1984 case XBC_SET: 1985 next->code = XBC_CALL_SET; 1986 next->data.builtin.offset = 1987 next->data.signed_short; 1988 next->data.builtin.num_arguments = 1989 tree->data.builtin.num_arguments; 1990 next->data.builtin.builtin = 1991 tree->data.builtin.builtin; 1992 goto remove_label; 1993 /* TODO add XBC_CALL_SETSYM */ 1994 default: 1995 break; 1996 } 1997 } 1998 break; 1999 case XBC_CAR: 2000 if (next && next->type == CodeTreeBytecode) { 2001 switch (next->code) { 2002 case XBC_SET: 2003 next->code = XBC_CAR_SET; 2004 goto remove_label; 2005 /* TODO add XBC_CAR_SETSYM */ 2006 case XBC_PUSH: 2007 next->code = XBC_CAR_PUSH; 2008 goto remove_label; 2009 default: 2010 break; 2011 } 2012 } 2013 break; 2014 case XBC_CDR: 2015 if (next && next->type == CodeTreeBytecode) { 2016 switch (next->code) { 2017 case XBC_SET: 2018 next->code = XBC_CDR_SET; 2019 goto remove_label; 2020 /* TODO add XBC_CDR_SETSYM */ 2021 case XBC_PUSH: 2022 next->code = XBC_CDR_PUSH; 2023 goto remove_label; 2024 default: 2025 break; 2026 } 2027 } 2028 break; 2029 case XBC_NIL: 2030 if (next && next->type == CodeTreeBytecode) { 2031 switch (next->code) { 2032 case XBC_SET: 2033 next->code = XBC_SET_NIL; 2034 goto remove_label; 2035 /* TODO add XBC_SETSYM_NIL */ 2036 default: 2037 break; 2038 } 2039 } 2040 break; 2041 case XBC_PUSH_NIL: 2042 if (next && next->type == CodeTreeBytecode && 2043 next->code == XBC_PUSH_NIL) { 2044 next->code = XBC_PUSH_NIL_N; 2045 next->data.signed_char = 2; 2046 goto remove_label; 2047 } 2048 break; 2049 case XBC_PUSH_NIL_N: 2050 if (next && next->type == CodeTreeBytecode && 2051 next->code == XBC_PUSH_NIL) { 2052 next->code = XBC_PUSH_NIL_N; 2053 next->data.signed_char = tree->data.signed_char + 1; 2054 goto remove_label; 2055 } 2056 break; 2057 case XBC_PUSH_UNSPEC: 2058 if (next && next->type == CodeTreeBytecode && 2059 next->code == XBC_PUSH_UNSPEC) { 2060 next->code = XBC_PUSH_UNSPEC_N; 2061 next->data.signed_char = 2; 2062 goto remove_label; 2063 } 2064 break; 2065 case XBC_PUSH_UNSPEC_N: 2066 if (next && next->type == CodeTreeBytecode && 2067 next->code == XBC_PUSH_UNSPEC) { 2068 next->code = XBC_PUSH_UNSPEC_N; 2069 next->data.signed_char = tree->data.signed_char + 1; 2070 goto remove_label; 2071 } 2072 break; 2073 default: 2074 break; 2075 } 2076 break; 2077 case CodeTreeBlock: 2078 LinkDoOptimize_0(com, tree->data.block); 2079 break; 2080 default: 2081 break; 2082 } 2083 goto update_label; 2084remove_label: 2085 if (tree == block->tree) { 2086 block->tree = prev = next; 2087 if (tree == block->tail) 2088 block->tail = tree; 2089 } 2090 else 2091 prev->next = next; 2092 CompileFreeTree(tree); 2093 tree = next; 2094 continue; 2095remove_next_label: 2096 tree->next = next->next; 2097 CompileFreeTree(next); 2098 continue; 2099update_label: 2100 prev = tree; 2101 tree = tree->next; 2102 } 2103} 2104 2105static void 2106LinkOptimize_0(LispCom *com) 2107{ 2108 /* Recursive */ 2109 LinkDoOptimize_0(com, com->block); 2110} 2111 2112static void 2113LinkResolveLabels(LispCom *com, CodeBlock *block) 2114{ 2115 int i; 2116 CodeTree *tree = block->tree; 2117 2118 for (; tree; tree = tree->next) { 2119 if (tree->type == CodeTreeBlock) 2120 LinkResolveLabels(com, tree->data.block); 2121 else if (tree->type == CodeTreeLabel) { 2122 for (i = 0; i < block->tagbody.length; i++) 2123 if (tree->data.object == block->tagbody.labels[i]) { 2124 block->tagbody.codes[i] = tree; 2125 break; 2126 } 2127 } 2128 } 2129} 2130 2131static void 2132LinkResolveJumps(LispCom *com, CodeBlock *block) 2133{ 2134 int i; 2135 CodeBlock *body = block; 2136 CodeTree *ptr, *tree = block->tree; 2137 2138 /* Check if there is a tagbody. Error checking already done */ 2139 while (body && body->type != LispBlockBody) 2140 body = body->prev; 2141 2142 for (; tree; tree = tree->next) { 2143 switch (tree->type) { 2144 case CodeTreeBytecode: 2145 case CodeTreeLabel: 2146 break; 2147 2148 case CodeTreeBlock: 2149 LinkResolveJumps(com, tree->data.block); 2150 break; 2151 2152 case CodeTreeGo: 2153 for (i = 0; i < body->tagbody.length; i++) 2154 if (tree->data.object == body->tagbody.labels[i]) 2155 break; 2156 if (i == body->tagbody.length) 2157 LispDestroy("COMPILE: no visible tag %s to GO", 2158 STROBJ(tree->data.object)); 2159 /* Now the jump code is known */ 2160 tree->data.tree = body->tagbody.codes[i]; 2161 break; 2162 2163 case CodeTreeCond: 2164 if (tree->code == XBC_JUMPNIL) 2165 /* If test is NIL, go to next test */ 2166 tree->data.tree = tree->group->next; 2167 else if (tree->code == XBC_JUMPT) { 2168 /* After executing code, test was T */ 2169 for (ptr = tree->group; 2170 ptr->code != XBC_NOOP; 2171 ptr = ptr->group) 2172 ; 2173 tree->data.tree = ptr; 2174 } 2175 break; 2176 2177 case CodeTreeJumpIf: 2178 if (tree->code != XBC_NOOP) { 2179 for (ptr = tree->group; 2180 ptr->code != XBC_NOOP; 2181 ptr = ptr->group) { 2182 if (ptr->type == CodeTreeJump) { 2183 /* ELSE code of IF */ 2184 ptr = ptr->next; 2185 /* Skip inconditional jump node */ 2186 break; 2187 } 2188 } 2189 tree->data.tree = ptr; 2190 } 2191 break; 2192 2193 case CodeTreeJump: 2194 if (tree->code != XBC_NOOP) 2195 tree->data.tree = tree->group; 2196 break; 2197 2198 case CodeTreeReturn: 2199 /* One bytecode is guaranteed to exist in the code tree */ 2200 if (tree->data.block->parent == NULL) 2201 /* Returning from the function or toplevel form */ 2202 tree->data.tree = tree->data.block->tail; 2203 else { 2204 for (;;) { 2205 ptr = tree->data.block->parent->next; 2206 if (ptr) { 2207 tree->data.tree = ptr; 2208 break; 2209 } 2210 else 2211 /* Move one BLOCK up */ 2212 tree->data.block = tree->data.block->prev; 2213 } 2214 } 2215 break; 2216 } 2217 } 2218} 2219 2220static long 2221LinkPad(long offset, long adjust, int preffix, int datalen) 2222{ 2223 /* If byte or aligned data */ 2224 if (datalen <= preffix || ((offset + adjust + preffix) % datalen) == 0) 2225 return (adjust); 2226 2227 return (adjust + (datalen - ((offset + adjust + preffix) % datalen))); 2228} 2229 2230static long 2231LinkFixupOffsets(LispCom *com, CodeTree *tree, long adjust) 2232{ 2233 for (; tree; tree = tree->next) { 2234 switch (tree->type) { 2235 case CodeTreeBytecode: 2236 switch (tree->code) { 2237 /* byte + short */ 2238 case XBC_JUMP: 2239 case XBC_JUMPT: 2240 case XBC_JUMPNIL: 2241 adjust = LinkPad(tree->offset, adjust, 1, 2242 sizeof(short)); 2243 /*FALLTROUGH*/ 2244 default: 2245 tree->offset += adjust; 2246 break; 2247 } 2248 break; 2249 case CodeTreeLabel: 2250 /* Labels are not loaded, just adjust offset */ 2251 tree->offset += adjust; 2252 break; 2253 case CodeTreeJump: 2254 case CodeTreeCond: 2255 case CodeTreeJumpIf: 2256 /* If an opcode will be generated. */ 2257 if (tree->code != XBC_NOOP) 2258 adjust = LinkPad(tree->offset, adjust, 1, sizeof(short)); 2259 tree->offset += adjust; 2260 break; 2261 case CodeTreeGo: 2262 case CodeTreeReturn: 2263 adjust = LinkPad(tree->offset, adjust, 1, sizeof(short)); 2264 tree->offset += adjust; 2265 break; 2266 case CodeTreeBlock: 2267 adjust = LinkFixupOffsets(com, tree->data.block->tree, adjust); 2268 break; 2269 } 2270 } 2271 2272 return (adjust); 2273} 2274 2275static void 2276LinkSkipPadding(LispCom *com, CodeTree *tree) 2277{ 2278 int found; 2279 CodeTree *ptr; 2280 2281 /* Recurse to adjust forward jumps or jumps to the start of the block */ 2282 for (ptr = tree; ptr; ptr = ptr->next) { 2283 if (ptr->type == CodeTreeBlock) { 2284 LinkSkipPadding(com, ptr->data.block->tree); 2285 ptr->offset = ptr->data.block->tree->offset; 2286 } 2287 } 2288 2289 /* Adjust the nodes offsets */ 2290 for (; tree; tree = tree->next) { 2291 switch (tree->type) { 2292 case CodeTreeBytecode: 2293 case CodeTreeBlock: 2294 case CodeTreeGo: 2295 case CodeTreeReturn: 2296 break; 2297 case CodeTreeJump: 2298 case CodeTreeCond: 2299 case CodeTreeJumpIf: 2300 if (tree->code != XBC_NOOP) 2301 /* If code will be generated */ 2302 break; 2303 case CodeTreeLabel: 2304 /* This should be done in reversed order, but to avoid 2305 * the requirement of a prev pointer, do the job in a 2306 * harder way here. */ 2307 for (found = 0, ptr = tree->next; ptr; ptr = ptr->next) { 2308 switch (ptr->type) { 2309 case CodeTreeBytecode: 2310 case CodeTreeBlock: 2311 case CodeTreeGo: 2312 case CodeTreeReturn: 2313 found = 1; 2314 break; 2315 case CodeTreeJump: 2316 case CodeTreeCond: 2317 case CodeTreeJumpIf: 2318 if (ptr->code != XBC_NOOP) 2319 found = 1; 2320 break; 2321 case CodeTreeLabel: 2322 break; 2323 } 2324 if (found) 2325 break; 2326 } 2327 if (found) 2328 tree->offset = ptr->offset; 2329 break; 2330 } 2331 } 2332} 2333 2334static void 2335LinkCalculateJump(LispCom *com, CodeTree *tree, LispByteOpcode code) 2336{ 2337 long jumpto, offset, distance; 2338 2339 tree->type = CodeTreeBytecode; 2340 /* After the opcode */ 2341 offset = tree->offset + 1; 2342 jumpto = tree->data.tree->offset; 2343 /* Effective distance */ 2344 distance = jumpto - offset; 2345 tree->code = code; 2346 if (distance < -32768 || distance > 32767) { 2347 COMPILE_FAILURE("jump too long"); 2348 } 2349 tree->data.signed_int = distance; 2350} 2351 2352static void 2353LinkFixupJumps(LispCom *com, CodeTree *tree) 2354{ 2355 for (; tree; tree = tree->next) { 2356 switch (tree->type) { 2357 case CodeTreeBytecode: 2358 case CodeTreeLabel: 2359 break; 2360 case CodeTreeCond: 2361 if (tree->code == XBC_JUMPNIL) 2362 /* Go to next test if NIL */ 2363 LinkCalculateJump(com, tree, XBC_JUMPNIL); 2364 else if (tree->code == XBC_JUMPT) 2365 /* After executing T code */ 2366 LinkCalculateJump(com, tree, XBC_JUMP); 2367 break; 2368 case CodeTreeJumpIf: 2369 if (tree->code != XBC_NOOP) 2370 LinkCalculateJump(com, tree, tree->code); 2371 break; 2372 case CodeTreeGo: 2373 /* Inconditional jump */ 2374 LinkCalculateJump(com, tree, XBC_JUMP); 2375 break; 2376 case CodeTreeReturn: 2377 /* Inconditional jump */ 2378 if (tree->data.tree != tree) 2379 /* If need to skip something */ 2380 LinkCalculateJump(com, tree, XBC_JUMP); 2381 break; 2382 case CodeTreeBlock: 2383 LinkFixupJumps(com, tree->data.block->tree); 2384 break; 2385 case CodeTreeJump: 2386 if (tree->code != XBC_NOOP) 2387 LinkCalculateJump(com, tree, tree->code); 2388 } 2389 } 2390} 2391 2392static void 2393LinkBuildTableSymbol(LispCom *com, LispAtom *symbol) 2394{ 2395 if (BuildTablePointer(symbol, (void***)&com->table.symbols, 2396 &com->table.num_symbols) > 0xff) { 2397 COMPILE_FAILURE("more than 256 symbols"); 2398 } 2399} 2400 2401static void 2402LinkBuildTableConstant(LispCom *com, LispObj *constant) 2403{ 2404 if (BuildTablePointer(constant, (void***)&com->table.constants, 2405 &com->table.num_constants) > 0xff) { 2406 COMPILE_FAILURE("more than 256 constants"); 2407 } 2408} 2409 2410static void 2411LinkBuildTableBuiltin(LispCom *com, LispBuiltin *builtin) 2412{ 2413 if (BuildTablePointer(builtin, (void***)&com->table.builtins, 2414 &com->table.num_builtins) > 0xff) { 2415 COMPILE_FAILURE("more than 256 functions"); 2416 } 2417} 2418 2419static void 2420LinkBuildTableBytecode(LispCom *com, LispObj *bytecode) 2421{ 2422 if (BuildTablePointer(bytecode, (void***)&com->table.bytecodes, 2423 &com->table.num_bytecodes) > 0xff) { 2424 COMPILE_FAILURE("more than 256 bytecode functions"); 2425 } 2426} 2427 2428static void 2429LinkBuildTables(LispCom *com, CodeBlock *block) 2430{ 2431 CodeTree *tree; 2432 2433 for (tree = block->tree; tree; tree = tree->next) { 2434 switch (tree->type) { 2435 case CodeTreeBytecode: 2436 switch (tree->code) { 2437 case XBC_LET: 2438 case XBC_LETX: 2439 case XBC_LET_NIL: 2440 case XBC_LETX_NIL: 2441 case XBC_SETSYM: 2442 case XBC_LOADSYM: 2443 case XBC_LOADSYM_PUSH: 2444 LinkBuildTableSymbol(com, tree->data.atom); 2445 break; 2446 case XBC_STRUCTP: 2447 case XBC_LOADCON: 2448 case XBC_LOADCON_PUSH: 2449 LinkBuildTableConstant(com, tree->data.object); 2450 break; 2451 case XBC_LOADCON_SET: 2452 LinkBuildTableConstant(com, tree->data.load_con_set.object); 2453 break; 2454 case XBC_CALL: 2455 case XBC_CALL_SET: 2456 LinkBuildTableBuiltin(com, tree->data.builtin.builtin); 2457 break; 2458 case XBC_BYTECALL: 2459 LinkBuildTableBytecode(com, tree->data.bytecall.code); 2460 break; 2461 case XBC_LOAD_LET: 2462 case XBC_LOAD_LETX: 2463 LinkBuildTableSymbol(com, tree->data.let.name); 2464 break; 2465 case XBC_STRUCT: 2466 LinkBuildTableConstant(com, tree->data.struc.definition); 2467 break; 2468 case XBC_LOADSYM_LET: 2469 case XBC_LOADSYM_LETX: 2470 LinkBuildTableSymbol(com, tree->data.let_sym.symbol); 2471 LinkBuildTableSymbol(com, tree->data.let_sym.name); 2472 break; 2473 case XBC_LOADCON_LET: 2474 case XBC_LOADCON_LETX: 2475 LinkBuildTableConstant(com, tree->data.let_con.object); 2476 LinkBuildTableSymbol(com, tree->data.let_con.name); 2477 break; 2478 case XBC_CCONS: 2479 case XBC_FUNCALL: 2480 LinkBuildTableConstant(com, tree->data.cons.car); 2481 LinkBuildTableConstant(com, tree->data.cons.cdr); 2482 break; 2483 default: 2484 break; 2485 } 2486 break; 2487 case CodeTreeBlock: 2488 LinkBuildTables(com, tree->data.block); 2489 break; 2490 default: 2491 break; 2492 } 2493 } 2494} 2495 2496static long 2497LinkEmmitBytecode(LispCom *com, CodeTree *tree, 2498 unsigned char *bytecode, long offset) 2499{ 2500 short i; 2501 2502 for (; tree; tree = tree->next) { 2503 /* Fill padding */ 2504 while (offset < tree->offset) 2505 bytecode[offset++] = XBC_NOOP; 2506 2507 switch (tree->type) { 2508 case CodeTreeBytecode: 2509 bytecode[offset++] = tree->code; 2510 switch (tree->code) { 2511 /* Noop should not enter the CodeTree */ 2512 case XBC_NOOP: 2513 INTERNAL_ERROR(__LINE__); 2514 break; 2515 2516 /* byte */ 2517 case XBC_BCONS: 2518 case XBC_BCONS1: 2519 case XBC_BCONS2: 2520 case XBC_BCONS3: 2521 case XBC_BCONS4: 2522 case XBC_BCONS5: 2523 case XBC_BCONS6: 2524 case XBC_BCONS7: 2525 case XBC_INV: 2526 case XBC_NIL: 2527 case XBC_T: 2528 case XBC_PUSH_NIL: 2529 case XBC_PUSH_UNSPEC: 2530 case XBC_PUSH_T: 2531 case XBC_CAR_PUSH: 2532 case XBC_CDR_PUSH: 2533 case XBC_PUSH: 2534 case XBC_LSTAR: 2535 case XBC_LCONS: 2536 case XBC_LFINI: 2537 case XBC_RETURN: 2538 case XBC_CSTAR: 2539 case XBC_CFINI: 2540 case XBC_CAR: 2541 case XBC_CDR: 2542 case XBC_RPLACA: 2543 case XBC_RPLACD: 2544 case XBC_EQ: 2545 case XBC_EQL: 2546 case XBC_EQUAL: 2547 case XBC_EQUALP: 2548 case XBC_LENGTH: 2549 case XBC_LAST: 2550 case XBC_NTHCDR: 2551 break; 2552 2553 /* byte + byte */ 2554 case XBC_LETREC: 2555 case XBC_PRED: 2556 case XBC_PUSH_NIL_N: 2557 case XBC_PUSH_UNSPEC_N: 2558 bytecode[offset++] = tree->data.signed_char; 2559 break; 2560 2561 /* byte + byte */ 2562 case XBC_CAR_SET: 2563 case XBC_CDR_SET: 2564 case XBC_SET: 2565 case XBC_SET_NIL: 2566 case XBC_LETBIND: 2567 case XBC_UNLET: 2568 case XBC_LOAD_PUSH: 2569 case XBC_LOAD: 2570 case XBC_LOAD_CAR: 2571 case XBC_LOAD_CDR: 2572 case XBC_LOAD_CAR_STORE: 2573 case XBC_LOAD_CDR_STORE: 2574 bytecode[offset++] = tree->data.signed_short; 2575 break; 2576 2577 /* byte + byte + byte */ 2578 case XBC_LOAD_SET: 2579 case XBC_LOAD_CAR_SET: 2580 case XBC_LOAD_CDR_SET: 2581 bytecode[offset++] = tree->data.load_set.load; 2582 bytecode[offset++] = tree->data.load_set.set; 2583 break; 2584 2585 /* byte + short */ 2586 case XBC_JUMP: 2587 case XBC_JUMPT: 2588 case XBC_JUMPNIL: 2589 *(short*)(bytecode + offset) = tree->data.signed_int; 2590 offset += sizeof(short); 2591 break; 2592 2593 /* byte + byte */ 2594 case XBC_LET: 2595 case XBC_LETX: 2596 case XBC_LET_NIL: 2597 case XBC_LETX_NIL: 2598 case XBC_SETSYM: 2599 case XBC_LOADSYM: 2600 case XBC_LOADSYM_PUSH: 2601 i = FindIndex(tree->data.atom, 2602 (void**)com->table.symbols, 2603 com->table.num_symbols); 2604 bytecode[offset++] = i; 2605 break; 2606 2607 /* byte + byte */ 2608 case XBC_STRUCTP: 2609 case XBC_LOADCON: 2610 case XBC_LOADCON_PUSH: 2611 i = FindIndex(tree->data.object, 2612 (void**)com->table.constants, 2613 com->table.num_constants); 2614 bytecode[offset++] = i; 2615 break; 2616 2617 /* byte + byte + byte */ 2618 case XBC_LOADCON_SET: 2619 i = FindIndex(tree->data.load_con_set.object, 2620 (void**)com->table.constants, 2621 com->table.num_constants); 2622 bytecode[offset++] = i; 2623 bytecode[offset++] = tree->data.load_con_set.offset; 2624 break; 2625 2626 /* byte + byte + byte */ 2627 case XBC_CALL: 2628 bytecode[offset++] = tree->data.builtin.num_arguments; 2629 i = FindIndex(tree->data.builtin.builtin, 2630 (void**)com->table.builtins, 2631 com->table.num_builtins); 2632 bytecode[offset++] = i; 2633 break; 2634 2635 /* byte + byte + byte */ 2636 case XBC_BYTECALL: 2637 bytecode[offset++] = tree->data.bytecall.num_arguments; 2638 i = FindIndex(tree->data.bytecall.code, 2639 (void**)com->table.bytecodes, 2640 com->table.num_bytecodes); 2641 bytecode[offset++] = i; 2642 break; 2643 2644 /* byte + byte + byte + byte */ 2645 case XBC_CALL_SET: 2646 bytecode[offset++] = tree->data.builtin.num_arguments; 2647 i = FindIndex(tree->data.builtin.builtin, 2648 (void**)com->table.builtins, 2649 com->table.num_builtins); 2650 bytecode[offset++] = i; 2651 bytecode[offset++] = tree->data.builtin.offset; 2652 break; 2653 2654 /* byte + byte + byte */ 2655 case XBC_LOAD_LET: 2656 case XBC_LOAD_LETX: 2657 bytecode[offset++] = tree->data.let.offset; 2658 i = FindIndex(tree->data.let.name, 2659 (void**)com->table.symbols, 2660 com->table.num_symbols); 2661 bytecode[offset++] = i; 2662 break; 2663 2664 /* byte + byte + byte */ 2665 case XBC_STRUCT: 2666 bytecode[offset++] = tree->data.struc.offset; 2667 i = FindIndex(tree->data.struc.definition, 2668 (void**)com->table.constants, 2669 com->table.num_constants); 2670 bytecode[offset++] = i; 2671 break; 2672 2673 /* byte + byte + byte */ 2674 case XBC_LOADSYM_LET: 2675 case XBC_LOADSYM_LETX: 2676 i = FindIndex(tree->data.let_sym.symbol, 2677 (void**)com->table.symbols, 2678 com->table.num_symbols); 2679 bytecode[offset++] = i; 2680 i = FindIndex(tree->data.let_sym.name, 2681 (void**)com->table.symbols, 2682 com->table.num_symbols); 2683 bytecode[offset++] = i; 2684 break; 2685 2686 /* byte + byte + byte */ 2687 case XBC_LOADCON_LET: 2688 case XBC_LOADCON_LETX: 2689 i = FindIndex(tree->data.let_con.object, 2690 (void**)com->table.constants, 2691 com->table.num_constants); 2692 bytecode[offset++] = i; 2693 i = FindIndex(tree->data.let_con.name, 2694 (void**)com->table.symbols, 2695 com->table.num_symbols); 2696 bytecode[offset++] = i; 2697 break; 2698 2699 /* byte + byte + byte */ 2700 case XBC_CCONS: 2701 case XBC_FUNCALL: 2702 i = FindIndex(tree->data.cons.car, 2703 (void**)com->table.constants, 2704 com->table.num_constants); 2705 bytecode[offset++] = i; 2706 i = FindIndex(tree->data.cons.cdr, 2707 (void**)com->table.constants, 2708 com->table.num_constants); 2709 bytecode[offset++] = i; 2710 break; 2711 } 2712 break; 2713 case CodeTreeLabel: 2714 /* Labels are not loaded */ 2715 break; 2716 case CodeTreeCond: 2717 case CodeTreeJump: 2718 case CodeTreeJumpIf: 2719 if (tree->code != XBC_NOOP) 2720 INTERNAL_ERROR(__LINE__); 2721 break; 2722 case CodeTreeGo: 2723 INTERNAL_ERROR(__LINE__); 2724 break; 2725 case CodeTreeReturn: 2726 if (tree->data.tree != tree) 2727 INTERNAL_ERROR(__LINE__); 2728 break; 2729 case CodeTreeBlock: 2730 offset = LinkEmmitBytecode(com, tree->data.block->tree, 2731 bytecode, offset); 2732 break; 2733 } 2734 } 2735 2736 return (offset); 2737} 2738 2739static void 2740LinkBytecode(LispCom *com) 2741{ 2742 long offset, count; 2743 unsigned char **codes; 2744 LispObj **names; 2745 2746 /* Close bytecode */ 2747 com_Bytecode(com, XBC_RETURN); 2748 2749 /* The only usage of this information for now, and still may generate 2750 * false positives because arguments to unamed functions are not being 2751 * parsed as well as arguments to yet undefined function/maros. 2752 * XXX should also add declaim/declare to let the code specify that 2753 * the argument is unused */ 2754 LinkWarnUnused(com, com->block); 2755 2756 /* First level optimization */ 2757 LinkOptimize_0(com); 2758 2759 /* Resolve tagbody labels */ 2760 LinkResolveLabels(com, com->block); 2761 2762 /* Resolve any pending jumps */ 2763 LinkResolveJumps(com, com->block); 2764 2765 /* Calculate unpadded offsets */ 2766 LinkBuildOffsets(com, com->block->tree, 0); 2767 2768 /* Do padding for aligned memory reads */ 2769 LinkFixupOffsets(com, com->block->tree, 0); 2770 2771 /* Jumps normally are to a node that does not generate code, 2772 * and due to padding, the jump may go to a address with a 2773 * XBC_NOOP, so adjust the jump to the next useful opcode. */ 2774 LinkSkipPadding(com, com->block->tree); 2775 2776 /* Now addresses are known */ 2777 LinkFixupJumps(com, com->block->tree); 2778 2779 /* Build symbol, constant and builtin tables */ 2780 LinkBuildTables(com, com->block); 2781 2782 /* Stack info */ 2783 com->length = sizeof(short) * 3; 2784 /* Tables info */ 2785 com->length += sizeof(short) * 4; 2786 com->length += com->table.num_constants * sizeof(LispObj*); 2787 com->length += com->table.num_symbols * sizeof(LispAtom*); 2788 com->length += com->table.num_builtins * sizeof(LispBuiltin*); 2789 com->length += com->table.num_bytecodes * sizeof(unsigned char*); 2790 com->length += com->table.num_bytecodes * sizeof(LispObj*); 2791 2792 /* Allocate space for the bytecode stream */ 2793 com->length += com->block->tail->offset + 1; 2794 com->bytecode = LispMalloc(com->length); 2795 2796 /* Add header */ 2797 offset = 0; 2798 *(short*)(com->bytecode + offset) = com->stack.stack; 2799 offset += sizeof(short); 2800 *(short*)(com->bytecode + offset) = com->stack.bstack; 2801 offset += sizeof(short); 2802 *(short*)(com->bytecode + offset) = com->stack.pstack; 2803 offset += sizeof(short); 2804 2805 *(short*)(com->bytecode + offset) = com->table.num_constants; 2806 offset += sizeof(short); 2807 *(short*)(com->bytecode + offset) = com->table.num_symbols; 2808 offset += sizeof(short); 2809 *(short*)(com->bytecode + offset) = com->table.num_builtins; 2810 offset += sizeof(short); 2811 *(short*)(com->bytecode + offset) = com->table.num_bytecodes; 2812 offset += sizeof(short); 2813 2814 count = sizeof(LispObj*) * com->table.num_constants; 2815 memcpy(com->bytecode + offset, com->table.constants, count); 2816 offset += count; 2817 count = sizeof(LispAtom*) * com->table.num_symbols; 2818 memcpy(com->bytecode + offset, com->table.symbols, count); 2819 offset += count; 2820 count = sizeof(LispBuiltin*) * com->table.num_builtins; 2821 memcpy(com->bytecode + offset, com->table.builtins, count); 2822 offset += count; 2823 2824 /* Store bytecode information */ 2825 for (count = 0, codes = (unsigned char**)(com->bytecode + offset); 2826 count < com->table.num_bytecodes; count++, codes++) 2827 *codes = com->table.bytecodes[count]->data.bytecode.bytecode->code; 2828 offset += com->table.num_bytecodes * sizeof(unsigned char*); 2829 /* Store names, only useful for disassemble but may also be used 2830 * to check if a function was redefined, and the bytecode is referencing 2831 * the older version, the current version can be checked looking at 2832 * <name>->data.atom */ 2833 for (count = 0, names = (LispObj**)(com->bytecode + offset); 2834 count < com->table.num_bytecodes; count++, names++) 2835 *names = com->table.bytecodes[count]->data.bytecode.name; 2836 offset += com->table.num_bytecodes * sizeof(LispObj*); 2837 2838 /* Generate it */ 2839 LinkEmmitBytecode(com, com->block->tree, com->bytecode + offset, 0); 2840} 2841 2842static LispObj * 2843ExecuteBytecode(register unsigned char *stream) 2844{ 2845 register LispObj *reg0; 2846 register LispAtom *atom; 2847 register short offset; 2848 LispObj *reg1; 2849 LispBuiltin *builtin; 2850 LispObj *lambda; 2851 LispObj *arguments; 2852 unsigned char *bytecode; 2853 2854 LispObj **constants; 2855 LispAtom **symbols; 2856 LispBuiltin **builtins; 2857 unsigned char **codes; 2858 short num_constants, num_symbols, num_builtins, num_codes; 2859 2860 int lex, len; 2861 2862 /* To control gc protected slots */ 2863 int phead, pbase; 2864 2865 long fixnum = 0; 2866 2867#if defined(__GNUC__) && !defined(ANSI_SOURCE) 2868#define ALLOW_GOTO_ADDRESS 2869#endif 2870 2871#ifdef ALLOW_GOTO_ADDRESS 2872#define JUMP_ADDRESS(label) &&label 2873 static const void *opcode_labels[] = { 2874 JUMP_ADDRESS(XBC_NOOP), 2875 JUMP_ADDRESS(XBC_INV), 2876 JUMP_ADDRESS(XBC_NIL), 2877 JUMP_ADDRESS(XBC_T), 2878 JUMP_ADDRESS(XBC_PRED), 2879 JUMP_ADDRESS(XBC_CAR), 2880 JUMP_ADDRESS(XBC_CDR), 2881 JUMP_ADDRESS(XBC_CAR_SET), 2882 JUMP_ADDRESS(XBC_CDR_SET), 2883 JUMP_ADDRESS(XBC_RPLACA), 2884 JUMP_ADDRESS(XBC_RPLACD), 2885 JUMP_ADDRESS(XBC_EQ), 2886 JUMP_ADDRESS(XBC_EQL), 2887 JUMP_ADDRESS(XBC_EQUAL), 2888 JUMP_ADDRESS(XBC_EQUALP), 2889 JUMP_ADDRESS(XBC_LENGTH), 2890 JUMP_ADDRESS(XBC_LAST), 2891 JUMP_ADDRESS(XBC_NTHCDR), 2892 JUMP_ADDRESS(XBC_CAR_PUSH), 2893 JUMP_ADDRESS(XBC_CDR_PUSH), 2894 JUMP_ADDRESS(XBC_PUSH), 2895 JUMP_ADDRESS(XBC_PUSH_NIL), 2896 JUMP_ADDRESS(XBC_PUSH_UNSPEC), 2897 JUMP_ADDRESS(XBC_PUSH_T), 2898 JUMP_ADDRESS(XBC_PUSH_NIL_N), 2899 JUMP_ADDRESS(XBC_PUSH_UNSPEC_N), 2900 JUMP_ADDRESS(XBC_LET), 2901 JUMP_ADDRESS(XBC_LETX), 2902 JUMP_ADDRESS(XBC_LET_NIL), 2903 JUMP_ADDRESS(XBC_LETX_NIL), 2904 JUMP_ADDRESS(XBC_LETBIND), 2905 JUMP_ADDRESS(XBC_UNLET), 2906 JUMP_ADDRESS(XBC_LOAD), 2907 JUMP_ADDRESS(XBC_LOAD_LET), 2908 JUMP_ADDRESS(XBC_LOAD_LETX), 2909 JUMP_ADDRESS(XBC_LOAD_PUSH), 2910 JUMP_ADDRESS(XBC_LOADCON), 2911 JUMP_ADDRESS(XBC_LOADCON_LET), 2912 JUMP_ADDRESS(XBC_LOADCON_LETX), 2913 JUMP_ADDRESS(XBC_LOADCON_PUSH), 2914 JUMP_ADDRESS(XBC_LOAD_CAR), 2915 JUMP_ADDRESS(XBC_LOAD_CDR), 2916 JUMP_ADDRESS(XBC_LOAD_CAR_STORE), 2917 JUMP_ADDRESS(XBC_LOAD_CDR_STORE), 2918 JUMP_ADDRESS(XBC_LOADCON_SET), 2919 JUMP_ADDRESS(XBC_LOADSYM), 2920 JUMP_ADDRESS(XBC_LOADSYM_LET), 2921 JUMP_ADDRESS(XBC_LOADSYM_LETX), 2922 JUMP_ADDRESS(XBC_LOADSYM_PUSH), 2923 JUMP_ADDRESS(XBC_LOAD_SET), 2924 JUMP_ADDRESS(XBC_LOAD_CAR_SET), 2925 JUMP_ADDRESS(XBC_LOAD_CDR_SET), 2926 JUMP_ADDRESS(XBC_SET), 2927 JUMP_ADDRESS(XBC_SETSYM), 2928 JUMP_ADDRESS(XBC_SET_NIL), 2929 JUMP_ADDRESS(XBC_CALL), 2930 JUMP_ADDRESS(XBC_CALL_SET), 2931 JUMP_ADDRESS(XBC_BYTECALL), 2932 JUMP_ADDRESS(XBC_FUNCALL), 2933 JUMP_ADDRESS(XBC_LETREC), 2934 JUMP_ADDRESS(XBC_BCONS), 2935 JUMP_ADDRESS(XBC_BCONS1), 2936 JUMP_ADDRESS(XBC_BCONS2), 2937 JUMP_ADDRESS(XBC_BCONS3), 2938 JUMP_ADDRESS(XBC_BCONS4), 2939 JUMP_ADDRESS(XBC_BCONS5), 2940 JUMP_ADDRESS(XBC_BCONS6), 2941 JUMP_ADDRESS(XBC_BCONS7), 2942 JUMP_ADDRESS(XBC_CCONS), 2943 JUMP_ADDRESS(XBC_CSTAR), 2944 JUMP_ADDRESS(XBC_CFINI), 2945 JUMP_ADDRESS(XBC_LSTAR), 2946 JUMP_ADDRESS(XBC_LCONS), 2947 JUMP_ADDRESS(XBC_LFINI), 2948 JUMP_ADDRESS(XBC_JUMP), 2949 JUMP_ADDRESS(XBC_JUMPT), 2950 JUMP_ADDRESS(XBC_JUMPNIL), 2951 JUMP_ADDRESS(XBC_STRUCT), 2952 JUMP_ADDRESS(XBC_STRUCTP), 2953 JUMP_ADDRESS(XBC_RETURN) 2954 }; 2955 static const void *predicate_opcode_labels[] = { 2956 JUMP_ADDRESS(XBP_CONSP), 2957 JUMP_ADDRESS(XBP_LISTP), 2958 JUMP_ADDRESS(XBP_NUMBERP) 2959 }; 2960#endif 2961 2962 reg0 = NIL; 2963 2964 bytecode = stream; 2965 pbase = lisp__data.protect.length; 2966 2967 /* stack */ 2968 offset = *(short*)stream; 2969 stream += sizeof(short); 2970 if (lisp__data.env.length + offset > lisp__data.env.space) { 2971 do 2972 LispMoreEnvironment(); 2973 while (lisp__data.env.length + offset >= lisp__data.env.space); 2974 } 2975 /* builtin stack */ 2976 offset = *(short*)stream; 2977 stream += sizeof(short); 2978 if (lisp__data.stack.length + offset >= lisp__data.stack.space) { 2979 do 2980 LispMoreStack(); 2981 while (lisp__data.stack.length + offset >= lisp__data.stack.space); 2982 } 2983 /* protect stack */ 2984 phead = *(short*)stream; 2985 stream += sizeof(short); 2986 if (lisp__data.protect.length + phead > lisp__data.protect.space) { 2987 do 2988 LispMoreProtects(); 2989 while (lisp__data.protect.length + phead >= lisp__data.protect.space); 2990 } 2991 2992 num_constants = *(short*)stream; 2993 stream += sizeof(short); 2994 num_symbols = *(short*)stream; 2995 stream += sizeof(short); 2996 num_builtins = *(short*)stream; 2997 stream += sizeof(short); 2998 num_codes = *(short*)stream; 2999 stream += sizeof(short); 3000 3001 constants = (LispObj**)stream; 3002 stream += num_constants * sizeof(LispObj*); 3003 symbols = (LispAtom**)stream; 3004 stream += num_symbols * sizeof(LispAtom*); 3005 builtins = (LispBuiltin**)stream; 3006 stream += num_builtins * sizeof(LispBuiltin*); 3007 codes = (unsigned char**)stream; 3008 stream += num_codes * (sizeof(unsigned char*) + sizeof(LispObj*)); 3009 3010 for (; phead > 0; phead--) 3011 lisp__data.protect.objects[lisp__data.protect.length++] = NIL; 3012 phead = pbase; 3013 3014#ifdef ALLOW_GOTO_ADDRESS 3015#define OPCODE_LABEL(label) label 3016#define NEXT_OPCODE() goto *opcode_labels[*stream++] 3017#define GOTO_PREDICATE() goto *predicate_opcode_labels[*stream++] 3018#else 3019#define OPCODE_LABEL(label) case label 3020#define NEXT_OPCODE() goto next_opcode 3021#define GOTO_PREDICATE() goto predicate_label 3022 for (;;) { 3023next_opcode: 3024 switch (*stream++) { 3025#endif /* ALLOW_GOTO_ADDRESS */ 3026 3027OPCODE_LABEL(XBC_NOOP): 3028 NEXT_OPCODE(); 3029 3030OPCODE_LABEL(XBC_PRED): 3031 GOTO_PREDICATE(); 3032 3033OPCODE_LABEL(XBC_INV): 3034 reg0 = reg0 == NIL ? T : NIL; 3035 NEXT_OPCODE(); 3036 3037OPCODE_LABEL(XBC_NIL): 3038 reg0 = NIL; 3039 NEXT_OPCODE(); 3040 3041OPCODE_LABEL(XBC_T): 3042 reg0 = T; 3043 NEXT_OPCODE(); 3044 3045OPCODE_LABEL(XBC_CAR): 3046car: 3047 if (reg0 != NIL) { 3048 if (!CONSP(reg0)) 3049 LispDestroy("CAR: %s is not a list", STROBJ(reg0)); 3050 reg0 = CAR(reg0); 3051 } 3052 NEXT_OPCODE(); 3053 3054OPCODE_LABEL(XBC_CDR): 3055cdr: 3056 if (reg0 != NIL) { 3057 if (!CONSP(reg0)) 3058 LispDestroy("CDR: %s is not a list", STROBJ(reg0)); 3059 reg0 = CDR(reg0); 3060 } 3061 NEXT_OPCODE(); 3062 3063OPCODE_LABEL(XBC_RPLACA): 3064 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3065 if (!CONSP(reg1)) 3066 LispDestroy("RPLACA: %s is not a cons", STROBJ(reg1)); 3067 RPLACA(reg1, reg0); 3068 reg0 = reg1; 3069 NEXT_OPCODE(); 3070 3071OPCODE_LABEL(XBC_RPLACD): 3072 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3073 if (!CONSP(reg1)) 3074 LispDestroy("RPLACD: %s is not a cons", STROBJ(reg1)); 3075 RPLACD(reg1, reg0); 3076 reg0 = reg1; 3077 NEXT_OPCODE(); 3078 3079OPCODE_LABEL(XBC_BCONS): 3080 CAR(cons) = reg0; 3081 lisp__data.stack.values[lisp__data.stack.length++] = cons; 3082 NEXT_OPCODE(); 3083 3084OPCODE_LABEL(XBC_BCONS1): 3085 offset = lisp__data.stack.length - 1; 3086 CAR(cons) = reg0; 3087 CAR(cons1) = lisp__data.stack.values[offset]; 3088 lisp__data.stack.values[offset] = cons1; 3089 NEXT_OPCODE(); 3090 3091OPCODE_LABEL(XBC_BCONS2): 3092 offset = lisp__data.stack.length; 3093 CAR(cons) = reg0; 3094 CAR(cons1) = lisp__data.stack.values[--offset]; 3095 CAR(cons2) = lisp__data.stack.values[--offset]; 3096 lisp__data.stack.values[offset] = cons2; 3097 lisp__data.stack.length = offset + 1; 3098 NEXT_OPCODE(); 3099 3100OPCODE_LABEL(XBC_BCONS3): 3101 offset = lisp__data.stack.length; 3102 CAR(cons) = reg0; 3103 CAR(cons1) = lisp__data.stack.values[--offset]; 3104 CAR(cons2) = lisp__data.stack.values[--offset]; 3105 CAR(cons3) = lisp__data.stack.values[--offset]; 3106 lisp__data.stack.values[offset] = cons3; 3107 lisp__data.stack.length = offset + 1; 3108 NEXT_OPCODE(); 3109 3110OPCODE_LABEL(XBC_BCONS4): 3111 offset = lisp__data.stack.length; 3112 CAR(cons) = reg0; 3113 CAR(cons1) = lisp__data.stack.values[--offset]; 3114 CAR(cons2) = lisp__data.stack.values[--offset]; 3115 CAR(cons3) = lisp__data.stack.values[--offset]; 3116 CAR(cons4) = lisp__data.stack.values[--offset]; 3117 lisp__data.stack.values[offset] = cons4; 3118 lisp__data.stack.length = offset + 1; 3119 NEXT_OPCODE(); 3120 3121OPCODE_LABEL(XBC_BCONS5): 3122 offset = lisp__data.stack.length; 3123 CAR(cons) = reg0; 3124 CAR(cons1) = lisp__data.stack.values[--offset]; 3125 CAR(cons2) = lisp__data.stack.values[--offset]; 3126 CAR(cons3) = lisp__data.stack.values[--offset]; 3127 CAR(cons4) = lisp__data.stack.values[--offset]; 3128 CAR(cons5) = lisp__data.stack.values[--offset]; 3129 lisp__data.stack.values[offset] = cons5; 3130 lisp__data.stack.length = offset + 1; 3131 NEXT_OPCODE(); 3132 3133OPCODE_LABEL(XBC_BCONS6): 3134 offset = lisp__data.stack.length; 3135 CAR(cons) = reg0; 3136 CAR(cons1) = lisp__data.stack.values[--offset]; 3137 CAR(cons2) = lisp__data.stack.values[--offset]; 3138 CAR(cons3) = lisp__data.stack.values[--offset]; 3139 CAR(cons4) = lisp__data.stack.values[--offset]; 3140 CAR(cons5) = lisp__data.stack.values[--offset]; 3141 CAR(cons6) = lisp__data.stack.values[--offset]; 3142 lisp__data.stack.values[offset] = cons6; 3143 lisp__data.stack.length = offset + 1; 3144 NEXT_OPCODE(); 3145 3146OPCODE_LABEL(XBC_BCONS7): 3147 offset = lisp__data.stack.length; 3148 CAR(cons) = reg0; 3149 CAR(cons1) = lisp__data.stack.values[--offset]; 3150 CAR(cons2) = lisp__data.stack.values[--offset]; 3151 CAR(cons3) = lisp__data.stack.values[--offset]; 3152 CAR(cons4) = lisp__data.stack.values[--offset]; 3153 CAR(cons5) = lisp__data.stack.values[--offset]; 3154 CAR(cons6) = lisp__data.stack.values[--offset]; 3155 CAR(cons7) = lisp__data.stack.values[--offset]; 3156 lisp__data.stack.values[offset] = cons7; 3157 lisp__data.stack.length = offset + 1; 3158 NEXT_OPCODE(); 3159 3160OPCODE_LABEL(XBC_EQ): 3161 reg0 = reg0 == lisp__data.stack.values[--lisp__data.stack.length] ? T : NIL; 3162 NEXT_OPCODE(); 3163 3164OPCODE_LABEL(XBC_EQL): 3165 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3166 reg0 = XEQL(reg1, reg0); 3167 NEXT_OPCODE(); 3168 3169OPCODE_LABEL(XBC_EQUAL): 3170 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3171 reg0 = XEQUAL(reg1, reg0); 3172 NEXT_OPCODE(); 3173 3174OPCODE_LABEL(XBC_EQUALP): 3175 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3176 reg0 = XEQUALP(reg1, reg0); 3177 NEXT_OPCODE(); 3178 3179OPCODE_LABEL(XBC_LENGTH): 3180 reg0 = FIXNUM(LispLength(reg0)); 3181 NEXT_OPCODE(); 3182 3183OPCODE_LABEL(XBC_LAST): 3184 { 3185 long length; 3186 3187 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3188 if (CONSP(reg1)) { 3189 if (reg0 != NIL) { 3190 if (!FIXNUMP(reg0) || (fixnum = FIXNUM_VALUE(reg0)) < 0) 3191 LispDestroy("LAST: %s is not a positive fixnum", 3192 STROBJ(reg0)); 3193 } 3194 else 3195 fixnum = 1; 3196 reg0 = reg1; 3197 for (reg0 = reg1, length = 0; 3198 CONSP(reg0); 3199 reg0 = CDR(reg0), length++) 3200 ; 3201 for (length -= fixnum, reg0 = reg1; length > 0; length--) 3202 reg0 = CDR(reg0); 3203 } 3204 else 3205 reg0 = reg1; 3206 } NEXT_OPCODE(); 3207 3208OPCODE_LABEL(XBC_NTHCDR): 3209 reg1 = lisp__data.stack.values[--lisp__data.stack.length]; 3210 if (!FIXNUMP(reg1) || (fixnum = FIXNUM_VALUE(reg1)) < 0) 3211 LispDestroy("NTHCDR: %s is not a positive fixnum", 3212 STROBJ(reg1)); 3213 if (reg0 != NIL) { 3214 if (!CONSP(reg0)) 3215 LispDestroy("NTHCDR: %s is not a list", STROBJ(reg0)); 3216 for (; fixnum > 0; fixnum--) { 3217 if (!CONSP(reg0)) 3218 break; 3219 reg0 = CDR(reg0); 3220 } 3221 } 3222 NEXT_OPCODE(); 3223 3224 /* Push to builtin stack */ 3225OPCODE_LABEL(XBC_CAR_PUSH): 3226 if (reg0 != NIL) { 3227 if (!CONSP(reg0)) 3228 LispDestroy("CAR: %s is not a list", STROBJ(reg0)); 3229 reg0 = CAR(reg0); 3230 } 3231 goto push_builtin; 3232 3233OPCODE_LABEL(XBC_CDR_PUSH): 3234 if (reg0 != NIL) { 3235 if (!CONSP(reg0)) 3236 LispDestroy("CDR: %s is not a list", STROBJ(reg0)); 3237 reg0 = CDR(reg0); 3238 } 3239 /*FALLTROUGH*/ 3240 3241OPCODE_LABEL(XBC_PUSH): 3242push_builtin: 3243 lisp__data.stack.values[lisp__data.stack.length++] = reg0; 3244 NEXT_OPCODE(); 3245 3246OPCODE_LABEL(XBC_PUSH_NIL): 3247 lisp__data.stack.values[lisp__data.stack.length++] = NIL; 3248 NEXT_OPCODE(); 3249 3250OPCODE_LABEL(XBC_PUSH_UNSPEC): 3251 lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC; 3252 NEXT_OPCODE(); 3253 3254OPCODE_LABEL(XBC_PUSH_T): 3255 lisp__data.stack.values[lisp__data.stack.length++] = T; 3256 NEXT_OPCODE(); 3257 3258OPCODE_LABEL(XBC_PUSH_NIL_N): 3259 for (offset = *stream++; offset > 0; offset--) 3260 lisp__data.stack.values[lisp__data.stack.length++] = NIL; 3261 NEXT_OPCODE(); 3262 3263OPCODE_LABEL(XBC_PUSH_UNSPEC_N): 3264 for (offset = *stream++; offset > 0; offset--) 3265 lisp__data.stack.values[lisp__data.stack.length++] = UNSPEC; 3266 NEXT_OPCODE(); 3267 3268OPCODE_LABEL(XBC_LET): 3269let_argument: 3270 /* The global object value is not changed, so it does not 3271 * matter if it is a constant symbol. An error would be 3272 * generated if it was declared as constant at the time of 3273 * bytecode generation. Check can be done looking at the 3274 * atom->constant field. */ 3275 atom = symbols[*stream++]; 3276 atom->offset = lisp__data.env.length; 3277 lisp__data.env.names[lisp__data.env.length] = atom->string; 3278 lisp__data.env.values[lisp__data.env.length++] = reg0; 3279 NEXT_OPCODE(); 3280 3281OPCODE_LABEL(XBC_LETX): 3282letx_argument: 3283 atom = symbols[*stream++]; 3284 atom->offset = lisp__data.env.length; 3285 lisp__data.env.names[lisp__data.env.length] = atom->string; 3286 lisp__data.env.values[lisp__data.env.length++] = reg0; 3287 lisp__data.env.head++; 3288 NEXT_OPCODE(); 3289 3290OPCODE_LABEL(XBC_LET_NIL): 3291 atom = symbols[*stream++]; 3292 atom->offset = lisp__data.env.length; 3293 lisp__data.env.names[lisp__data.env.length] = atom->string; 3294 lisp__data.env.values[lisp__data.env.length++] = NIL; 3295 NEXT_OPCODE(); 3296 3297OPCODE_LABEL(XBC_LETX_NIL): 3298 atom = symbols[*stream++]; 3299 atom->offset = lisp__data.env.length; 3300 lisp__data.env.names[lisp__data.env.length] = atom->string; 3301 lisp__data.env.values[lisp__data.env.length++] = NIL; 3302 lisp__data.env.head++; 3303 NEXT_OPCODE(); 3304 3305 /* Bind locally added variables to a block */ 3306OPCODE_LABEL(XBC_LETBIND): 3307 offset = *stream++; 3308 lisp__data.env.head += offset; 3309 NEXT_OPCODE(); 3310 3311 /* Unbind locally added variables to a block */ 3312OPCODE_LABEL(XBC_UNLET): 3313 offset = *stream++; 3314 lisp__data.env.head -= offset; 3315 lisp__data.env.length -= offset; 3316 NEXT_OPCODE(); 3317 3318 /* Load value from stack */ 3319OPCODE_LABEL(XBC_LOAD): 3320 offset = *stream++; 3321 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3322 NEXT_OPCODE(); 3323 3324OPCODE_LABEL(XBC_LOAD_CAR): 3325 offset = *stream++; 3326 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3327 goto car; 3328 3329OPCODE_LABEL(XBC_LOAD_CDR): 3330 offset = *stream++; 3331 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3332 goto cdr; 3333 3334OPCODE_LABEL(XBC_LOAD_CAR_STORE): 3335 offset = *stream++; 3336 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3337 if (reg0 != NIL) { 3338 if (!CONSP(reg0)) 3339 LispDestroy("CAR: %s is not a list", STROBJ(reg0)); 3340 reg0 = CAR(reg0); 3341 lisp__data.env.values[lisp__data.env.lex + offset] = reg0; 3342 } 3343 NEXT_OPCODE(); 3344 3345OPCODE_LABEL(XBC_LOAD_CDR_STORE): 3346 offset = *stream++; 3347 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3348 if (reg0 != NIL) { 3349 if (!CONSP(reg0)) 3350 LispDestroy("CDR: %s is not a list", STROBJ(reg0)); 3351 reg0 = CDR(reg0); 3352 lisp__data.env.values[lisp__data.env.lex + offset] = reg0; 3353 } 3354 NEXT_OPCODE(); 3355 3356OPCODE_LABEL(XBC_LOAD_LET): 3357 offset = *stream++; 3358 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3359 goto let_argument; 3360 3361OPCODE_LABEL(XBC_LOAD_LETX): 3362 offset = *stream++; 3363 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3364 goto letx_argument; 3365 3366OPCODE_LABEL(XBC_LOAD_PUSH): 3367 offset = *stream++; 3368 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3369 lisp__data.stack.values[lisp__data.stack.length++] = reg0; 3370 NEXT_OPCODE(); 3371 3372 /* Load pointer to constant */ 3373OPCODE_LABEL(XBC_LOADCON): 3374 reg0 = constants[*stream++]; 3375 NEXT_OPCODE(); 3376 3377OPCODE_LABEL(XBC_LOADCON_LET): 3378 reg0 = constants[*stream++]; 3379 goto let_argument; 3380 3381OPCODE_LABEL(XBC_LOADCON_LETX): 3382 reg0 = constants[*stream++]; 3383 goto letx_argument; 3384 3385OPCODE_LABEL(XBC_LOADCON_PUSH): 3386 reg0 = constants[*stream++]; 3387 lisp__data.stack.values[lisp__data.stack.length++] = reg0; 3388 NEXT_OPCODE(); 3389 3390OPCODE_LABEL(XBC_LOADCON_SET): 3391 reg0 = constants[*stream++]; 3392 offset = *stream++; 3393 lisp__data.env.values[lisp__data.env.lex + offset] = reg0; 3394 NEXT_OPCODE(); 3395 3396 /* Change value of local variable */ 3397OPCODE_LABEL(XBC_CAR_SET): 3398car_set: 3399 if (reg0 != NIL) { 3400 if (!CONSP(reg0)) 3401 LispDestroy("CAR: %s is not a list", STROBJ(reg0)); 3402 reg0 = CAR(reg0); 3403 } 3404 goto set_local_variable; 3405 3406OPCODE_LABEL(XBC_CDR_SET): 3407cdr_set: 3408 if (reg0 != NIL) { 3409 if (!CONSP(reg0)) 3410 LispDestroy("CDR: %s is not a list", STROBJ(reg0)); 3411 reg0 = CDR(reg0); 3412 } 3413 goto set_local_variable; 3414 3415OPCODE_LABEL(XBC_LOAD_CAR_SET): 3416 offset = *stream++; 3417 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3418 goto car_set; 3419 3420OPCODE_LABEL(XBC_LOAD_CDR_SET): 3421 offset = *stream++; 3422 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3423 goto cdr_set; 3424 3425OPCODE_LABEL(XBC_LOAD_SET): 3426 offset = *stream++; 3427 reg0 = lisp__data.env.values[lisp__data.env.lex + offset]; 3428 /*FALLTROUGH*/ 3429 3430OPCODE_LABEL(XBC_SET): 3431set_local_variable: 3432 offset = *stream++; 3433 lisp__data.env.values[lisp__data.env.lex + offset] = reg0; 3434 NEXT_OPCODE(); 3435 3436OPCODE_LABEL(XBC_SET_NIL): 3437 offset = *stream++; 3438 lisp__data.env.values[lisp__data.env.lex + offset] = NIL; 3439 NEXT_OPCODE(); 3440 3441 /* Change value of a global/special variable */ 3442OPCODE_LABEL(XBC_SETSYM): 3443 atom = symbols[*stream++]; 3444 if (atom->dyn) { 3445 /* atom->dyn and atom->constant are exclusive, no 3446 * need to check if variable declared as constant. */ 3447 if (atom->offset < lisp__data.env.head && 3448 lisp__data.env.names[atom->offset] == atom->string) 3449 lisp__data.env.values[atom->offset] = reg0; 3450 else { 3451 if (atom->watch) 3452 LispSetAtomObjectProperty(atom, reg0); 3453 else 3454 SETVALUE(atom, reg0); 3455 } 3456 } 3457 else if (atom->a_object) { 3458 if (atom->constant) 3459 LispDestroy("EVAL: %s is a constant", 3460 STROBJ(atom->object)); 3461 else if (atom->watch) 3462 LispSetAtomObjectProperty(atom, reg0); 3463 else 3464 SETVALUE(atom, reg0); 3465 } 3466 else { 3467 /* Create new global variable */ 3468 LispPackage *pack; 3469 3470 LispWarning("the variable %s was not declared", 3471 atom->string); 3472 LispSetAtomObjectProperty(atom, reg0); 3473 pack = atom->package->data.package.package; 3474 if (pack->glb.length >= pack->glb.space) 3475 LispMoreGlobals(pack); 3476 pack->glb.pairs[pack->glb.length++] = atom->object; 3477 } 3478 NEXT_OPCODE(); 3479 3480/* Resolve symbol value at runtime */ 3481#define LOAD_SYMBOL_VALUE() \ 3482 atom = symbols[*stream++]; \ 3483 if (atom->dyn) { \ 3484 if (atom->offset < lisp__data.env.head && \ 3485 lisp__data.env.names[atom->offset] == atom->string) \ 3486 reg0 = lisp__data.env.values[atom->offset]; \ 3487 else { \ 3488 reg0 = atom->property->value; \ 3489 if (reg0 == UNBOUND) \ 3490 LispDestroy("EVAL: the symbol %s is unbound", \ 3491 STROBJ(atom->object)); \ 3492 } \ 3493 } \ 3494 else { \ 3495 if (atom->a_object) \ 3496 reg0 = atom->property->value; \ 3497 else \ 3498 LispDestroy("EVAL: the symbol %s is unbound", \ 3499 STROBJ(atom->object)); \ 3500 } 3501 3502OPCODE_LABEL(XBC_LOADSYM): 3503 LOAD_SYMBOL_VALUE(); 3504 NEXT_OPCODE(); 3505 3506OPCODE_LABEL(XBC_LOADSYM_LET): 3507 LOAD_SYMBOL_VALUE(); 3508 goto let_argument; 3509 3510OPCODE_LABEL(XBC_LOADSYM_LETX): 3511 LOAD_SYMBOL_VALUE(); 3512 goto letx_argument; 3513 3514OPCODE_LABEL(XBC_LOADSYM_PUSH): 3515 LOAD_SYMBOL_VALUE(); 3516 lisp__data.stack.values[lisp__data.stack.length++] = reg0; 3517 NEXT_OPCODE(); 3518 3519 /* Builtin function */ 3520OPCODE_LABEL(XBC_CALL): 3521 offset = *stream++; 3522 lisp__data.stack.base = lisp__data.stack.length - offset; 3523 builtin = builtins[*stream++]; 3524 if (builtin->multiple_values) { 3525 RETURN_COUNT = 0; 3526 reg0 = builtin->function(builtin); 3527 } 3528 else { 3529 reg0 = builtin->function(builtin); 3530 RETURN_COUNT = 0; 3531 } 3532 lisp__data.stack.length -= offset; 3533 NEXT_OPCODE(); 3534 3535OPCODE_LABEL(XBC_CALL_SET): 3536 offset = *stream++; 3537 lisp__data.stack.base = lisp__data.stack.length - offset; 3538 builtin = builtins[*stream++]; 3539 if (builtin->multiple_values) { 3540 RETURN_COUNT = 0; 3541 reg0 = builtin->function(builtin); 3542 } 3543 else { 3544 reg0 = builtin->function(builtin); 3545 RETURN_COUNT = 0; 3546 } 3547 lisp__data.stack.length -= offset; 3548 offset = *stream++; 3549 lisp__data.env.values[lisp__data.env.lex + offset] = reg0; 3550 NEXT_OPCODE(); 3551 3552 /* Bytecode call */ 3553OPCODE_LABEL(XBC_BYTECALL): 3554 lex = lisp__data.env.lex; 3555 offset = *stream++; 3556 lisp__data.env.head = lisp__data.env.length; 3557 len = lisp__data.env.lex = lisp__data.env.length - offset; 3558 reg0 = ExecuteBytecode(codes[*stream++]); 3559 lisp__data.env.length = lisp__data.env.head = len; 3560 lisp__data.env.lex = lex; 3561 NEXT_OPCODE(); 3562 3563 /* Unimplemented function/macro call */ 3564OPCODE_LABEL(XBC_FUNCALL): 3565 lambda = constants[*stream++]; 3566 arguments = constants[*stream++]; 3567 reg0 = LispFuncall(lambda, arguments, 1); 3568 NEXT_OPCODE(); 3569 3570OPCODE_LABEL(XBC_JUMP): 3571 stream += *(signed short*)stream; 3572 NEXT_OPCODE(); 3573 3574OPCODE_LABEL(XBC_JUMPT): 3575 if (reg0 != NIL) 3576 stream += *(signed short*)stream; 3577 else 3578 /* skip jump relative offset */ 3579 stream += sizeof(signed short); 3580 NEXT_OPCODE(); 3581 3582OPCODE_LABEL(XBC_JUMPNIL): 3583 if (reg0 == NIL) 3584 stream += *(signed short*)stream; 3585 else 3586 /* skip jump relative offset */ 3587 stream += sizeof(signed short); 3588 NEXT_OPCODE(); 3589 3590 /* Build CONS of two constant arguments */ 3591OPCODE_LABEL(XBC_CCONS): 3592 reg0 = constants[*stream++]; 3593 reg1 = constants[*stream++]; 3594 reg0 = CONS(reg0, reg1); 3595 NEXT_OPCODE(); 3596 3597 /* Start CONS */ 3598OPCODE_LABEL(XBC_CSTAR): 3599 /* This the CAR of the CONS */ 3600 lisp__data.protect.objects[phead++] = reg0; 3601 NEXT_OPCODE(); 3602 3603 /* Finish CONS */ 3604OPCODE_LABEL(XBC_CFINI): 3605 reg0 = CONS(lisp__data.protect.objects[--phead], reg0); 3606 NEXT_OPCODE(); 3607 3608 /* Start building list */ 3609OPCODE_LABEL(XBC_LSTAR): 3610 reg1 = CONS(reg0, NIL); 3611 /* Start of list stored here */ 3612 lisp__data.protect.objects[phead++] = reg1; 3613 /* Tail of list stored here */ 3614 lisp__data.protect.objects[phead++] = reg1; 3615 NEXT_OPCODE(); 3616 3617 /* Add to list */ 3618OPCODE_LABEL(XBC_LCONS): 3619 reg1 = lisp__data.protect.objects[phead - 2]; 3620 RPLACD(reg1, CONS(reg0, NIL)); 3621 lisp__data.protect.objects[phead - 2] = CDR(reg1); 3622 NEXT_OPCODE(); 3623 3624 /* Finish list */ 3625OPCODE_LABEL(XBC_LFINI): 3626 phead -= 2; 3627 reg0 = lisp__data.protect.objects[phead + 1]; 3628 NEXT_OPCODE(); 3629 3630OPCODE_LABEL(XBC_STRUCT): 3631 offset = *stream++; 3632 reg1 = constants[*stream++]; 3633 if (!STRUCTP(reg0) || reg0->data.struc.def != reg1) { 3634 char *name = ATOMID(CAR(reg1)); 3635 3636 for (reg1 = CDR(reg1); offset; offset--) 3637 reg1 = CDR(reg1); 3638 LispDestroy("%s-%s: %s is not a %s", 3639 name, ATOMID(CAR(reg1)), STROBJ(reg0), name); 3640 } 3641 for (reg0 = reg0->data.struc.fields; offset; offset--) 3642 reg0 = CDR(reg0); 3643 reg0 = CAR(reg0); 3644 NEXT_OPCODE(); 3645 3646OPCODE_LABEL(XBC_STRUCTP): 3647 reg1 = constants[*stream++]; 3648 reg0 = STRUCTP(reg0) && reg0->data.struc.def == reg1 ? T : NIL; 3649 NEXT_OPCODE(); 3650 3651OPCODE_LABEL(XBC_LETREC): 3652 /* XXX could/should optimize, shouldn't need to parse 3653 * the bytecode header again */ 3654 lex = lisp__data.env.lex; 3655 offset = *stream++; 3656 lisp__data.env.head = lisp__data.env.length; 3657 len = lisp__data.env.lex = lisp__data.env.length - offset; 3658 reg0 = ExecuteBytecode(bytecode); 3659 lisp__data.env.length = lisp__data.env.head = len; 3660 lisp__data.env.lex = lex; 3661 NEXT_OPCODE(); 3662 3663OPCODE_LABEL(XBC_RETURN): 3664 lisp__data.protect.length = pbase; 3665 return (reg0); 3666 3667#ifndef ALLOW_GOTO_ADDRESS 3668 } /* end of switch */ 3669 3670predicate_label: 3671 switch (*stream++) { 3672#endif 3673 3674OPCODE_LABEL(XBP_CONSP): 3675 reg0 = CONSP(reg0) ? T : NIL; 3676 NEXT_OPCODE(); 3677 3678OPCODE_LABEL(XBP_LISTP): 3679 reg0 = LISTP(reg0) ? T : NIL; 3680 NEXT_OPCODE(); 3681 3682OPCODE_LABEL(XBP_NUMBERP): 3683 reg0 = NUMBERP(reg0) ? T : NIL; 3684 NEXT_OPCODE(); 3685 3686#ifndef ALLOW_GOTO_ADDRESS 3687 } /* end of switch */ 3688 } 3689#endif 3690 3691 /*NOTREACHED*/ 3692 return (reg0); 3693} 3694