зеркало из https://github.com/github/ruby.git
Invalidate fastpath when calling attr_writer by super
We started to use fastpath on invokesuper when a method is not refinements
since 5c27681813
, but we shouldn't have used fastpath for attr_writer either.
`cc->aux_.attr_index` is for an actual receiver class, while we store
its superclass in `cc->klass` and therefore there's no way to properly
invalidate attr_writer's inline cache when it's called by super.
[Bug #16785]
I suspect the same bug also exists in attr_reader. I'll address that in
another commit.
This commit is contained in:
Родитель
2c12d111cb
Коммит
8355a99883
|
@ -603,4 +603,34 @@ class TestSuper < Test::Unit::TestCase
|
|||
assert_equal :boo, subklass.new.baz
|
||||
assert_equal :boo2, subklass.new.boo
|
||||
end
|
||||
|
||||
def test_super_attr_writer # Bug #16785
|
||||
writer_class = Class.new do
|
||||
attr_writer :test
|
||||
end
|
||||
superwriter_class = Class.new(writer_class) do
|
||||
def initialize
|
||||
@test = 1 # index: 1
|
||||
end
|
||||
|
||||
def test=(test)
|
||||
super(test)
|
||||
end
|
||||
end
|
||||
inherited_class = Class.new(superwriter_class) do
|
||||
def initialize
|
||||
@a = nil
|
||||
@test = 2 # index: 2
|
||||
end
|
||||
end
|
||||
|
||||
superwriter = superwriter_class.new
|
||||
superwriter.test = 3 # set ic->index of superwriter_class#test= to 1
|
||||
|
||||
inherited = inherited_class.new
|
||||
inherited.test = 4 # it may set 4 to index=1 while it should be index=2
|
||||
|
||||
assert_equal 3, superwriter.instance_variable_get(:@test)
|
||||
assert_equal 4, inherited.instance_variable_get(:@test)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3231,9 +3231,18 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c
|
|||
const struct rb_callcache *cc = vm_cc_new(klass, cme, vm_call_super_method);
|
||||
RB_OBJ_WRITE(reg_cfp->iseq, &cd->cc, cc);
|
||||
}
|
||||
else if (cached_cme->def->type == VM_METHOD_TYPE_REFINED) {
|
||||
// vm_call_refined (search_refined_method) assumes cc->call is vm_call_super_method on invokesuper.
|
||||
vm_cc_call_set(cd->cc, vm_call_super_method);
|
||||
else {
|
||||
switch (cached_cme->def->type) {
|
||||
// vm_call_refined (search_refined_method) assumes cc->call is vm_call_super_method on invokesuper
|
||||
case VM_METHOD_TYPE_REFINED:
|
||||
// cc->klass is superclass of a class of receiver. Checking cc->klass is not enough to invalidate IVC for the receiver class.
|
||||
case VM_METHOD_TYPE_ATTRSET:
|
||||
// TODO: case VM_METHOD_TYPE_IVAR:
|
||||
vm_cc_call_set(cd->cc, vm_call_super_method); // invalidate fastpath
|
||||
break;
|
||||
default:
|
||||
break; // use fastpath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче