[pypy-svn] r26969 - in pypy/dist/pypy: rpython rpython/lltypesystem translator/stackless
arigo at codespeak.net
arigo at codespeak.net
Mon May 8 17:29:19 CEST 2006
Author: arigo
Date: Mon May 8 17:29:17 2006
New Revision: 26969
Modified:
pypy/dist/pypy/rpython/llinterp.py
pypy/dist/pypy/rpython/lltypesystem/lltype.py
pypy/dist/pypy/rpython/rbuiltin.py
pypy/dist/pypy/translator/stackless/code.py
pypy/dist/pypy/translator/stackless/transform.py
Log:
(pedronis, arigo)
Stackless transform: type erasure in a GC-friendly way,
with GcOpaqueType. Added some comments, changed some strange
usages of numbers into strange usages of globals() in a very
Pythonic way, etc.
Modified: pypy/dist/pypy/rpython/llinterp.py
==============================================================================
--- pypy/dist/pypy/rpython/llinterp.py (original)
+++ pypy/dist/pypy/rpython/llinterp.py Mon May 8 17:29:17 2006
@@ -333,10 +333,10 @@
elif operation.opname == 'indirect_call':
assert isinstance(operation.args[0], Variable)
vals = [self.getval(x) for x in operation.args]
- # if these special cases pile up, do something better here
+ # XXX these special cases DO pile up, do something better here
if operation.opname in ['cast_pointer', 'ooupcast', 'oodowncast',
'cast_adr_to_ptr', 'cast_int_to_ptr',
- 'cast_opaque_ptr']:
+ 'cast_opaque_ptr', 'unsafe_call']:
vals.insert(0, operation.result.concretetype)
try:
retval = ophandler(*vals)
@@ -479,7 +479,7 @@
log.warn("op_indirect_call with graphs=None:", f)
return self.op_direct_call(f, *args)
- def op_unsafe_call(self, f):
+ def op_unsafe_call(self, TGT, f):
assert isinstance(f, llmemory.fakeaddress)
assert f.offset is None
obj = self.llinterpreter.typer.type_system.deref(f.ob)
@@ -490,9 +490,7 @@
args.append(arg.concretetype._defl())
frame = self.__class__(graph, args, self.llinterpreter, self)
result = frame.eval()
- if isinstance(lltype.typeOf(result), lltype.Ptr):
- result = llmemory.cast_ptr_to_adr(result)
- return result
+ return lltype._cast_whatever(TGT, result)
def op_malloc(self, obj):
if self.llinterpreter.gc is not None:
Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py Mon May 8 17:29:17 2006
@@ -580,7 +580,28 @@
if cast is None:
raise TypeError, "unsupported cast"
return cast(value)
-
+
+def _cast_whatever(TGT, value):
+ from pypy.rpython.lltypesystem import llmemory
+ ORIG = typeOf(value)
+ if ORIG == TGT:
+ return value
+ if (isinstance(TGT, Primitive) and
+ isinstance(ORIG, Primitive)):
+ return cast_primitive(TGT, value)
+ elif isinstance(TGT, Ptr):
+ if isinstance(ORIG, Ptr):
+ if (isinstance(TGT.TO, OpaqueType) or
+ isinstance(ORIG.TO, OpaqueType)):
+ return cast_opaque_ptr(TGT, value)
+ else:
+ return cast_pointer(TGT, value)
+ elif ORIG == llmemory.Address:
+ return llmemory.cast_adr_to_ptr(value, TGT)
+ elif TGT == llmemory.Address and isinstance(ORIG, Ptr):
+ return llmemory.cast_ptr_to_adr(value)
+ raise TypeError("don't know how to cast from %r to %r" % (ORIG, TGT))
+
class InvalidCast(TypeError):
pass
Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py (original)
+++ pypy/dist/pypy/rpython/rbuiltin.py Mon May 8 17:29:17 2006
@@ -399,7 +399,12 @@
return v_value
elif isinstance(TGT, lltype.Ptr):
if isinstance(ORIG, lltype.Ptr):
- return llops.genop('cast_pointer', [v_value], resulttype = TGT)
+ if (isinstance(TGT.TO, lltype.OpaqueType) or
+ isinstance(ORIG.TO, lltype.OpaqueType)):
+ return llops.genop('cast_opaque_ptr', [v_value],
+ resulttype = TGT)
+ else:
+ return llops.genop('cast_pointer', [v_value], resulttype = TGT)
elif ORIG == llmemory.Address:
return llops.genop('cast_adr_to_ptr', [v_value], resulttype = TGT)
elif TGT == llmemory.Address and isinstance(ORIG, lltype.Ptr):
Modified: pypy/dist/pypy/translator/stackless/code.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/code.py (original)
+++ pypy/dist/pypy/translator/stackless/code.py Mon May 8 17:29:17 2006
@@ -2,9 +2,29 @@
from pypy.rpython import rarithmetic
from pypy.rpython import extfunctable
+SAVED_REFERENCE = lltype.Ptr(lltype.GcOpaqueType('stackless.saved_ref'))
+null_saved_ref = lltype.nullptr(SAVED_REFERENCE.TO)
-def ll_frame_switch(state):
+STORAGE_TYPES = [lltype.Void, SAVED_REFERENCE, llmemory.Address,
+ lltype.Signed, lltype.Float, lltype.SignedLongLong]
+
+STORAGE_FIELDS = {SAVED_REFERENCE: 'ref',
+ llmemory.Address: 'addr',
+ lltype.Signed: 'long',
+ lltype.Float: 'float',
+ lltype.SignedLongLong: 'longlong',
+ }
+
+RETVAL_VOID = 0
+for _key, _value in STORAGE_FIELDS.items():
+ globals()['RETVAL_' + _value.upper()] = STORAGE_TYPES.index(_key)
+
+# ____________________________________________________________
+
+def ll_frame_switch(targetstate):
if global_state.restart_substate == 0:
+ # normal entry point for a call to state.switch()
+ # first unwind the stack
u = UnwindException()
s = lltype.malloc(SWITCH_STATE)
s.header.restartstate = 1
@@ -12,26 +32,35 @@
f = ll_frame_switch
if global_state.restart_substate:
f = None
- s.c = llmemory.cast_ptr_to_adr(state)
+ s.c = lltype.cast_opaque_ptr(SAVED_REFERENCE, targetstate)
s.header.function = llmemory.cast_ptr_to_adr(f)
+ s.header.retval_type = RETVAL_REF
add_frame_state(u, s.header)
raise u
elif global_state.restart_substate == 1:
+ # STATE 1: we didn't do anything so far, but the stack is unwound
global_state.restart_substate = 0
- top = global_state.top
- s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), top)
- top.restartstate = 2
- state = llmemory.cast_adr_to_ptr(s.c, lltype.Ptr(STATE_HEADER))
- global_state.top = state
- global_state.retval_void_p = llmemory.cast_ptr_to_adr(top)
- raise UnwindException()
+ # grab the frame corresponding to ourself, and prepare it for
+ # the future switch() back, which will go to STATE 2 below
+ sourcestate = global_state.top
+ sourcestate.restartstate = 2
+ # the 'targetstate' local is garbage here, it must be read back from
+ # 's.c' where we saved it by STATE 0 above
+ s = lltype.cast_pointer(lltype.Ptr(SWITCH_STATE), sourcestate)
+ targetstate = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER), s.c)
+ global_state.top = targetstate
+ global_state.retval_ref = lltype.cast_opaque_ptr(SAVED_REFERENCE,
+ sourcestate)
+ raise UnwindException() # this jumps to targetstate
else:
- top = global_state.top
+ # STATE 2: switching back into a tasklet suspended by
+ # a call to switch()
global_state.top = null_state
global_state.restart_substate = 0
- origin_state = llmemory.cast_adr_to_ptr(fetch_retval_void_p(),
- OPAQUE_STATE_HEADER_PTR)
- return origin_state
+ origin_state = lltype.cast_opaque_ptr(OPAQUE_STATE_HEADER_PTR,
+ fetch_retval_ref())
+ return origin_state # a normal return into the current tasklet,
+ # with the source state as return value
ll_frame_switch.stackless_explicit = True
STATE_HEADER = lltype.GcStruct('state_header',
@@ -55,10 +84,12 @@
SWITCH_STATE = lltype.GcStruct('state_switch',
('header', STATE_HEADER),
- ('c', llmemory.Address))
+ ('c', SAVED_REFERENCE))
def yield_current_frame_to_caller():
if global_state.restart_substate == 0:
+ # normal entry point for yield_current_frame_to_caller()
+ # first unwind the stack
u = UnwindException()
s = lltype.malloc(STATE_HEADER)
s.restartstate = 1
@@ -67,45 +98,50 @@
if global_state.restart_substate:
f = None
s.function = llmemory.cast_ptr_to_adr(f)
- s.retval_type = RETVAL_VOID_P
+ s.retval_type = RETVAL_REF
add_frame_state(u, s)
- raise u
+ raise u # this goes to 'STATE 1' below
+
elif global_state.restart_substate == 1:
+ # STATE 1: we didn't do anything so far, but the stack is unwound
global_state.restart_substate = 0
ycftc_state = global_state.top
- ycftc_state.restartstate = 2
our_caller_state = ycftc_state.f_back
caller_state = our_caller_state.f_back
# the next three lines are pure rtyper-pleasing hacks
f = yield_current_frame_to_caller
if global_state.restart_substate:
f = None
+ # when our immediate caller finishes (which is later, when the
+ # tasklet finishes), then we will jump to 'STATE 2' below
endstate = lltype.malloc(STATE_HEADER)
- endstate.restartstate = 3
+ endstate.restartstate = 2
endstate.function = llmemory.cast_ptr_to_adr(f)
our_caller_state.f_back = endstate
global_state.top = caller_state
- global_state.retval_void_p = llmemory.cast_ptr_to_adr(ycftc_state)
- raise UnwindException()
- elif global_state.restart_substate == 2:
- top = global_state.top
- global_state.top = null_state
- global_state.restart_substate = 0
- origin_state = llmemory.cast_adr_to_ptr(fetch_retval_void_p(),
- OPAQUE_STATE_HEADER_PTR)
- return origin_state
+ global_state.retval_ref = lltype.cast_opaque_ptr(SAVED_REFERENCE,
+ our_caller_state)
+ raise UnwindException() # this goes to the caller's caller
+
else:
+ # STATE 2: this is a slight abuse of yield_current_frame_to_caller(),
+ # as we return here when our immediate caller returns (and thus the
+ # new tasklet finishes).
global_state.restart_substate = 0
- next_state = llmemory.cast_adr_to_ptr(fetch_retval_void_p(),
- lltype.Ptr(STATE_HEADER))
+ next_state = lltype.cast_opaque_ptr(lltype.Ptr(STATE_HEADER),
+ fetch_retval_ref())
+ # return a NULL state pointer to the target of the implicit switch
global_state.top = next_state
- global_state.retval_void_p = llmemory.NULL
- raise UnwindException()
+ global_state.retval_ref = null_saved_ref
+ raise UnwindException() # this goes to the switch target given by
+ # the 'return' at the end of our caller
yield_current_frame_to_caller.stackless_explicit = True
def stack_frames_depth():
if not global_state.restart_substate:
+ # normal entry point for stack_frames_depth()
+ # first unwind the stack
u = UnwindException()
s = lltype.malloc(STATE_HEADER)
s.restartstate = 1
@@ -116,8 +152,10 @@
s.function = llmemory.cast_ptr_to_adr(f)
s.retval_type = RETVAL_LONG
add_frame_state(u, s)
- raise u
+ raise u # goes to STATE 1 below
else:
+ # STATE 1: now the stack is unwound, and we can count the frames
+ # in the heap
cur = global_state.top
global_state.restart_substate = 0
depth = 0
@@ -129,6 +167,8 @@
def ll_stack_unwind():
if not global_state.restart_substate:
+ # normal entry point for stack_frames_depth()
+ # first unwind the stack in the usual way
u = UnwindException()
s = lltype.malloc(STATE_HEADER)
s.restartstate = 1
@@ -139,8 +179,10 @@
s.function = llmemory.cast_ptr_to_adr(f)
s.retval_type = RETVAL_VOID
add_frame_state(u, s)
- raise u
+ raise u # goes to STATE 1 below
else:
+ # STATE 1: now the stack is unwound. That was the goal.
+ # Return to caller.
global_state.restart_substate = 0
ll_stack_unwind.stackless_explicit = True
@@ -151,29 +193,30 @@
self.retval_long = 0
self.retval_longlong = rarithmetic.r_longlong(0)
self.retval_float = 0.0
- self.retval_void_p = llmemory.NULL
+ self.retval_addr = llmemory.NULL
+ self.retval_ref = null_saved_ref
self.exception = None
global_state = StacklessData()
-RETVAL_VOID, RETVAL_LONG, RETVAL_LONGLONG, RETVAL_FLOAT, RETVAL_VOID_P = \
- range(5)
-
def call_function(fn, retval_code):
if retval_code == RETVAL_VOID:
lloperation.llop.unsafe_call(lltype.Void, fn)
+ elif retval_code == RETVAL_REF:
+ global_state.retval_ref = lloperation.llop.unsafe_call(
+ SAVED_REFERENCE, fn)
+ elif retval_code == RETVAL_ADDR:
+ global_state.retval_addr = lloperation.llop.unsafe_call(
+ llmemory.Address, fn)
elif retval_code == RETVAL_LONG:
global_state.retval_long = lloperation.llop.unsafe_call(
lltype.Signed, fn)
- elif retval_code == RETVAL_LONGLONG:
- global_state.retval_longlong = lloperation.llop.unsafe_call(
- lltype.SignedLongLong, fn)
elif retval_code == RETVAL_FLOAT:
global_state.retval_float = lloperation.llop.unsafe_call(
lltype.Float, fn)
- elif retval_code == RETVAL_VOID_P:
- global_state.retval_void_p = lloperation.llop.unsafe_call(
- llmemory.Address, fn)
+ elif retval_code == RETVAL_LONGLONG:
+ global_state.retval_longlong = lloperation.llop.unsafe_call(
+ lltype.SignedLongLong, fn)
call_function.stackless_explicit = True
class UnwindException(lloperation.StackException):
@@ -274,11 +317,24 @@
return global_state.retval_float
fetch_retval_float.stackless_explicit = True
-def fetch_retval_void_p():
+def fetch_retval_addr():
+ e = global_state.exception
+ if e:
+ global_state.exception = None
+ raise e
+ else:
+ res = global_state.retval_addr
+ global_state.retval_addr = llmemory.NULL
+ return res
+fetch_retval_addr.stackless_explicit = True
+
+def fetch_retval_ref():
e = global_state.exception
if e:
global_state.exception = None
raise e
else:
- return global_state.retval_void_p
-fetch_retval_void_p.stackless_explicit = True
+ res = global_state.retval_ref
+ global_state.retval_ref = null_saved_ref
+ return res
+fetch_retval_ref.stackless_explicit = True
Modified: pypy/dist/pypy/translator/stackless/transform.py
==============================================================================
--- pypy/dist/pypy/translator/stackless/transform.py (original)
+++ pypy/dist/pypy/translator/stackless/transform.py Mon May 8 17:29:17 2006
@@ -6,7 +6,9 @@
from pypy.translator import unsimplify
from pypy.annotation import model as annmodel
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
-from pypy.translator.stackless import code
+from pypy.translator.stackless import code
+from pypy.translator.stackless.code import SAVED_REFERENCE, STORAGE_TYPES
+from pypy.translator.stackless.code import STORAGE_FIELDS
from pypy.rpython.rclass import getinstancerepr
from pypy.rpython.rbuiltin import gen_cast
from pypy.rpython.rtyper import LowLevelOpList
@@ -14,28 +16,24 @@
from pypy.translator.stackless.code import STATE_HEADER, null_state
-STORAGE_TYPES = [llmemory.Address,
- lltype.Signed,
- lltype.Float,
- lltype.SignedLongLong]
-STORAGE_FIELDS = ['addr',
- 'long',
- 'float',
- 'longlong']
-
def storage_type(T):
- """Return the index into STORAGE_TYPES
+ """Return the 'erased' storage type corresponding to T.
"""
if T is lltype.Void:
- return None
+ return lltype.Void
+ elif isinstance(T, lltype.Ptr):
+ if T._needsgc():
+ return SAVED_REFERENCE
+ else:
+ return llmemory.Address
elif T is lltype.Float:
- return 2
+ return lltype.Float
elif T in [lltype.SignedLongLong, lltype.UnsignedLongLong]:
- return 3
- elif T is llmemory.Address or isinstance(T, lltype.Ptr):
- return 0
+ return lltype.SignedLongLong
+ elif T is llmemory.Address:
+ return lltype.Address
elif isinstance(T, lltype.Primitive):
- return 1
+ return lltype.Signed
else:
raise Exception("don't know about %r" % (T,))
@@ -107,16 +105,20 @@
self.resume_state_ptr = mixlevelannotator.constfunc(
code.resume_state, [], annmodel.SomeInteger())
- self.fetch_retval_void_ptr = mixlevelannotator.constfunc(
- code.fetch_retval_void, [], annmodel.s_None)
- self.fetch_retval_long_ptr = mixlevelannotator.constfunc(
- code.fetch_retval_long, [], annmodel.SomeInteger())
- self.fetch_retval_longlong_ptr = mixlevelannotator.constfunc(
- code.fetch_retval_longlong, [], annmodel.SomeInteger(size=2))
- self.fetch_retval_float_ptr = mixlevelannotator.constfunc(
- code.fetch_retval_float, [], annmodel.SomeFloat())
- self.fetch_retval_void_p_ptr = mixlevelannotator.constfunc(
- code.fetch_retval_void_p, [], annmodel.SomeAddress())
+ self.fetch_retvals = {
+ lltype.Void: mixlevelannotator.constfunc(
+ code.fetch_retval_void, [], annmodel.s_None),
+ lltype.Signed: mixlevelannotator.constfunc(
+ code.fetch_retval_long, [], annmodel.SomeInteger()),
+ lltype.SignedLongLong: mixlevelannotator.constfunc(
+ code.fetch_retval_longlong, [], annmodel.SomeInteger(size=2)),
+ lltype.Float: mixlevelannotator.constfunc(
+ code.fetch_retval_float, [], annmodel.SomeFloat()),
+ llmemory.Address: mixlevelannotator.constfunc(
+ code.fetch_retval_addr, [], annmodel.SomeAddress()),
+ SAVED_REFERENCE: mixlevelannotator.constfunc(
+ code.fetch_retval_ref, [], annmodel.SomePtr(SAVED_REFERENCE)),
+ }
s_StatePtr = annmodel.SomePtr(code.OPAQUE_STATE_HEADER_PTR)
self.suggested_primitives = {
@@ -145,25 +147,24 @@
def frame_type_for_vars(self, vars):
fieldnames = []
- counts = [0] * len(STORAGE_TYPES)
+ counts = {}
for v in vars:
t = storage_type(v.concretetype)
- if t is None:
+ if t is lltype.Void:
fieldnames.append(None)
else:
- fieldnames.append('state_%s_%d' % (STORAGE_FIELDS[t],
- counts[t]))
- counts[t] = counts[t] + 1
- key = tuple(counts)
+ n = counts.get(t, 0)
+ fieldnames.append('state_%s_%d' % (STORAGE_FIELDS[t], n))
+ counts[t] = n + 1
+ key = lltype.frozendict(counts)
if key in self.frametypes:
T = self.frametypes[key]
else:
fields = []
- for t in range(len(STORAGE_TYPES)):
- for j in range(counts[t]):
- fields.append(('state_%s_%d'%(STORAGE_FIELDS[t], j),
- STORAGE_TYPES[t]))
- T = lltype.GcStruct("FrameState_%d_%d_%d_%d" % tuple(key),
+ for t in STORAGE_TYPES:
+ for j in range(counts.get(t, 0)):
+ fields.append(('state_%s_%d' % (STORAGE_FIELDS[t], j), t))
+ T = lltype.GcStruct("FrameState",
('header', STATE_HEADER),
*fields)
self.frametypes[key] = T
@@ -244,36 +245,16 @@
for i, arg in enumerate(resume_point.args):
assert arg is not resume_point.var_result
t = storage_type(arg.concretetype)
- if t is None:
+ if t is lltype.Void:
continue
fname = model.Constant(resume_point.fieldnames[i], lltype.Void)
v_newarg = llops.genop('getfield', [frame_top, fname],
- resulttype = STORAGE_TYPES[t])
+ resulttype = t)
v_newarg = gen_cast(llops, arg.concretetype, v_newarg)
varmap[arg] = v_newarg
- r = storage_type(resume_point.var_result.concretetype)
- if r is not None:
- rettype = STORAGE_TYPES[r]
- else:
- rettype = lltype.Void
-
- if rettype == lltype.Signed:
- getretval = self.fetch_retval_long_ptr
- if rettype == lltype.SignedLongLong:
- getretval = self.fetch_retval_longlong_ptr
- elif rettype == lltype.Void:
- getretval = self.fetch_retval_void_ptr
- elif rettype == lltype.Float:
- getretval = self.fetch_retval_float_ptr
- elif rettype == llmemory.Address:
-## if resume_point.var_result.concretetype is not \
-## llmemory.Address:
-## if resume_point.var_result in \
-## resume_point.links_to_resumption[0].args:
-## need_address_conversion = True
- getretval = self.fetch_retval_void_p_ptr
-
+ rettype = storage_type(resume_point.var_result.concretetype)
+ getretval = self.fetch_retvals[rettype]
retval = llops.genop("direct_call", [getretval],
resulttype = rettype)
varmap[resume_point.var_result] = retval
@@ -476,12 +457,8 @@
model.Constant(llmemory.fakeaddress(funcptr), llmemory.Address)],
varoftype(lltype.Void)))
rettype = lltype.typeOf(funcptr).TO.RESULT
- retval_type = {None: code.RETVAL_VOID,
- 0: code.RETVAL_VOID_P,
- 1: code.RETVAL_LONG,
- 2: code.RETVAL_FLOAT,
- 3: code.RETVAL_LONGLONG}[storage_type(rettype)]
-
+ retval_type = STORAGE_TYPES.index(storage_type(rettype))
+
saveops.append(model.SpaceOperation(
"setfield", [var_header, model.Constant("retval_type", lltype.Void),
model.Constant(retval_type, lltype.Signed)],
@@ -509,6 +486,6 @@
if t is lltype.Void:
continue
fname = model.Constant(fieldnames[i], lltype.Void)
- v_typeerased = gen_cast(llops, STORAGE_TYPES[t], var)
+ v_typeerased = gen_cast(llops, t, var)
llops.genop('setfield', [frame_state_var, fname, v_typeerased])
return llops
More information about the Pypy-commit
mailing list