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)
This commit is contained in:
Alan Wu 2020-10-21 18:15:43 -04:00
Родитель d49edada2e
Коммит c2cb6a6fd3
1 изменённых файлов: 8 добавлений и 9 удалений

Просмотреть файл

@ -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));