• dearblue's avatar
    Replace global jump with catch handler implementation · c1f112c4
    dearblue authored
    When a global jump occurs, look at the catch handler table to determine where to jump.
    In that case, `pc` already shows the following instruction, but since the table shows `begin_offset ... end_offset`, the comparison is done with `begin_offset < pc && pc <= end_offset`.
    If there is a corresponding handler, move `pc` to `handler.target_offset` and continue running the VM.
    
    When a global jump across `ensure` is made by `return`, `break`, `next`, `redo` and `retry`, the extended `RBreak` object saves and restores the C-level execution position.
    This extended `RBreak` can have tag information, which makes it a pseudo coroutine (the "tag" mimics CRuby).
    
    The implementation of pseudo coroutines by `RBreak` is summarized by `CHECKPOINT_RESTORE ... CHECKPOINT_MAIN ... CHECKPOINT_END` and `throw_tagged_break` / `unwind_ensure` macros.
    The restart of processing is branched by `RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS)`.
    
    - Not only `rescue` blocks but also `ensure` blocks are now sandwiched between `OP_EXCEPT` and `OP_RAISEIF`.
    
    - Remove the function `ecall()`.
      It is no longer necessary to re-enter the VM to perform an "ensure block".
    
      This will resolves #1888.
    
    - Added instruction `OP_JUW` (Jump while UnWind).
    
      It jumps unconditionally like `OP_JMP`, but searches the catch handler table and executes the ensure block.
      Since it searches the catch handler table, it is much heavier than `OP_JMP`.
    c1f112c4
gc.c 37.8 KB