Class: RubyVM::RJIT::Compiler
- Inherits:
-
Object
- Object
- RubyVM::RJIT::Compiler
- Defined in:
- lib/ruby_vm/rjit/compiler.rb
Instance Attribute Summary collapse
-
#write_pos ⇒ Object
Returns the value of attribute write_pos.
Class Method Summary collapse
Instance Method Summary collapse
-
#branch_stub_hit(branch_stub, cfp, target0_p) ⇒ Integer
Compile a branch stub.
-
#compile(iseq, cfp) ⇒ Object
Compile an ISEQ from its entry point.
-
#entry_stub_hit(entry_stub, cfp) ⇒ Object
Compile an entry.
-
#initialize ⇒ Compiler
constructor
A new instance of Compiler.
- #invalidate_block(block) ⇒ Object
- #invalidate_blocks(iseq, pc) ⇒ Object
Constructor Details
#initialize ⇒ Compiler
Returns a new instance of Compiler.
48 49 50 51 52 53 54 55 56 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 48 def initialize mem_size = C.rjit_opts.exec_mem_size * 1024 * 1024 mem_block = C.mmap(mem_size) @cb = CodeBlock.new(mem_block: mem_block, mem_size: mem_size / 2) @ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true) @exit_compiler = ExitCompiler.new @insn_compiler = InsnCompiler.new(@cb, @ocb, @exit_compiler) Invariants.initialize(@cb, @ocb, self, @exit_compiler) end |
Instance Attribute Details
#write_pos ⇒ Object
Returns the value of attribute write_pos.
42 43 44 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 42 def write_pos @write_pos end |
Class Method Details
.decode_insn(encoded) ⇒ Object
44 45 46 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 44 def self.decode_insn(encoded) INSNS.fetch(C.rb_vm_insn_decode(encoded)) end |
Instance Method Details
#branch_stub_hit(branch_stub, cfp, target0_p) ⇒ Integer
Compile a branch stub.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 122 def branch_stub_hit(branch_stub, cfp, target0_p) # Update cfp->pc for `jit.at_current_insn?` target = target0_p ? branch_stub.target0 : branch_stub.target1 cfp.pc = target.pc # Reuse an existing block if it already exists block = find_block(branch_stub.iseq, target.pc, target.ctx) # If the branch stub's jump is the last code, allow overwriting part of # the old branch code with the new block code. fallthrough = block.nil? && @cb.write_addr == branch_stub.end_addr if fallthrough # If the branch stub's jump is the last code, allow overwriting part of # the old branch code with the new block code. @cb.set_write_addr(branch_stub.start_addr) branch_stub.shape = target0_p ? Next0 : Next1 Assembler.new.tap do |branch_asm| branch_stub.compile.call(branch_asm) @cb.write(branch_asm) end end # Reuse or generate a block if block target.address = block.start_addr else jit = JITState.new(iseq: branch_stub.iseq, cfp:) target.address = Assembler.new.then do |asm| compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup) @cb.write(asm) end block = jit.block end block.incoming << branch_stub # prepare for invalidate_block # Re-generate the branch code for non-fallthrough cases unless fallthrough @cb.with_write_addr(branch_stub.start_addr) do branch_asm = Assembler.new branch_stub.compile.call(branch_asm) @cb.write(branch_asm) end end return target.address rescue Exception => e STDERR.puts e. exit 1 end |
#compile(iseq, cfp) ⇒ Object
Compile an ISEQ from its entry point.
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 61 def compile(iseq, cfp) return unless supported_platform? pc = cfp.pc.to_i jit = JITState.new(iseq:, cfp:) asm = Assembler.new compile_prologue(asm, iseq, pc) compile_block(asm, jit:, pc:) iseq.body.jit_entry = @cb.write(asm) rescue Exception => e STDERR.puts "#{e.class}: #{e.}" STDERR.puts e.backtrace exit 1 end |
#entry_stub_hit(entry_stub, cfp) ⇒ Object
Compile an entry.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 77 def entry_stub_hit(entry_stub, cfp) # Compile a new entry guard as a next entry pc = cfp.pc.to_i next_entry = Assembler.new.then do |asm| compile_entry_chain_guard(asm, cfp.iseq, pc) @cb.write(asm) end # Try to find an existing compiled version of this block ctx = Context.new block = find_block(cfp.iseq, pc, ctx) if block # If an existing block is found, generate a jump to the block. asm = Assembler.new asm.jmp(block.start_addr) @cb.write(asm) else # If this block hasn't yet been compiled, generate blocks after the entry guard. asm = Assembler.new jit = JITState.new(iseq: cfp.iseq, cfp:) compile_block(asm, jit:, pc:, ctx:) @cb.write(asm) block = jit.block end # Regenerate the previous entry @cb.with_write_addr(entry_stub.start_addr) do # The last instruction of compile_entry_chain_guard is jne asm = Assembler.new asm.jne(next_entry) @cb.write(asm) end return block.start_addr rescue Exception => e STDERR.puts e. exit 1 end |
#invalidate_block(block) ⇒ Object
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 186 def invalidate_block(block) iseq = block.iseq # Avoid touching GCed ISEQs. We assume it won't be re-entered. return unless C.imemo_type_p(iseq, C.imemo_iseq) # Remove this block from the version array remove_block(iseq, block) # Invalidate the block with entry exit unless block.invalidated @cb.with_write_addr(block.start_addr) do asm = Assembler.new asm.comment('invalidate_block') asm.jmp(block.entry_exit) @cb.write(asm) end block.invalidated = true end # Re-stub incoming branches block.incoming.each do |branch_stub| target = [branch_stub.target0, branch_stub.target1].compact.find do |target| target.pc == block.pc && target.ctx == block.ctx end next if target.nil? # TODO: Could target.address be a stub address? Is invalidation not needed in that case? # If the target being re-generated is currently a fallthrough block, # the fallthrough code must be rewritten with a jump to the stub. if target.address == branch_stub.end_addr branch_stub.shape = Default end target.address = Assembler.new.then do |ocb_asm| @exit_compiler.compile_branch_stub(block.ctx, ocb_asm, branch_stub, target == branch_stub.target0) @ocb.write(ocb_asm) end @cb.with_write_addr(branch_stub.start_addr) do branch_asm = Assembler.new branch_stub.compile.call(branch_asm) @cb.write(branch_asm) end end end |
#invalidate_blocks(iseq, pc) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/ruby_vm/rjit/compiler.rb', line 174 def invalidate_blocks(iseq, pc) list_blocks(iseq, pc).each do |block| invalidate_block(block) end # If they were the ISEQ's first blocks, re-compile RJIT entry as well if iseq.body.iseq_encoded.to_i == pc iseq.body.jit_entry = 0 iseq.body.jit_entry_calls = 0 end end |