Author: Gregor Wegberg <[email protected]>
Branch: gc-incminimark-pinning
Changeset: r72908:e87564c16230
Date: 2014-08-19 16:24 +0200
http://bitbucket.org/pypy/pypy/changeset/e87564c16230/
Log: don't allow objects to be pinned that can contain GC pointers
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -988,6 +988,12 @@
# to check if can_move(obj) already returns True in which
# case a call to pin() is unnecessary.
return False
+ if self.has_gcptr(self.get_type_id(obj)):
+ # objects containing GC pointers can't be pinned. If we would add
+ # it, we would have to track all pinned objects and trace them
+ # every minor collection to make sure the referenced object are
+ # kept alive.
+ return False
if self._is_pinned(obj):
# Already pinned, we do not allow to pin it again.
# Reason: It would be possible that the first caller unpins
diff --git a/rpython/memory/gc/test/test_object_pinning.py
b/rpython/memory/gc/test/test_object_pinning.py
--- a/rpython/memory/gc/test/test_object_pinning.py
+++ b/rpython/memory/gc/test/test_object_pinning.py
@@ -3,29 +3,29 @@
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC, WORD
from test_direct import BaseDirectGCTest
+T = lltype.GcForwardReference()
+T.become(lltype.GcStruct('pinning_test_struct2',
+ ('someInt', lltype.Signed)))
+
S = lltype.GcForwardReference()
S.become(lltype.GcStruct('pinning_test_struct1',
('someInt', lltype.Signed),
- ('next', lltype.Ptr(S)),
- ('data', lltype.Ptr(S))))
-
-T = lltype.GcForwardReference()
-T.become(lltype.GcStruct('pinning_test_struct2',
- ('someInt', lltype.Signed)))
+ ('next', lltype.Ptr(T)),
+ ('data', lltype.Ptr(T))))
class PinningGCTest(BaseDirectGCTest):
def test_pin_can_move(self):
# even a pinned object is considered to be movable. Only the caller
# of pin() knows if it is currently movable or not.
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
assert self.gc.can_move(adr)
assert self.gc.pin(adr)
assert self.gc.can_move(adr)
def test_pin_twice(self):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
assert self.gc.pin(adr)
assert not self.gc.pin(adr)
@@ -37,7 +37,7 @@
self.gc.unpin, llmemory.cast_ptr_to_adr(ptr))
def test__is_pinned(self):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
assert not self.gc._is_pinned(adr)
assert self.gc.pin(adr)
@@ -46,7 +46,7 @@
assert not self.gc._is_pinned(adr)
def test_prebuilt_not_pinnable(self):
- ptr = lltype.malloc(S, immortal=True)
+ ptr = lltype.malloc(T, immortal=True)
self.consider_constant(ptr)
assert not self.gc.pin(llmemory.cast_ptr_to_adr(ptr))
self.gc.collect()
@@ -59,6 +59,13 @@
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
from rpython.memory.gc.incminimark import STATE_SCANNING
+ def test_try_pin_gcref_containing_type(self):
+ # scenario: incminimark's object pinning can't pin objects that may
+ # contain GC pointers
+ obj = self.malloc(S)
+ assert not self.gc.pin(llmemory.cast_ptr_to_adr(obj))
+
+
def test_pin_old(self):
# scenario: try pinning an old object. This should be not possible and
# we want to make sure everything stays as it is.
@@ -78,11 +85,11 @@
def pin_pin_pinned_object_count(self, collect_func):
# scenario: pin two objects that are referenced from stackroots. Check
# if the pinned objects count is correct, even after an other
collection
- pinned1_ptr = self.malloc(S)
+ pinned1_ptr = self.malloc(T)
pinned1_ptr.someInt = 100
self.stackroots.append(pinned1_ptr)
#
- pinned2_ptr = self.malloc(S)
+ pinned2_ptr = self.malloc(T)
pinned2_ptr.someInt = 200
self.stackroots.append(pinned2_ptr)
#
@@ -105,7 +112,7 @@
def pin_unpin_pinned_object_count(self, collect_func):
# scenario: pin an object and check the pinned object count. Unpin it
# and check the count again.
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.stackroots.append(pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -131,7 +138,7 @@
# scenario: a pinned object that is part of the stack roots. Check if
# it is not moved
#
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
ptr.someInt = 100
self.stackroots.append(ptr)
assert self.stackroots[0] == ptr # validate our assumption
@@ -162,7 +169,7 @@
# that we do stepwise major collection and check in each step for
# a correct state
#
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
ptr.someInt = 100
self.stackroots.append(ptr)
assert self.stackroots[0] == ptr # validate our assumption
@@ -199,7 +206,7 @@
# scenario: test if the pinned object is moved after being unpinned.
# the second part of the scenario is the tested one. The first part
# is already tests by other tests.
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
ptr.someInt = 100
self.stackroots.append(ptr)
assert self.stackroots[0] == ptr # validate our assumption
@@ -246,7 +253,7 @@
assert not self.gc.is_in_nursery(llmemory.cast_ptr_to_adr(old_ptr))
#
# create young pinned one and let the old one reference the young one
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(old_ptr, 'next', pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -283,7 +290,7 @@
assert not self.gc.is_in_nursery(old_adr)
#
# create young pinned one and let the old one reference the young one
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(old_ptr, 'next', pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -329,7 +336,7 @@
collect_func() # make it old
old_ptr = self.stackroots[0]
#
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(old_ptr, 'next', pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -342,7 +349,7 @@
assert self.gc.is_in_nursery(pinned_adr)
assert self.gc._is_pinned(pinned_adr)
# remove the reference
- self.write(old_ptr, 'next', lltype.nullptr(S))
+ self.write(old_ptr, 'next', lltype.nullptr(T))
# from now on the pinned object is dead. Do a collection and make sure
# old object still there and the pinned one is gone.
collect_func()
@@ -377,7 +384,7 @@
collect_func()
old_ptr = self.stackroots[0]
#
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(old_ptr, 'next', pinned_ptr)
assert self.gc.pin(llmemory.cast_ptr_to_adr(pinned_ptr))
@@ -424,7 +431,7 @@
self.stackroots.append(root_ptr)
assert self.stackroots[0] == root_ptr # validate assumption
#
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(root_ptr, 'next', pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -467,7 +474,7 @@
prebuilt_adr = llmemory.cast_ptr_to_adr(prebuilt_ptr)
collect_func()
#
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
self.write(prebuilt_ptr, 'next', pinned_ptr)
pinned_adr = llmemory.cast_ptr_to_adr(pinned_ptr)
@@ -506,7 +513,7 @@
old2_ptr.someInt = 800
self.stackroots.append(old2_ptr)
- pinned_ptr = self.malloc(S)
+ pinned_ptr = self.malloc(T)
pinned_ptr.someInt = 100
assert self.gc.pin(llmemory.cast_ptr_to_adr(pinned_ptr))
@@ -528,7 +535,7 @@
def pin_shadow_1(self, collect_func):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
self.stackroots.append(ptr)
ptr.someInt = 100
@@ -553,7 +560,7 @@
# scenario: malloc two objects of different type and pin them. Do a
# minor and major collection in between. This test showed a bug that
was
# present in a previous implementation of pinning.
- obj1 = self.malloc(S)
+ obj1 = self.malloc(T)
self.stackroots.append(obj1)
assert self.gc.pin(llmemory.cast_ptr_to_adr(obj1))
#
@@ -565,7 +572,7 @@
def pin_shadow_2(self, collect_func):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
self.stackroots.append(ptr)
ptr.someInt = 100
@@ -587,19 +594,19 @@
def test_pin_nursery_top_scenario1(self):
- ptr1 = self.malloc(S)
+ ptr1 = self.malloc(T)
adr1 = llmemory.cast_ptr_to_adr(ptr1)
ptr1.someInt = 101
self.stackroots.append(ptr1)
assert self.gc.pin(adr1)
- ptr2 = self.malloc(S)
+ ptr2 = self.malloc(T)
adr2 = llmemory.cast_ptr_to_adr(ptr2)
ptr2.someInt = 102
self.stackroots.append(ptr2)
assert self.gc.pin(adr2)
- ptr3 = self.malloc(S)
+ ptr3 = self.malloc(T)
adr3 = llmemory.cast_ptr_to_adr(ptr3)
ptr3.someInt = 103
self.stackroots.append(ptr3)
@@ -625,19 +632,19 @@
def test_pin_nursery_top_scenario2(self):
- ptr1 = self.malloc(S)
+ ptr1 = self.malloc(T)
adr1 = llmemory.cast_ptr_to_adr(ptr1)
ptr1.someInt = 101
self.stackroots.append(ptr1)
assert self.gc.pin(adr1)
- ptr2 = self.malloc(S)
+ ptr2 = self.malloc(T)
adr2 = llmemory.cast_ptr_to_adr(ptr2)
ptr2.someInt = 102
self.stackroots.append(ptr2)
assert self.gc.pin(adr2)
- ptr3 = self.malloc(S)
+ ptr3 = self.malloc(T)
adr3 = llmemory.cast_ptr_to_adr(ptr3)
ptr3.someInt = 103
self.stackroots.append(ptr3)
@@ -665,19 +672,19 @@
def test_pin_nursery_top_scenario3(self):
- ptr1 = self.malloc(S)
+ ptr1 = self.malloc(T)
adr1 = llmemory.cast_ptr_to_adr(ptr1)
ptr1.someInt = 101
self.stackroots.append(ptr1)
assert self.gc.pin(adr1)
- ptr2 = self.malloc(S)
+ ptr2 = self.malloc(T)
adr2 = llmemory.cast_ptr_to_adr(ptr2)
ptr2.someInt = 102
self.stackroots.append(ptr2)
assert self.gc.pin(adr2)
- ptr3 = self.malloc(S)
+ ptr3 = self.malloc(T)
adr3 = llmemory.cast_ptr_to_adr(ptr3)
ptr3.someInt = 103
self.stackroots.append(ptr3)
@@ -707,19 +714,19 @@
def test_pin_nursery_top_scenario4(self):
- ptr1 = self.malloc(S)
+ ptr1 = self.malloc(T)
adr1 = llmemory.cast_ptr_to_adr(ptr1)
ptr1.someInt = 101
self.stackroots.append(ptr1)
assert self.gc.pin(adr1)
- ptr2 = self.malloc(S)
+ ptr2 = self.malloc(T)
adr2 = llmemory.cast_ptr_to_adr(ptr2)
ptr2.someInt = 102
self.stackroots.append(ptr2)
assert self.gc.pin(adr2)
- ptr3 = self.malloc(S)
+ ptr3 = self.malloc(T)
adr3 = llmemory.cast_ptr_to_adr(ptr3)
ptr3.someInt = 103
self.stackroots.append(ptr3)
@@ -750,19 +757,19 @@
def test_pin_nursery_top_scenario5(self):
- ptr1 = self.malloc(S)
+ ptr1 = self.malloc(T)
adr1 = llmemory.cast_ptr_to_adr(ptr1)
ptr1.someInt = 101
self.stackroots.append(ptr1)
assert self.gc.pin(adr1)
- ptr2 = self.malloc(S)
+ ptr2 = self.malloc(T)
adr2 = llmemory.cast_ptr_to_adr(ptr2)
ptr2.someInt = 102
self.stackroots.append(ptr2)
assert self.gc.pin(adr2)
- ptr3 = self.malloc(S)
+ ptr3 = self.malloc(T)
adr3 = llmemory.cast_ptr_to_adr(ptr3)
ptr3.someInt = 103
self.stackroots.append(ptr3)
@@ -811,12 +818,12 @@
def fill_nursery_with_pinned_objects(self):
- typeid = self.get_type_id(S)
+ typeid = self.get_type_id(T)
size = self.gc.fixed_size(typeid) +
self.gc.gcheaderbuilder.size_gc_header
raw_size = llmemory.raw_malloc_usage(size)
object_mallocs = self.gc.nursery_size // raw_size
for instance_nr in xrange(object_mallocs):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
ptr.someInt = 100 + instance_nr
self.stackroots.append(ptr)
@@ -824,9 +831,9 @@
def test_full_pinned_nursery_pin_fail(self):
self.fill_nursery_with_pinned_objects()
- # nursery should be full now, at least no space for another `S`.
+ # nursery should be full now, at least no space for another `T`.
# Next malloc should fail.
- py.test.raises(Exception, self.malloc, S)
+ py.test.raises(Exception, self.malloc, T)
def test_full_pinned_nursery_arena_reset(self):
# there were some bugs regarding the 'arena_reset()' calls at
@@ -836,21 +843,21 @@
def test_pinning_limit(self):
for instance_nr in xrange(self.gc.max_number_of_pinned_objects):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
ptr.someInt = 100 + instance_nr
self.stackroots.append(ptr)
self.gc.pin(adr)
#
# now we reached the maximum amount of pinned objects
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
self.stackroots.append(ptr)
assert not self.gc.pin(adr)
test_pinning_limit.GC_PARAMS = {'max_number_of_pinned_objects': 5}
def test_full_pinned_nursery_pin_fail(self):
- typeid = self.get_type_id(S)
+ typeid = self.get_type_id(T)
size = self.gc.fixed_size(typeid) +
self.gc.gcheaderbuilder.size_gc_header
raw_size = llmemory.raw_malloc_usage(size)
object_mallocs = self.gc.nursery_size // raw_size
@@ -858,15 +865,15 @@
# but rather the case of a nursery full with pinned objects.
assert object_mallocs < self.gc.max_number_of_pinned_objects
for instance_nr in xrange(object_mallocs):
- ptr = self.malloc(S)
+ ptr = self.malloc(T)
adr = llmemory.cast_ptr_to_adr(ptr)
ptr.someInt = 100 + instance_nr
self.stackroots.append(ptr)
self.gc.pin(adr)
#
- # nursery should be full now, at least no space for another `S`.
+ # nursery should be full now, at least no space for another `T`.
# Next malloc should fail.
- py.test.raises(Exception, self.malloc, S)
+ py.test.raises(Exception, self.malloc, T)
test_full_pinned_nursery_pin_fail.GC_PARAMS = \
{'max_number_of_pinned_objects': 50}
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit