[pypy-commit] pypy default: Merged in exctrans (pull request #390)
rlamy
pypy.commits at gmail.com
Tue Jan 26 15:39:44 EST 2016
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch:
Changeset: r81955:467f4a616ad1
Date: 2016-01-26 20:39 +0000
http://bitbucket.org/pypy/pypy/changeset/467f4a616ad1/
Log: Merged in exctrans (pull request #390)
Some refactoring of databasing
diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py
--- a/rpython/memory/gctransform/boehm.py
+++ b/rpython/memory/gctransform/boehm.py
@@ -74,7 +74,7 @@
def gct_fv_gc_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size,
c_offset_to_length):
- # XXX same behavior for zero=True: in theory that's wrong
+ # XXX same behavior for zero=True: in theory that's wrong
if c_offset_to_length is None:
v_raw = hop.genop("direct_call",
[self.malloc_varsize_no_length_ptr, v_length,
@@ -156,6 +156,11 @@
resulttype = lltype.Signed)
hop.genop('int_invert', [v_int], resultvar=hop.spaceop.result)
+ def gcheader_initdata(self, defnode):
+ hdr = lltype.malloc(self.HDR, immortal=True)
+ hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr())
+ return hdr._obj
+
########## weakrefs ##########
# Boehm: weakref objects are small structures containing only a Boehm
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -288,7 +288,6 @@
s_gcref = SomePtr(llmemory.GCREF)
gcdata = self.gcdata
- translator = self.translator
#use the GC flag to find which malloc method to use
#malloc_zero_filled == Ture -> malloc_fixedsize/varsize_clear
#malloc_zero_filled == Flase -> malloc_fixedsize/varsize
@@ -322,7 +321,7 @@
GCClass.malloc_varsize.im_func,
[s_gc, s_typeid16]
+ [annmodel.SomeInteger(nonneg=True) for i in range(4)], s_gcref)
-
+
self.collect_ptr = getfn(GCClass.collect.im_func,
[s_gc, annmodel.SomeInteger()], annmodel.s_None)
self.can_move_ptr = getfn(GCClass.can_move.im_func,
@@ -1385,7 +1384,7 @@
[v] + previous_steps + [c_name, c_null])
else:
llops.genop('bare_setfield', [v, c_name, c_null])
-
+
return
elif isinstance(TYPE, lltype.Array):
ITEM = TYPE.OF
@@ -1412,6 +1411,25 @@
resulttype=llmemory.Address)
llops.genop('raw_memclear', [v_adr, v_totalsize])
+ def gcheader_initdata(self, defnode):
+ o = lltype.top_container(defnode.obj)
+ needs_hash = self.get_prebuilt_hash(o) is not None
+ hdr = self.gc_header_for(o, needs_hash)
+ return hdr._obj
+
+ def get_prebuilt_hash(self, obj):
+ # for prebuilt objects that need to have their hash stored and
+ # restored. Note that only structures that are StructNodes all
+ # the way have their hash stored (and not e.g. structs with var-
+ # sized arrays at the end). 'obj' must be the top_container.
+ TYPE = lltype.typeOf(obj)
+ if not isinstance(TYPE, lltype.GcStruct):
+ return None
+ if TYPE._is_varsize():
+ return None
+ return getattr(obj, '_hash_cache_', None)
+
+
class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
diff --git a/rpython/memory/gctransform/refcounting.py b/rpython/memory/gctransform/refcounting.py
--- a/rpython/memory/gctransform/refcounting.py
+++ b/rpython/memory/gctransform/refcounting.py
@@ -285,3 +285,7 @@
resulttype=llmemory.Address)
hop.genop("direct_call", [self.identityhash_ptr, v_adr],
resultvar=hop.spaceop.result)
+
+ def gcheader_initdata(self, defnode):
+ top = lltype.top_container(defnode.obj)
+ return self.gcheaderbuilder.header_of_object(top)._obj
diff --git a/rpython/memory/gctransform/test/test_framework.py b/rpython/memory/gctransform/test/test_framework.py
--- a/rpython/memory/gctransform/test/test_framework.py
+++ b/rpython/memory/gctransform/test/test_framework.py
@@ -40,7 +40,7 @@
t.config.translation.gc = "minimark"
cbuild = CStandaloneBuilder(t, entrypoint, t.config,
gcpolicy=FrameworkGcPolicy2)
- db = cbuild.generate_graphs_for_llinterp()
+ db = cbuild.build_database()
entrypointptr = cbuild.getentrypointptr()
entrygraph = entrypointptr._obj.graph
@@ -69,7 +69,7 @@
return -x
t = rtype(g, [int])
gg = graphof(t, g)
- assert not CollectAnalyzer(t).analyze_direct_call(gg)
+ assert not CollectAnalyzer(t).analyze_direct_call(gg)
def test_cancollect_external():
fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=False)
@@ -110,12 +110,12 @@
def entrypoint(argv):
return g() + 2
-
+
t = rtype(entrypoint, [s_list_of_strings])
t.config.translation.gc = "minimark"
cbuild = CStandaloneBuilder(t, entrypoint, t.config,
gcpolicy=FrameworkGcPolicy2)
- db = cbuild.generate_graphs_for_llinterp()
+ db = cbuild.build_database()
def test_no_collect_detection():
from rpython.rlib import rgc
@@ -134,12 +134,13 @@
def entrypoint(argv):
return g() + 2
-
+
t = rtype(entrypoint, [s_list_of_strings])
t.config.translation.gc = "minimark"
cbuild = CStandaloneBuilder(t, entrypoint, t.config,
gcpolicy=FrameworkGcPolicy2)
- f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+ with py.test.raises(Exception) as f:
+ cbuild.build_database()
expected = "'no_collect' function can trigger collection: <function g at "
assert str(f.value).startswith(expected)
@@ -163,11 +164,12 @@
t.config.translation.gc = "minimark"
cbuild = CStandaloneBuilder(t, entrypoint, t.config,
gcpolicy=FrameworkGcPolicy2)
- f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+ with py.test.raises(Exception) as f:
+ cbuild.build_database()
assert 'can cause the GC to be called' in str(f.value)
assert 'trace_func' in str(f.value)
assert 'MyStructure' in str(f.value)
-
+
class WriteBarrierTransformer(ShadowStackFrameworkGCTransformer):
clean_sets = {}
GC_PARAMS = {}
@@ -252,7 +254,7 @@
t.config.translation.gc = "minimark"
cbuild = CStandaloneBuilder(t, g, t.config,
gcpolicy=FrameworkGcPolicy2)
- db = cbuild.generate_graphs_for_llinterp()
+ db = cbuild.build_database()
ff = graphof(t, f)
#ff.show()
@@ -306,7 +308,7 @@
def test_find_clean_setarrayitems():
S = lltype.GcStruct('S')
A = lltype.GcArray(lltype.Ptr(S))
-
+
def f():
l = lltype.malloc(A, 3)
l[0] = lltype.malloc(S)
@@ -327,7 +329,7 @@
def test_find_clean_setarrayitems_2():
S = lltype.GcStruct('S')
A = lltype.GcArray(lltype.Ptr(S))
-
+
def f():
l = lltype.malloc(A, 3)
l[0] = lltype.malloc(S)
@@ -349,7 +351,7 @@
def test_find_clean_setarrayitems_3():
S = lltype.GcStruct('S')
A = lltype.GcArray(lltype.Ptr(S))
-
+
def f():
l = lltype.malloc(A, 3)
l[0] = lltype.malloc(S)
diff --git a/rpython/memory/gctransform/test/test_transform.py b/rpython/memory/gctransform/test/test_transform.py
--- a/rpython/memory/gctransform/test/test_transform.py
+++ b/rpython/memory/gctransform/test/test_transform.py
@@ -16,7 +16,7 @@
t = rtype(f, args_s)
# XXX we shouldn't need an actual gcpolicy here.
cbuild = CStandaloneBuilder(t, f, t.config, gcpolicy=self.gcpolicy)
- cbuild.generate_graphs_for_llinterp()
+ cbuild.build_database()
graph = cbuild.getentrypointptr()._obj.graph
# arguments cannot be GC objects because nobody would put a
# proper header on them
diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py
--- a/rpython/memory/gctransform/transform.py
+++ b/rpython/memory/gctransform/transform.py
@@ -113,21 +113,14 @@
self.seen_graphs.add(graph)
self.minimal_transform.add(graph)
- def prepare_inline_helpers(self, graphs):
+ def inline_helpers(self, graphs):
from rpython.translator.backendopt.inline import iter_callsites
+ raise_analyzer = RaiseAnalyzer(self.translator)
for graph in graphs:
- self.graph_dependencies[graph] = {}
+ to_enum = []
for called, block, i in iter_callsites(graph, None):
if called in self.graphs_to_inline:
- self.graph_dependencies[graph][called] = True
- self.prepared = True
-
- def inline_helpers(self, graph):
- if not self.prepared:
- raise Exception("Need to call prepare_inline_helpers first")
- if self.inline:
- raise_analyzer = RaiseAnalyzer(self.translator)
- to_enum = self.graph_dependencies.get(graph, self.graphs_to_inline)
+ to_enum.append(called)
must_constfold = False
for inline_graph in to_enum:
try:
@@ -378,6 +371,10 @@
return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP),
lltype.nullptr(ARRAY_TYPEID_MAP)))
+ def get_prebuilt_hash(self, obj):
+ return None
+
+
class MinimalGCTransformer(BaseGCTransformer):
def __init__(self, parenttransformer):
BaseGCTransformer.__init__(self, parenttransformer.translator)
diff --git a/rpython/memory/test/test_transformed_gc.py b/rpython/memory/test/test_transformed_gc.py
--- a/rpython/memory/test/test_transformed_gc.py
+++ b/rpython/memory/test/test_transformed_gc.py
@@ -110,7 +110,7 @@
cbuild = CStandaloneBuilder(t, entrypoint, config=t.config,
gcpolicy=cls.gcpolicy)
- db = cbuild.generate_graphs_for_llinterp()
+ db = cbuild.build_database()
entrypointptr = cbuild.getentrypointptr()
entrygraph = entrypointptr._obj.graph
if option.view:
@@ -1071,7 +1071,7 @@
def test_adr_of_nursery(self):
run = self.runner("adr_of_nursery")
res = run([])
-
+
class TestGenerationalNoFullCollectGC(GCTest):
# test that nursery is doing its job and that no full collection
@@ -1131,7 +1131,7 @@
'large_object': 8*WORD,
'translated_to_c': False}
root_stack_depth = 200
-
+
def define_ref_from_rawmalloced_to_regular(cls):
import gc
S = lltype.GcStruct('S', ('x', lltype.Signed))
@@ -1182,7 +1182,7 @@
run = self.runner("write_barrier_direct")
res = run([])
assert res == 42
-
+
class TestMiniMarkGC(TestHybridGC):
gcname = "minimark"
GC_CAN_TEST_ID = True
@@ -1199,7 +1199,7 @@
'translated_to_c': False,
}
root_stack_depth = 200
-
+
def define_no_clean_setarrayitems(cls):
# The optimization find_clean_setarrayitems() in
# gctransformer/framework.py does not work with card marking.
@@ -1224,7 +1224,7 @@
run = self.runner("no_clean_setarrayitems")
res = run([])
assert res == 123
-
+
def define_nursery_hash_base(cls):
class A:
pass
@@ -1283,19 +1283,19 @@
'translated_to_c': False,
}
root_stack_depth = 200
-
+
def define_malloc_array_of_gcptr(self):
S = lltype.GcStruct('S', ('x', lltype.Signed))
A = lltype.GcArray(lltype.Ptr(S))
def f():
lst = lltype.malloc(A, 5)
- return (lst[0] == lltype.nullptr(S)
+ return (lst[0] == lltype.nullptr(S)
and lst[1] == lltype.nullptr(S)
and lst[2] == lltype.nullptr(S)
and lst[3] == lltype.nullptr(S)
and lst[4] == lltype.nullptr(S))
return f
-
+
def test_malloc_array_of_gcptr(self):
run = self.runner('malloc_array_of_gcptr')
res = run([])
@@ -1376,7 +1376,7 @@
def define_gettypeid(cls):
class A(object):
pass
-
+
def fn():
a = A()
return rgc.get_typeid(a)
diff --git a/rpython/rtyper/extfunc.py b/rpython/rtyper/extfunc.py
--- a/rpython/rtyper/extfunc.py
+++ b/rpython/rtyper/extfunc.py
@@ -46,6 +46,12 @@
impl = getattr(self, 'lltypeimpl', None)
fakeimpl = getattr(self, 'lltypefakeimpl', self.instance)
if impl:
+ if (rtyper.annotator.translator.config.translation.sandbox
+ and not self.safe_not_sandboxed):
+ from rpython.translator.sandbox.rsandbox import (
+ make_sandbox_trampoline)
+ impl = make_sandbox_trampoline(
+ self.name, signature_args, s_result)
if hasattr(self, 'lltypefakeimpl'):
# If we have both an llimpl and an llfakeimpl,
# we need a wrapper that selects the proper one and calls it
@@ -74,15 +80,10 @@
return original_impl(%s)
""" % (args, args, args)) in d
impl = func_with_new_name(d['ll_wrapper'], name + '_wrapper')
- if rtyper.annotator.translator.config.translation.sandbox:
- impl._dont_inline_ = True
# store some attributes to the 'impl' function, where
# the eventual call to rtyper.getcallable() will find them
# and transfer them to the final lltype.functionptr().
- impl._llfnobjattrs_ = {
- '_name': self.name,
- '_safe_not_sandboxed': self.safe_not_sandboxed,
- }
+ impl._llfnobjattrs_ = {'_name': self.name}
obj = rtyper.getannmixlevel().delayedfunction(
impl, signature_args, hop.s_result)
else:
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -13,8 +13,9 @@
from rpython.rtyper.lltypesystem.lltype import (
Ptr, Struct, GcStruct, malloc, cast_pointer, castable, nullptr,
RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, Void, FuncType, Bool, Signed,
- functionptr)
+ functionptr, attachRuntimeTypeInfo)
from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.llannotation import SomePtr
from rpython.rtyper.lltypesystem import rstr
from rpython.rtyper.rmodel import (
Repr, getgcflavor, inputconst, warning, mangle)
@@ -590,10 +591,17 @@
_callable=graph.func)
else:
destrptr = None
- OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
- self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
- ll_runtime_type_info,
- OBJECT, destrptr)
+ self.rtyper.call_all_setups() # compute ForwardReferences now
+ args_s = [SomePtr(Ptr(OBJECT))]
+ graph = self.rtyper.annotate_helper(ll_runtime_type_info, args_s)
+ s = self.rtyper.annotation(graph.getreturnvar())
+ if (not isinstance(s, SomePtr) or
+ s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
+ raise TyperError("runtime type info function returns %r, "
+ "expected Ptr(RuntimeTypeInfo)" % (s))
+ funcptr = self.rtyper.getcallable(graph)
+ attachRuntimeTypeInfo(self.object_type, funcptr, destrptr)
+
vtable = self.rclass.getvtable()
self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -1,14 +1,14 @@
"""
RTyper: converts high-level operations into low-level operations in flow graphs.
-The main class, with code to walk blocks and dispatch individual operations
-to the care of the rtype_*() methods implemented in the other r* modules.
-For each high-level operation 'hop', the rtype_*() methods produce low-level
-operations that are collected in the 'llops' list defined here. When necessary,
-conversions are inserted.
+The main class, with code to walk blocks and dispatch individual operations to
+the care of the rtype_*() methods implemented in the other r* modules. For
+each high-level operation 'hop', the rtype_*() methods produce low-level
+operations that are collected in the 'llops' list defined here. When
+necessary, conversions are inserted.
-This logic borrows a bit from rpython.annotator.annrpython, without the fixpoint
-computation part.
+This logic borrows a bit from rpython.annotator.annrpython, without the
+fixpoint computation part.
"""
import os
@@ -16,19 +16,20 @@
import py, math
from rpython.annotator import model as annmodel, unaryop, binaryop
-from rpython.rtyper.llannotation import SomePtr, lltype_to_annotation
+from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.flowspace.model import Variable, Constant, SpaceOperation
-from rpython.rtyper.annlowlevel import annotate_lowlevel_helper, LowLevelAnnotatorPolicy
+from rpython.rtyper.annlowlevel import (
+ annotate_lowlevel_helper, LowLevelAnnotatorPolicy)
from rpython.rtyper.error import TyperError
from rpython.rtyper.exceptiondata import ExceptionData
from rpython.rtyper.lltypesystem.lltype import (Signed, Void, LowLevelType,
- Ptr, ContainerType, FuncType, typeOf, RuntimeTypeInfo,
- attachRuntimeTypeInfo, Primitive, getfunctionptr)
-from rpython.rtyper.rmodel import Repr, inputconst, BrokenReprTyperError
+ ContainerType, typeOf, Primitive, getfunctionptr)
+from rpython.rtyper.rmodel import Repr, inputconst
from rpython.rtyper import rclass
from rpython.rtyper.rclass import RootClassRepr
from rpython.tool.pairtype import pair
from rpython.translator.unsimplify import insert_empty_block
+from rpython.translator.sandbox.rsandbox import make_sandbox_trampoline
class RPythonTyper(object):
@@ -561,6 +562,17 @@
def getcallable(self, graph):
def getconcretetype(v):
return self.bindingrepr(v).lowleveltype
+ if self.annotator.translator.config.translation.sandbox:
+ try:
+ name = graph.func._sandbox_external_name
+ except AttributeError:
+ pass
+ else:
+ args_s = [v.annotation for v in graph.getargs()]
+ s_result = graph.getreturnvar().annotation
+ sandboxed = make_sandbox_trampoline(name, args_s, s_result)
+ return self.getannmixlevel().delayedfunction(
+ sandboxed, args_s, s_result)
return getfunctionptr(graph, getconcretetype)
@@ -590,21 +602,6 @@
graph = self.annotate_helper(ll_function, argtypes)
return self.getcallable(graph)
- def attachRuntimeTypeInfoFunc(self, GCSTRUCT, func, ARG_GCSTRUCT=None,
- destrptr=None):
- self.call_all_setups() # compute ForwardReferences now
- if ARG_GCSTRUCT is None:
- ARG_GCSTRUCT = GCSTRUCT
- args_s = [SomePtr(Ptr(ARG_GCSTRUCT))]
- graph = self.annotate_helper(func, args_s)
- s = self.annotation(graph.getreturnvar())
- if (not isinstance(s, SomePtr) or
- s.ll_ptrtype != Ptr(RuntimeTypeInfo)):
- raise TyperError("runtime type info function %r returns %r, "
- "excepted Ptr(RuntimeTypeInfo)" % (func, s))
- funcptr = self.getcallable(graph)
- attachRuntimeTypeInfo(GCSTRUCT, funcptr, destrptr)
-
# register operations from annotation model
RPythonTyper._registeroperations(unaryop.UNARY_OPERATIONS, binaryop.BINARY_OPERATIONS)
diff --git a/rpython/translator/c/database.py b/rpython/translator/c/database.py
--- a/rpython/translator/c/database.py
+++ b/rpython/translator/c/database.py
@@ -1,3 +1,4 @@
+from collections import OrderedDict
from rpython.rtyper.lltypesystem.lltype import (Primitive, Ptr, typeOf,
RuntimeTypeInfo, Struct, Array, FuncType, Void, ContainerType, OpaqueType,
@@ -8,9 +9,9 @@
from rpython.rtyper.lltypesystem import llgroup
from rpython.tool.sourcetools import valid_identifier
from rpython.translator.c.primitive import PrimitiveName, PrimitiveType
-from rpython.translator.c.node import StructDefNode, ArrayDefNode
-from rpython.translator.c.node import FixedSizeArrayDefNode, BareBoneArrayDefNode
-from rpython.translator.c.node import ContainerNodeFactory, ExtTypeOpaqueDefNode
+from rpython.translator.c.node import (
+ StructDefNode, ArrayDefNode, FixedSizeArrayDefNode, BareBoneArrayDefNode,
+ ContainerNodeFactory, ExtTypeOpaqueDefNode, FuncNode)
from rpython.translator.c.support import cdecl, CNameManager
from rpython.translator.c.support import log, barebonearray
from rpython.translator.c.extfunc import do_the_getting
@@ -28,6 +29,7 @@
def __init__(self, translator=None, standalone=False,
gcpolicyclass=None,
+ exctransformer=None,
thread_enabled=False,
sandbox=False):
self.translator = translator
@@ -36,6 +38,7 @@
if gcpolicyclass is None:
gcpolicyclass = gc.RefcountingGcPolicy
self.gcpolicy = gcpolicyclass(self, thread_enabled)
+ self.exctransformer = exctransformer
self.structdefnodes = {}
self.pendingsetupnodes = []
@@ -45,7 +48,7 @@
self.delayedfunctionptrs = []
self.completedcontainers = 0
self.containerstats = {}
- self.helper2ptr = {}
+ self.helpers = OrderedDict()
# late_initializations is for when the value you want to
# assign to a constant object is something C doesn't think is
@@ -53,12 +56,8 @@
self.late_initializations = []
self.namespace = CNameManager()
- if translator is None or translator.rtyper is None:
- self.exctransformer = None
- else:
- self.exctransformer = translator.getexceptiontransformer()
if translator is not None:
- self.gctransformer = self.gcpolicy.gettransformer()
+ self.gctransformer = self.gcpolicy.gettransformer(translator)
self.completed = False
self.instrument_ncounter = 0
@@ -348,6 +347,8 @@
assert not self.delayedfunctionptrs
self.completed = True
+ if self.gctransformer is not None and self.gctransformer.inline:
+ self.gctransformer.inline_helpers(self.all_graphs())
if show_progress:
dump()
log.database("Completed")
@@ -379,30 +380,10 @@
produce(node)
return result
- def need_sandboxing(self, fnobj):
- if not self.sandbox:
- return False
- if hasattr(fnobj, '_safe_not_sandboxed'):
- return not fnobj._safe_not_sandboxed
- elif getattr(getattr(fnobj, '_callable', None),
- '_sandbox_external_name', None):
- return True
- else:
- return "if_external"
-
- def prepare_inline_helpers(self):
- all_nodes = self.globalcontainers()
- funcnodes = [node for node in all_nodes if node.nodekind == 'func']
- graphs = []
- for node in funcnodes:
- for graph in node.graphs_to_patch():
- graphs.append(graph)
- self.gctransformer.prepare_inline_helpers(graphs)
-
def all_graphs(self):
graphs = []
for node in self.containerlist:
- if node.nodekind == 'func':
+ if isinstance(node, FuncNode):
for graph in node.graphs_to_patch():
graphs.append(graph)
return graphs
diff --git a/rpython/translator/c/external.py b/rpython/translator/c/external.py
deleted file mode 100644
--- a/rpython/translator/c/external.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from rpython.rtyper.lltypesystem.lltype import typeOf, Void
-from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
-from rpython.translator.c.support import cdecl, somelettersfrom
-
-class CExternalFunctionCodeGenerator(object):
- if USESLOTS:
- __slots__ = """db fnptr FUNCTYPE argtypenames resulttypename""".split()
-
- def __init__(self, fnptr, db):
- self.fnptr = fnptr
- self.db = db
- self.FUNCTYPE = typeOf(fnptr)
- assert Void not in self.FUNCTYPE.ARGS
- self.argtypenames = [db.gettype(T) for T in self.FUNCTYPE.ARGS]
- self.resulttypename = db.gettype(self.FUNCTYPE.RESULT)
-
- def graphs_to_patch(self):
- return []
-
- def name(self, cname): #virtual
- return cname
-
- def argnames(self):
- return ['%s%d' % (somelettersfrom(self.argtypenames[i]), i)
- for i in range(len(self.argtypenames))]
-
- def allconstantvalues(self):
- return []
-
- def implementation_begin(self):
- pass
-
- def cfunction_declarations(self):
- if self.FUNCTYPE.RESULT is not Void:
- yield '%s;' % cdecl(self.resulttypename, 'result')
-
- def cfunction_body(self):
- try:
- convert_params = self.fnptr.convert_params
- except AttributeError:
- convert_params = lambda backend, args: [arg for _,arg in args]
- call = '%s(%s)' % (self.fnptr._name, ', '.join(convert_params("c", zip(self.FUNCTYPE.ARGS, self.argnames()))))
- if self.FUNCTYPE.RESULT is not Void:
- yield 'result = %s;' % call
- yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();'
- yield 'return result;'
- else:
- yield '%s;' % call
- yield 'if (PyErr_Occurred()) RPyConvertExceptionFromCPython();'
-
- def implementation_end(self):
- pass
-
-assert not USESLOTS or '__dict__' not in dir(CExternalFunctionCodeGenerator)
diff --git a/rpython/translator/c/extfunc.py b/rpython/translator/c/extfunc.py
--- a/rpython/translator/c/extfunc.py
+++ b/rpython/translator/c/extfunc.py
@@ -1,23 +1,23 @@
import types
from rpython.flowspace.model import FunctionGraph
-from rpython.rtyper.lltypesystem import lltype, rstr, rlist
+from rpython.annotator.listdef import s_list_of_strings
+from rpython.rtyper.lltypesystem import lltype, rlist
from rpython.rtyper.lltypesystem.rstr import STR, mallocstr
from rpython.translator.c.support import cdecl
def find_list_of_str(rtyper):
- for r in rtyper.reprs.itervalues():
- if isinstance(r, rlist.ListRepr) and r.item_repr is rstr.string_repr:
- return r.lowleveltype.TO
- return None
+ r_strlist = rtyper.getrepr(s_list_of_strings)
+ rtyper.call_all_setups()
+ return r_strlist.lowleveltype.TO
+
def predeclare_common_types(db, rtyper):
# Common types
yield ('RPyString', STR)
LIST_OF_STR = find_list_of_str(rtyper)
- if LIST_OF_STR is not None:
- yield ('RPyListOfString', LIST_OF_STR)
+ yield ('RPyListOfString', LIST_OF_STR)
def predeclare_utility_functions(db, rtyper):
# Common utility functions
@@ -32,40 +32,38 @@
# returned directly as results
LIST_OF_STR = find_list_of_str(rtyper)
- if LIST_OF_STR is not None:
- p = lltype.Ptr(LIST_OF_STR)
+ p = lltype.Ptr(LIST_OF_STR)
- def _RPyListOfString_New(length=lltype.Signed):
- return LIST_OF_STR.ll_newlist(length)
+ def _RPyListOfString_New(length=lltype.Signed):
+ return LIST_OF_STR.ll_newlist(length)
- def _RPyListOfString_SetItem(l=p,
- index=lltype.Signed,
- newstring=lltype.Ptr(STR)):
- rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring)
+ def _RPyListOfString_SetItem(l=p,
+ index=lltype.Signed,
+ newstring=lltype.Ptr(STR)):
+ rlist.ll_setitem_nonneg(rlist.dum_nocheck, l, index, newstring)
- def _RPyListOfString_GetItem(l=p,
- index=lltype.Signed):
- return rlist.ll_getitem_fast(l, index)
+ def _RPyListOfString_GetItem(l=p,
+ index=lltype.Signed):
+ return rlist.ll_getitem_fast(l, index)
- def _RPyListOfString_Length(l=p):
- return rlist.ll_length(l)
+ def _RPyListOfString_Length(l=p):
+ return rlist.ll_length(l)
for fname, f in locals().items():
if isinstance(f, types.FunctionType):
# XXX this is painful :(
- if (LIST_OF_STR, fname) in db.helper2ptr:
- yield (fname, db.helper2ptr[LIST_OF_STR, fname])
+ if fname in db.helpers:
+ yield (fname, db.helpers[fname])
else:
# hack: the defaults give the type of the arguments
graph = rtyper.annotate_helper(f, f.func_defaults)
- db.helper2ptr[LIST_OF_STR, fname] = graph
+ db.helpers[fname] = graph
yield (fname, graph)
-def predeclare_exception_data(db, rtyper):
+def predeclare_exception_data(exctransformer, rtyper):
# Exception-related types and constants
exceptiondata = rtyper.exceptiondata
- exctransformer = db.exctransformer
yield ('RPYTHON_EXCEPTION_VTABLE', exceptiondata.lltype_of_exception_type)
yield ('RPYTHON_EXCEPTION', exceptiondata.lltype_of_exception_value)
@@ -93,19 +91,19 @@
def predeclare_all(db, rtyper):
for fn in [predeclare_common_types,
predeclare_utility_functions,
- predeclare_exception_data,
]:
for t in fn(db, rtyper):
yield t
+ exctransformer = db.exctransformer
+ for t in predeclare_exception_data(exctransformer, rtyper):
+ yield t
+
def get_all(db, rtyper):
- for fn in [predeclare_common_types,
- predeclare_utility_functions,
- predeclare_exception_data,
- ]:
- for t in fn(db, rtyper):
- yield t[1]
+ for name, fnptr in predeclare_all(db, rtyper):
+ yield fnptr
+
# ____________________________________________________________
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -1,9 +1,8 @@
import sys
-from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
from rpython.translator.c.support import cdecl
from rpython.translator.c.support import llvalue_from_constant, gen_assignments
from rpython.translator.c.support import c_string_constant, barebonearray
-from rpython.flowspace.model import Variable, Constant, copygraph
+from rpython.flowspace.model import Variable, Constant
from rpython.rtyper.lltypesystem.lltype import (Ptr, Void, Bool, Signed, Unsigned,
SignedLongLong, Float, UnsignedLongLong, Char, UniChar, ContainerType,
Array, FixedSizeArray, ForwardReference, FuncType)
@@ -19,39 +18,30 @@
KEEP_INLINED_GRAPHS = False
+def make_funcgen(graph, db, exception_policy, functionname):
+ graph._seen_by_the_backend = True
+ # apply the exception transformation
+ if db.exctransformer:
+ db.exctransformer.create_exception_handling(graph)
+ # apply the gc transformation
+ if db.gctransformer:
+ db.gctransformer.transform_graph(graph)
+ return FunctionCodeGenerator(graph, db, exception_policy, functionname)
+
class FunctionCodeGenerator(object):
"""
Collects information about a function which we have to generate
from a flow graph.
"""
- if USESLOTS:
- __slots__ = """graph db gcpolicy
- exception_policy
- more_ll_values
- vars all_cached_consts
- illtypes
- functionname
- blocknum
- innerloops
- oldgraph""".split()
-
- def __init__(self, graph, db, exception_policy=None, functionname=None):
- graph._seen_by_the_backend = True
+ def __init__(self, graph, db, exception_policy, functionname):
self.graph = graph
self.db = db
self.gcpolicy = db.gcpolicy
self.exception_policy = exception_policy
self.functionname = functionname
- # apply the exception transformation
- if self.db.exctransformer:
- self.db.exctransformer.create_exception_handling(self.graph)
- # apply the gc transformation
- if self.db.gctransformer:
- self.db.gctransformer.transform_graph(self.graph)
- #self.graph.show()
+
self.collect_var_and_types()
-
for v in self.vars:
T = v.concretetype
# obscure: skip forward references and hope for the best
@@ -84,12 +74,6 @@
self.more_ll_values.append(link.llexitcase)
elif link.exitcase is not None:
mix.append(Constant(link.exitcase))
- if self.exception_policy == "CPython":
- v, exc_cleanup_ops = self.graph.exc_cleanup
- mix.append(v)
- for cleanupop in exc_cleanup_ops:
- mix.extend(cleanupop.args)
- mix.append(cleanupop.result)
uniquemix = []
seen = identity_dict()
@@ -99,20 +83,7 @@
seen[v] = True
self.vars = uniquemix
- def name(self, cname): #virtual
- return cname
-
- def patch_graph(self, copy_graph):
- graph = self.graph
- if self.db.gctransformer and self.db.gctransformer.inline:
- if copy_graph:
- graph = copygraph(graph, shallow=True)
- self.db.gctransformer.inline_helpers(graph)
- return graph
-
def implementation_begin(self):
- self.oldgraph = self.graph
- self.graph = self.patch_graph(copy_graph=True)
SSI_to_SSA(self.graph)
self.collect_var_and_types()
self.blocknum = {}
@@ -138,8 +109,6 @@
self.vars = None
self.blocknum = None
self.innerloops = None
- self.graph = self.oldgraph
- del self.oldgraph
def argnames(self):
return [LOCALVAR % v.name for v in self.graph.getargs()]
@@ -247,8 +216,6 @@
yield '}'
link = block.exits[0]
assert link.exitcase in (False, True)
- #yield 'assert(%s == %s);' % (self.expr(block.exitswitch),
- # self.genc.nameofvalue(link.exitcase, ct))
for op in self.gen_link(link):
yield op
elif TYPE in (Signed, Unsigned, SignedLongLong,
@@ -894,14 +861,11 @@
def getdebugfunctionname(self):
name = self.functionname
- if not name:
- return "?"
if name.startswith('pypy_g_'):
name = name[7:]
return name
def OP_DEBUG_RECORD_TRACEBACK(self, op):
- #if self.functionname is None, we print "?" as the argument */
return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % (
self.getdebugfunctionname(),)
@@ -941,5 +905,3 @@
cdecl(typename, ''),
self.expr(op.args[0]),
self.expr(op.result))
-
-assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
diff --git a/rpython/translator/c/gc.py b/rpython/translator/c/gc.py
--- a/rpython/translator/c/gc.py
+++ b/rpython/translator/c/gc.py
@@ -1,8 +1,7 @@
import sys
from rpython.flowspace.model import Constant
-from rpython.rtyper.lltypesystem import lltype
-from rpython.rtyper.lltypesystem.lltype import (typeOf, RttiStruct,
- RuntimeTypeInfo, top_container)
+from rpython.rtyper.lltypesystem.lltype import (RttiStruct,
+ RuntimeTypeInfo)
from rpython.translator.c.node import ContainerNode
from rpython.translator.c.support import cdecl
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -18,23 +17,12 @@
return defnode.db.gctransformer.HDR
return None
- def common_gcheader_initdata(self, defnode):
- if defnode.db.gctransformer is not None:
- raise NotImplementedError
- return None
-
def struct_gcheader_definition(self, defnode):
return self.common_gcheader_definition(defnode)
- def struct_gcheader_initdata(self, defnode):
- return self.common_gcheader_initdata(defnode)
-
def array_gcheader_definition(self, defnode):
return self.common_gcheader_definition(defnode)
- def array_gcheader_initdata(self, defnode):
- return self.common_gcheader_initdata(defnode)
-
def compilation_info(self):
if not self.db:
return ExternalCompilationInfo()
@@ -46,9 +34,6 @@
]
)
- def get_prebuilt_hash(self, obj):
- return None
-
def need_no_typeptr(self):
return False
@@ -109,16 +94,9 @@
class RefcountingGcPolicy(BasicGcPolicy):
- def gettransformer(self):
+ def gettransformer(self, translator):
from rpython.memory.gctransform import refcounting
- return refcounting.RefcountingGCTransformer(self.db.translator)
-
- def common_gcheader_initdata(self, defnode):
- if defnode.db.gctransformer is not None:
- gct = defnode.db.gctransformer
- top = top_container(defnode.obj)
- return gct.gcheaderbuilder.header_of_object(top)._obj
- return None
+ return refcounting.RefcountingGCTransformer(translator)
# for structs
@@ -197,16 +175,9 @@
class BoehmGcPolicy(BasicGcPolicy):
- def gettransformer(self):
+ def gettransformer(self, translator):
from rpython.memory.gctransform import boehm
- return boehm.BoehmGCTransformer(self.db.translator)
-
- def common_gcheader_initdata(self, defnode):
- if defnode.db.gctransformer is not None:
- hdr = lltype.malloc(defnode.db.gctransformer.HDR, immortal=True)
- hdr.hash = lltype.identityhash_nocache(defnode.obj._as_ptr())
- return hdr._obj
- return None
+ return boehm.BoehmGCTransformer(translator)
def array_setup(self, arraydefnode):
pass
@@ -313,9 +284,9 @@
class BasicFrameworkGcPolicy(BasicGcPolicy):
- def gettransformer(self):
+ def gettransformer(self, translator):
if hasattr(self, 'transformerclass'): # for rpython/memory tests
- return self.transformerclass(self.db.translator)
+ return self.transformerclass(translator)
raise NotImplementedError
def struct_setup(self, structdefnode, rtti):
@@ -362,24 +333,6 @@
args = [funcgen.expr(v) for v in op.args]
return '%s = %s; /* for moving GCs */' % (args[1], args[0])
- def common_gcheader_initdata(self, defnode):
- o = top_container(defnode.obj)
- needs_hash = self.get_prebuilt_hash(o) is not None
- hdr = defnode.db.gctransformer.gc_header_for(o, needs_hash)
- return hdr._obj
-
- def get_prebuilt_hash(self, obj):
- # for prebuilt objects that need to have their hash stored and
- # restored. Note that only structures that are StructNodes all
- # the way have their hash stored (and not e.g. structs with var-
- # sized arrays at the end). 'obj' must be the top_container.
- TYPE = typeOf(obj)
- if not isinstance(TYPE, lltype.GcStruct):
- return None
- if TYPE._is_varsize():
- return None
- return getattr(obj, '_hash_cache_', None)
-
def need_no_typeptr(self):
config = self.db.translator.config
return config.translation.gcremovetypeptr
@@ -440,15 +393,15 @@
class ShadowStackFrameworkGcPolicy(BasicFrameworkGcPolicy):
- def gettransformer(self):
+ def gettransformer(self, translator):
from rpython.memory.gctransform import shadowstack
- return shadowstack.ShadowStackFrameworkGCTransformer(self.db.translator)
+ return shadowstack.ShadowStackFrameworkGCTransformer(translator)
class AsmGcRootFrameworkGcPolicy(BasicFrameworkGcPolicy):
- def gettransformer(self):
+ def gettransformer(self, translator):
from rpython.memory.gctransform import asmgcroot
- return asmgcroot.AsmGcRootFrameworkGCTransformer(self.db.translator)
+ return asmgcroot.AsmGcRootFrameworkGCTransformer(translator)
def GC_KEEPALIVE(self, funcgen, v):
return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -126,8 +126,10 @@
if not self.standalone:
raise NotImplementedError("--gcrootfinder=asmgcc requires standalone")
+ exctransformer = translator.getexceptiontransformer()
db = LowLevelDatabase(translator, standalone=self.standalone,
gcpolicyclass=gcpolicyclass,
+ exctransformer=exctransformer,
thread_enabled=self.config.translation.thread,
sandbox=self.config.translation.sandbox)
self.db = db
@@ -193,22 +195,8 @@
DEBUG_DEFINES = {'RPY_ASSERT': 1,
'RPY_LL_ASSERT': 1}
- def generate_graphs_for_llinterp(self, db=None):
- # prepare the graphs as when the source is generated, but without
- # actually generating the source.
- if db is None:
- db = self.build_database()
- graphs = db.all_graphs()
- db.gctransformer.prepare_inline_helpers(graphs)
- for node in db.containerlist:
- if hasattr(node, 'funcgens'):
- for funcgen in node.funcgens:
- funcgen.patch_graph(copy_graph=False)
- return db
-
def generate_source(self, db=None, defines={}, exe_name=None):
assert self.c_source_filename is None
-
if db is None:
db = self.build_database()
pf = self.getentrypointptr()
@@ -846,7 +834,6 @@
#
sg = SourceGenerator(database)
sg.set_strategy(targetdir, split)
- database.prepare_inline_helpers()
sg.gen_readable_parts_of_source(f)
headers_to_precompile = sg.headers_to_precompile[:]
headers_to_precompile.insert(0, incfilename)
diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py
--- a/rpython/translator/c/node.py
+++ b/rpython/translator/c/node.py
@@ -3,8 +3,7 @@
Void, OpaqueType, Float, RuntimeTypeInfo, getRuntimeTypeInfo, Char,
_subarray)
from rpython.rtyper.lltypesystem import llmemory, llgroup
-from rpython.translator.c.funcgen import FunctionCodeGenerator
-from rpython.translator.c.external import CExternalFunctionCodeGenerator
+from rpython.translator.c.funcgen import make_funcgen
from rpython.translator.c.support import USESLOTS # set to False if necessary while refactoring
from rpython.translator.c.support import cdecl, forward_cdecl, somelettersfrom
from rpython.translator.c.support import c_char_array_constant, barebonearray
@@ -540,7 +539,17 @@
class StructNode(ContainerNode):
nodekind = 'struct'
if USESLOTS:
- __slots__ = ()
+ __slots__ = ('gc_init',)
+
+ def __init__(self, db, T, obj):
+ ContainerNode.__init__(self, db, T, obj)
+ if needs_gcheader(T):
+ gct = self.db.gctransformer
+ if gct is not None:
+ self.gc_init = gct.gcheader_initdata(self)
+ db.getcontainernode(self.gc_init)
+ else:
+ self.gc_init = None
def basename(self):
T = self.getTYPE()
@@ -567,8 +576,7 @@
data = []
if needs_gcheader(T):
- gc_init = self.db.gcpolicy.struct_gcheader_initdata(self)
- data.append(('gcheader', gc_init))
+ data.append(('gcheader', self.gc_init))
for name in defnode.fieldnames:
data.append((name, getattr(self.obj, name)))
@@ -641,7 +649,7 @@
def implementation(self):
hash_typename = self.get_hash_typename()
- hash = self.db.gcpolicy.get_prebuilt_hash(self.obj)
+ hash = self.db.gctransformer.get_prebuilt_hash(self.obj)
assert hash is not None
lines = list(self.initializationexpr())
lines.insert(0, '%s = { {' % (
@@ -651,7 +659,8 @@
return lines
def gcstructnode_factory(db, T, obj):
- if db.gcpolicy.get_prebuilt_hash(obj) is not None:
+ if (db.gctransformer and
+ db.gctransformer.get_prebuilt_hash(obj) is not None):
cls = GcStructNodeWithHash
else:
cls = StructNode
@@ -661,7 +670,17 @@
class ArrayNode(ContainerNode):
nodekind = 'array'
if USESLOTS:
- __slots__ = ()
+ __slots__ = ('gc_init',)
+
+ def __init__(self, db, T, obj):
+ ContainerNode.__init__(self, db, T, obj)
+ if needs_gcheader(T):
+ gct = self.db.gctransformer
+ if gct is not None:
+ self.gc_init = gct.gcheader_initdata(self)
+ db.getcontainernode(self.gc_init)
+ else:
+ self.gc_init = None
def getptrname(self):
if barebonearray(self.getTYPE()):
@@ -681,8 +700,7 @@
T = self.getTYPE()
yield '{'
if needs_gcheader(T):
- gc_init = self.db.gcpolicy.array_gcheader_initdata(self)
- lines = generic_initializationexpr(self.db, gc_init, 'gcheader',
+ lines = generic_initializationexpr(self.db, self.gc_init, 'gcheader',
'%sgcheader' % (decoration,))
for line in lines:
yield line
@@ -781,81 +799,64 @@
comma = ''
expr += comma
i = expr.find('\n')
- if i<0: i = len(expr)
+ if i < 0:
+ i = len(expr)
expr = '%s\t/* %s */%s' % (expr[:i], decoration, expr[i:])
return expr.split('\n')
# ____________________________________________________________
-class FuncNode(ContainerNode):
+class FuncNodeBase(ContainerNode):
nodekind = 'func'
eci_name = 'compilation_info'
# there not so many node of this kind, slots should not
# be necessary
-
- def __init__(self, db, T, obj, forcename=None):
+ def __init__(self, db, T, obj, ptrname):
Node.__init__(self, db)
self.globalcontainer = True
self.T = T
self.obj = obj
- callable = getattr(obj, '_callable', None)
- if (callable is not None and
- getattr(callable, 'c_name', None) is not None):
- self.name = forcename or obj._callable.c_name
- elif getattr(obj, 'external', None) == 'C' and not db.need_sandboxing(obj):
- self.name = forcename or self.basename()
- else:
- self.name = (forcename or
- db.namespace.uniquename('g_' + self.basename()))
- self.make_funcgens()
+ self.name = ptrname
self.typename = db.gettype(T) #, who_asks=self)
def getptrname(self):
return self.name
- def make_funcgens(self):
- self.funcgens = select_function_code_generators(self.obj, self.db, self.name)
- if self.funcgens:
- argnames = self.funcgens[0].argnames() #Assume identical for all funcgens
- self.implementationtypename = self.db.gettype(self.T, argnames=argnames)
- self._funccodegen_owner = self.funcgens[0]
- else:
- self._funccodegen_owner = None
-
def basename(self):
return self.obj._name
+
+class FuncNode(FuncNodeBase):
+ def __init__(self, db, T, obj, ptrname):
+ FuncNodeBase.__init__(self, db, T, obj, ptrname)
+ exception_policy = getattr(obj, 'exception_policy', None)
+ self.funcgen = make_funcgen(obj.graph, db, exception_policy, ptrname)
+ argnames = self.funcgen.argnames()
+ self.implementationtypename = db.gettype(T, argnames=argnames)
+ self._funccodegen_owner = self.funcgen
+
def enum_dependencies(self):
- if not self.funcgens:
- return []
- return self.funcgens[0].allconstantvalues() #Assume identical for all funcgens
+ return self.funcgen.allconstantvalues()
def forward_declaration(self):
callable = getattr(self.obj, '_callable', None)
is_exported = getattr(callable, 'exported_symbol', False)
- for funcgen in self.funcgens:
- yield '%s;' % (
- forward_cdecl(self.implementationtypename,
- funcgen.name(self.name), self.db.standalone,
- is_exported=is_exported))
+ yield '%s;' % (
+ forward_cdecl(self.implementationtypename,
+ self.name, self.db.standalone, is_exported=is_exported))
+
+ def graphs_to_patch(self):
+ for i in self.funcgen.graphs_to_patch():
+ yield i
def implementation(self):
- for funcgen in self.funcgens:
- for s in self.funcgen_implementation(funcgen):
- yield s
-
- def graphs_to_patch(self):
- for funcgen in self.funcgens:
- for i in funcgen.graphs_to_patch():
- yield i
-
- def funcgen_implementation(self, funcgen):
+ funcgen = self.funcgen
funcgen.implementation_begin()
# recompute implementationtypename as the argnames may have changed
argnames = funcgen.argnames()
implementationtypename = self.db.gettype(self.T, argnames=argnames)
- yield '%s {' % cdecl(implementationtypename, funcgen.name(self.name))
+ yield '%s {' % cdecl(implementationtypename, self.name)
#
# declare the local variables
#
@@ -866,7 +867,7 @@
while start < len(localnames):
# pack the local declarations over as few lines as possible
total = lengths[start] + 8
- end = start+1
+ end = start + 1
while total + lengths[end] < 77:
total += lengths[end] + 1
end += 1
@@ -897,44 +898,55 @@
del bodyiter
funcgen.implementation_end()
-def sandbox_stub(fnobj, db):
- # unexpected external function for --sandbox translation: replace it
- # with a "Not Implemented" stub. To support these functions, port them
- # to the new style registry (e.g. rpython.module.ll_os.RegisterOs).
- from rpython.translator.sandbox import rsandbox
- graph = rsandbox.get_external_function_sandbox_graph(fnobj, db,
- force_stub=True)
- return [FunctionCodeGenerator(graph, db)]
+class ExternalFuncNode(FuncNodeBase):
+ def __init__(self, db, T, obj, ptrname):
+ FuncNodeBase.__init__(self, db, T, obj, ptrname)
+ self._funccodegen_owner = None
-def sandbox_transform(fnobj, db):
- # for --sandbox: replace a function like os_open_llimpl() with
- # code that communicates with the external process to ask it to
- # perform the operation.
- from rpython.translator.sandbox import rsandbox
- graph = rsandbox.get_external_function_sandbox_graph(fnobj, db)
- return [FunctionCodeGenerator(graph, db)]
+ def enum_dependencies(self):
+ return []
-def select_function_code_generators(fnobj, db, functionname):
- sandbox = db.need_sandboxing(fnobj)
- if hasattr(fnobj, 'graph'):
- if sandbox and sandbox != "if_external":
- # apply the sandbox transformation
- return sandbox_transform(fnobj, db)
- exception_policy = getattr(fnobj, 'exception_policy', None)
- return [FunctionCodeGenerator(fnobj.graph, db, exception_policy,
- functionname)]
- elif getattr(fnobj, 'external', None) is not None:
- if sandbox:
- return sandbox_stub(fnobj, db)
- elif fnobj.external == 'C':
- return []
- else:
- assert fnobj.external == 'CPython'
- return [CExternalFunctionCodeGenerator(fnobj, db)]
- elif hasattr(fnobj._callable, "c_name"):
- return [] # this case should only be used for entrypoints
+ def forward_declaration(self):
+ return []
+
+ def implementation(self):
+ return []
+
+def new_funcnode(db, T, obj, forcename=None):
+ if db.sandbox:
+ if (getattr(obj, 'external', None) is not None and
+ not obj._safe_not_sandboxed):
+ from rpython.translator.sandbox import rsandbox
+ obj.__dict__['graph'] = rsandbox.get_sandbox_stub(
+ obj, db.translator.rtyper)
+ obj.__dict__.pop('_safe_not_sandboxed', None)
+ obj.__dict__.pop('external', None)
+ if forcename:
+ name = forcename
else:
- raise ValueError("don't know how to generate code for %r" % (fnobj,))
+ name = _select_name(db, obj)
+ if hasattr(obj, 'graph'):
+ return FuncNode(db, T, obj, name)
+ elif getattr(obj, 'external', None) is not None:
+ assert obj.external == 'C'
+ if db.sandbox:
+ assert obj._safe_not_sandboxed
+ return ExternalFuncNode(db, T, obj, name)
+ elif hasattr(obj._callable, "c_name"):
+ return ExternalFuncNode(db, T, obj, name) # this case should only be used for entrypoints
+ else:
+ raise ValueError("don't know how to generate code for %r" % (obj,))
+
+
+def _select_name(db, obj):
+ try:
+ return obj._callable.c_name
+ except AttributeError:
+ pass
+ if getattr(obj, 'external', None) == 'C':
+ return obj._name
+ return db.namespace.uniquename('g_' + obj._name)
+
class ExtType_OpaqueNode(ContainerNode):
nodekind = 'rpyopaque'
@@ -1044,7 +1056,7 @@
Array: ArrayNode,
GcArray: ArrayNode,
FixedSizeArray: FixedSizeArrayNode,
- FuncType: FuncNode,
+ FuncType: new_funcnode,
OpaqueType: opaquenode_factory,
llmemory._WeakRefType: weakrefnode_factory,
llgroup.GroupType: GroupNode,
diff --git a/rpython/translator/c/test/test_database.py b/rpython/translator/c/test/test_database.py
--- a/rpython/translator/c/test/test_database.py
+++ b/rpython/translator/c/test/test_database.py
@@ -9,8 +9,6 @@
def dump_on_stdout(database):
- if database.gctransformer:
- database.prepare_inline_helpers()
print '/*********************************/'
structdeflist = database.getstructdeflist()
for node in structdeflist:
@@ -171,7 +169,7 @@
F = FuncType([Signed], Signed)
f = functionptr(F, "f", graph=graph)
- db = LowLevelDatabase(t)
+ db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
db.get(f)
db.complete()
dump_on_stdout(db)
@@ -186,7 +184,7 @@
return p.x * p.y
t, graph = makegraph(ll_f, [int])
- db = LowLevelDatabase(t)
+ db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
db.get(getfunctionptr(graph))
db.complete()
dump_on_stdout(db)
@@ -207,7 +205,7 @@
return s.ptr1.x * s.ptr2.x
t, graph = makegraph(ll_f, [int])
- db = LowLevelDatabase(t)
+ db = LowLevelDatabase(t, exctransformer=t.getexceptiontransformer())
db.get(getfunctionptr(graph))
db.complete()
dump_on_stdout(db)
diff --git a/rpython/translator/c/test/test_refcount.py b/rpython/translator/c/test/test_refcount.py
--- a/rpython/translator/c/test/test_refcount.py
+++ b/rpython/translator/c/test/test_refcount.py
@@ -106,37 +106,6 @@
assert fn(1) == 4
assert fn(0) == 5
- def test_del_basic(self):
- py.test.skip("xxx fix or kill")
- S = lltype.GcStruct('S', ('x', lltype.Signed), rtti=True)
- TRASH = lltype.GcStruct('TRASH', ('x', lltype.Signed))
- GLOBAL = lltype.Struct('GLOBAL', ('x', lltype.Signed))
- glob = lltype.malloc(GLOBAL, immortal=True)
- def destructor(s):
- glob.x = s.x + 1
- def type_info_S(s):
- return lltype.getRuntimeTypeInfo(S)
-
- def g(n):
- s = lltype.malloc(S)
- s.x = n
- # now 's' should go away
- def entrypoint(n):
- g(n)
- # llop.gc__collect(lltype.Void)
- return glob.x
-
- t = TranslationContext()
- t.buildannotator().build_types(entrypoint, [int])
- rtyper = t.buildrtyper()
- destrptr = rtyper.annotate_helper_fn(destructor, [lltype.Ptr(S)])
- rtyper.attachRuntimeTypeInfoFunc(S, type_info_S, destrptr=destrptr)
- rtyper.specialize()
- fn = self.compile_func(entrypoint, None, t)
-
- res = fn(123)
- assert res == 124
-
def test_del_catches(self):
import os
def g():
diff --git a/rpython/translator/sandbox/rsandbox.py b/rpython/translator/sandbox/rsandbox.py
--- a/rpython/translator/sandbox/rsandbox.py
+++ b/rpython/translator/sandbox/rsandbox.py
@@ -16,7 +16,6 @@
from rpython.rlib import rposix
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.llannotation import lltype_to_annotation
-from rpython.tool.sourcetools import func_with_new_name
from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator
from rpython.tool.ansi_print import ansi_log
@@ -37,7 +36,8 @@
sandboxsafe=True)
- at signature(types.int(), types.ptr(rffi.CCHARP.TO), types.int(), returns=types.none())
+ at signature(types.int(), types.ptr(rffi.CCHARP.TO), types.int(),
+ returns=types.none())
def writeall_not_sandboxed(fd, buf, length):
while length > 0:
size = rffi.cast(rffi.SIZE_T, length)
@@ -85,15 +85,24 @@
return loader
def reraise_error(error, loader):
- if error == 1: raise OSError(load_int(loader), "external error")
- elif error == 2: raise IOError
- elif error == 3: raise OverflowError
- elif error == 4: raise ValueError
- elif error == 5: raise ZeroDivisionError
- elif error == 6: raise MemoryError
- elif error == 7: raise KeyError
- elif error == 8: raise IndexError
- else: raise RuntimeError
+ if error == 1:
+ raise OSError(load_int(loader), "external error")
+ elif error == 2:
+ raise IOError
+ elif error == 3:
+ raise OverflowError
+ elif error == 4:
+ raise ValueError
+ elif error == 5:
+ raise ZeroDivisionError
+ elif error == 6:
+ raise MemoryError
+ elif error == 7:
+ raise KeyError
+ elif error == 8:
+ raise IndexError
+ else:
+ raise RuntimeError
@signature(types.str(), returns=types.impossible())
@@ -101,51 +110,46 @@
STDERR = 2
with rffi.scoped_str2charp(msg + '\n') as buf:
writeall_not_sandboxed(STDERR, buf, len(msg) + 1)
- raise RuntimeError(msg) # XXX in RPython, the msg is ignored at the moment
+ raise RuntimeError(msg) # XXX in RPython, the msg is ignored
+
+def make_stub(fnname, msg):
+ """Build always-raising stub function to replace unsupported external."""
+ log.WARNING(msg)
+
+ def execute(*args):
+ not_implemented_stub(msg)
+ execute.__name__ = 'sandboxed_%s' % (fnname,)
+ return execute
+
+def sig_ll(fnobj):
+ FUNCTYPE = lltype.typeOf(fnobj)
+ args_s = [lltype_to_annotation(ARG) for ARG in FUNCTYPE.ARGS]
+ s_result = lltype_to_annotation(FUNCTYPE.RESULT)
+ return args_s, s_result
dump_string = rmarshal.get_marshaller(str)
-load_int = rmarshal.get_loader(int)
+load_int = rmarshal.get_loader(int)
-def get_external_function_sandbox_graph(fnobj, db, force_stub=False):
- """Build the graph of a helper trampoline function to be used
- in place of real calls to the external function 'fnobj'. The
- trampoline marshals its input arguments, dumps them to STDOUT,
- and waits for an answer on STDIN.
+def get_sandbox_stub(fnobj, rtyper):
+ fnname = fnobj._name
+ args_s, s_result = sig_ll(fnobj)
+ msg = "Not implemented: sandboxing for external function '%s'" % (fnname,)
+ execute = make_stub(fnname, msg)
+ return _annotate(rtyper, execute, args_s, s_result)
+
+def make_sandbox_trampoline(fnname, args_s, s_result):
+ """Create a trampoline function with the specified signature.
+
+ The trampoline is meant to be used in place of real calls to the external
+ function named 'fnname'. It marshals its input arguments, dumps them to
+ STDOUT, and waits for an answer on STDIN.
"""
- if getattr(getattr(fnobj, '_callable', None),
- '_sandbox_external_name', None):
- fnname = fnobj._callable._sandbox_external_name
- else:
- fnname = fnobj._name
- if hasattr(fnobj, 'graph'):
- # get the annotation of the input arguments and the result
- graph = fnobj.graph
- annotator = db.translator.annotator
- args_s = [annotator.binding(v) for v in graph.getargs()]
- s_result = annotator.binding(graph.getreturnvar())
- else:
- # pure external function - fall back to the annotations
- # corresponding to the ll types
- FUNCTYPE = lltype.typeOf(fnobj)
- args_s = [lltype_to_annotation(ARG) for ARG in FUNCTYPE.ARGS]
- s_result = lltype_to_annotation(FUNCTYPE.RESULT)
-
try:
- if force_stub: # old case - don't try to support suggested_primitive
- raise NotImplementedError("sandboxing for external function '%s'"
- % (fnname,))
-
dump_arguments = rmarshal.get_marshaller(tuple(args_s))
load_result = rmarshal.get_loader(s_result)
-
- except (NotImplementedError,
- rmarshal.CannotMarshal,
- rmarshal.CannotUnmarshall), e:
- msg = 'Not Implemented: %s' % (e,)
- log.WARNING(msg)
- def execute(*args):
- not_implemented_stub(msg)
-
+ except (rmarshal.CannotMarshal, rmarshal.CannotUnmarshall) as e:
+ msg = "Cannot sandbox function '%s': %s" % (fnname, e)
+ execute = make_stub(fnname, msg)
else:
def execute(*args):
# marshal the function name and input arguments
@@ -158,9 +162,12 @@
result = load_result(loader)
loader.check_finished()
return result
- execute = func_with_new_name(execute, 'sandboxed_' + fnname)
+ execute.__name__ = 'sandboxed_%s' % (fnname,)
+ return execute
- ann = MixLevelHelperAnnotator(db.translator.rtyper)
- graph = ann.getgraph(execute, args_s, s_result)
+
+def _annotate(rtyper, f, args_s, s_result):
+ ann = MixLevelHelperAnnotator(rtyper)
+ graph = ann.getgraph(f, args_s, s_result)
ann.finish()
return graph
More information about the pypy-commit
mailing list