From c2cb6a6fd38eea3ce91d3370a62aaf6ba15e410a Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Wed, 21 Oct 2020 18:15:43 -0400 Subject: [PATCH] MicroJIT: Read pointer to call cache from call data The call cache changes when the call site becomes polymophic and can result in the generated code falsely assuming cd->cc->cme is not NULL. Here is a crasher: def body(thing) thing.strip end str = "" 10.times { body(str) } body(0) rescue p 'not found' body(str) --- ujit_compile.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ujit_compile.c b/ujit_compile.c index 4dd2c988b1..7beab133c0 100644 --- a/ujit_compile.c +++ b/ujit_compile.c @@ -563,12 +563,14 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) // Pointer to the klass field of the receiver &(recv->klass) x86opnd_t klass_opnd = mem_opnd(64, REG0, offsetof(struct RBasic, klass)); - // FIXME: currently assuming that cc->klass doesn't change - // Ideally we would like the GC to update the klass pointer - // - // Check if we have a cache hit - mov(cb, REG1, const_ptr_opnd((void*)cd->cc->klass)); - cmp(cb, REG1, klass_opnd); + // Load the call cache into REG1 + mov(cb, REG1, const_ptr_opnd(cd)); + x86opnd_t ptr_to_cc = member_opnd(REG1, struct rb_call_data, cc); + mov(cb, REG1, ptr_to_cc); + + // Check the class of the receiver against the call cache + mov(cb, REG0, klass_opnd); + cmp(cb, REG0, mem_opnd(64, REG1, offsetof(struct rb_callcache, klass))); jne_ptr(cb, side_exit); // NOTE: there *has to be* a way to optimize the entry invalidated check @@ -577,9 +579,6 @@ gen_opt_send_without_block(codeblock_t* cb, codeblock_t* ocb, ctx_t* ctx) // Check that the method entry is not invalidated // cd->cc->cme->flags // #define METHOD_ENTRY_INVALIDATED(me) ((me)->flags & IMEMO_FL_USER5) - mov(cb, REG1, const_ptr_opnd(cd)); - x86opnd_t ptr_to_cc = member_opnd(REG1, struct rb_call_data, cc); - mov(cb, REG1, ptr_to_cc); x86opnd_t ptr_to_cme_ = mem_opnd(64, REG1, offsetof(struct rb_callcache, cme_)); mov(cb, REG1, ptr_to_cme_); x86opnd_t flags_opnd = mem_opnd(64, REG1, offsetof(rb_callable_method_entry_t, flags));