aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ruby_vm
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2023-04-02 23:34:57 -0700
committerTakashi Kokubun <takashikkbn@gmail.com>2023-04-02 23:37:15 -0700
commitd876c008ecb823a042021bebdb6667ff0c8ff028 (patch)
tree4a66d1addd5f7fa51218648cf31e5daf97096b3b /lib/ruby_vm
parent3bacc3877a8d61a2e66f6b9d874a60f3be0e7f53 (diff)
downloadruby-d876c008ecb823a042021bebdb6667ff0c8ff028.tar.gz
RJIT: Limit the number of versions per block
Diffstat (limited to 'lib/ruby_vm')
-rw-r--r--lib/ruby_vm/rjit/compiler.rb31
1 files changed, 31 insertions, 0 deletions
diff --git a/lib/ruby_vm/rjit/compiler.rb b/lib/ruby_vm/rjit/compiler.rb
index e714669889..5eebef9a77 100644
--- a/lib/ruby_vm/rjit/compiler.rb
+++ b/lib/ruby_vm/rjit/compiler.rb
@@ -34,6 +34,10 @@ module RubyVM::RJIT
# Mark objects in this Array during GC
GC_REFS = []
+ # Maximum number of versions per block
+ # 1 means always create generic versions
+ MAX_VERSIONS = 4
+
class Compiler
attr_accessor :write_pos
@@ -277,6 +281,7 @@ module RubyVM::RJIT
# @param asm [RubyVM::RJIT::Assembler]
def compile_block(asm, jit:, pc:, ctx: Context.new)
# Mark the block start address and prepare an exit code storage
+ ctx = limit_block_versions(jit.iseq, pc, ctx)
block = Block.new(iseq: jit.iseq, pc:, ctx: ctx.dup)
jit.block = block
asm.block(block)
@@ -346,6 +351,32 @@ module RubyVM::RJIT
end
end
+ # Produce a generic context when the block version limit is hit for the block
+ def limit_block_versions(iseq, pc, ctx)
+ # Guard chains implement limits separately, do nothing
+ if ctx.chain_depth > 0
+ return ctx.dup
+ end
+
+ # If this block version we're about to add will hit the version limit
+ if list_blocks(iseq, pc).size + 1 >= MAX_VERSIONS
+ # Produce a generic context that stores no type information,
+ # but still respects the stack_size and sp_offset constraints.
+ # This new context will then match all future requests.
+ generic_ctx = Context.new
+ generic_ctx.stack_size = ctx.stack_size
+ generic_ctx.sp_offset = ctx.sp_offset
+
+ if ctx.diff(generic_ctx) == TypeDiff::Incompatible
+ raise 'should substitute a compatible context'
+ end
+
+ return generic_ctx
+ end
+
+ return ctx.dup
+ end
+
def list_blocks(iseq, pc)
rjit_blocks(iseq)[pc]
end