@@ -3894,14 +3894,25 @@ impl Function {
38943894 }
38953895
38963896 self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
3897+
3898+ let id = unsafe { get_cme_def_body_attr_id(cme) };
38973899 if let Some(profiled_type) = profiled_type {
38983900 let argc = unsafe { vm_ci_argc(ci) } as i32;
38993901 recv = self.push_insn(block, Insn::GuardType { val: recv, guard_type: Type::from_profiled_type(profiled_type), state, recompile: Some(Recompile::ProfileSend{ argc }) });
3900- }
3901- let id = unsafe { get_cme_def_body_attr_id(cme) };
39023902
3903- let getivar = self.push_insn(block, Insn::GetIvar { self_val: recv, id, ic: std::ptr::null(), state });
3904- self.make_equal_to(insn_id, getivar);
3903+ let replacement = self.try_emit_optimized_getivar(block, recv, id, profiled_type, state).unwrap_or_else(|counter| {
3904+ self.count(block, counter);
3905+ self.push_insn(block, Insn::GetIvar { self_val: recv, id, ic: std::ptr::null(), state })
3906+ });
3907+ self.make_equal_to(insn_id, replacement);
3908+ } else {
3909+ // No shape information, just static class information
3910+ let resolution = self.resolve_receiver_type_from_profile(recv, state);
3911+ let counter = Self::getivar_fallback_reason(resolution, std::ptr::null());
3912+ self.count(block, counter);
3913+ let getivar = self.push_insn(block, Insn::GetIvar { self_val: recv, id, ic: std::ptr::null(), state });
3914+ self.make_equal_to(insn_id, getivar);
3915+ }
39053916 } else if let (false, VM_METHOD_TYPE_ATTRSET, &[val]) = (has_block, def_type, args.as_slice()) {
39063917 // Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
39073918 // We omit gen_prepare_non_leaf_call on gen_getivar, so it's unsafe to raise for multi-ractor mode.
@@ -4904,43 +4915,35 @@ impl Function {
49044915 }
49054916 }
49064917
4918+ fn try_emit_optimized_getivar(&mut self, block: BlockId, self_val: InsnId, id: ID, profiled_type: ProfiledType, state: InsnId) -> Result<InsnId, Counter> {
4919+ if profiled_type.flags().is_immediate() {
4920+ // Instance variable lookups on immediate values are always nil
4921+ return Err(Counter::getivar_fallback_immediate);
4922+ }
4923+ assert!(profiled_type.shape().is_valid());
4924+ if profiled_type.shape().is_complex() {
4925+ // too-complex shapes can't use index access
4926+ return Err(Counter::getivar_fallback_complex);
4927+ }
4928+ if self.policy.no_side_exits {
4929+ // On the final version, skip GetIvar shape specialization.
4930+ // iseq_to_hir already generates polymorphic branches with a
4931+ // GetIvar C call fallback for getinstancevariable, so we don't
4932+ // need to wrap it again here.
4933+ return Err(Counter::getivar_fallback_no_side_exits);
4934+ }
4935+ let self_val = self.guard_heap(block, self_val, state);
4936+ let shape = self.load_shape(block, self_val);
4937+ self.guard_shape(block, shape, profiled_type.shape(), state, Some(Recompile::ProfileSelf));
4938+ Ok(self.load_ivar(block, self_val, profiled_type, id))
4939+ }
4940+
49074941 fn optimize_getivar(&mut self) {
49084942 for block in self.reverse_post_order() {
49094943 let old_insns = std::mem::take(&mut self.blocks[block.0].insns);
49104944 assert!(self.blocks[block.0].insns.is_empty());
49114945 for insn_id in old_insns {
49124946 match self.find(insn_id) {
4913- Insn::GetIvar { self_val, id, ic, state } => {
4914- let Some(recv_type) = self.profiled_type_of_at(self_val, state) else {
4915- let resolution = self.resolve_receiver_type_from_profile(self_val, state);
4916- let counter = Self::getivar_fallback_reason(resolution, ic);
4917- self.count(block, counter);
4918- self.push_insn_id(block, insn_id); continue;
4919- };
4920- if recv_type.flags().is_immediate() {
4921- // Instance variable lookups on immediate values are always nil
4922- self.count(block, Counter::getivar_fallback_immediate);
4923- self.push_insn_id(block, insn_id); continue;
4924- }
4925- assert!(recv_type.shape().is_valid());
4926- if recv_type.shape().is_complex() {
4927- // too-complex shapes can't use index access
4928- self.count(block, Counter::getivar_fallback_complex);
4929- self.push_insn_id(block, insn_id); continue;
4930- }
4931- if self.policy.no_side_exits {
4932- // On the final version, skip GetIvar shape specialization.
4933- // iseq_to_hir already generates polymorphic branches with a
4934- // GetIvar C call fallback for getinstancevariable, so we don't
4935- // need to wrap it again here.
4936- self.push_insn_id(block, insn_id); continue;
4937- }
4938- let self_val = self.guard_heap(block, self_val, state);
4939- let shape = self.load_shape(block, self_val);
4940- self.guard_shape(block, shape, recv_type.shape(), state, Some(Recompile::ProfileSelf));
4941- let replacement = self.load_ivar(block, self_val, recv_type, id);
4942- self.make_equal_to(insn_id, replacement);
4943- }
49444947 Insn::SetIvar { self_val, id, val, state, ic } => {
49454948 let Some(recv_type) = self.profiled_type_of_at(self_val, state) else {
49464949 // No (monomorphic/skewed polymorphic) profile info
@@ -9045,9 +9048,19 @@ fn add_iseq_to_hir(
90459048 // make the right number of Params
90469049 block = join_block;
90479050 } else {
9048- // Possibly monomorphic case; handled in optimize_getivar
9049- let result = fun.push_insn(block, Insn::GetIvar { self_val: self_param, id, ic, state: exit_id });
9050- state.stack_push(result);
9051+ if let Some(profiled_type) = fun.monomorphic_summary(&profiles, self_param, exit_id) {
9052+ let result = fun.try_emit_optimized_getivar(block, self_param, id, profiled_type, exit_id).unwrap_or_else(|counter| {
9053+ fun.count(block, counter);
9054+ fun.push_insn(block, Insn::GetIvar { self_val: self_param, id, ic: std::ptr::null(), state: exit_id })
9055+ });
9056+ state.stack_push(result);
9057+ } else {
9058+ let resolution = fun.resolve_receiver_type_from_profile(self_param, exit_id);
9059+ let counter = Function::getivar_fallback_reason(resolution, ic);
9060+ fun.count(block, counter);
9061+ let result = fun.push_insn(block, Insn::GetIvar { self_val: self_param, id, ic, state: exit_id });
9062+ state.stack_push(result);
9063+ }
90519064 }
90529065 }
90539066 YARVINSN_setinstancevariable => {
0 commit comments