Class: RubyVM::RJIT::Invariants

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_vm/rjit/invariants.rb

Class Method Summary collapse

Class Method Details

.assume_bop_not_redefined(jit, klass, op) ⇒ Object

Parameters:



27
28
29
30
31
32
33
# File 'lib/ruby_vm/rjit/invariants.rb', line 27

def assume_bop_not_redefined(jit, klass, op)
  return false unless C.BASIC_OP_UNREDEFINED_P(klass, op)

  ensure_block_entry_exit(jit, cause: 'assume_bop_not_redefined')
  @bop_blocks << jit.block
  true
end

.assume_method_basic_definition(jit, klass, mid) ⇒ Object

Parameters:



42
43
44
45
46
47
48
49
50
# File 'lib/ruby_vm/rjit/invariants.rb', line 42

def assume_method_basic_definition(jit, klass, mid)
  if C.rb_method_basic_definition_p(klass, mid)
    cme = C.rb_callable_method_entry(klass, mid)
    assume_method_lookup_stable(jit, cme)
    true
  else
    false
  end
end

.assume_method_lookup_stable(jit, cme) ⇒ Object

Parameters:



36
37
38
39
# File 'lib/ruby_vm/rjit/invariants.rb', line 36

def assume_method_lookup_stable(jit, cme)
  ensure_block_entry_exit(jit, cause: 'assume_method_lookup_stable')
  @cme_blocks[cme.to_i] << jit.block
end

.assume_stable_constant_names(jit, idlist) ⇒ Object



52
53
54
55
56
57
# File 'lib/ruby_vm/rjit/invariants.rb', line 52

def assume_stable_constant_names(jit, idlist)
  (0..).each do |i|
    break if (id = idlist[i]) == 0
    @const_blocks[id] << jit.block
  end
end

.ensure_block_entry_exit(jit, cause:) ⇒ Object

Parameters:



119
120
121
122
123
124
125
126
127
# File 'lib/ruby_vm/rjit/invariants.rb', line 119

def ensure_block_entry_exit(jit, cause:)
  block = jit.block
  if block.entry_exit.nil?
    block.entry_exit = Assembler.new.then do |asm|
      @exit_compiler.compile_entry_exit(block.pc, block.ctx, asm, cause:)
      @ocb.write(asm)
    end
  end
end

.initialize(cb, ocb, compiler, exit_compiler) ⇒ Object

Called by RubyVM::RJIT::Compiler to lazily initialize this

Parameters:



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/ruby_vm/rjit/invariants.rb', line 11

def initialize(cb, ocb, compiler, exit_compiler)
  @cb = cb
  @ocb = ocb
  @compiler = compiler
  @exit_compiler = exit_compiler
  @bop_blocks = Set.new # TODO: actually invalidate this
  @cme_blocks = Hash.new { |h, k| h[k] = Set.new }
  @const_blocks = Hash.new { |h, k| h[k] = Set.new }
  @patches = {}

  # freeze # workaround a binding.irb issue. TODO: resurrect this
end

.on_cme_invalidate(cme) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ruby_vm/rjit/invariants.rb', line 69

def on_cme_invalidate(cme)
  @cme_blocks.fetch(cme.to_i, []).each do |block|
    @cb.with_write_addr(block.start_addr) do
      asm = Assembler.new
      asm.comment('on_cme_invalidate')
      asm.jmp(block.entry_exit)
      @cb.write(asm)
    end
    # TODO: re-generate branches that refer to this block
  end
  @cme_blocks.delete(cme.to_i)
end

.on_constant_ic_update(iseq, ic, insn_idx) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ruby_vm/rjit/invariants.rb', line 82

def on_constant_ic_update(iseq, ic, insn_idx)
  # TODO: check multi ractor as well
  if ic.entry.ic_cref
    # No need to recompile the slowpath
    return
  end

  pc = iseq.body.iseq_encoded + insn_idx
  insn_name = Compiler.decode_insn(pc.*).name
  if insn_name != :opt_getconstant_path && insn_name != :trace_opt_getconstant_path
    raise 'insn_idx was not at opt_getconstant_path'
  end
  if ic.to_i != pc[1]
    raise 'insn_idx + 1 was not at the updated IC'
  end
  @compiler.invalidate_blocks(iseq, pc.to_i)
end

.on_constant_state_changed(id) ⇒ Object



100
101
102
103
104
# File 'lib/ruby_vm/rjit/invariants.rb', line 100

def on_constant_state_changed(id)
  @const_blocks.fetch(id, []).each do |block|
    @compiler.invalidate_block(block)
  end
end

.on_tracing_invalidate_allObject



106
107
108
# File 'lib/ruby_vm/rjit/invariants.rb', line 106

def on_tracing_invalidate_all
  invalidate_all
end

.on_update_referencesObject



110
111
112
113
114
115
# File 'lib/ruby_vm/rjit/invariants.rb', line 110

def on_update_references
  # Give up. In order to support GC.compact, you'd have to update ISEQ
  # addresses in BranchStub, etc. Ideally, we'd need to update moved
  # pointers in JITed code here, but we just invalidate all for now.
  invalidate_all
end

.record_global_inval_patch(asm, target) ⇒ Object

Parameters:



60
61
62
63
64
65
66
67
# File 'lib/ruby_vm/rjit/invariants.rb', line 60

def record_global_inval_patch(asm, target)
  asm.pos_marker do |address|
    if @patches.key?(address)
      raise 'multiple patches in the same address'
    end
    @patches[address] = target
  end
end