[pypy-svn] r38437 - in pypy/dist/pypy: rpython rpython/lltypesystem rpython/memory/gctransform translator/backendopt translator/c translator/stackless
arigo at codespeak.net
arigo at codespeak.net
Sun Feb 11 02:00:57 CET 2007
Author: arigo
Date: Sun Feb 11 02:00:53 2007
New Revision: 38437
Modified:
pypy/dist/pypy/rpython/llinterp.py
pypy/dist/pypy/rpython/lltypesystem/lloperation.py
pypy/dist/pypy/rpython/memory/gctransform/framework.py
pypy/dist/pypy/translator/backendopt/graphanalyze.py
pypy/dist/pypy/translator/c/funcgen.py
pypy/dist/pypy/translator/stackless/code.py
pypy/dist/pypy/translator/stackless/frame.py
pypy/dist/pypy/translator/stackless/transform.py
Log:
(pedronis, arigo)
Remove the unsafe_call operation because its C equivalent is really unsafe:
passing less arguments than expected in a C call is not really valid
and crashes on some platforms with some optimization levels.
Whacked instead at the stackless transform to avoid the operation.
The principle of conservation of mess means that we had to introduce
another similar operation, though, 'adr_call'. Don't use it.
Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py (original)
+++ pypy/dist/pypy/rpython/llinterp.py Sun Feb 11 02:00:53 2007
@@ -576,20 +576,20 @@
log.warn("op_indirect_call with graphs=None:", f)
return self.op_direct_call(f, *args)
- def op_unsafe_call(self, TGT, f):
+ def op_adr_call(self, TGT, f, *inargs):
checkadr(f)
obj = self.llinterpreter.typer.type_system.deref(f.ref())
assert hasattr(obj, 'graph') # don't want to think about that
graph = obj.graph
args = []
- for arg in obj.graph.startblock.inputargs:
- args.append(arg.concretetype._defl())
+ for inarg, arg in zip(inargs, obj.graph.startblock.inputargs):
+ args.append(lltype._cast_whatever(arg.concretetype, inarg))
frame = self.__class__(graph, args, self.llinterpreter, self)
result = frame.eval()
from pypy.translator.stackless.frame import storage_type
assert storage_type(lltype.typeOf(result)) == TGT
return lltype._cast_whatever(TGT, result)
- op_unsafe_call.need_result_type = True
+ op_adr_call.need_result_type = True
def op_malloc(self, obj):
if self.llinterpreter.gc is not None:
Modified: pypy/dist/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/lloperation.py Sun Feb 11 02:00:53 2007
@@ -135,8 +135,6 @@
'direct_call': LLOp(canraise=(Exception,)),
'indirect_call': LLOp(canraise=(Exception,)),
- #'safe_call': LLOp(),
- 'unsafe_call': LLOp(canraise=(Exception,)),
# __________ numeric operations __________
@@ -347,6 +345,7 @@
'adr_ne': LLOp(canfold=True),
'adr_gt': LLOp(canfold=True),
'adr_ge': LLOp(canfold=True),
+ 'adr_call': LLOp(canraise=(Exception,)),
'cast_ptr_to_adr': LLOp(canfold=True),
'cast_adr_to_ptr': LLOp(canfold=True),
'cast_ptr_to_weakadr': LLOp(canfold=True),
Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform/framework.py Sun Feb 11 02:00:53 2007
@@ -443,7 +443,6 @@
self.default(hop)
gct_indirect_call = gct_direct_call
- gct_unsafe_call = gct_direct_call
def gct_malloc(self, hop):
op = hop.spaceop
Modified: pypy/dist/pypy/translator/backendopt/graphanalyze.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/graphanalyze.py (original)
+++ pypy/dist/pypy/translator/backendopt/graphanalyze.py Sun Feb 11 02:00:53 2007
@@ -38,8 +38,6 @@
if op.args[-1].value is None:
return True
return self.analyze_indirect_call(op.args[-1].value, seen)
- elif op.opname == "unsafe_call":
- return True
if self.operation_is_true(op):
return True
Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py (original)
+++ pypy/dist/pypy/translator/c/funcgen.py Sun Feb 11 02:00:53 2007
@@ -10,7 +10,7 @@
from pypy.rpython.lltypesystem.lltype import UnsignedLongLong, Char, UniChar
from pypy.rpython.lltypesystem.lltype import pyobjectptr, ContainerType
from pypy.rpython.lltypesystem.lltype import Struct, Array, FixedSizeArray
-from pypy.rpython.lltypesystem.lltype import ForwardReference
+from pypy.rpython.lltypesystem.lltype import ForwardReference, FuncType
from pypy.rpython.lltypesystem.llmemory import Address, WeakGcAddress
from pypy.translator.backendopt.ssa import SSI_to_SSA
@@ -377,10 +377,10 @@
r = self.expr(op.result)
return 'OP_CALL_ARGS((%s), %s);' % (', '.join(args), r)
- def OP_DIRECT_CALL(self, op):
+ def generic_call(self, FUNC, fnexpr, args_v, v_result):
args = []
- fn = op.args[0]
- for v, ARGTYPE in zip(op.args[1:], fn.concretetype.TO.ARGS):
+ assert len(args_v) == len(FUNC.TO.ARGS)
+ for v, ARGTYPE in zip(args_v, FUNC.TO.ARGS):
if ARGTYPE is Void:
continue # skip 'void' argument
args.append(self.expr(v))
@@ -388,25 +388,32 @@
if isinstance(ARGTYPE, ContainerType):
args[-1] = '*%s' % (args[-1],)
- line = '%s(%s);' % (self.expr(fn), ', '.join(args))
- if self.lltypemap(op.result) is not Void:
+ line = '%s(%s);' % (fnexpr, ', '.join(args))
+ if self.lltypemap(v_result) is not Void:
# skip assignment of 'void' return value
- r = self.expr(op.result)
+ r = self.expr(v_result)
line = '%s = %s' % (r, line)
return line
- # the following works since the extra arguments that indirect_call has
- # is removed by zip()
- OP_INDIRECT_CALL = OP_DIRECT_CALL
-
- def OP_UNSAFE_CALL(self, op):
- line = '((%s (*)())(%s))();' % (cdecl(self.lltypename(op.result), ''),
- self.expr(op.args[0]))
- if self.lltypemap(op.result) is not Void:
- r = self.expr(op.result)
- line = '%s = %s' % (r, line)
- return line
-
+ def OP_DIRECT_CALL(self, op):
+ fn = op.args[0]
+ return self.generic_call(fn.concretetype, self.expr(fn),
+ op.args[1:], op.result)
+
+ def OP_INDIRECT_CALL(self, op):
+ fn = op.args[0]
+ return self.generic_call(fn.concretetype, self.expr(fn),
+ op.args[1:-1], op.result)
+
+ def OP_ADR_CALL(self, op):
+ ARGTYPES = [v.concretetype for v in op.args[1:]]
+ RESTYPE = op.result.concretetype
+ FUNC = Ptr(FuncType(ARGTYPES, RESTYPE))
+ typename = self.db.gettype(FUNC)
+ fnaddr = op.args[0]
+ fnexpr = '((%s)%s)' % (cdecl(typename, ''), self.expr(fnaddr))
+ return self.generic_call(FUNC, fnexpr, op.args[1:], op.result)
+
# low-level operations
def generic_get(self, op, sourceexpr):
T = self.lltypemap(op.result)
Modified: pypy/dist/pypy/translator/stackless/code.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/code.py (original)
+++ pypy/dist/pypy/translator/stackless/code.py Sun Feb 11 02:00:53 2007
@@ -1,4 +1,5 @@
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
+from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib import rarithmetic
from pypy.rpython import extfunctable
from pypy.translator.stackless import frame
@@ -282,7 +283,6 @@
for _lltype, typename in STORAGE_TYPES_AND_FIELDS:
if typename == 'void': continue
- if typename == 'weak': continue
exec template%dict(typename=typename, TYPENAME=typename.upper())
# ____________________________________________________________
@@ -296,30 +296,54 @@
self.retval_float = 0.0
self.retval_addr = llmemory.NULL
self.retval_ref = frame.null_saved_ref
+ self.retval_weak = llmemory.WEAKNULL
self.exception = None
self.masterarray = lltype.malloc(frame.FRAME_INFO_ARRAY, 0,
immortal=True)
global_state = StacklessData()
-def call_function(fn, retval_code):
+# the following functions are patched by transform.py in finish()
+# so that they don't really do what they appear to - we discovered
+# that it was not safe at all to produce this kind of C code
+def define_call_function_retval(TYPE, typename):
+ FUNCTYPE = lltype.Ptr(lltype.FuncType([], TYPE))
+ def call_function_retval_xyz(fnaddr, signature_index):
+ fn = llmemory.cast_adr_to_ptr(fnaddr, FUNCTYPE)
+ return fn()
+ call_function_retval_xyz.stackless_explicit = True
+ call_function_retval_xyz.dont_inline = True
+ fnname = 'call_function_retval_' + typename
+ fn = func_with_new_name(call_function_retval_xyz, fnname)
+ globals()[fnname] = fn
+for _lltype, _typename in STORAGE_TYPES_AND_FIELDS:
+ define_call_function_retval(_lltype, _typename)
+
+
+def call_function(fn, signature_index):
+ retval_code = signature_index & frame.storage_type_bitmask
if retval_code == frame.RETVAL_VOID:
- lloperation.llop.unsafe_call(lltype.Void, fn)
+ call_function_retval_void(fn, signature_index)
elif retval_code == frame.RETVAL_REF:
- global_state.retval_ref = lloperation.llop.unsafe_call(
- SAVED_REFERENCE, fn)
+ global_state.retval_ref = (
+ call_function_retval_ref(fn, signature_index))
elif retval_code == frame.RETVAL_ADDR:
- global_state.retval_addr = lloperation.llop.unsafe_call(
- llmemory.Address, fn)
+ global_state.retval_addr = (
+ call_function_retval_addr(fn, signature_index))
elif retval_code == frame.RETVAL_LONG:
- global_state.retval_long = lloperation.llop.unsafe_call(
- lltype.Signed, fn)
+ global_state.retval_long = (
+ call_function_retval_long(fn, signature_index))
elif retval_code == frame.RETVAL_FLOAT:
- global_state.retval_float = lloperation.llop.unsafe_call(
- lltype.Float, fn)
+ global_state.retval_float = (
+ call_function_retval_float(fn, signature_index))
elif retval_code == frame.RETVAL_LONGLONG:
- global_state.retval_longlong = lloperation.llop.unsafe_call(
- lltype.SignedLongLong, fn)
+ global_state.retval_longlong = (
+ call_function_retval_longlong(fn, signature_index))
+ elif retval_code == frame.RETVAL_WEAK:
+ global_state.retval_weak = (
+ call_function_retval_weak(fn, signature_index))
+ else:
+ assert False
call_function.stackless_explicit = True
class UnwindException(lloperation.StackException):
@@ -343,9 +367,9 @@
while True:
back = pending.f_back
decoded = frame.decodestate(pending.f_restart)
- (fn, global_state.restart_substate, retval_type) = decoded
+ (fn, global_state.restart_substate, signature_index) = decoded
try:
- call_function(fn, retval_type)
+ call_function(fn, signature_index)
except UnwindException, u: #XXX annotation support needed
if u.frame_bottom:
u.frame_bottom.f_back = back
@@ -425,3 +449,12 @@
global_state.retval_ref = frame.null_saved_ref
return res
fetch_retval_ref.stackless_explicit = True
+
+def fetch_retval_weak():
+ e = global_state.exception
+ if e:
+ global_state.exception = None
+ raise e
+ else:
+ return global_state.retval_weak
+fetch_retval_weak.stackless_explicit = True
Modified: pypy/dist/pypy/translator/stackless/frame.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/frame.py (original)
+++ pypy/dist/pypy/translator/stackless/frame.py Sun Feb 11 02:00:53 2007
@@ -30,6 +30,9 @@
if _TYPE not in STORAGE_TYPES:
STORAGE_TYPES.append(_TYPE)
+storage_type_bitmask = 0x07 # a power of two - 1
+assert storage_type_bitmask >= len(STORAGE_TYPES)
+
STORAGE_FIELDS = dict(STORAGE_TYPES_AND_FIELDS)
del STORAGE_FIELDS[lltype.Void]
@@ -98,7 +101,7 @@
finfo = masterarray[index - restartstate]
return (finfo.fnaddr, # function ptr
restartstate, # restart state within function
- finfo.info) # retval_type
+ finfo.info) # signature_index
decodestate.stackless_explicit = True
@@ -116,7 +119,7 @@
self.resume_point_count = resume_point_count
self.frame_types = ()
- def compress(self, rtyper):
+ def compress(self, signaturecodes, rtyper):
"""This returns sufficient information to be able to build the
entries that will go in the global array of restart
information."""
@@ -126,10 +129,18 @@
if not isinstance(graph, FunctionGraph):
graph = bk.getdesc(graph).getuniquegraph()
funcptr = getfunctionptr(graph)
- rettype = lltype.typeOf(funcptr).TO.RESULT
- retval_type = STORAGE_TYPES.index(storage_type(rettype))
-
- result = [(llmemory.cast_ptr_to_adr(funcptr), retval_type)]
+ FUNC = lltype.typeOf(funcptr).TO
+ rettype_index = STORAGE_TYPES.index(storage_type(FUNC.RESULT))
+ cache = signaturecodes[rettype_index]
+ key = tuple([storage_type(ARG) for ARG in FUNC.ARGS])
+ try:
+ signature_index = cache[key]
+ except KeyError:
+ signature_index = len(cache) * (storage_type_bitmask+1)
+ signature_index |= rettype_index
+ cache[key] = signature_index
+ assert (signature_index & storage_type_bitmask) == rettype_index
+ result = [(llmemory.cast_ptr_to_adr(funcptr), signature_index)]
for i in range(1, self.resume_point_count):
result.append((llmemory.NULL, i))
else:
Modified: pypy/dist/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/transform.py (original)
+++ pypy/dist/pypy/translator/stackless/transform.py Sun Feb 11 02:00:53 2007
@@ -293,7 +293,14 @@
self.frametyper = FrameTyper(stackless_gc, self)
self.masterarray1 = []
self.curr_graph = None
-
+
+ self.signaturecodes = [{} for RETTYPE in frame.STORAGE_TYPES]
+ # self.signaturecodes[n] is a dict {ARGTYPES: signature_index}
+ # where n is the return type as an index in STORAGE_TYPES.
+ # the signature_index is an arbitrary number but it encodes
+ # the type of the result, i.e.
+ # n == (signature_index & storage_type_bitmask)
+
bk = translator.annotator.bookkeeper
self.unwind_exception_type = getinstancerepr(
@@ -363,6 +370,8 @@
code.fetch_retval_addr, [], annmodel.SomeAddress()),
SAVED_REFERENCE: mixlevelannotator.constfunc(
code.fetch_retval_ref, [], annmodel.SomePtr(SAVED_REFERENCE)),
+ llmemory.WeakGcAddress: mixlevelannotator.constfunc(
+ code.fetch_retval_weak, [], annmodel.SomeWeakGcAddress()),
}
s_StatePtr = annmodel.SomePtr(frame.OPAQUE_STATE_HEADER_PTR)
@@ -413,6 +422,10 @@
code.resume_after_ref,
[s_StatePtr, annmodel.SomePtr(SAVED_REFERENCE)],
annmodel.s_None),
+ llmemory.WeakGcAddress: mixlevelannotator.constfunc(
+ code.resume_after_weak,
+ [s_StatePtr, annmodel.SomeWeakGcAddress()],
+ annmodel.s_None),
}
exception_def = bk.getuniqueclassdef(Exception)
self.resume_after_raising_ptr = mixlevelannotator.constfunc(
@@ -1098,7 +1111,7 @@
def register_restart_info(self, restartinfo):
assert not self.is_finished
rtyper = self.translator.rtyper
- for frame_info in restartinfo.compress(rtyper):
+ for frame_info in restartinfo.compress(self.signaturecodes, rtyper):
self.masterarray1.append(frame_info)
def finish(self):
@@ -1108,6 +1121,44 @@
import cPickle
cPickle.dump(self.stats, open('stackless-stats.pickle', 'wb'))
+ # fun fun fun patching the call_function_retval_xyz() functions!
+ for RESTYPE, typename in frame.STORAGE_TYPES_AND_FIELDS:
+ rettype_index = STORAGE_TYPES.index(RESTYPE)
+ cache = self.signaturecodes[rettype_index]
+ if not cache:
+ continue # not used anyway, don't produce a broken empty switch
+ func = getattr(code, 'call_function_retval_' + typename)
+ desc = self.translator.annotator.bookkeeper.getdesc(func)
+ graph = desc.getuniquegraph()
+
+ [v_fnaddr, v_signature_index] = graph.getargs()
+ block = model.Block([v_fnaddr, v_signature_index])
+ block.exitswitch = v_signature_index
+ block.isstartblock = True
+ graph.startblock = block
+ switchlinks = []
+
+ for ARGTYPES, signature_index in cache.items():
+ # XXX because of type erasure, the following cast is
+ # kind of invalid, but we hope that nobody will notice
+ FUNCTYPE = lltype.Ptr(lltype.FuncType(ARGTYPES, RESTYPE))
+ v_fnaddr1 = varoftype(v_fnaddr.concretetype)
+ callblock = model.Block([v_fnaddr1])
+ llops = LowLevelOpList()
+ args_v = [model.Constant(TYPE._defl(), concretetype=TYPE)
+ for TYPE in ARGTYPES]
+ v_res = llops.genop('adr_call', [v_fnaddr1] + args_v,
+ resulttype = RESTYPE)
+ callblock.operations[:] = llops
+ callblock.closeblock(model.Link([v_res], graph.returnblock))
+ link = model.Link([v_fnaddr], callblock)
+ link.exitcase = signature_index
+ link.llexitcase = signature_index
+ switchlinks.append(link)
+
+ block.closeblock(*switchlinks)
+ model.checkgraph(graph)
+
self.is_finished = True
masterarray = lltype.malloc(frame.FRAME_INFO_ARRAY,
len(self.masterarray1),
More information about the Pypy-commit
mailing list