diff options
author | Antonio Cuni <anto.cuni@gmail.com> | 2020-10-02 17:39:55 +0200 |
---|---|---|
committer | Antonio Cuni <anto.cuni@gmail.com> | 2020-10-02 17:39:55 +0200 |
commit | a4e34281dacb2b091b154f5937a8a0d2ca51bd7f (patch) | |
tree | 9088963dde2f15ef8b68cb81d2846ec5cb067acc | |
parent | Merge branch 'branch/darwin-sendfile-2.7' into 'branch/default' (diff) | |
download | pypy-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.py | 16 | ||||
-rw-r--r-- | rpython/rlib/objectmodel.py | 10 | ||||
-rw-r--r-- | rpython/rlib/test/test_objectmodel.py | 24 | ||||
-rw-r--r-- | rpython/rtyper/rclass.py | 3 |
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 |