Mercurial > emacs
comparison src/bytecode.c @ 26363:efb608f1cb10
(struct byte_stack): New.
(byte_stack_list, mark_byte_stack, relocate_byte_pcs): New
(BEFORE_POTENTIAL_GC, AFTER_POTENTIAL_GC): New.
(FETCH, PUSH, POP, DISCARD, TOP, MAYBE_GC): Rewritten.
(HANDLE_RELOCATION): Removed.
(Fbyte_code): Use byte_stack structures.
| author | Gerd Moellmann <gerd@gnu.org> |
|---|---|
| date | Fri, 05 Nov 1999 21:26:15 +0000 |
| parents | a14111a2a100 |
| children | b3378aff433e |
comparison
equal
deleted
inserted
replaced
| 26362:dc0efddbdd77 | 26363:efb608f1cb10 |
|---|---|
| 222 #define BconcatN 0260 | 222 #define BconcatN 0260 |
| 223 #define BinsertN 0261 | 223 #define BinsertN 0261 |
| 224 | 224 |
| 225 #define Bconstant 0300 | 225 #define Bconstant 0300 |
| 226 #define CONSTANTLIM 0100 | 226 #define CONSTANTLIM 0100 |
| 227 | |
| 228 /* Structure describing a value stack used during byte-code execution | |
| 229 in Fbyte_code. */ | |
| 230 | |
| 231 struct byte_stack | |
| 232 { | |
| 233 /* Program counter. This points into the byte_string below | |
| 234 and is relocated when that string is relocated. */ | |
| 235 unsigned char *pc; | |
| 236 | |
| 237 /* Top and bottom of stack. The bottom points to an area of memory | |
| 238 allocated with alloca in Fbyte_code. */ | |
| 239 Lisp_Object *top, *bottom; | |
| 240 | |
| 241 /* The string containing the byte-code, and its current address. | |
| 242 Storing this here protects it from GC because mark_byte_stack | |
| 243 marks it. */ | |
| 244 Lisp_Object byte_string; | |
| 245 unsigned char *byte_string_start; | |
| 246 | |
| 247 /* The vector of constants used during byte-code execution. Storing | |
| 248 this here protects it from GC because mark_byte_stack marks it. */ | |
| 249 Lisp_Object constants; | |
| 250 | |
| 251 /* Next entry in byte_stack_list. */ | |
| 252 struct byte_stack *next; | |
| 253 }; | |
| 254 | |
| 255 /* A list of currently active byte-code execution value stacks. | |
| 256 Fbyte_code adds an entry to the head of this list before it starts | |
| 257 processing byte-code, and it removed the entry again when it is | |
| 258 done. Signalling an error truncates the list analoguous to | |
| 259 gcprolist. */ | |
| 260 | |
| 261 struct byte_stack *byte_stack_list; | |
| 262 | |
| 263 /* Mark objects on byte_stack_list. Called during GC. */ | |
| 264 | |
| 265 void | |
| 266 mark_byte_stack () | |
| 267 { | |
| 268 struct byte_stack *stack; | |
| 269 Lisp_Object *obj; | |
| 270 | |
| 271 for (stack = byte_stack_list; stack; stack = stack->next) | |
| 272 { | |
| 273 if (!stack->top) | |
| 274 abort (); | |
| 275 | |
| 276 for (obj = stack->bottom; obj <= stack->top; ++obj) | |
| 277 mark_object (obj); | |
| 278 | |
| 279 mark_object (&stack->byte_string); | |
| 280 mark_object (&stack->constants); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 | |
| 285 /* Relocate program counters in the stacks on byte_stack_list. Called | |
| 286 when GC has completed. */ | |
| 287 | |
| 288 void | |
| 289 relocate_byte_pcs () | |
| 290 { | |
| 291 struct byte_stack *stack; | |
| 292 | |
| 293 for (stack = byte_stack_list; stack; stack = stack->next) | |
| 294 if (stack->byte_string_start != XSTRING (stack->byte_string)->data) | |
| 295 { | |
| 296 int offset = stack->pc - stack->byte_string_start; | |
| 297 stack->byte_string_start = XSTRING (stack->byte_string)->data; | |
| 298 stack->pc = stack->byte_string_start + offset; | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 | |
| 227 | 303 |
| 228 /* Fetch the next byte from the bytecode stream */ | 304 /* Fetch the next byte from the bytecode stream */ |
| 229 | 305 |
| 230 #define FETCH *pc++ | 306 #define FETCH *stack.pc++ |
| 231 | 307 |
| 232 /* Fetch two bytes from the bytecode stream | 308 /* Fetch two bytes from the bytecode stream |
| 233 and make a 16-bit number out of them */ | 309 and make a 16-bit number out of them */ |
| 234 | 310 |
| 235 #define FETCH2 (op = FETCH, op + (FETCH << 8)) | 311 #define FETCH2 (op = FETCH, op + (FETCH << 8)) |
| 236 | 312 |
| 237 /* Push x onto the execution stack. */ | 313 /* Push x onto the execution stack. */ |
| 238 | 314 |
| 239 /* This used to be #define PUSH(x) (*++stackp = (x)) | 315 /* This used to be #define PUSH(x) (*++stackp = (x)) This oddity is |
| 240 This oddity is necessary because Alliant can't be bothered to | 316 necessary because Alliant can't be bothered to compile the |
| 241 compile the preincrement operator properly, as of 4/91. -JimB */ | 317 preincrement operator properly, as of 4/91. -JimB */ |
| 242 #define PUSH(x) (stackp++, *stackp = (x)) | 318 |
| 319 #define PUSH(x) (top++, *top = (x)) | |
| 243 | 320 |
| 244 /* Pop a value off the execution stack. */ | 321 /* Pop a value off the execution stack. */ |
| 245 | 322 |
| 246 #define POP (*stackp--) | 323 #define POP (*top--) |
| 247 | 324 |
| 248 /* Discard n values from the execution stack. */ | 325 /* Discard n values from the execution stack. */ |
| 249 | 326 |
| 250 #define DISCARD(n) (stackp -= (n)) | 327 #define DISCARD(n) (top -= (n)) |
| 251 | 328 |
| 252 /* Get the value which is at the top of the execution stack, but don't pop it. */ | 329 /* Get the value which is at the top of the execution stack, but don't |
| 253 | 330 pop it. */ |
| 254 #define TOP (*stackp) | 331 |
| 332 #define TOP (*top) | |
| 333 | |
| 334 /* Actions that must performed before and after calling a function | |
| 335 that might GC. */ | |
| 336 | |
| 337 #define BEFORE_POTENTIAL_GC() stack.top = top | |
| 338 #define AFTER_POTENTIAL_GC() stack.top = NULL | |
| 255 | 339 |
| 256 /* Garbage collect if we have consed enough since the last time. | 340 /* Garbage collect if we have consed enough since the last time. |
| 257 We do this at every branch, to avoid loops that never GC. */ | 341 We do this at every branch, to avoid loops that never GC. */ |
| 258 | 342 |
| 259 #define MAYBE_GC() \ | 343 #define MAYBE_GC() \ |
| 260 if (consing_since_gc > gc_cons_threshold) \ | 344 if (consing_since_gc > gc_cons_threshold) \ |
| 261 { \ | 345 { \ |
| 346 BEFORE_POTENTIAL_GC (); \ | |
| 262 Fgarbage_collect (); \ | 347 Fgarbage_collect (); \ |
| 263 HANDLE_RELOCATION (); \ | 348 AFTER_POTENTIAL_GC (); \ |
| 264 } \ | 349 } \ |
| 265 else | 350 else |
| 266 | 351 |
| 267 /* Relocate BYTESTR if there has been a GC recently. */ | |
| 268 #define HANDLE_RELOCATION() \ | |
| 269 if (! EQ (string_saved, bytestr)) \ | |
| 270 { \ | |
| 271 pc = pc - XSTRING (string_saved)->data + XSTRING (bytestr)->data; \ | |
| 272 string_saved = bytestr; \ | |
| 273 } \ | |
| 274 else | |
| 275 | |
| 276 /* Check for jumping out of range. */ | 352 /* Check for jumping out of range. */ |
| 353 | |
| 354 #ifdef BYTE_CODE_SAFE | |
| 355 | |
| 277 #define CHECK_RANGE(ARG) \ | 356 #define CHECK_RANGE(ARG) \ |
| 278 if (ARG >= bytestr_length) abort () | 357 if (ARG >= bytestr_length) abort () |
| 358 | |
| 359 #else | |
| 360 | |
| 361 #define CHECK_RANGE(ARG) | |
| 362 | |
| 363 #endif | |
| 364 | |
| 279 | 365 |
| 280 DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, | 366 DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, |
| 281 "Function used internally in byte-compiled code.\n\ | 367 "Function used internally in byte-compiled code.\n\ |
| 282 The first argument, BYTESTR, is a string of byte code;\n\ | 368 The first argument, BYTESTR, is a string of byte code;\n\ |
| 283 the second, VECTOR, a vector of constants;\n\ | 369 the second, VECTOR, a vector of constants;\n\ |
| 284 the third, MAXDEPTH, the maximum stack depth used in this function.\n\ | 370 the third, MAXDEPTH, the maximum stack depth used in this function.\n\ |
| 285 If the third argument is incorrect, Emacs may crash.") | 371 If the third argument is incorrect, Emacs may crash.") |
| 286 (bytestr, vector, maxdepth) | 372 (bytestr, vector, maxdepth) |
| 287 Lisp_Object bytestr, vector, maxdepth; | 373 Lisp_Object bytestr, vector, maxdepth; |
| 288 { | 374 { |
| 289 struct gcpro gcpro1, gcpro2, gcpro3; | |
| 290 int count = specpdl_ptr - specpdl; | 375 int count = specpdl_ptr - specpdl; |
| 291 #ifdef BYTE_CODE_METER | 376 #ifdef BYTE_CODE_METER |
| 292 int this_op = 0; | 377 int this_op = 0; |
| 293 int prev_op; | 378 int prev_op; |
| 294 #endif | 379 #endif |
| 295 register int op; | 380 int op; |
| 296 unsigned char *pc; | 381 Lisp_Object v1, v2; |
| 297 Lisp_Object *stack; | 382 Lisp_Object *stackp; |
| 298 register Lisp_Object *stackp; | 383 Lisp_Object *vectorp = XVECTOR (vector)->contents; |
| 384 #ifdef BYTE_CODE_SAFE | |
| 385 int const_length = XVECTOR (vector)->size; | |
| 299 Lisp_Object *stacke; | 386 Lisp_Object *stacke; |
| 300 register Lisp_Object v1, v2; | |
| 301 register Lisp_Object *vectorp = XVECTOR (vector)->contents; | |
| 302 #ifdef BYTE_CODE_SAFE | |
| 303 register int const_length = XVECTOR (vector)->size; | |
| 304 #endif | 387 #endif |
| 305 /* Copy of BYTESTR, saved so we can tell if BYTESTR was relocated. */ | |
| 306 Lisp_Object string_saved; | |
| 307 /* Cached address of beginning of string, | |
| 308 valid if BYTESTR equals STRING_SAVED. */ | |
| 309 register unsigned char *strbeg; | |
| 310 int bytestr_length = STRING_BYTES (XSTRING (bytestr)); | 388 int bytestr_length = STRING_BYTES (XSTRING (bytestr)); |
| 389 struct byte_stack stack; | |
| 390 Lisp_Object *top; | |
| 311 | 391 |
| 312 CHECK_STRING (bytestr, 0); | 392 CHECK_STRING (bytestr, 0); |
| 313 if (!VECTORP (vector)) | 393 if (!VECTORP (vector)) |
| 314 vector = wrong_type_argument (Qvectorp, vector); | 394 vector = wrong_type_argument (Qvectorp, vector); |
| 315 CHECK_NUMBER (maxdepth, 2); | 395 CHECK_NUMBER (maxdepth, 2); |
| 316 | 396 |
| 317 stackp = (Lisp_Object *) alloca (XFASTINT (maxdepth) * sizeof (Lisp_Object)); | 397 stack.byte_string = bytestr; |
| 318 bzero (stackp, XFASTINT (maxdepth) * sizeof (Lisp_Object)); | 398 stack.pc = stack.byte_string_start = XSTRING (bytestr)->data; |
| 319 GCPRO3 (bytestr, vector, *stackp); | 399 stack.constants = vector; |
| 320 gcpro3.nvars = XFASTINT (maxdepth); | 400 stack.bottom = (Lisp_Object *) alloca (XFASTINT (maxdepth) |
| 321 | 401 * sizeof (Lisp_Object)); |
| 322 --stackp; | 402 top = stack.bottom - 1; |
| 323 stack = stackp; | 403 stack.top = NULL; |
| 324 stacke = stackp + XFASTINT (maxdepth); | 404 stack.next = byte_stack_list; |
| 325 | 405 byte_stack_list = &stack; |
| 326 /* Initialize the saved pc-pointer for fetching from the string. */ | 406 |
| 327 string_saved = bytestr; | 407 #ifdef BYTE_CODE_SAFE |
| 328 pc = XSTRING (string_saved)->data; | 408 stacke = stack.bottom - 1 + XFASTINT (maxdepth); |
| 329 | 409 #endif |
| 410 | |
| 330 while (1) | 411 while (1) |
| 331 { | 412 { |
| 332 #ifdef BYTE_CODE_SAFE | 413 #ifdef BYTE_CODE_SAFE |
| 333 if (stackp > stacke) | 414 if (top > stacks) |
| 334 error ("Byte code stack overflow (byte compiler bug), pc %d, depth %d", | 415 error ("Byte code stack overflow (byte compiler bug), pc %d, depth %d", |
| 335 pc - XSTRING (string_saved)->data, stacke - stackp); | 416 stack.pc - stack.byte_string_start, stacke - top); |
| 336 if (stackp < stack) | 417 else if (top < stack.bottom - 1) |
| 337 error ("Byte code stack underflow (byte compiler bug), pc %d", | 418 error ("Byte code stack underflow (byte compiler bug), pc %d", |
| 338 pc - XSTRING (string_saved)->data); | 419 stack.pc - stack.byte_string_start); |
| 339 #endif | 420 #endif |
| 340 | |
| 341 /* Update BYTESTR if we had a garbage collection. */ | |
| 342 HANDLE_RELOCATION (); | |
| 343 | 421 |
| 344 #ifdef BYTE_CODE_METER | 422 #ifdef BYTE_CODE_METER |
| 345 prev_op = this_op; | 423 prev_op = this_op; |
| 346 this_op = op = FETCH; | 424 this_op = op = FETCH; |
| 347 METER_CODE (prev_op, op); | 425 METER_CODE (prev_op, op); |
| 428 XSETINT (v2, XINT (v2) + 1); | 506 XSETINT (v2, XINT (v2) + 1); |
| 429 Fput (v1, Qbyte_code_meter, v2); | 507 Fput (v1, Qbyte_code_meter, v2); |
| 430 } | 508 } |
| 431 } | 509 } |
| 432 #endif | 510 #endif |
| 511 BEFORE_POTENTIAL_GC (); | |
| 433 TOP = Ffuncall (op + 1, &TOP); | 512 TOP = Ffuncall (op + 1, &TOP); |
| 513 AFTER_POTENTIAL_GC (); | |
| 434 break; | 514 break; |
| 435 | 515 |
| 436 case Bunbind+6: | 516 case Bunbind+6: |
| 437 op = FETCH; | 517 op = FETCH; |
| 438 goto dounbind; | 518 goto dounbind; |
| 443 | 523 |
| 444 case Bunbind: case Bunbind+1: case Bunbind+2: case Bunbind+3: | 524 case Bunbind: case Bunbind+1: case Bunbind+2: case Bunbind+3: |
| 445 case Bunbind+4: case Bunbind+5: | 525 case Bunbind+4: case Bunbind+5: |
| 446 op -= Bunbind; | 526 op -= Bunbind; |
| 447 dounbind: | 527 dounbind: |
| 528 BEFORE_POTENTIAL_GC (); | |
| 448 unbind_to (specpdl_ptr - specpdl - op, Qnil); | 529 unbind_to (specpdl_ptr - specpdl - op, Qnil); |
| 530 AFTER_POTENTIAL_GC (); | |
| 449 break; | 531 break; |
| 450 | 532 |
| 451 case Bunbind_all: | 533 case Bunbind_all: |
| 452 /* To unbind back to the beginning of this frame. Not used yet, | 534 /* To unbind back to the beginning of this frame. Not used yet, |
| 453 but will be needed for tail-recursion elimination. */ | 535 but will be needed for tail-recursion elimination. */ |
| 536 BEFORE_POTENTIAL_GC (); | |
| 454 unbind_to (count, Qnil); | 537 unbind_to (count, Qnil); |
| 538 AFTER_POTENTIAL_GC (); | |
| 455 break; | 539 break; |
| 456 | 540 |
| 457 case Bgoto: | 541 case Bgoto: |
| 458 MAYBE_GC (); | 542 MAYBE_GC (); |
| 459 QUIT; | 543 QUIT; |
| 460 op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ | 544 op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ |
| 461 CHECK_RANGE (op); | 545 CHECK_RANGE (op); |
| 462 pc = XSTRING (string_saved)->data + op; | 546 stack.pc = stack.byte_string_start + op; |
| 463 break; | 547 break; |
| 464 | 548 |
| 465 case Bgotoifnil: | 549 case Bgotoifnil: |
| 466 MAYBE_GC (); | 550 MAYBE_GC (); |
| 467 op = FETCH2; | 551 op = FETCH2; |
| 468 if (NILP (POP)) | 552 if (NILP (POP)) |
| 469 { | 553 { |
| 470 QUIT; | 554 QUIT; |
| 471 CHECK_RANGE (op); | 555 CHECK_RANGE (op); |
| 472 pc = XSTRING (string_saved)->data + op; | 556 stack.pc = stack.byte_string_start + op; |
| 473 } | 557 } |
| 474 break; | 558 break; |
| 475 | 559 |
| 476 case Bgotoifnonnil: | 560 case Bgotoifnonnil: |
| 477 MAYBE_GC (); | 561 MAYBE_GC (); |
| 478 op = FETCH2; | 562 op = FETCH2; |
| 479 if (!NILP (POP)) | 563 if (!NILP (POP)) |
| 480 { | 564 { |
| 481 QUIT; | 565 QUIT; |
| 482 CHECK_RANGE (op); | 566 CHECK_RANGE (op); |
| 483 pc = XSTRING (string_saved)->data + op; | 567 stack.pc = stack.byte_string_start + op; |
| 484 } | 568 } |
| 485 break; | 569 break; |
| 486 | 570 |
| 487 case Bgotoifnilelsepop: | 571 case Bgotoifnilelsepop: |
| 488 MAYBE_GC (); | 572 MAYBE_GC (); |
| 489 op = FETCH2; | 573 op = FETCH2; |
| 490 if (NILP (TOP)) | 574 if (NILP (TOP)) |
| 491 { | 575 { |
| 492 QUIT; | 576 QUIT; |
| 493 CHECK_RANGE (op); | 577 CHECK_RANGE (op); |
| 494 pc = XSTRING (string_saved)->data + op; | 578 stack.pc = stack.byte_string_start + op; |
| 495 } | 579 } |
| 496 else DISCARD (1); | 580 else DISCARD (1); |
| 497 break; | 581 break; |
| 498 | 582 |
| 499 case Bgotoifnonnilelsepop: | 583 case Bgotoifnonnilelsepop: |
| 501 op = FETCH2; | 585 op = FETCH2; |
| 502 if (!NILP (TOP)) | 586 if (!NILP (TOP)) |
| 503 { | 587 { |
| 504 QUIT; | 588 QUIT; |
| 505 CHECK_RANGE (op); | 589 CHECK_RANGE (op); |
| 506 pc = XSTRING (string_saved)->data + op; | 590 stack.pc = stack.byte_string_start + op; |
| 507 } | 591 } |
| 508 else DISCARD (1); | 592 else DISCARD (1); |
| 509 break; | 593 break; |
| 510 | 594 |
| 511 case BRgoto: | 595 case BRgoto: |
| 512 MAYBE_GC (); | 596 MAYBE_GC (); |
| 513 QUIT; | 597 QUIT; |
| 514 pc += (int) *pc - 127; | 598 stack.pc += (int) *stack.pc - 127; |
| 515 break; | 599 break; |
| 516 | 600 |
| 517 case BRgotoifnil: | 601 case BRgotoifnil: |
| 518 MAYBE_GC (); | 602 MAYBE_GC (); |
| 519 if (NILP (POP)) | 603 if (NILP (POP)) |
| 520 { | 604 { |
| 521 QUIT; | 605 QUIT; |
| 522 pc += (int) *pc - 128; | 606 stack.pc += (int) *stack.pc - 128; |
| 523 } | 607 } |
| 524 pc++; | 608 stack.pc++; |
| 525 break; | 609 break; |
| 526 | 610 |
| 527 case BRgotoifnonnil: | 611 case BRgotoifnonnil: |
| 528 MAYBE_GC (); | 612 MAYBE_GC (); |
| 529 if (!NILP (POP)) | 613 if (!NILP (POP)) |
| 530 { | 614 { |
| 531 QUIT; | 615 QUIT; |
| 532 pc += (int) *pc - 128; | 616 stack.pc += (int) *stack.pc - 128; |
| 533 } | 617 } |
| 534 pc++; | 618 stack.pc++; |
| 535 break; | 619 break; |
| 536 | 620 |
| 537 case BRgotoifnilelsepop: | 621 case BRgotoifnilelsepop: |
| 538 MAYBE_GC (); | 622 MAYBE_GC (); |
| 539 op = *pc++; | 623 op = *stack.pc++; |
| 540 if (NILP (TOP)) | 624 if (NILP (TOP)) |
| 541 { | 625 { |
| 542 QUIT; | 626 QUIT; |
| 543 pc += op - 128; | 627 stack.pc += op - 128; |
| 544 } | 628 } |
| 545 else DISCARD (1); | 629 else DISCARD (1); |
| 546 break; | 630 break; |
| 547 | 631 |
| 548 case BRgotoifnonnilelsepop: | 632 case BRgotoifnonnilelsepop: |
| 549 MAYBE_GC (); | 633 MAYBE_GC (); |
| 550 op = *pc++; | 634 op = *stack.pc++; |
| 551 if (!NILP (TOP)) | 635 if (!NILP (TOP)) |
| 552 { | 636 { |
| 553 QUIT; | 637 QUIT; |
| 554 pc += op - 128; | 638 stack.pc += op - 128; |
| 555 } | 639 } |
| 556 else DISCARD (1); | 640 else DISCARD (1); |
| 557 break; | 641 break; |
| 558 | 642 |
| 559 case Breturn: | 643 case Breturn: |
| 601 break; | 685 break; |
| 602 | 686 |
| 603 case Bcondition_case: | 687 case Bcondition_case: |
| 604 v1 = POP; | 688 v1 = POP; |
| 605 v1 = Fcons (POP, v1); | 689 v1 = Fcons (POP, v1); |
| 690 BEFORE_POTENTIAL_GC (); | |
| 606 TOP = Fcondition_case (Fcons (TOP, v1)); | 691 TOP = Fcondition_case (Fcons (TOP, v1)); |
| 692 AFTER_POTENTIAL_GC (); | |
| 607 break; | 693 break; |
| 608 | 694 |
| 609 case Btemp_output_buffer_setup: | 695 case Btemp_output_buffer_setup: |
| 610 temp_output_buffer_setup (XSTRING (TOP)->data); | 696 temp_output_buffer_setup (XSTRING (TOP)->data); |
| 611 TOP = Vstandard_output; | 697 TOP = Vstandard_output; |
| 614 case Btemp_output_buffer_show: | 700 case Btemp_output_buffer_show: |
| 615 v1 = POP; | 701 v1 = POP; |
| 616 temp_output_buffer_show (TOP); | 702 temp_output_buffer_show (TOP); |
| 617 TOP = v1; | 703 TOP = v1; |
| 618 /* pop binding of standard-output */ | 704 /* pop binding of standard-output */ |
| 705 BEFORE_POTENTIAL_GC (); | |
| 619 unbind_to (specpdl_ptr - specpdl - 1, Qnil); | 706 unbind_to (specpdl_ptr - specpdl - 1, Qnil); |
| 707 AFTER_POTENTIAL_GC (); | |
| 620 break; | 708 break; |
| 621 | 709 |
| 622 case Bnth: | 710 case Bnth: |
| 623 v1 = POP; | 711 v1 = POP; |
| 624 v2 = TOP; | 712 v2 = TOP; |
| 1144 #endif | 1232 #endif |
| 1145 } | 1233 } |
| 1146 } | 1234 } |
| 1147 | 1235 |
| 1148 exit: | 1236 exit: |
| 1149 UNGCPRO; | 1237 |
| 1238 byte_stack_list = byte_stack_list->next; | |
| 1239 | |
| 1150 /* Binds and unbinds are supposed to be compiled balanced. */ | 1240 /* Binds and unbinds are supposed to be compiled balanced. */ |
| 1151 if (specpdl_ptr - specpdl != count) | 1241 if (specpdl_ptr - specpdl != count) |
| 1152 #ifdef BYTE_CODE_SAFE | 1242 #ifdef BYTE_CODE_SAFE |
| 1153 error ("binding stack not balanced (serious byte compiler bug)"); | 1243 error ("binding stack not balanced (serious byte compiler bug)"); |
| 1154 #else | 1244 #else |
| 1155 abort (); | 1245 abort (); |
| 1156 #endif | 1246 #endif |
| 1247 | |
| 1157 return v1; | 1248 return v1; |
| 1158 } | 1249 } |
| 1159 | 1250 |
| 1160 void | 1251 void |
| 1161 syms_of_bytecode () | 1252 syms_of_bytecode () |
