Author: Armin Rigo <[email protected]>
Branch: tealet
Changeset: r45999:f3d3bf4acb0c
Date: 2011-07-26 11:01 +0200
http://bitbucket.org/pypy/pypy/changeset/f3d3bf4acb0c/
Log: Waaa. Intermediate check-in (untested) of this scary code.
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -31,7 +31,8 @@
BoolOption("tealet", "enable stackless features via tealets",
default=False, cmdline="--tealet",
requires=[("translation.type_system", "lltype"),
- ("translation.gctransformer", "framework")]),
+ ("translation.gctransformer", "framework"),
+ ("translation.gcrootfinder", "asmgcc")]), #XXX for now
ChoiceOption("type_system", "Type system to use when RTyping",
["lltype", "ootype"], cmdline=None, default="lltype",
requires={
diff --git a/pypy/rlib/_tealet_rffi.py b/pypy/rlib/_tealet_rffi.py
--- a/pypy/rlib/_tealet_rffi.py
+++ b/pypy/rlib/_tealet_rffi.py
@@ -24,3 +24,7 @@
rffi.VOIDP], rffi.INT)
tealet_switch = llexternal("tealet_switch", [TEALET_P], rffi.INT)
tealet_current = llexternal("tealet_current", [TEALET_P], TEALET_P)
+
+_tealet_translate_pointer = llexternal("_tealet_translate_pointer",
+ [TEALET_P, llmemory.Address],
+ llmemory.Address)
diff --git a/pypy/rlib/rtealet.py b/pypy/rlib/rtealet.py
--- a/pypy/rlib/rtealet.py
+++ b/pypy/rlib/rtealet.py
@@ -22,8 +22,7 @@
class Tealet(base_class):
lltealet = _tealet_rffi.NULL_TEALET
- _gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO)
- _gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO)
+ _suspended_stack = NULL_SUSPSTACK
def switch(self):
_switch(self)
@@ -61,22 +60,22 @@
exception = None
switcher = Switcher()
+llswitcher = lltype.malloc(rffi.CArray(_tealet_rffi.TEALET_P), 1,
+ flavor='raw', zero=True)
+
def _new(main, starting_tealet):
switcher.current = main.current
switcher.target = starting_tealet
- llmain = main.lltealet
+ llswitcher[0] = main.lltealet
+ r = _stack_protected_call(llhelper(FUNCNOARG, _new_critical))
+ _check_exception(r)
+
+def _new_critical():
+ # critical function: no gc operation, and no gc variable alive!
+ llmain = llswitcher[0]
llrun = llhelper(_tealet_rffi.TEALET_RUN_P, _run)
llarg = _tealet_rffi.NULL
- r = _new_critical(llmain, llrun, llarg)
- _check_exception(r)
-
-def _new_critical(llmain, llrun, llarg):
- # critical function: no gc operation, and no gc variable alive!
- _save_shadow_stack()
- r = _tealet_rffi.tealet_new(llmain, llrun, llarg)
- _restore_shadow_stack()
- return r
-_new_critical._dont_inline_ = True
+ return _tealet_rffi.tealet_new(llmain, llrun, llarg)
def _run(lltealet, llarg):
llop.gc_stack_bottom(lltype.Void)
@@ -110,20 +109,18 @@
switcher.current = main.current
switcher.target = target
main.current = target
- r = _switch_critical(target.lltealet)
+ llswitcher[0] = target.lltealet
+ r = _stack_protected_call(llhelper(FUNCNOARG, _switch_critical))
+ _check_exception(r)
+
+def _switch_critical():
+ # critical code: no gc operation!
+ lltarget = llswitcher[0]
+ return _tealet_rffi.tealet_switch(lltarget)
+
+def _check_exception(r):
switcher.current = None
switcher.target = None
- _check_exception(r)
-
-def _switch_critical(lltarget):
- # critical code: no gc operation!
- _save_shadow_stack()
- r = _tealet_rffi.tealet_switch(lltarget)
- _restore_shadow_stack()
- return r
-_switch_critical._dont_inline_ = True
-
-def _check_exception(r):
r = rffi.cast(lltype.Signed, r)
if r != 0:
# rare case: tealet.c complains, e.g. out of memory. I think that
@@ -138,36 +135,177 @@
# ____________________________________________________________
#
-# Shadow stack saving/restoring.
+# AsmGcRoot stack walking.
+# XXX rethink the interfacing with asmgcroot.py
+#
+# This is a copy of the logic in asmgcroot.py, rewritten so that all
+# pointer reads from the stack go via _tealet_translate_pointer()
+# and also rewritten in an iterator-like style, with a next() method
+# that just returns the next stack pointer.
+# XXX avoid copying so much of the logic of asmgcroot
-GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF))
-SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed))
-WALKER_PTR = lltype.Ptr(lltype.Struct('walker',
- ('gcptr_array', GCPTR_ARRAY),
- ('signed_array', SIGNED_ARRAY)))
-walker = lltype.malloc(WALKER_PTR.TO, immortal=True)
+_asmstackrootwalker = None # BIG HACK: monkey-patched by asmgcroot.py
+_tealetrootwalker = None
-def _save_shadow_stack():
- llop.gc_save_stack_roots(lltype.Void, walker)
- tealet = switcher.current
- ll_assert(not tealet._gc_gcptr_array, "tealet stack mismatch (save)")
- tealet._gc_gcptr_array = walker.gcptr_array
- tealet._gc_signed_array = walker.signed_array
- walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO)
- walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO)
-_save_shadow_stack._dont_inline_ = True
+def get_tealetrootwalker():
+ # lazily called, to make the following imports lazy
+ global _tealetrootwalker
+ if _tealetrootwalker is not None:
+ return _tealetrootwalker
-def _restore_shadow_stack():
- tealet = switcher.target
- ll_assert(bool(tealet._gc_gcptr_array), "tealet stack mismatch (restore)")
- walker.gcptr_array = tealet._gc_gcptr_array
- walker.signed_array = tealet._gc_signed_array
- tealet._gc_gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO)
- tealet._gc_signed_array = lltype.nullptr(SIGNED_ARRAY.TO)
- llop.gc_restore_stack_roots(lltype.Void, walker)
- walker.gcptr_array = lltype.nullptr(GCPTR_ARRAY.TO)
- walker.signed_array = lltype.nullptr(SIGNED_ARRAY.TO)
-_restore_shadow_stack._dont_inline_ = True
+ from pypy.rpython.memory.gctransform.asmgcroot import (
+ WALKFRAME, CALLEE_SAVED_REGS)
+
+ assert _asmstackrootwalker is not None, "should have been monkey-patched"
+ basewalker = _asmstackrootwalker
+
+ class TealetRootWalker(object):
+ _alloc_flavor_ = "raw"
+
+ enumerating = False
+
+ def setup(self, obj):
+ # initialization: read the SUSPSTACK object
+ p = llmemory.cast_adr_to_ptr(obj, lltype.Ptr(SUSPSTACK))
+ if not p.context:
+ return False
+ self.context = p.context
+ initialframedata = p.initialframedata
+ del p
+ self.curframe = lltype.malloc(WALKFRAME, flavor='raw')
+ self.otherframe = lltype.malloc(WALKFRAME, flavor='raw')
+ basewalker.fill_initial_frame(self.curframe, self.initialframedata)
+ return True
+
+ def teardown(self):
+ lltype.free(self.curframe, flavor='raw')
+ lltype.free(self.otherframe, flavor='raw')
+ self.context = _tealet_rffi.NULL_TEALET
+ return llmemory.NULL
+
+ def next(self, obj, prev):
+ #
+ # Pointers to the stack can be "translated" or not:
+ #
+ # * Non-translated pointers point to where the data would be
+ # if the stack was installed and running.
+ #
+ # * Translated pointers correspond to where the data
+ # is now really in memory.
+ #
+ # Note that 'curframe' contains non-translated pointers, and
+ # of course the stack itself is full of non-translated pointers.
+ #
+ while True:
+ callee = self.curframe
+ #
+ if not self.enumerating:
+ if not prev:
+ if not self.setup(obj): # one-time initialization
+ return llmemory.NULL
+ prev = obj # random value, but non-NULL
+ retaddraddr = self.translateptr(callee.frame_address)
+ retaddr = retaddraddr.address[0]
+ basewalker.locate_caller_based_on_retaddr(retaddr)
+ self.enumerating = True
+ #
+ # not really a loop, but kept this way for similarity
+ # with asmgcroot:
+ while True:
+ location = basewalker._shape_decompressor.next()
+ if location == 0:
+ break
+ addr = basewalker.getlocation(callee, location)
+ # yield the translated addr of the next GCREF in the stack
+ return self.translateptr(addr)
+ #
+ self.enumerating = False
+ caller = self.otherframe
+ reg = CALLEE_SAVED_REGS - 1
+ while reg >= 0:
+ location = basewalker._shape_decompressor.next()
+ addr = basewalker.getlocation(callee, location)
+ caller.regs_stored_at[reg] = addr # non-translated
+ reg -= 1
+
+ location = basewalker._shape_decompressor.next()
+ caller.frame_address = basewalker.getlocation(callee, location)
+ # ^^^ non-translated
+ if caller.frame_address == llmemory.NULL:
+ return self.teardown() # completely done with this stack
+ #
+ self.otherframe = callee
+ self.curframe = caller
+ # loop back
+
+ def translateptr(self, addr):
+ return _tealet_rffi._tealet_translate_pointer(self.context, addr)
+
+ _tealetrootwalker = TealetRootWalker()
+ return _tealetrootwalker
+get_tealetrootwalker._annspecialcase_ = 'specialize:memo'
+
+
+def customtrace(obj, prev):
+ tealetrootwalker = get_tealetrootwalker()
+ return tealetrootwalker.next(obj, prev)
+
+ASM_FRAMEDATA_HEAD_PTR = lltype.Ptr(lltype.FixedSizeArray(llmemory.Address, 2))
+SUSPSTACK = lltype.GcStruct('SuspStack',
+ ('context', _tealet_rffi.TEALET_P),
+ ('anchor', ASM_FRAMEDATA_HEAD_PTR),
+ ('my_index', lltype.Signed),
+ ('next_unused', lltype.Signed),
+ rtti=True)
+CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
+ llmemory.Address)
+customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
+lltype.attachRuntimeTypeInfo(SUSPSTACK, customtraceptr=customtraceptr)
+NULL_SUSPSTACK = lltype.Ptr(SUSPSTACK)
+
+
+class SuspendedStacks:
+
+ def __init__(self):
+ self.lst = []
+ self.first_unused = -1
+
+ def acquire(self):
+ if self.first_unused == -1:
+ p = lltype.malloc(SUSPSTACK)
+ p.context = _tealet_rffi.NULL_TEALET
+ p.my_index = len(self.lst)
+ self.lst.append(p)
+ else:
+ p = self.lst[self.first_unused]
+ self.first_unused = p.next_unused
+ return p
+
+ def release(self, p):
+ p.next_unused = self.first_unused
+ self.first_unused = p.my_index
+
+suspendedstacks = SuspendedStacks()
+
+def _stack_protected_call(callback):
+ # :-/
+ p = suspendedstacks.acquire()
+ suspendedstacks.callback = callback
+ anchor = lltype.malloc(ASM_FRAMEDATA_HEAD_PTR.TO, flavor='raw')
+ anchor[0] = anchor[1] = llmemory.cast_ptr_to_adr(anchor)
+ p.anchor = anchor
+ r = pypy_asm_stackwalk2(callback, anchor)
+ suspendedstacks.release(p)
+ lltype.free(anchor, flavor='raw')
+ return r
+
+FUNCNOARG = lltype.FuncType([], rffi.INT)
+
+pypy_asm_stackwalk2 = rffi.llexternal('pypy_asm_stackwalk',
+ [lltype.Ptr(FUNCNOARG),
+ ASM_FRAMEDATA_HEAD_PTR],
+ rffi.INT, sandboxsafe=True,
+ _nowrapper=True)
# ____________________________________________________________
diff --git a/pypy/rpython/memory/gctransform/asmgcroot.py
b/pypy/rpython/memory/gctransform/asmgcroot.py
--- a/pypy/rpython/memory/gctransform/asmgcroot.py
+++ b/pypy/rpython/memory/gctransform/asmgcroot.py
@@ -149,52 +149,9 @@
self._extra_mark_sorted = lambda: True
def need_tealet_support(self, gctransformer, getfn):
- # tealet support: hooks to save and restore the GC pointers
- # from the stack before it is whisked away by "tealet.c".
- GCPTR_ARRAY = lltype.Ptr(lltype.GcArray(llmemory.GCREF))
- SIGNED_ARRAY = lltype.Ptr(lltype.GcArray(lltype.Signed))
- WALKER_PTR = lltype.Ptr(lltype.Struct('walker',
- ('gcptr_array', GCPTR_ARRAY),
- ('signed_array', SIGNED_ARRAY)))
- gcdata = self.gcdata
- #
- def ll_count_locations(gc, addr):
- gcdata._gc_tealet_count += 1
- #
- def ll_save_locations(gc, addr):
- gcref = llmemory.cast_adr_to_ptr(addr.address[0], llmemory.GCREF)
- gcdata._gc_tealet_array[gcdata._gc_tealet_count] = gcref
- gcdata._gc_tealet_count += 1
- #
- def ll_restore_locations(gc, addr):
- gcref = gcdata._gc_tealet_array[gcdata._gc_tealet_count]
- gcdata._gc_tealet_count += 1
- addr.address[0] = llmemory.cast_ptr_to_adr(gcref)
- #
- def ll_save_stack_roots(walker):
- gcdata._gc_tealet_count = 0
- self.walk_stack_roots(ll_count_locations)
- count = gcdata._gc_tealet_count
- gcdata._gc_tealet_count = 0
- gcdata._gc_tealet_array = lltype.malloc(GCPTR_ARRAY.TO, count)
- self.walk_stack_roots(ll_save_locations)
- walker.gcptr_array = gcdata._gc_tealet_array
- gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO)
- #
- def ll_restore_stack_roots(walker):
- gcdata._gc_tealet_array = walker.gcptr_array
- gcdata._gc_tealet_count = 0
- self.walk_stack_roots(ll_restore_locations)
- gcdata._gc_tealet_array = lltype.nullptr(GCPTR_ARRAY.TO)
- #
- self.ll_save_stack_roots_ptr = getfn(ll_save_stack_roots,
- [annmodel.SomePtr(WALKER_PTR)],
- annmodel.s_None,
- minimal_transform=False)
- self.ll_restore_stack_roots_ptr = getfn(ll_restore_stack_roots,
- [annmodel.SomePtr(WALKER_PTR)],
- annmodel.s_None,
- minimal_transform=False)
+ # tealet support: BIG HACK for rlib.rtealet
+ from pypy.rlib import rtealet
+ rtealet._asmstackrootwalker = self # as a global! argh
def need_thread_support(self, gctransformer, getfn):
# Threads supported "out of the box" by the rest of the code.
diff --git a/pypy/translator/c/gcc/trackgcroot.py
b/pypy/translator/c/gcc/trackgcroot.py
--- a/pypy/translator/c/gcc/trackgcroot.py
+++ b/pypy/translator/c/gcc/trackgcroot.py
@@ -1593,31 +1593,20 @@
{
__asm {
mov\tedx, DWORD PTR [esp+4]\t; 1st argument, which is the
callback
- mov\tecx, DWORD PTR [esp+8]\t; 2nd argument, which is
gcrootanchor
mov\teax, esp\t\t; my frame top address
push\teax\t\t\t; ASM_FRAMEDATA[6]
push\tebp\t\t\t; ASM_FRAMEDATA[5]
push\tedi\t\t\t; ASM_FRAMEDATA[4]
push\tesi\t\t\t; ASM_FRAMEDATA[3]
push\tebx\t\t\t; ASM_FRAMEDATA[2]
-
- ; Add this ASM_FRAMEDATA to the front of the circular linked
- ; list. Let's call it 'self'.
-
- mov\teax, DWORD PTR [ecx+4]\t\t; next = gcrootanchor->next
- push\teax\t\t\t\t\t\t\t\t\t; self->next = next
- push\tecx ; self->prev = gcrootanchor
- mov\tDWORD PTR [ecx+4], esp\t\t; gcrootanchor->next = self
- mov\tDWORD PTR [eax+0], esp\t\t\t\t\t; next->prev = self
+ xor\teax, eax
+ push\teax\t\t\t; ASM_FRAMEDATA[1]
+ push\teax\t\t\t; ASM_FRAMEDATA[0]
call\tedx\t\t\t\t\t\t; invoke the callback
- ; Detach this ASM_FRAMEDATA from the circular linked list
- pop\tesi\t\t\t\t\t\t\t; prev = self->prev
- pop\tedi\t\t\t\t\t\t\t; next = self->next
- mov\tDWORD PTR [esi+4], edi\t\t; prev->next = next
- mov\tDWORD PTR [edi+0], esi\t\t; next->prev = prev
-
+ pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[0]
+ pop\tecx\t\t\t\t; ignored ASM_FRAMEDATA[1]
pop\tebx\t\t\t\t; restore from ASM_FRAMEDATA[2]
pop\tesi\t\t\t\t; restore from ASM_FRAMEDATA[3]
pop\tedi\t\t\t\t; restore from ASM_FRAMEDATA[4]
@@ -1640,7 +1629,6 @@
/* See description in asmgcroot.py */
.cfi_startproc
/* %rdi is the 1st argument, which is the callback */
- /* %rsi is the 2nd argument, which is gcrootanchor */
movq\t%rsp, %rax\t/* my frame top address */
pushq\t%rax\t\t/* ASM_FRAMEDATA[8] */
pushq\t%rbp\t\t/* ASM_FRAMEDATA[7] */
@@ -1649,26 +1637,17 @@
pushq\t%r13\t\t/* ASM_FRAMEDATA[4] */
pushq\t%r12\t\t/* ASM_FRAMEDATA[3] */
pushq\t%rbx\t\t/* ASM_FRAMEDATA[2] */
+ xorq\t%rax,%rax
+ pushq\t%rax\t\t/* ASM_FRAMEDATA[1] */
+ pushq\t%rax\t\t/* ASM_FRAMEDATA[0] */
- /* Add this ASM_FRAMEDATA to the front of the circular linked */
- /* list. Let's call it 'self'. */
-
- movq\t8(%rsi), %rax\t/* next = gcrootanchor->next */
- pushq\t%rax\t\t\t\t/* self->next = next */
- pushq\t%rsi\t\t\t/* self->prev = gcrootanchor */
- movq\t%rsp, 8(%rsi)\t/* gcrootanchor->next = self */
- movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */
.cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */
/* note: the Mac OS X 16 bytes aligment must be respected. */
call\t*%rdi\t\t/* invoke the callback */
- /* Detach this ASM_FRAMEDATA from the circular linked list */
- popq\t%rsi\t\t/* prev = self->prev */
- popq\t%rdi\t\t/* next = self->next */
- movq\t%rdi, 8(%rsi)\t/* prev->next = next */
- movq\t%rsi, 0(%rdi)\t/* next->prev = prev */
-
+ popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[0] */
+ popq\t%rcx\t\t/* ignored ASM_FRAMEDATA[1] */
popq\t%rbx\t\t/* restore from ASM_FRAMEDATA[2] */
popq\t%r12\t\t/* restore from ASM_FRAMEDATA[3] */
popq\t%r13\t\t/* restore from ASM_FRAMEDATA[4] */
@@ -1701,32 +1680,21 @@
print >> output, """\
/* See description in asmgcroot.py */
movl\t4(%esp), %edx\t/* 1st argument, which is the callback */
- movl\t8(%esp), %ecx\t/* 2nd argument, which is gcrootanchor */
movl\t%esp, %eax\t/* my frame top address */
pushl\t%eax\t\t/* ASM_FRAMEDATA[6] */
pushl\t%ebp\t\t/* ASM_FRAMEDATA[5] */
pushl\t%edi\t\t/* ASM_FRAMEDATA[4] */
pushl\t%esi\t\t/* ASM_FRAMEDATA[3] */
pushl\t%ebx\t\t/* ASM_FRAMEDATA[2] */
-
- /* Add this ASM_FRAMEDATA to the front of the circular linked */
- /* list. Let's call it 'self'. */
-
- movl\t4(%ecx), %eax\t/* next = gcrootanchor->next */
- pushl\t%eax\t\t\t\t/* self->next = next */
- pushl\t%ecx\t\t\t/* self->prev = gcrootanchor */
- movl\t%esp, 4(%ecx)\t/* gcrootanchor->next = self */
- movl\t%esp, 0(%eax)\t\t\t/* next->prev = self */
+ xorl\t%eax,%eax
+ pushl\t%eax\t\t/* ASM_FRAMEDATA[1] */
+ pushl\t%eax\t\t/* ASM_FRAMEDATA[0] */
/* note: the Mac OS X 16 bytes aligment must be respected. */
call\t*%edx\t\t/* invoke the callback */
- /* Detach this ASM_FRAMEDATA from the circular linked list */
- popl\t%esi\t\t/* prev = self->prev */
- popl\t%edi\t\t/* next = self->next */
- movl\t%edi, 4(%esi)\t/* prev->next = next */
- movl\t%esi, 0(%edi)\t/* next->prev = prev */
-
+ popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[0] */
+ popl\t%ecx\t\t/* ignored ASM_FRAMEDATA[1] */
popl\t%ebx\t\t/* restore from ASM_FRAMEDATA[2] */
popl\t%esi\t\t/* restore from ASM_FRAMEDATA[3] */
popl\t%edi\t\t/* restore from ASM_FRAMEDATA[4] */
diff --git a/pypy/translator/c/src/mem.h b/pypy/translator/c/src/mem.h
--- a/pypy/translator/c/src/mem.h
+++ b/pypy/translator/c/src/mem.h
@@ -6,7 +6,7 @@
extern char __gcmapstart;
extern char __gcmapend;
extern char __gccallshapes;
-extern long pypy_asm_stackwalk(void*, void*);
+extern long pypy_asm_stackwalk(void*);
#define __gcnoreorderhack __gcmapend
/* The following pseudo-instruction is used by --gcrootfinder=asmgcc
@@ -52,7 +52,7 @@
extern void* __gcmapstart;
extern void* __gcmapend;
extern char* __gccallshapes;
-extern long pypy_asm_stackwalk(void*, void*);
+extern long pypy_asm_stackwalk(void*);
/* With the msvc Microsoft Compiler, the optimizer seems free to move
any code (even asm) that involves local memory (registers and stack).
diff --git a/pypy/translator/c/src/tealet/tealet.c
b/pypy/translator/c/src/tealet/tealet.c
--- a/pypy/translator/c/src/tealet/tealet.c
+++ b/pypy/translator/c/src/tealet/tealet.c
@@ -598,3 +598,21 @@
stack_free(g_main, g_target->stack_copy);
g_free(g_main, g_target);
}
+
+#if STACK_DIRECTION != 0
+# error "fix _tealet_translate_pointer below"
+#endif
+char **_tealet_translate_pointer(tealet_t *context, char **ptr)
+{
+ tealet_sub_t *g_tealet = (tealet_sub_t *)context;
+ /* if g_tealet is not suspended, then stack_start is probably NULL,
+ giving nonsense in the following computation. But then stack_saved
+ is 0, so the following test can never be true. */
+ char *p = (char *)ptr;
+ long delta = p - g_tealet->stack_start;
+ if (((unsigned long)delta) < ((unsigned long)g_tealet->stack_saved)) {
+ /* a pointer to a saved away word */
+ return (char **)(g_tealet->stack_copy + delta);
+ }
+ return ptr;
+}
diff --git a/pypy/translator/c/src/tealet/tealet.h
b/pypy/translator/c/src/tealet/tealet.h
--- a/pypy/translator/c/src/tealet/tealet.h
+++ b/pypy/translator/c/src/tealet/tealet.h
@@ -144,4 +144,10 @@
TEALET_API
int tealet_stub_run(tealet_t *stub, tealet_run_t run, void *run_arg);
+/* Hack: translate a pointer into the stack of a tealet into a pointer
+ * to where it is really stored so far. Only to access word-sized data.
+ */
+TEALET_API
+char **_tealet_translate_pointer(tealet_t *context, char **ptr);
+
#endif /* _TEALET_H_ */
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit