aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cuni <anto.cuni@gmail.com>2020-10-02 17:39:55 +0200
committerAntonio Cuni <anto.cuni@gmail.com>2020-10-02 17:39:55 +0200
commita4e34281dacb2b091b154f5937a8a0d2ca51bd7f (patch)
tree9088963dde2f15ef8b68cb81d2846ec5cb067acc
parentMerge branch 'branch/darwin-sendfile-2.7' into 'branch/default' (diff)
downloadpypy-a4e34281dacb2b091b154f5937a8a0d2ca51bd7f.tar.gz
pypy-a4e34281dacb2b091b154f5937a8a0d2ca51bd7f.tar.bz2
pypy-a4e34281dacb2b091b154f5937a8a0d2ca51bd7f.zip
introduce a @never_allocate class decorator, which ensure that a certain RPython class is never actually instantiated at runtime. Useful to ensure that e.g. it's always constant-folded away
-rw-r--r--rpython/memory/gctransform/transform.py16
-rw-r--r--rpython/rlib/objectmodel.py10
-rw-r--r--rpython/rlib/test/test_objectmodel.py24
-rw-r--r--rpython/rtyper/rclass.py3
4 files changed, 50 insertions, 3 deletions
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
index d793f91ef2..d3dd64702f 100644
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -19,6 +19,8 @@ from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.translator.simplify import cleanup_graph
from rpython.memory.gctransform.log import log
+class GCTransformError(Exception):
+ pass
class GcHighLevelOp(object):
def __init__(self, gct, op, index, llops):
@@ -236,8 +238,12 @@ class BaseGCTransformer(object):
inserted_empty_startblock = True
is_borrowed = self.compute_borrowed_vars(graph)
- for block in graph.iterblocks():
- self.transform_block(block, is_borrowed)
+ try:
+ for block in graph.iterblocks():
+ self.transform_block(block, is_borrowed)
+ except GCTransformError as e:
+ e.args = ('[function %s]: %s' % (graph.name, e.message),)
+ raise
for link, livecounts in self.links_to_split.iteritems():
llops = LowLevelOpList()
@@ -519,6 +525,12 @@ class GCTransformer(BaseGCTransformer):
def gct_malloc(self, hop, add_flags=None):
TYPE = hop.spaceop.result.concretetype.TO
+ if TYPE._hints.get('never_allocate'):
+ raise GCTransformError(
+ "struct %s was marked as @never_allocate but a call to malloc() "
+ "was found. This probably means that the corresponding class is "
+ "supposed to be constant-folded away, but for some reason it was not."
+ % TYPE._name)
assert not TYPE._is_varsize()
flags = hop.spaceop.args[1].value
flavor = flags['flavor']
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
index 8e59b387ec..0b3647ae2c 100644
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -1058,3 +1058,13 @@ def import_from_mixin(M, special_methods=['__init__', '__del__']):
target[key] = value
if immutable_fields:
target['_immutable_fields_'] = target.get('_immutable_fields_', []) + immutable_fields
+
+def never_allocate(cls):
+ """
+ Class decorator to ensure that a class is NEVER instantiated at runtime.
+
+ Useful e.g for context manager which are expected to be constant-folded
+ away.
+ """
+ cls._rpython_never_allocate_ = True
+ return cls
diff --git a/rpython/rlib/test/test_objectmodel.py b/rpython/rlib/test/test_objectmodel.py
index 6bcb9d60c6..8aef08cdd1 100644
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -7,7 +7,8 @@ from rpython.rlib.objectmodel import (
resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
- fetch_translated_config, try_inline, delitem_if_value_is, move_to_end)
+ fetch_translated_config, try_inline, delitem_if_value_is, move_to_end,
+ never_allocate, dont_inline)
from rpython.translator.translator import TranslationContext, graphof
from rpython.rtyper.test.tool import BaseRtypingTest
from rpython.rtyper.test.test_llinterp import interpret
@@ -851,3 +852,24 @@ def test_import_from_mixin_immutable_fields():
import_from_mixin(C)
assert BA._immutable_fields_ == ['c', 'a']
+
+
+def test_never_allocate():
+ from rpython.translator.c.test.test_genc import compile as c_compile
+ from rpython.memory.gctransform.transform import GCTransformError
+
+ @never_allocate
+ class MyClass(object):
+ pass
+
+ @dont_inline
+ def allocate_MyClass():
+ return MyClass()
+
+ def f():
+ allocate_MyClass()
+
+ with py.test.raises(GCTransformError) as exc:
+ c_compile(f, [])
+ assert '[function allocate_MyClass]' in str(exc)
+ assert 'was marked as @never_allocate' in str(exc)
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
index 0d09123617..a98a04649b 100644
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -527,6 +527,9 @@ class InstanceRepr(Repr):
if hints is None:
hints = {}
hints = self._check_for_immutable_hints(hints)
+ if self.classdef.classdesc.get_param('_rpython_never_allocate_'):
+ hints['never_allocate'] = True
+
kwds = {}
if self.gcflavor == 'gc':
kwds['rtti'] = True