Store MJIT blocks on each ISEQ

This commit is contained in:
Takashi Kokubun 2023-02-24 13:52:43 -08:00
parent 63d96ccbcd
commit 32e6f15beb
Notes: git 2023-03-06 07:29:53 +00:00
6 changed files with 41 additions and 33 deletions

4
iseq.c
View File

@ -357,7 +357,7 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
if (reference_updating) { if (reference_updating) {
#if USE_MJIT #if USE_MJIT
rb_mjit_iseq_update_references(iseq); rb_mjit_iseq_update_references(body);
#endif #endif
#if USE_YJIT #if USE_YJIT
rb_yjit_iseq_update_references(body->yjit_payload); rb_yjit_iseq_update_references(body->yjit_payload);
@ -365,7 +365,7 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
} }
else { else {
#if USE_MJIT #if USE_MJIT
mjit_mark_cc_entries(body); rb_mjit_iseq_mark(body->mjit_blocks);
#endif #endif
#if USE_YJIT #if USE_YJIT
rb_yjit_iseq_mark(body->yjit_payload); rb_yjit_iseq_mark(body->yjit_payload);

View File

@ -29,21 +29,12 @@ module RubyVM::MJIT
# Scratch registers: rax, rcx # Scratch registers: rax, rcx
# Mark objects in this Array during GC
GC_REFS = []
class Compiler class Compiler
attr_accessor :write_pos attr_accessor :write_pos
IseqBlocks = Hash.new do |iseq_pc_ctx, iseq|
iseq_pc_ctx[iseq] = Hash.new do |pc_ctx, pc|
pc_ctx[pc] = {}
end
end
DeadBlocks = [] # invalidated IseqBlocks, but kept for safety
def self.reset_blocks
DeadBlocks << IseqBlocks.dup
IseqBlocks.clear
end
def self.decode_insn(encoded) def self.decode_insn(encoded)
INSNS.fetch(C.rb_vm_insn_decode(encoded)) INSNS.fetch(C.rb_vm_insn_decode(encoded))
end end
@ -268,24 +259,34 @@ module RubyVM::MJIT
end end
def list_blocks(iseq, pc) def list_blocks(iseq, pc)
IseqBlocks[iseq.to_i][pc].values mjit_blocks(iseq)[pc].values
end end
# @param [Integer] pc # @param [Integer] pc
# @param [RubyVM::MJIT::Context] ctx # @param [RubyVM::MJIT::Context] ctx
# @return [RubyVM::MJIT::Block,NilClass] # @return [RubyVM::MJIT::Block,NilClass]
def find_block(iseq, pc, ctx) def find_block(iseq, pc, ctx)
IseqBlocks[iseq.to_i][pc][ctx] mjit_blocks(iseq)[pc][ctx]
end end
# @param [RubyVM::MJIT::Block] block # @param [RubyVM::MJIT::Block] block
def set_block(iseq, block) def set_block(iseq, block)
IseqBlocks[iseq.to_i][block.pc][block.ctx] = block mjit_blocks(iseq)[block.pc][block.ctx] = block
end end
# @param [RubyVM::MJIT::Block] block # @param [RubyVM::MJIT::Block] block
def remove_block(iseq, block) def remove_block(iseq, block)
IseqBlocks[iseq.to_i][block.pc].delete(block.ctx) mjit_blocks(iseq)[block.pc].delete(block.ctx)
end
def mjit_blocks(iseq)
unless iseq.body.mjit_blocks
iseq.body.mjit_blocks = Hash.new { |h, k| h[k] = {} }
# For some reason, rb_mjit_iseq_mark didn't protect this Hash
# from being freed. So we rely on GC_REFS to keep the Hash.
GC_REFS << iseq.body.mjit_blocks
end
iseq.body.mjit_blocks
end end
end end
end end

View File

@ -112,12 +112,11 @@ module RubyVM::MJIT
end end
@patches.clear @patches.clear
# Avoid reusing past code
Compiler.reset_blocks
C.mjit_for_each_iseq do |iseq| C.mjit_for_each_iseq do |iseq|
# Disable entering past code # Avoid entering past code
iseq.body.jit_func = 0 iseq.body.jit_func = 0
# Avoid reusing past code
iseq.body.mjit_blocks.clear if iseq.body.mjit_blocks
# Compile this again if not converted to trace_* insns # Compile this again if not converted to trace_* insns
iseq.body.total_calls = 0 iseq.body.total_calls = 0
end end

24
mjit.c
View File

@ -272,12 +272,6 @@ mjit_child_after_fork(void)
// TODO: remove this // TODO: remove this
} }
void
mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body)
{
// TODO: implement
}
// Compile ISeq to C code in `f`. It returns true if it succeeds to compile. // Compile ISeq to C code in `f`. It returns true if it succeeds to compile.
bool bool
mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id) mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id)
@ -394,11 +388,13 @@ mjit_iseq_update_references(void *data)
} }
void void
rb_mjit_iseq_update_references(const rb_iseq_t *iseq) rb_mjit_iseq_update_references(struct rb_iseq_constant_body *const body)
{ {
if (!mjit_enabled) return; if (!mjit_enabled) return;
// TODO: update mjit_blocks if (body->mjit_blocks) {
body->mjit_blocks = rb_gc_location(body->mjit_blocks);
}
// Asynchronously hook the Ruby code to avoid allocation during GC.compact. // Asynchronously hook the Ruby code to avoid allocation during GC.compact.
// Using _one because it's too slow to invalidate all for each ISEQ. Thus // Using _one because it's too slow to invalidate all for each ISEQ. Thus
@ -406,6 +402,18 @@ rb_mjit_iseq_update_references(const rb_iseq_t *iseq)
rb_postponed_job_register_one(0, mjit_iseq_update_references, NULL); rb_postponed_job_register_one(0, mjit_iseq_update_references, NULL);
} }
void
rb_mjit_iseq_mark(VALUE mjit_blocks)
{
if (!mjit_enabled) return;
// Note: This wasn't enough for some reason.
// We actually rely on RubyVM::MJIT::GC_REFS to mark this.
if (mjit_blocks) {
rb_gc_mark_movable(mjit_blocks);
}
}
// TODO: Use this in more places // TODO: Use this in more places
VALUE VALUE
rb_mjit_iseq_new(rb_iseq_t *iseq) rb_mjit_iseq_new(rb_iseq_t *iseq)

4
mjit.h
View File

@ -106,9 +106,9 @@ extern void mjit_cancel_all(const char *reason);
extern bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id); extern bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id);
extern void mjit_init(const struct mjit_options *opts); extern void mjit_init(const struct mjit_options *opts);
extern void mjit_free_iseq(const rb_iseq_t *iseq); extern void mjit_free_iseq(const rb_iseq_t *iseq);
extern void rb_mjit_iseq_update_references(const rb_iseq_t *iseq); extern void rb_mjit_iseq_update_references(struct rb_iseq_constant_body *const body);
extern void mjit_mark(void); extern void mjit_mark(void);
extern void mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body); extern void rb_mjit_iseq_mark(VALUE mjit_blocks);
extern void mjit_notify_waitpid(int exit_code); extern void mjit_notify_waitpid(int exit_code);
extern void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop); extern void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);

View File

@ -511,7 +511,7 @@ struct rb_iseq_constant_body {
#endif #endif
#if USE_MJIT #if USE_MJIT
// MJIT stores { Context => Block } for each iseq. // MJIT stores some data on each iseq.
VALUE mjit_blocks; VALUE mjit_blocks;
#endif #endif