mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
7424ea184f
This commit implements Objects on Variable Width Allocation. This allows Objects with more ivars to be embedded (i.e. contents directly follow the object header) which improves performance through better cache locality.
110 lines
6.1 KiB
Text
110 lines
6.1 KiB
Text
% # -*- C -*-
|
|
% # Copyright (c) 2018 Takashi Kokubun. All rights reserved.
|
|
% #
|
|
% # This file is a part of the programming language Ruby. Permission is hereby
|
|
% # granted, to either redistribute and/or modify this file, provided that the
|
|
% # conditions mentioned in the file COPYING are met. Consult the file for
|
|
% # details.
|
|
%
|
|
% # Optimized case of get_instancevariable instruction.
|
|
#if OPT_IC_FOR_IVAR
|
|
{
|
|
% # compiler: Prepare operands which may be used by `insn.call_attribute`
|
|
% insn.opes.each_with_index do |ope, i|
|
|
MAYBE_UNUSED(<%= ope.fetch(:decl) %>) = (<%= ope.fetch(:type) %>)operands[<%= i %>];
|
|
% end
|
|
% # compiler: Use copied IVC to avoid race condition
|
|
IVC ic_copy = &(status->is_entries + ((union iseq_inline_storage_entry *)ic - body->is_entries))->iv_cache;
|
|
%
|
|
if (!status->compile_info->disable_ivar_cache && ic_copy->entry) { // Only ic_copy is enabled.
|
|
% # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
|
|
% # <%= render 'mjit_compile_pc_and_sp', locals: { insn: insn } -%>
|
|
%
|
|
% # JIT: prepare vm_getivar/vm_setivar arguments and variables
|
|
fprintf(f, "{\n");
|
|
fprintf(f, " VALUE obj = GET_SELF();\n");
|
|
fprintf(f, " const uint32_t index = %u;\n", (ic_copy->entry->index));
|
|
if (status->merge_ivar_guards_p) {
|
|
% # JIT: Access ivar without checking these VM_ASSERTed prerequisites as we checked them in the beginning of `mjit_compile_body`
|
|
fprintf(f, " VM_ASSERT(RB_TYPE_P(obj, T_OBJECT));\n");
|
|
fprintf(f, " VM_ASSERT((rb_serial_t)%"PRI_SERIALT_PREFIX"u == RCLASS_SERIAL(RBASIC(obj)->klass));\n", ic_copy->entry->class_serial);
|
|
fprintf(f, " VM_ASSERT(index < ROBJECT_NUMIV(obj));\n");
|
|
% if insn.name == 'setinstancevariable'
|
|
#if USE_RVARGC
|
|
fprintf(f, " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && index < ROBJECT_NUMIV(obj))) {\n");
|
|
fprintf(f, " RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], stack[%d]);\n", b->stack_size - 1);
|
|
#else
|
|
fprintf(f, " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && %s)) {\n", status->max_ivar_index >= ROBJECT_EMBED_LEN_MAX ? "true" : "RB_FL_ANY_RAW(obj, ROBJECT_EMBED)");
|
|
fprintf(f, " RB_OBJ_WRITE(obj, &ROBJECT(obj)->as.%s, stack[%d]);\n",
|
|
status->max_ivar_index >= ROBJECT_EMBED_LEN_MAX ? "heap.ivptr[index]" : "ary[index]", b->stack_size - 1);
|
|
#endif
|
|
fprintf(f, " }\n");
|
|
% else
|
|
fprintf(f, " VALUE val;\n");
|
|
#if USE_RVARGC
|
|
fprintf(f, " if (LIKELY(index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n");
|
|
#else
|
|
fprintf(f, " if (LIKELY(%s && (val = ROBJECT(obj)->as.%s) != Qundef)) {\n",
|
|
status->max_ivar_index >= ROBJECT_EMBED_LEN_MAX ? "true" : "RB_FL_ANY_RAW(obj, ROBJECT_EMBED)",
|
|
status->max_ivar_index >= ROBJECT_EMBED_LEN_MAX ? "heap.ivptr[index]" : "ary[index]");
|
|
#endif
|
|
fprintf(f, " stack[%d] = val;\n", b->stack_size);
|
|
fprintf(f, " }\n");
|
|
%end
|
|
}
|
|
else {
|
|
fprintf(f, " const rb_serial_t ic_serial = (rb_serial_t)%"PRI_SERIALT_PREFIX"u;\n", ic_copy->entry->class_serial);
|
|
% # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar)
|
|
% if insn.name == 'setinstancevariable'
|
|
fprintf(f, " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && !RB_OBJ_FROZEN_RAW(obj))) {\n");
|
|
fprintf(f, " VALUE *ptr = ROBJECT_IVPTR(obj);\n");
|
|
fprintf(f, " RB_OBJ_WRITE(obj, &ptr[index], stack[%d]);\n", b->stack_size - 1);
|
|
fprintf(f, " }\n");
|
|
% else
|
|
fprintf(f, " VALUE val;\n");
|
|
fprintf(f, " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n");
|
|
fprintf(f, " stack[%d] = val;\n", b->stack_size);
|
|
fprintf(f, " }\n");
|
|
% end
|
|
}
|
|
fprintf(f, " else {\n");
|
|
fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", pos);
|
|
fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size);
|
|
fprintf(f, " goto ivar_cancel;\n");
|
|
fprintf(f, " }\n");
|
|
|
|
% # compiler: Move JIT compiler's internal stack pointer
|
|
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
|
fprintf(f, "}\n");
|
|
break;
|
|
}
|
|
% if insn.name == 'getinstancevariable'
|
|
else if (!status->compile_info->disable_exivar_cache && ic_copy->entry) {
|
|
% # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
|
|
% # <%= render 'mjit_compile_pc_and_sp', locals: { insn: insn } -%>
|
|
%
|
|
% # JIT: prepare vm_getivar's arguments and variables
|
|
fprintf(f, "{\n");
|
|
fprintf(f, " VALUE obj = GET_SELF();\n");
|
|
fprintf(f, " const rb_serial_t ic_serial = (rb_serial_t)%"PRI_SERIALT_PREFIX"u;\n", ic_copy->entry->class_serial);
|
|
fprintf(f, " const uint32_t index = %u;\n", ic_copy->entry->index);
|
|
% # JIT: cache hit path of vm_getivar, or cancel JIT (recompile it without any ivar optimization)
|
|
fprintf(f, " struct gen_ivtbl *ivtbl;\n");
|
|
fprintf(f, " VALUE val;\n");
|
|
fprintf(f, " if (LIKELY(FL_TEST_RAW(obj, FL_EXIVAR) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl) && index < ivtbl->numiv && (val = ivtbl->ivptr[index]) != Qundef)) {\n");
|
|
fprintf(f, " stack[%d] = val;\n", b->stack_size);
|
|
fprintf(f, " }\n");
|
|
fprintf(f, " else {\n");
|
|
fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", pos);
|
|
fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size);
|
|
fprintf(f, " goto exivar_cancel;\n");
|
|
fprintf(f, " }\n");
|
|
|
|
% # compiler: Move JIT compiler's internal stack pointer
|
|
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
|
fprintf(f, "}\n");
|
|
break;
|
|
}
|
|
% end
|
|
}
|
|
#endif // OPT_IC_FOR_IVAR
|