github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-compile.c (about) 1 /* 2 * jit-compile.c - Function compilation. 3 * 4 * Copyright (C) 2004, 2006-2008 Southern Storm Software, Pty Ltd. 5 * Copyright (C) 2012 Aleksey Demakov 6 * 7 * This file is part of the libjit library. 8 * 9 * The libjit library is free software: you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public License 11 * as published by the Free Software Foundation, either version 2.1 of 12 * the License, or (at your option) any later version. 13 * 14 * The libjit library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with the libjit library. If not, see 21 * <http://www.gnu.org/licenses/>. 22 */ 23 24 #include "jit-internal.h" 25 #include "jit-rules.h" 26 #include "jit-reg-alloc.h" 27 #include "jit-setjmp.h" 28 #ifdef _JIT_COMPILE_DEBUG 29 # include <jit/jit-dump.h> 30 # include <stdio.h> 31 #endif 32 33 /* 34 * Misc data needed for compilation 35 */ 36 typedef struct 37 { 38 jit_function_t func; 39 40 int memory_locked; 41 int memory_started; 42 43 int restart; 44 int page_factor; 45 46 struct jit_gencode gen; 47 48 } _jit_compile_t; 49 50 #define _JIT_RESULT_TO_OBJECT(x) ((void *) ((jit_nint) (x) - JIT_RESULT_OK)) 51 #define _JIT_RESULT_FROM_OBJECT(x) ((jit_nint) ((void *) (x)) + JIT_RESULT_OK) 52 53 /* 54 * This exception handler overrides a user-defined handler during compilation. 55 */ 56 static void * 57 internal_exception_handler(int exception_type) 58 { 59 return _JIT_RESULT_TO_OBJECT(exception_type); 60 } 61 62 /* 63 * Optimize a function. 64 */ 65 static void 66 optimize(jit_function_t func) 67 { 68 if(func->is_optimized || func->optimization_level == JIT_OPTLEVEL_NONE) 69 { 70 /* The function is already optimized or does not need optimization */ 71 return; 72 } 73 74 /* Build control flow graph */ 75 _jit_block_build_cfg(func); 76 77 /* Eliminate useless control flow */ 78 _jit_block_clean_cfg(func); 79 80 /* Optimization is done */ 81 func->is_optimized = 1; 82 } 83 84 /*@ 85 * @deftypefun int jit_optimize (jit_function_t @var{func}) 86 * Optimize a function by analyzing and transforming its intermediate 87 * representation. If the function was already compiled or optimized, 88 * then do nothing. 89 * 90 * Returns @code{JIT_RESUlT_OK} on success, otherwise it might return 91 * @code{JIT_RESULT_OUT_OF_MEMORY}, @code{JIT_RESULT_COMPILE_ERROR} or 92 * possibly some other more specific @code{JIT_RESULT_} code. 93 * 94 * Normally this function should not be used because @code{jit_compile} 95 * performs all the optimization anyway. However it might be useful for 96 * debugging to verify the effect of the @code{libjit} code optimization. 97 * This might be done, for instance, by calling @code{jit_dump_function} 98 * before and after @code{jit_optimize}. 99 * @end deftypefun 100 @*/ 101 int 102 jit_optimize(jit_function_t func) 103 { 104 jit_jmp_buf jbuf; 105 jit_exception_func handler; 106 107 /* Bail out on invalid parameter */ 108 if(!func) 109 { 110 return JIT_RESULT_NULL_FUNCTION; 111 } 112 113 /* Bail out if there is nothing to do here */ 114 if(!func->builder) 115 { 116 if(func->is_compiled) 117 { 118 /* The function is already compiled and we can't optimize it */ 119 return JIT_RESULT_OK; 120 } 121 else 122 { 123 /* We don't have anything to optimize at all */ 124 return JIT_RESULT_NULL_FUNCTION; 125 } 126 } 127 128 /* Override user's exception handler */ 129 handler = jit_exception_set_handler(internal_exception_handler); 130 131 /* Establish a "setjmp" point here so that we can unwind the 132 stack to this point when an exception occurs and then prevent 133 the exception from propagating further up the stack */ 134 _jit_unwind_push_setjmp(&jbuf); 135 if(setjmp(jbuf.buf)) 136 { 137 _jit_unwind_pop_setjmp(); 138 jit_exception_set_handler(handler); 139 return _JIT_RESULT_FROM_OBJECT(jit_exception_get_last_and_clear()); 140 } 141 142 /* Perform the optimizations */ 143 optimize(func); 144 145 /* Restore the "setjmp" contexts and exit */ 146 _jit_unwind_pop_setjmp(); 147 jit_exception_set_handler(handler); 148 return JIT_RESULT_OK; 149 } 150 151 /* 152 * Mark the current position with a bytecode offset value. 153 */ 154 void 155 mark_offset(jit_gencode_t gen, jit_function_t func, unsigned long offset) 156 { 157 unsigned long native_offset = gen->ptr - gen->mem_start; 158 if(!_jit_varint_encode_uint(&gen->offset_encoder, (jit_uint) offset)) 159 { 160 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 161 } 162 if(!_jit_varint_encode_uint(&gen->offset_encoder, (jit_uint) native_offset)) 163 { 164 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 165 } 166 } 167 168 /* 169 * Compile a single basic block within a function. 170 */ 171 static void 172 compile_block(jit_gencode_t gen, jit_function_t func, jit_block_t block) 173 { 174 jit_insn_iter_t iter; 175 jit_insn_t insn; 176 177 #ifdef _JIT_COMPILE_DEBUG 178 printf("Block #%d: %d\n\n", func->builder->block_count++, block->label); 179 #endif 180 181 /* Iterate over all blocks in the function */ 182 jit_insn_iter_init(&iter, block); 183 while((insn = jit_insn_iter_next(&iter)) != 0) 184 { 185 #ifdef _JIT_COMPILE_DEBUG 186 unsigned char *p1, *p2; 187 p1 = gen->ptr; 188 printf("Insn #%d: ", func->builder->insn_count++); 189 jit_dump_insn(stdout, func, insn); 190 printf("\nStart of binary code: 0x%08x\n", p1); 191 #endif 192 193 switch(insn->opcode) 194 { 195 case JIT_OP_NOP: 196 /* Ignore NOP's */ 197 break; 198 199 case JIT_OP_CHECK_NULL: 200 /* Determine if we can optimize the null check away */ 201 if(!_jit_insn_check_is_redundant(&iter)) 202 { 203 _jit_gen_insn(gen, func, block, insn); 204 } 205 break; 206 207 #ifndef JIT_BACKEND_INTERP 208 case JIT_OP_CALL: 209 case JIT_OP_CALL_TAIL: 210 case JIT_OP_CALL_INDIRECT: 211 case JIT_OP_CALL_INDIRECT_TAIL: 212 case JIT_OP_CALL_VTABLE_PTR: 213 case JIT_OP_CALL_VTABLE_PTR_TAIL: 214 case JIT_OP_CALL_EXTERNAL: 215 case JIT_OP_CALL_EXTERNAL_TAIL: 216 /* Spill all caller-saved registers before a call */ 217 _jit_regs_spill_all(gen); 218 /* Generate code for the instruction with the back end */ 219 _jit_gen_insn(gen, func, block, insn); 220 /* Free outgoing registers if any */ 221 _jit_regs_clear_all_outgoing(gen); 222 break; 223 #endif 224 225 #ifndef JIT_BACKEND_INTERP 226 case JIT_OP_IMPORT: 227 /* Make sure the import target has a frame_offset */ 228 _jit_gen_fix_value(insn->value2); 229 230 /* change the current instruction to an instruction calculating the 231 address of the import target */ 232 insn->opcode = JIT_OP_ADD_RELATIVE; 233 insn->value2 = jit_value_create_nint_constant(func, jit_type_nint, 234 insn->value2->frame_offset); 235 236 /* generate the instruction */ 237 _jit_gen_insn(gen, func, block, insn); 238 break; 239 #endif 240 241 #ifndef JIT_BACKEND_INTERP 242 case JIT_OP_INCOMING_REG: 243 /* Assign a register to an incoming value */ 244 _jit_regs_set_incoming(gen, 245 (int)jit_value_get_nint_constant(insn->value2), 246 insn->value1); 247 /* Generate code for the instruction with the back end */ 248 _jit_gen_insn(gen, func, block, insn); 249 break; 250 #endif 251 252 case JIT_OP_INCOMING_FRAME_POSN: 253 /* Set the frame position for an incoming value */ 254 insn->value1->frame_offset = jit_value_get_nint_constant(insn->value2); 255 insn->value1->in_register = 0; 256 insn->value1->has_frame_offset = 1; 257 if(insn->value1->has_global_register) 258 { 259 insn->value1->in_global_register = 1; 260 _jit_gen_load_global(gen, insn->value1->global_reg, insn->value1); 261 } 262 else 263 { 264 insn->value1->in_frame = 1; 265 } 266 break; 267 268 #ifndef JIT_BACKEND_INTERP 269 case JIT_OP_OUTGOING_REG: 270 /* Copy a value into an outgoing register */ 271 _jit_regs_set_outgoing(gen, 272 (int)jit_value_get_nint_constant(insn->value2), 273 insn->value1); 274 break; 275 #endif 276 277 #ifndef JIT_BACKEND_INTERP 278 case JIT_OP_RETURN_REG: 279 /* Assign a register to a return value */ 280 _jit_regs_set_incoming(gen, 281 (int)jit_value_get_nint_constant(insn->value2), 282 insn->value1); 283 /* Generate code for the instruction with the back end */ 284 _jit_gen_insn(gen, func, block, insn); 285 break; 286 #endif 287 288 case JIT_OP_MARK_OFFSET: 289 /* Mark the current code position as corresponding 290 to a particular bytecode offset */ 291 mark_offset(gen, func, (unsigned long)(long)jit_value_get_nint_constant(insn->value1)); 292 break; 293 294 default: 295 /* Generate code for the instruction with the back end */ 296 _jit_gen_insn(gen, func, block, insn); 297 break; 298 } 299 300 #ifdef _JIT_COMPILE_DEBUG 301 p2 = gen->ptr; 302 printf("Length of binary code: %d\n\n", p2 - p1); 303 fflush(stdout); 304 #endif 305 } 306 } 307 308 /* 309 * Reset value on codegen restart. 310 */ 311 static void 312 reset_value(jit_value_t value) 313 { 314 value->reg = -1; 315 value->in_register = 0; 316 value->in_global_register = value->has_global_register; 317 value->in_frame = 0; 318 } 319 320 /* 321 * Clean up the compilation state on codegen restart. 322 */ 323 static void 324 cleanup_on_restart(jit_gencode_t gen, jit_function_t func) 325 { 326 jit_block_t block; 327 jit_insn_iter_t iter; 328 jit_insn_t insn; 329 330 block = 0; 331 while((block = jit_block_next(func, block)) != 0) 332 { 333 /* Clear the block addresses and fixup lists */ 334 block->address = 0; 335 block->fixup_list = 0; 336 block->fixup_absolute_list = 0; 337 338 /* Reset values referred to by block instructions */ 339 jit_insn_iter_init(&iter, block); 340 while((insn = jit_insn_iter_next(&iter)) != 0) 341 { 342 if(insn->dest && (insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0) 343 { 344 reset_value(insn->dest); 345 } 346 if(insn->value1 && (insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0) 347 { 348 reset_value(insn->value1); 349 } 350 if(insn->value2 && (insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0) 351 { 352 reset_value(insn->value2); 353 } 354 } 355 } 356 357 /* Reset values referred to by builder */ 358 if(func->builder->setjmp_value) 359 { 360 reset_value(func->builder->setjmp_value); 361 } 362 if(func->builder->parent_frame) 363 { 364 reset_value(func->builder->parent_frame); 365 } 366 367 /* Reset the "touched" registers mask. The first time compilation 368 might have followed wrong code paths and thus allocated wrong 369 registers. */ 370 if(func->builder->has_tail_call) 371 { 372 /* For functions with tail calls _jit_regs_alloc_global() 373 does not allocate any global registers. The "permanent" 374 mask has all global registers set to prevent their use. */ 375 gen->touched = jit_regused_init; 376 } 377 else 378 { 379 gen->touched = gen->permanent; 380 } 381 382 /* Reset the epilog fixup list */ 383 gen->epilog_fixup = 0; 384 } 385 386 /* 387 * Acquire the memory context. 388 */ 389 static void 390 memory_acquire(_jit_compile_t *state) 391 { 392 /* Store the function's context as codegen context */ 393 state->gen.context = state->func->context; 394 395 /* Acquire the memory context lock */ 396 _jit_memory_lock(state->gen.context); 397 398 /* Remember that the lock is acquired */ 399 state->memory_locked = 1; 400 401 if(!_jit_memory_ensure(state->gen.context)) 402 { 403 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 404 } 405 } 406 407 /* 408 * Release the memory context. 409 */ 410 static void 411 memory_release(_jit_compile_t *state) 412 { 413 /* Release the lock if it was previously acquired */ 414 if(state->memory_locked) 415 { 416 _jit_memory_unlock(state->gen.context); 417 state->memory_locked = 0; 418 } 419 } 420 421 /* 422 * Align the method code on a particular boundary if the 423 * difference between the current position and the aligned 424 * boundary is less than "diff". The "nop" value is used 425 * to pad unused bytes. 426 */ 427 static void 428 memory_align(_jit_compile_t *state, int align, int diff, int nop) 429 { 430 jit_nuint p, n; 431 432 /* Adjust the required alignment */ 433 if(align < 1) 434 { 435 align = 1; 436 } 437 438 /* Determine the location of the next alignment boundary */ 439 p = (jit_nuint) state->gen.ptr; 440 n = (p + (jit_nuint) align - 1) & ~((jit_nuint) align - 1); 441 if(p == n || (p - n) >= (jit_nuint) diff) 442 { 443 return; 444 } 445 446 /* Determine the actual alignment */ 447 align = (int) (n - p); 448 449 /* Detect overflow of the free memory region */ 450 _jit_gen_check_space(&state->gen, align); 451 452 #ifdef jit_should_pad 453 /* Use CPU-specific padding, because it may be more efficient */ 454 _jit_pad_buffer(state->gen.ptr, align); 455 #else 456 jit_memset(state->gen.ptr, nop, align); 457 state->gen.ptr += align; 458 #endif 459 } 460 461 /* 462 * Prepare to start code generation with just allocated code space. 463 */ 464 static void 465 memory_start(_jit_compile_t *state) 466 { 467 /* Remember the memory context state */ 468 state->memory_started = 1; 469 470 /* Store the bounds of the available space */ 471 state->gen.mem_start = _jit_memory_get_break(state->gen.context); 472 state->gen.mem_limit = _jit_memory_get_limit(state->gen.context); 473 474 /* Align the function code start as required */ 475 state->gen.ptr = state->gen.mem_start; 476 memory_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0); 477 478 /* Prepare the bytecode offset encoder */ 479 _jit_varint_init_encoder(&state->gen.offset_encoder); 480 } 481 482 /* 483 * Allocate some amount of code space. 484 */ 485 static void 486 memory_alloc(_jit_compile_t *state) 487 { 488 int result; 489 490 /* Try to allocate within the current memory limit */ 491 result = _jit_memory_start_function(state->gen.context, state->func); 492 if(result == JIT_MEMORY_RESTART) 493 { 494 /* Not enough space. Request to extend the limit and retry */ 495 _jit_memory_extend_limit(state->gen.context, state->page_factor++); 496 result = _jit_memory_start_function(state->gen.context, state->func); 497 } 498 if(result != JIT_MEMORY_OK) 499 { 500 /* Failed to allocate any space */ 501 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 502 } 503 504 /* Start with with allocated space */ 505 memory_start(state); 506 } 507 508 /* 509 * Finish code generation. 510 */ 511 static void 512 memory_flush(_jit_compile_t *state) 513 { 514 int result; 515 516 if(state->memory_started) 517 { 518 /* Reset the memory state */ 519 state->memory_started = 0; 520 521 /* Let the memory context know the address we ended at */ 522 _jit_memory_set_break(state->gen.context, state->gen.code_end); 523 524 /* Finally end the function */ 525 result = _jit_memory_end_function(state->gen.context, JIT_MEMORY_OK); 526 if(result != JIT_MEMORY_OK) 527 { 528 if(result == JIT_MEMORY_RESTART) 529 { 530 /* Throw an internal exception that causes 531 a larger code space to be allocated and 532 the code generation to restart */ 533 jit_exception_builtin(JIT_RESULT_MEMORY_FULL); 534 } 535 else 536 { 537 /* Throw exception that indicates failure 538 to allocate enough code space */ 539 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 540 } 541 } 542 543 #ifndef JIT_BACKEND_INTERP 544 /* On success perform a CPU cache flush, to make the code executable */ 545 _jit_flush_exec(state->gen.code_start, 546 state->gen.code_end - state->gen.code_start); 547 #endif 548 549 /* Terminate the debug information and flush it */ 550 if(!_jit_varint_encode_end(&state->gen.offset_encoder)) 551 { 552 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 553 } 554 state->func->bytecode_offset = _jit_varint_get_data(&state->gen.offset_encoder); 555 } 556 } 557 558 /* 559 * Give back the allocated space in case of failure to generate the code. 560 */ 561 static void 562 memory_abort(_jit_compile_t *state) 563 { 564 if(state->memory_started) 565 { 566 state->memory_started = 0; 567 568 /* Release the code space */ 569 _jit_memory_end_function(state->gen.context, JIT_MEMORY_RESTART); 570 571 /* Free encoded bytecode offset data */ 572 _jit_varint_free_data(_jit_varint_get_data(&state->gen.offset_encoder)); 573 } 574 } 575 576 /* 577 * Allocate more code space. 578 */ 579 static void 580 memory_realloc(_jit_compile_t *state) 581 { 582 int result; 583 584 /* Release the previously allocated code space */ 585 memory_abort(state); 586 587 /* Request to extend memory limit and retry space allocation */ 588 _jit_memory_extend_limit(state->gen.context, state->page_factor++); 589 result = _jit_memory_start_function(state->gen.context, state->func); 590 if(result != JIT_MEMORY_OK) 591 { 592 /* Failed to allocate enough space */ 593 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 594 } 595 596 /* Start with with allocated space */ 597 memory_start(state); 598 } 599 600 /* 601 * Prepare function info needed for code generation. 602 */ 603 static void 604 codegen_prepare(_jit_compile_t *state) 605 { 606 /* Intuit "nothrow" and "noreturn" flags for this function */ 607 if(!state->func->builder->may_throw) 608 { 609 state->func->no_throw = 1; 610 } 611 if(!state->func->builder->ordinary_return) 612 { 613 state->func->no_return = 1; 614 } 615 616 /* Compute liveness and "next use" information for this function */ 617 _jit_function_compute_liveness(state->func); 618 619 /* Allocate global registers to variables within the function */ 620 #ifndef JIT_BACKEND_INTERP 621 _jit_regs_alloc_global(&state->gen, state->func); 622 #endif 623 } 624 625 /* 626 * Run codegen. 627 */ 628 static void 629 codegen(_jit_compile_t *state) 630 { 631 jit_function_t func = state->func; 632 struct jit_gencode *gen = &state->gen; 633 jit_block_t block; 634 635 /* Remember the start code address (due to alignment it may differ from 636 the available space start - gen->start) */ 637 gen->code_start = gen->ptr; 638 639 #ifdef JIT_PROLOG_SIZE 640 /* Output space for the function prolog */ 641 _jit_gen_check_space(gen, JIT_PROLOG_SIZE); 642 gen->ptr += JIT_PROLOG_SIZE; 643 #endif 644 645 /* Generate code for the blocks in the function */ 646 block = 0; 647 while((block = jit_block_next(func, block)) != 0) 648 { 649 /* Notify the back end that the block is starting */ 650 _jit_gen_start_block(gen, block); 651 652 #ifndef JIT_BACKEND_INTERP 653 /* Clear the local register assignments */ 654 _jit_regs_init_for_block(gen); 655 #endif 656 657 /* Generate the block's code */ 658 compile_block(gen, func, block); 659 660 #ifndef JIT_BACKEND_INTERP 661 /* Spill all live register values back to their frame positions */ 662 _jit_regs_spill_all(gen); 663 #endif 664 665 /* Notify the back end that the block is finished */ 666 _jit_gen_end_block(gen, block); 667 } 668 669 /* Output the function epilog. All return paths will jump to here */ 670 _jit_gen_epilog(gen, func); 671 672 /* Remember the end code address */ 673 gen->code_end = gen->ptr; 674 675 #ifdef JIT_PROLOG_SIZE 676 /* Back-patch the function prolog and get the real entry point */ 677 gen->code_start = _jit_gen_prolog(gen, func, gen->code_start); 678 #endif 679 680 #if !defined(JIT_BACKEND_INTERP) && (!defined(jit_redirector_size) || !defined(jit_indirector_size)) 681 /* If the function is recompilable, then we need an extra entry 682 point to properly redirect previous references to the function */ 683 if(func->is_recompilable && !func->indirector) 684 { 685 /* TODO: use _jit_create_indirector() instead of 686 _jit_gen_redirector() as both do the same. */ 687 func->indirector = _jit_gen_redirector(&gen, func); 688 } 689 #endif 690 } 691 692 /* 693 * Compile a function and return its entry point. 694 */ 695 static int 696 compile(_jit_compile_t *state, jit_function_t func) 697 { 698 jit_exception_func handler; 699 jit_jmp_buf jbuf; 700 int result; 701 702 /* Initialize compilation state */ 703 jit_memzero(state, sizeof(_jit_compile_t)); 704 state->func = func; 705 706 /* Replace user's exception handler with internal handler */ 707 handler = jit_exception_set_handler(internal_exception_handler); 708 709 /* Establish a "setjmp" point here so that we can unwind the 710 stack to this point when an exception occurs and then prevent 711 the exception from propagating further up the stack */ 712 _jit_unwind_push_setjmp(&jbuf); 713 714 restart: 715 /* Handle compilation exceptions */ 716 if(setjmp(jbuf.buf)) 717 { 718 result = _JIT_RESULT_FROM_OBJECT(jit_exception_get_last_and_clear()); 719 if(result == JIT_RESULT_MEMORY_FULL) 720 { 721 /* Restart code generation after the memory full condition */ 722 state->restart = 1; 723 goto restart; 724 } 725 726 /* Release allocated code space and exit */ 727 memory_abort(state); 728 goto exit; 729 } 730 731 if(state->restart == 0) 732 { 733 /* Start compilation */ 734 735 /* Perform machine-independent optimizations */ 736 optimize(state->func); 737 738 /* Prepare data needed for code generation */ 739 codegen_prepare(state); 740 741 /* Allocate some space */ 742 memory_acquire(state); 743 memory_alloc(state); 744 } 745 else 746 { 747 /* Restart compilation */ 748 749 /* Clean up the compilation state */ 750 cleanup_on_restart(&state->gen, state->func); 751 752 /* Allocate more space */ 753 memory_realloc(state); 754 } 755 756 #ifdef _JIT_COMPILE_DEBUG 757 if(state->restart == 0) 758 { 759 printf("\n*** Start code generation ***\n\n"); 760 } 761 else 762 { 763 printf("\n*** Restart code generation ***\n\n"); 764 } 765 state->func->builder->block_count = 0; 766 state->func->builder->insn_count = 0; 767 #endif 768 769 #ifdef jit_extra_gen_init 770 /* Initialize information that may need to be reset both 771 on start and restart */ 772 jit_extra_gen_init(&state->gen); 773 #endif 774 775 /* Perform code generation */ 776 codegen(state); 777 778 #ifdef jit_extra_gen_cleanup 779 /* Clean up the extra code generation state */ 780 jit_extra_gen_cleanup(&state->gen); 781 #endif 782 783 /* End the function's output process */ 784 memory_flush(state); 785 786 /* Compilation done, no exceptions occurred */ 787 result = JIT_RESULT_OK; 788 789 exit: 790 /* Release the memory context */ 791 memory_release(state); 792 793 /* Restore the "setjmp" context */ 794 _jit_unwind_pop_setjmp(); 795 796 /* Restore user's exception handler */ 797 jit_exception_set_handler(handler); 798 799 return result; 800 } 801 802 /*@ 803 * @deftypefun int jit_compile (jit_function_t @var{func}) 804 * Compile a function to its executable form. If the function was 805 * already compiled, then do nothing. Returns zero on error. 806 * 807 * If an error occurs, you can use @code{jit_function_abandon} to 808 * completely destroy the function. Once the function has been compiled 809 * successfully, it can no longer be abandoned. 810 * 811 * Sometimes you may wish to recompile a function, to apply greater 812 * levels of optimization the second time around. You must call 813 * @code{jit_function_set_recompilable} before you compile the function 814 * the first time. On the second time around, build the function's 815 * instructions again, and call @code{jit_compile} a second time. 816 * @end deftypefun 817 @*/ 818 int 819 jit_compile(jit_function_t func) 820 { 821 _jit_compile_t state; 822 int result; 823 824 /* Bail out on invalid parameter */ 825 if(!func) 826 { 827 return JIT_RESULT_NULL_FUNCTION; 828 } 829 830 /* Bail out if there is nothing to do here */ 831 if(!func->builder) 832 { 833 if(func->is_compiled) 834 { 835 /* The function is already compiled, and we don't need to recompile */ 836 return JIT_RESULT_OK; 837 } 838 else 839 { 840 /* We don't have anything to compile at all */ 841 return JIT_RESULT_NULL_FUNCTION; 842 } 843 } 844 845 /* Compile and record the entry point */ 846 result = compile(&state, func); 847 if(result == JIT_RESULT_OK) 848 { 849 func->entry_point = state.gen.code_start; 850 func->is_compiled = 1; 851 852 /* Free the builder structure, which we no longer require */ 853 _jit_function_free_builder(func); 854 } 855 856 return result; 857 } 858 859 /*@ 860 * @deftypefun int jit_compile_entry (jit_function_t @var{func}, void **@var{entry_point}) 861 * Compile a function to its executable form but do not make it 862 * available for invocation yet. It may be made available later 863 * with @code{jit_function_setup_entry}. 864 * @end deftypefun 865 @*/ 866 int 867 jit_compile_entry(jit_function_t func, void **entry_point) 868 { 869 _jit_compile_t state; 870 int result; 871 872 /* Init entry_point */ 873 if(entry_point) 874 { 875 *entry_point = 0; 876 } 877 else 878 { 879 return JIT_RESULT_NULL_REFERENCE; 880 } 881 882 /* Bail out on invalid parameter */ 883 if(!func) 884 { 885 return JIT_RESULT_NULL_FUNCTION; 886 } 887 888 /* Bail out if there is nothing to do here */ 889 if(!func->builder) 890 { 891 if(func->is_compiled) 892 { 893 /* The function is already compiled, and we don't need to recompile */ 894 *entry_point = func->entry_point; 895 return JIT_RESULT_OK; 896 } 897 else 898 { 899 /* We don't have anything to compile at all */ 900 return JIT_RESULT_NULL_FUNCTION; 901 } 902 } 903 904 /* Compile and return the entry point */ 905 result = compile(&state, func); 906 if(result == JIT_RESULT_OK) 907 { 908 *entry_point = state.gen.code_start; 909 } 910 911 return result; 912 } 913 914 /*@ 915 * @deftypefun int jit_function_setup_entry (jit_function_t @var{func}, void *@var{entry_point}) 916 * Make a function compiled with @code{jit_function_compile_entry} 917 * available for invocation and free the resources used for 918 * compilation. If @var{entry_point} is null then it only 919 * frees the resources. 920 * @end deftypefun 921 @*/ 922 void 923 jit_function_setup_entry(jit_function_t func, void *entry_point) 924 { 925 /* Bail out if we have nothing to do */ 926 if(!func) 927 { 928 return; 929 } 930 /* Record the entry point */ 931 if(entry_point) 932 { 933 func->entry_point = entry_point; 934 func->is_compiled = 1; 935 } 936 _jit_function_free_builder(func); 937 } 938 939 /*@ 940 * @deftypefun int jit_function_compile (jit_function_t @var{func}) 941 * Compile a function to its executable form. If the function was 942 * already compiled, then do nothing. Returns zero on error. 943 * 944 * If an error occurs, you can use @code{jit_function_abandon} to 945 * completely destroy the function. Once the function has been compiled 946 * successfully, it can no longer be abandoned. 947 * 948 * Sometimes you may wish to recompile a function, to apply greater 949 * levels of optimization the second time around. You must call 950 * @code{jit_function_set_recompilable} before you compile the function 951 * the first time. On the second time around, build the function's 952 * instructions again, and call @code{jit_function_compile} 953 * a second time. 954 * @end deftypefun 955 @*/ 956 int 957 jit_function_compile(jit_function_t func) 958 { 959 return (JIT_RESULT_OK == jit_compile(func)); 960 } 961 962 /*@ 963 * @deftypefun int jit_function_compile_entry (jit_function_t @var{func}, void **@var{entry_point}) 964 * Compile a function to its executable form but do not make it 965 * available for invocation yet. It may be made available later 966 * with @code{jit_function_setup_entry}. 967 * @end deftypefun 968 @*/ 969 int 970 jit_function_compile_entry(jit_function_t func, void **entry_point) 971 { 972 return (JIT_RESULT_OK == jit_compile_entry(func, entry_point)); 973 } 974 975 void * 976 _jit_function_compile_on_demand(jit_function_t func) 977 { 978 _jit_compile_t state; 979 int result; 980 981 /* Lock down the context */ 982 jit_context_build_start(func->context); 983 984 /* Fast return if we are already compiled */ 985 if(func->is_compiled) 986 { 987 jit_context_build_end(func->context); 988 return func->entry_point; 989 } 990 991 if(!func->on_demand) 992 { 993 /* Bail out with an error if the user didn't supply an 994 on-demand compiler */ 995 result = JIT_RESULT_COMPILE_ERROR; 996 } 997 else 998 { 999 /* Call the user's on-demand compiler. */ 1000 result = (func->on_demand)(func); 1001 if(result == JIT_RESULT_OK && !func->is_compiled) 1002 { 1003 /* Compile the function if the user didn't do so */ 1004 result = compile(&state, func); 1005 if(result == JIT_RESULT_OK) 1006 { 1007 func->entry_point = state.gen.code_start; 1008 func->is_compiled = 1; 1009 } 1010 } 1011 _jit_function_free_builder(func); 1012 } 1013 1014 /* Unlock the context and report the result */ 1015 jit_context_build_end(func->context); 1016 if(result != JIT_RESULT_OK) 1017 { 1018 jit_exception_builtin(result); 1019 /* Normally this should be unreachable but just in case... */ 1020 return 0; 1021 } 1022 1023 return func->entry_point; 1024 } 1025 1026 #define JIT_CACHE_NO_OFFSET (~((unsigned long)0)) 1027 1028 unsigned long 1029 _jit_function_get_bytecode(jit_function_t func, 1030 void *func_info, void *pc, int exact) 1031 { 1032 unsigned long offset = JIT_CACHE_NO_OFFSET; 1033 void *start; 1034 unsigned long native_offset; 1035 jit_varint_decoder_t decoder; 1036 jit_uint off, noff; 1037 1038 start = _jit_memory_get_function_start(func->context, func_info); 1039 native_offset = pc - start; 1040 1041 _jit_varint_init_decoder(&decoder, func->bytecode_offset); 1042 for(;;) 1043 { 1044 off = _jit_varint_decode_uint(&decoder); 1045 noff = _jit_varint_decode_uint(&decoder); 1046 if(_jit_varint_decode_end(&decoder)) 1047 { 1048 if(exact) 1049 { 1050 offset = JIT_CACHE_NO_OFFSET; 1051 } 1052 break; 1053 } 1054 if(noff >= native_offset) 1055 { 1056 if(noff == native_offset) 1057 { 1058 offset = off; 1059 } 1060 else if (exact) 1061 { 1062 offset = JIT_CACHE_NO_OFFSET; 1063 } 1064 break; 1065 } 1066 offset = off; 1067 } 1068 1069 return offset; 1070 }