Author: David Schneider <david.schnei...@picle.org> Branch: jitframe-on-heap Changeset: r62088:283351509284 Date: 2013-03-05 15:53 +0100 http://bitbucket.org/pypy/pypy/changeset/283351509284/
Log: merge heads diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py --- a/pypy/module/_continuation/interp_continuation.py +++ b/pypy/module/_continuation/interp_continuation.py @@ -19,11 +19,6 @@ # - normal: self.sthread != None, not is_empty_handle(self.h) # - finished: self.sthread != None, is_empty_handle(self.h) - def __del__(self): - sthread = self.sthread - if sthread is not None and not sthread.is_empty_handle(self.h): - sthread.destroy(self.h) - def check_sthread(self): ec = self.space.getexecutioncontext() if ec.stacklet_thread is not self.sthread: diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -598,7 +598,7 @@ jitframe.JITFRAMEINFO_SIZE, alignment=WORD) clt.frame_info = rffi.cast(jitframe.JITFRAMEINFOPTR, frame_info) clt.allgcrefs = [] - clt.frame_info.set_frame_depth(0, 0) # for now + clt.frame_info.update_frame_depth(0, 0) # for now if False and log: operations = self._inject_debugging_code(looptoken, operations, @@ -854,7 +854,7 @@ def update_frame_depth(self, frame_depth): baseofs = self.cpu.get_baseofs_of_frame_field() - self.current_clt.frame_info.set_frame_depth(baseofs, frame_depth) + self.current_clt.frame_info.update_frame_depth(baseofs, frame_depth) def write_pending_failure_recoveries(self): for tok in self.pending_guards: diff --git a/rpython/jit/backend/llsupport/jitframe.py b/rpython/jit/backend/llsupport/jitframe.py --- a/rpython/jit/backend/llsupport/jitframe.py +++ b/rpython/jit/backend/llsupport/jitframe.py @@ -15,9 +15,10 @@ NULLGCMAP = lltype.nullptr(GCMAP) @enforceargs(None, int, int) -def jitframeinfo_set_depth(jfi, base_ofs, new_depth): - jfi.jfi_frame_depth = new_depth - jfi.jfi_frame_size = base_ofs + new_depth * SIZEOFSIGNED +def jitframeinfo_update_depth(jfi, base_ofs, new_depth): + if new_depth > jfi.jfi_frame_depth: + jfi.jfi_frame_depth = new_depth + jfi.jfi_frame_size = base_ofs + new_depth * SIZEOFSIGNED JITFRAMEINFO_SIZE = 2 * SIZEOFSIGNED # make sure this stays correct @@ -28,7 +29,7 @@ # the total size of the frame, in bytes ('jfi_frame_size', lltype.Signed), adtmeths = { - 'set_frame_depth': jitframeinfo_set_depth, + 'update_frame_depth': jitframeinfo_update_depth, }, ) @@ -113,6 +114,9 @@ elif fld == -3: (obj_addr + getofs('jf_gc_trace_state')).signed[0] = -4 return obj_addr + getofs('jf_guard_exc') + elif fld == -4: + (obj_addr + getofs('jf_gc_trace_state')).signed[0] = -5 + return obj_addr + getofs('jf_forward') else: if not (obj_addr + getofs('jf_gcmap')).address[0]: return llmemory.NULL # done diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py --- a/rpython/jit/backend/llsupport/llmodel.py +++ b/rpython/jit/backend/llsupport/llmodel.py @@ -86,12 +86,13 @@ if size > frame.jf_frame_info.jfi_frame_depth: # update the frame_info size, which is for whatever reason # not up to date - frame.jf_frame_info.set_frame_depth(base_ofs, size) + frame.jf_frame_info.update_frame_depth(base_ofs, size) new_frame = jitframe.JITFRAME.allocate(frame.jf_frame_info) frame.jf_forward = new_frame i = 0 while i < len(frame.jf_frame): new_frame.jf_frame[i] = frame.jf_frame[i] + frame.jf_frame[i] = 0 i += 1 new_frame.jf_savedata = frame.jf_savedata new_frame.jf_guard_exc = frame.jf_guard_exc diff --git a/rpython/jit/backend/llsupport/test/test_gc.py b/rpython/jit/backend/llsupport/test/test_gc.py --- a/rpython/jit/backend/llsupport/test/test_gc.py +++ b/rpython/jit/backend/llsupport/test/test_gc.py @@ -296,20 +296,20 @@ assert all_addrs[counter] == frame_adr + jitframe.getofs(name) counter += 1 # gcpattern - assert all_addrs[4] == indexof(0) - assert all_addrs[5] == indexof(1) - assert all_addrs[6] == indexof(3) - assert all_addrs[7] == indexof(5) - assert all_addrs[8] == indexof(7) + assert all_addrs[5] == indexof(0) + assert all_addrs[6] == indexof(1) + assert all_addrs[7] == indexof(3) + assert all_addrs[8] == indexof(5) + assert all_addrs[9] == indexof(7) if sys.maxint == 2**31 - 1: - assert all_addrs[9] == indexof(31) - assert all_addrs[10] == indexof(33 + 32) + assert all_addrs[10] == indexof(31) + assert all_addrs[11] == indexof(33 + 32) else: - assert all_addrs[9] == indexof(63) - assert all_addrs[10] == indexof(65 + 64) + assert all_addrs[10] == indexof(63) + assert all_addrs[11] == indexof(65 + 64) - assert len(all_addrs) == 4 + 6 + 4 - # 4 static fields, 4 addresses from gcmap, 2 from gcpattern + assert len(all_addrs) == 5 + 6 + 4 + # 5 static fields, 4 addresses from gcmap, 2 from gcpattern lltype.free(frame_info, flavor='raw') lltype.free(frame.jf_gcmap, flavor='raw') diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py --- a/rpython/jit/backend/model.py +++ b/rpython/jit/backend/model.py @@ -315,10 +315,11 @@ for ref in oldlooptoken.looptokens_redirected_to: looptoken = ref() if looptoken: - looptoken.frame_info.set_frame_depth(baseofs, + looptoken.frame_info.update_frame_depth(baseofs, new_fi.jfi_frame_depth) new_loop_tokens.append(ref) - oldlooptoken.frame_info.set_frame_depth(baseofs, new_fi.jfi_frame_depth) + oldlooptoken.frame_info.update_frame_depth(baseofs, + new_fi.jfi_frame_depth) assert oldlooptoken is not None new_loop_tokens.append(weakref.ref(oldlooptoken)) self.looptokens_redirected_to = new_loop_tokens diff --git a/rpython/jit/backend/test/test_model.py b/rpython/jit/backend/test/test_model.py --- a/rpython/jit/backend/test/test_model.py +++ b/rpython/jit/backend/test/test_model.py @@ -13,7 +13,7 @@ def __init__(self, depth): self.jfi_frame_depth = depth - def set_frame_depth(self, baseofs, newdepth): + def update_frame_depth(self, baseofs, newdepth): self.jfi_frame_depth = newdepth def test_redirect_loop_token(): diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -471,7 +471,7 @@ jitframe.JITFRAMEINFO_SIZE, alignment=WORD) clt.frame_info = rffi.cast(jitframe.JITFRAMEINFOPTR, frame_info) clt.allgcrefs = [] - clt.frame_info.set_frame_depth(0, 0) # for now + clt.frame_info.update_frame_depth(0, 0) # for now if log: operations = self._inject_debugging_code(looptoken, operations, @@ -622,7 +622,7 @@ def update_frame_depth(self, frame_depth): baseofs = self.cpu.get_baseofs_of_frame_field() - self.current_clt.frame_info.set_frame_depth(baseofs, frame_depth) + self.current_clt.frame_info.update_frame_depth(baseofs, frame_depth) def _check_frame_depth(self, mc, gcmap, expected_size=-1): """ check if the frame is of enough depth to follow this bridge. @@ -2392,18 +2392,6 @@ not_implemented("not implemented operation (guard): %s" % op.getopname()) - def check_frame_before_jump(self, target_token): - if target_token in self.target_tokens_currently_compiling: - return - if target_token._x86_clt is self.current_clt: - return - # We can have a frame coming from god knows where that's - # passed to a jump to another loop. Make sure it has the - # correct depth - expected_size = target_token._x86_clt.frame_info.jfi_frame_depth - self._check_frame_depth(self.mc, self._regalloc.get_gcmap(), - expected_size=expected_size) - def closing_jump(self, target_token): target = target_token._ll_loop_code if target_token in self.target_tokens_currently_compiling: diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1238,7 +1238,6 @@ tmpreg = None xmmtmp = None # Do the remapping - assembler.check_frame_before_jump(self.jump_target_descr) remap_frame_layout_mixed(assembler, src_locations1, dst_locations1, tmpreg, src_locations2, dst_locations2, xmmtmp) diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py --- a/rpython/memory/gc/base.py +++ b/rpython/memory/gc/base.py @@ -341,7 +341,7 @@ break obj = self.run_finalizers.popleft() finalizer = self.getfinalizer(self.get_type_id(obj)) - finalizer(obj, llmemory.NULL) + finalizer(obj) finally: self.finalizer_lock_count -= 1 diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py --- a/rpython/memory/gc/minimark.py +++ b/rpython/memory/gc/minimark.py @@ -940,6 +940,11 @@ def get_forwarding_address(self, obj): return llmemory.cast_adr_to_ptr(obj, FORWARDSTUBPTR).forw + def get_possibly_forwarded_type_id(self, obj): + if self.is_in_nursery(obj) and self.is_forwarded(obj): + obj = self.get_forwarding_address(obj) + return self.get_type_id(obj) + def get_total_memory_used(self): """Return the total memory used, not counting any object in the nursery: only objects in the ArenaCollection or raw-malloced. @@ -1890,7 +1895,7 @@ if not self.is_forwarded(obj): finalizer = self.getlightfinalizer(self.get_type_id(obj)) ll_assert(bool(finalizer), "no light finalizer found") - finalizer(obj, llmemory.NULL) + finalizer(obj) else: obj = self.get_forwarding_address(obj) self.old_objects_with_light_finalizers.append(obj) @@ -1911,7 +1916,7 @@ # dying finalizer = self.getlightfinalizer(self.get_type_id(obj)) ll_assert(bool(finalizer), "no light finalizer found") - finalizer(obj, llmemory.NULL) + finalizer(obj) self.old_objects_with_light_finalizers.delete() self.old_objects_with_light_finalizers = new_objects diff --git a/rpython/memory/gc/semispace.py b/rpython/memory/gc/semispace.py --- a/rpython/memory/gc/semispace.py +++ b/rpython/memory/gc/semispace.py @@ -438,6 +438,12 @@ def visit_external_object(self, obj): pass # hook for the HybridGC + def get_possibly_forwarded_type_id(self, obj): + tid = self.header(obj).tid + if self.is_forwarded(obj) and not (tid & GCFLAG_EXTERNAL): + obj = self.get_forwarding_address(obj) + return self.get_type_id(obj) + def set_forwarding_address(self, obj, newobj, objsize): # To mark an object as forwarded, we set the GCFLAG_FORWARDED and # overwrite the object with a FORWARDSTUB. Doing so is a bit @@ -494,7 +500,7 @@ new_objects.append(self.get_forwarding_address(obj)) else: finalizer = self.getfinalizer(self.get_type_id(obj)) - finalizer(obj, llmemory.NULL) + finalizer(obj) self.objects_with_light_finalizers.delete() self.objects_with_light_finalizers = new_objects diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -139,11 +139,13 @@ if self._with_jit: jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] + self.gctransformer = gctransformer def need_stacklet_support(self, gctransformer, getfn): # stacklet support: BIG HACK for rlib.rstacklet from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh + _stacklet_asmgcc.complete_destrptr(gctransformer) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. @@ -411,7 +413,7 @@ # to a JITFRAME object. from rpython.jit.backend.llsupport.jitframe import STACK_DEPTH_OFS - tid = self.gc.get_type_id(ebp_in_caller) + tid = self.gc.get_possibly_forwarded_type_id(ebp_in_caller) ll_assert(rffi.cast(lltype.Signed, tid) == rffi.cast(lltype.Signed, self.frame_tid), "found a stack frame that does not belong " 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 @@ -645,11 +645,9 @@ c_type_id = rmodel.inputconst(TYPE_ID, type_id) info = self.layoutbuilder.get_info(type_id) c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) - kind_and_fptr = self.special_funcptr_for_type(TYPE) - has_finalizer = (kind_and_fptr is not None and - kind_and_fptr[0] == "finalizer") - has_light_finalizer = (kind_and_fptr is not None and - kind_and_fptr[0] == "light_finalizer") + fptrs = self.special_funcptr_for_type(TYPE) + has_finalizer = "finalizer" in fptrs + has_light_finalizer = "light_finalizer" in fptrs if has_light_finalizer: has_finalizer = True c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer) @@ -798,11 +796,6 @@ [self.root_walker.gc_shadowstackref_context_ptr, op.args[0]], resultvar=op.result) - def gct_gc_shadowstackref_destroy(self, hop): - op = hop.spaceop - hop.genop("direct_call", - [self.root_walker.gc_shadowstackref_destroy_ptr, op.args[0]]) - def gct_gc_save_current_state_away(self, hop): op = hop.spaceop hop.genop("direct_call", @@ -1213,8 +1206,8 @@ None) def has_light_finalizer(self, TYPE): - special = self.special_funcptr_for_type(TYPE) - return special is not None and special[0] == 'light_finalizer' + fptrs = self.special_funcptr_for_type(TYPE) + return "light_finalizer" in fptrs def has_custom_trace(self, TYPE): rtti = get_rtti(TYPE) @@ -1228,14 +1221,16 @@ destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] typename = TYPE.__name__ - def ll_finalizer(addr, ignored): + def ll_finalizer(addr): v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) ll_call_destructor(destrptr, v, typename) - return llmemory.NULL fptr = self.transformer.annotate_finalizer(ll_finalizer, - [llmemory.Address, llmemory.Address], llmemory.Address) - g = destrptr._obj.graph - light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g) + [llmemory.Address], lltype.Void) + try: + g = destrptr._obj.graph + light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g) + except lltype.DelayedPointer: + light = False # XXX bah, too bad return fptr, light def make_custom_trace_funcptr_for_type(self, TYPE): diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py --- a/rpython/memory/gctransform/shadowstack.py +++ b/rpython/memory/gctransform/shadowstack.py @@ -1,6 +1,7 @@ from rpython.annotator import model as annmodel from rpython.rlib.debug import ll_assert from rpython.rlib.nonconst import NonConstant +from rpython.rlib import rgc from rpython.rtyper import rmodel from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.lltypesystem import lltype, llmemory @@ -226,10 +227,6 @@ ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) return ssref.context - def gc_shadowstackref_destroy(gcref): - ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) - shadow_stack_pool.destroy(ssref) - def gc_save_current_state_away(gcref, ncontext): ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref) shadow_stack_pool.save_current_state_away(ssref, ncontext) @@ -252,9 +249,6 @@ self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context, [s_gcref], s_addr, inline=True) - self.gc_shadowstackref_destroy_ptr = getfn(gc_shadowstackref_destroy, - [s_gcref], annmodel.s_None, - inline=True) self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away, [s_gcref, s_addr], annmodel.s_None, @@ -340,10 +334,6 @@ self.gcdata.root_stack_top = self.unused_full_stack self.unused_full_stack = llmemory.NULL - def destroy(self, shadowstackref): - llmemory.raw_free(shadowstackref.base) - self._cleanup(shadowstackref) - def _cleanup(self, shadowstackref): shadowstackref.base = llmemory.NULL shadowstackref.top = llmemory.NULL @@ -402,7 +392,20 @@ CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], llmemory.Address) customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace) - lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, customtraceptr=customtraceptr) + + def shadowstack_destructor(shadowstackref): + from rpython.rlib import _rffi_stacklet as _c + h = shadowstackref.context + h = llmemory.cast_adr_to_ptr(h, _c.handle) + llmemory.raw_free(shadowstackref.base) + if h: + _c.destroy(h) + + destrptr = gctransformer.annotate_helper(shadowstack_destructor, + [SHADOWSTACKREFPTR], lltype.Void) + + lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, customtraceptr=customtraceptr, + destrptr=destrptr) gctransformer._SHADOWSTACKREF = SHADOWSTACKREF return SHADOWSTACKREF diff --git a/rpython/memory/gctypelayout.py b/rpython/memory/gctypelayout.py --- a/rpython/memory/gctypelayout.py +++ b/rpython/memory/gctypelayout.py @@ -17,20 +17,22 @@ OFFSETS_TO_GC_PTR = lltype.Array(lltype.Signed) - # When used as a finalizer, the following functions only take one - # address and ignore the second, and return NULL. When used as a - # custom tracer (CT), it enumerates the addresses that contain GCREFs. + # A custom tracer (CT), enumerates the addresses that contain GCREFs. # It is called with the object as first argument, and the previous # returned address (or NULL the first time) as the second argument. - FINALIZER_OR_CT_FUNC = lltype.FuncType([llmemory.Address, - llmemory.Address], - llmemory.Address) - FINALIZER_OR_CT = lltype.Ptr(FINALIZER_OR_CT_FUNC) + FINALIZER_FUNC = lltype.FuncType([llmemory.Address], lltype.Void) + CUSTOMTRACER_FUNC = lltype.FuncType([llmemory.Address, llmemory.Address], + llmemory.Address) + FINALIZER = lltype.Ptr(FINALIZER_FUNC) + CUSTOMTRACER = lltype.Ptr(CUSTOMTRACER_FUNC) + EXTRA = lltype.Struct("type_info_extra", + ('finalizer', FINALIZER), + ('customtracer', CUSTOMTRACER)) # structure describing the layout of a typeid TYPE_INFO = lltype.Struct("type_info", ("infobits", lltype.Signed), # combination of the T_xxx consts - ("finalizer_or_customtrace", FINALIZER_OR_CT), + ("extra", lltype.Ptr(EXTRA)), ("fixedsize", lltype.Signed), ("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)), hints={'immutable': True}, @@ -80,16 +82,16 @@ def q_finalizer(self, typeid): typeinfo = self.get(typeid) if typeinfo.infobits & T_HAS_FINALIZER: - return typeinfo.finalizer_or_customtrace + return typeinfo.extra.finalizer else: - return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC) + return lltype.nullptr(GCData.FINALIZER_FUNC) def q_light_finalizer(self, typeid): typeinfo = self.get(typeid) if typeinfo.infobits & T_HAS_LIGHTWEIGHT_FINALIZER: - return typeinfo.finalizer_or_customtrace + return typeinfo.extra.finalizer else: - return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC) + return lltype.nullptr(GCData.FINALIZER_FUNC) def q_offsets_to_gc_pointers(self, typeid): return self.get(typeid).ofstoptrs @@ -131,7 +133,7 @@ ll_assert(self.q_has_custom_trace(typeid), "T_HAS_CUSTOM_TRACE missing") typeinfo = self.get(typeid) - return typeinfo.finalizer_or_customtrace + return typeinfo.extra.customtracer def q_fast_path_tracing(self, typeid): # return True if none of the flags T_HAS_GCPTR_IN_VARSIZE, @@ -196,18 +198,20 @@ infobits = index info.ofstoptrs = builder.offsets2table(offsets, TYPE) # - kind_and_fptr = builder.special_funcptr_for_type(TYPE) - if kind_and_fptr is not None: - kind, fptr = kind_and_fptr - info.finalizer_or_customtrace = fptr - if kind == "finalizer": + fptrs = builder.special_funcptr_for_type(TYPE) + if fptrs: + extra = lltype.malloc(GCData.EXTRA, zero=True, immortal=True, + flavor='raw') + if "finalizer" in fptrs: + extra.finalizer = fptrs["finalizer"] infobits |= T_HAS_FINALIZER - elif kind == 'light_finalizer': + if "light_finalizer" in fptrs: + extra.finalizer = fptrs["light_finalizer"] infobits |= T_HAS_FINALIZER | T_HAS_LIGHTWEIGHT_FINALIZER - elif kind == "custom_trace": + if "custom_trace" in fptrs: + extra.customtracer = fptrs["custom_trace"] infobits |= T_HAS_CUSTOM_TRACE - else: - assert 0, kind + info.extra = extra # if not TYPE._is_varsize(): info.fixedsize = llarena.round_up_for_allocation( @@ -379,19 +383,16 @@ return self._special_funcptrs[TYPE] fptr1, is_lightweight = self.make_finalizer_funcptr_for_type(TYPE) fptr2 = self.make_custom_trace_funcptr_for_type(TYPE) - assert not (fptr1 and fptr2), ( - "type %r needs both a finalizer and a custom tracer" % (TYPE,)) + result = {} if fptr1: if is_lightweight: - kind_and_fptr = "light_finalizer", fptr1 + result["light_finalizer"] = fptr1 else: - kind_and_fptr = "finalizer", fptr1 - elif fptr2: - kind_and_fptr = "custom_trace", fptr2 - else: - kind_and_fptr = None - self._special_funcptrs[TYPE] = kind_and_fptr - return kind_and_fptr + result["finalizer"] = fptr1 + if fptr2: + result["custom_trace"] = fptr2 + self._special_funcptrs[TYPE] = result + return result def make_finalizer_funcptr_for_type(self, TYPE): # must be overridden for proper finalizer support diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py --- a/rpython/memory/gcwrapper.py +++ b/rpython/memory/gcwrapper.py @@ -216,16 +216,14 @@ t = self.llinterp.typer.annotator.translator light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph) - def ll_finalizer(addr, dummy): - assert dummy == llmemory.NULL + def ll_finalizer(addr): try: v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG) self.llinterp.eval_graph(destrgraph, [v], recursive=True) except llinterp.LLException: raise RuntimeError( "a finalizer raised an exception, shouldn't happen") - return llmemory.NULL - return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light + return llhelper(gctypelayout.GCData.FINALIZER, ll_finalizer), light def make_custom_trace_funcptr_for_type(self, TYPE): from rpython.memory.gctransform.support import get_rtti diff --git a/rpython/rlib/_rffi_stacklet.py b/rpython/rlib/_rffi_stacklet.py --- a/rpython/rlib/_rffi_stacklet.py +++ b/rpython/rlib/_rffi_stacklet.py @@ -56,9 +56,9 @@ new = llexternal('stacklet_new', [thread_handle, run_fn, llmemory.Address], handle, random_effects_on_gcobjs=True) -switch = llexternal('stacklet_switch', [thread_handle, handle], handle, +switch = llexternal('stacklet_switch', [handle], handle, random_effects_on_gcobjs=True) -destroy = llexternal('stacklet_destroy', [thread_handle, handle], lltype.Void) +destroy = llexternal('stacklet_destroy', [handle], lltype.Void) _translate_pointer = llexternal("_stacklet_translate_pointer", [llmemory.Address, llmemory.Address], diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -1,8 +1,9 @@ -from rpython.rlib import _rffi_stacklet as _c from rpython.rlib.debug import ll_assert from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rtyper.lltypesystem.lloperation import llop -from rpython.rtyper.annlowlevel import llhelper +from rpython.rtyper.annlowlevel import llhelper, MixLevelHelperAnnotator +from rpython.annotator import model as annmodel +from rpython.rlib import _rffi_stacklet as _c _asmstackrootwalker = None # BIG HACK: monkey-patched by asmgcroot.py @@ -129,11 +130,26 @@ return _stackletrootwalker get_stackletrootwalker._annspecialcase_ = 'specialize:memo' +def complete_destrptr(gctransformer): + translator = gctransformer.translator + mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper) + args_s = [annmodel.lltype_to_annotation(lltype.Ptr(SUSPSTACK))] + s_result = annmodel.s_None + destrptr = mixlevelannotator.delayedfunction(suspstack_destructor, + args_s, s_result) + mixlevelannotator.finish() + lltype.attachRuntimeTypeInfo(SUSPSTACK, destrptr=destrptr) + def customtrace(obj, prev): stackletrootwalker = get_stackletrootwalker() return stackletrootwalker.next(obj, prev) +def suspstack_destructor(suspstack): + h = suspstack.handle + if h: + _c.destroy(h) + SUSPSTACK = lltype.GcStruct('SuspStack', ('handle', _c.handle), @@ -169,7 +185,7 @@ # stacklet with stacklet_new(). If this call fails, then we # are just returning NULL. _stack_just_closed() - return _c.new(gcrootfinder.thrd, llhelper(_c.run_fn, _new_runfn), + return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn), llmemory.NULL) def _stack_just_closed(): @@ -216,7 +232,7 @@ # # gcrootfinder.suspstack.anchor is left with the anchor of the # previous place (i.e. before the call to switch()). - h2 = _c.switch(gcrootfinder.thrd, h) + h2 = _c.switch(h) # if not h2: # MemoryError: restore gcrootfinder.suspstack.anchor = oldanchor @@ -228,7 +244,7 @@ suspstack = NULL_SUSPSTACK def new(self, thrd, callback, arg): - self.thrd = thrd._thrd + self.newthrd = thrd._thrd self.runfn = callback self.arg = arg # make a fresh new clean SUSPSTACK @@ -240,8 +256,7 @@ alternateanchor) return self.get_result_suspstack(h) - def switch(self, thrd, suspstack): - self.thrd = thrd._thrd + def switch(self, suspstack): self.suspstack = suspstack h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) @@ -267,11 +282,6 @@ # This is a return that gave us a real handle. Store it. return self.attach_handle_on_suspstack(h) - def destroy(self, thrd, suspstack): - h = suspstack.handle - suspstack.handle = _c.null_handle - _c.destroy(thrd._thrd, h) - def is_empty_handle(self, suspstack): return not suspstack diff --git a/rpython/rlib/_stacklet_shadowstack.py b/rpython/rlib/_stacklet_shadowstack.py --- a/rpython/rlib/_stacklet_shadowstack.py +++ b/rpython/rlib/_stacklet_shadowstack.py @@ -79,25 +79,18 @@ return get_result_suspstack(h) new._dont_inline_ = True - def switch(thrd, suspstack): + def switch(suspstack): # suspstack has a handle to target, i.e. where to switch to ll_assert(suspstack != gcrootfinder.oldsuspstack, "stacklet: invalid use") gcrootfinder.newsuspstack = suspstack - thread_handle = thrd._thrd h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) h = llmemory.cast_adr_to_ptr(h, _c.handle) prepare_old_suspstack() - h = _c.switch(thread_handle, h) + h = _c.switch(h) return get_result_suspstack(h) switch._dont_inline_ = True - def destroy(thrd, suspstack): - h = llop.gc_shadowstackref_context(llmemory.Address, suspstack) - h = llmemory.cast_adr_to_ptr(h, _c.handle) - llop.gc_shadowstackref_destroy(lltype.Void, suspstack) - _c.destroy(thrd._thrd, h) - def is_empty_handle(suspstack): return not suspstack diff --git a/rpython/rlib/rstacklet.py b/rpython/rlib/rstacklet.py --- a/rpython/rlib/rstacklet.py +++ b/rpython/rlib/rstacklet.py @@ -34,17 +34,11 @@ def switch(self, stacklet): if DEBUG: debug.remove(stacklet) - h = self._gcrootfinder.switch(self, stacklet) + h = self._gcrootfinder.switch(stacklet) if DEBUG: debug.add(h) return h - @jit.dont_look_inside - def destroy(self, stacklet): - if DEBUG: - debug.remove(stacklet) - self._gcrootfinder.destroy(self, stacklet) - def is_empty_handle(self, stacklet): # note that "being an empty handle" and being equal to # "get_null_handle()" may be the same, or not; don't rely on it diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -6,7 +6,7 @@ except CompilationError, e: py.test.skip("cannot import rstacklet: %s" % e) -from rpython.rlib import rrandom +from rpython.rlib import rrandom, rgc from rpython.rlib.rarithmetic import intmask from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.translator.c.test.test_standalone import StandaloneTests @@ -72,7 +72,9 @@ self.status = 0 h = self.sthread.new(switchbackonce_callback, rffi.cast(llmemory.Address, 321)) - self.sthread.destroy(h) + # 'h' ignored + if (i % 5000) == 2500: + rgc.collect() def any_alive(self): for task in self.tasks: diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -890,8 +890,6 @@ raise NotImplementedError("gc_shadowstackref_new") def op_gc_shadowstackref_context(self): raise NotImplementedError("gc_shadowstackref_context") - def op_gc_shadowstackref_destroy(self): - raise NotImplementedError("gc_shadowstackref_destroy") def op_gc_save_current_state_away(self): raise NotImplementedError("gc_save_current_state_away") def op_gc_forget_current_state(self): diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py --- a/rpython/rtyper/lltypesystem/lloperation.py +++ b/rpython/rtyper/lltypesystem/lloperation.py @@ -518,7 +518,6 @@ # for stacklet+shadowstack support 'gc_shadowstackref_new': LLOp(canmallocgc=True), 'gc_shadowstackref_context': LLOp(), - 'gc_shadowstackref_destroy': LLOp(), 'gc_save_current_state_away': LLOp(), 'gc_forget_current_state': LLOp(), 'gc_restore_state_from': LLOp(), 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 @@ -313,19 +313,19 @@ def struct_setup(self, structdefnode, rtti): if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'): - destrptr = rtti._obj.destructor_funcptr + gctransf = self.db.gctransformer + TYPE = structdefnode.STRUCT + fptrs = gctransf.special_funcptr_for_type(TYPE) # make sure this is seen by the database early, i.e. before # finish_helpers() on the gctransformer + destrptr = rtti._obj.destructor_funcptr self.db.get(destrptr) # the following, on the other hand, will only discover ll_finalizer # helpers. The get() sees and records a delayed pointer. It is # still important to see it so that it can be followed as soon as # the mixlevelannotator resolves it. - gctransf = self.db.gctransformer - TYPE = structdefnode.STRUCT - kind_and_fptr = gctransf.special_funcptr_for_type(TYPE) - if kind_and_fptr: - self.db.get(kind_and_fptr[1]) + for fptr in fptrs.values(): + self.db.get(fptr) def array_setup(self, arraydefnode): pass diff --git a/rpython/translator/c/src/stacklet/stacklet.c b/rpython/translator/c/src/stacklet/stacklet.c --- a/rpython/translator/c/src/stacklet/stacklet.c +++ b/rpython/translator/c/src/stacklet/stacklet.c @@ -52,6 +52,8 @@ * main stack. */ struct stacklet_s *stack_prev; + + stacklet_thread_handle stack_thrd; /* the thread where the stacklet is */ }; void *(*_stacklet_switchstack)(void*(*)(void*, void*), @@ -132,6 +134,7 @@ stacklet->stack_stop = thrd->g_current_stack_stop; stacklet->stack_saved = 0; stacklet->stack_prev = thrd->g_stack_chain_head; + stacklet->stack_thrd = thrd; thrd->g_stack_chain_head = stacklet; return 0; } @@ -293,10 +296,10 @@ return thrd->g_source; } -stacklet_handle stacklet_switch(stacklet_thread_handle thrd, - stacklet_handle target) +stacklet_handle stacklet_switch(stacklet_handle target) { long stackmarker; + stacklet_thread_handle thrd = target->stack_thrd; if (thrd->g_current_stack_stop <= (char *)&stackmarker) thrd->g_current_stack_stop = ((char *)&stackmarker) + 1; @@ -305,15 +308,23 @@ return thrd->g_source; } -void stacklet_destroy(stacklet_thread_handle thrd, stacklet_handle target) +void stacklet_destroy(stacklet_handle target) { - /* remove 'target' from the chained list 'unsaved_stack', if it is there */ - struct stacklet_s **pp = &thrd->g_stack_chain_head; - for (; *pp != NULL; pp = &(*pp)->stack_prev) - if (*pp == target) { - *pp = target->stack_prev; - break; - } + if (target->stack_prev != NULL) { + /* 'target' appears to be in the chained list 'unsaved_stack', + so remove it from there. Note that if 'thrd' was already + deleted, it means that we left the thread and all stacklets + still in the thread should be fully copied away from the + stack --- so should have stack_prev == NULL. In this case + we don't even read 'stack_thrd', already deallocated. */ + stacklet_thread_handle thrd = target->stack_thrd; + struct stacklet_s **pp = &thrd->g_stack_chain_head; + for (; *pp != NULL; pp = &(*pp)->stack_prev) + if (*pp == target) { + *pp = target->stack_prev; + break; + } + } free(target); } diff --git a/rpython/translator/c/src/stacklet/stacklet.h b/rpython/translator/c/src/stacklet/stacklet.h --- a/rpython/translator/c/src/stacklet/stacklet.h +++ b/rpython/translator/c/src/stacklet/stacklet.h @@ -44,13 +44,12 @@ * Don't call this with an already-used target, with EMPTY_STACKLET_HANDLE, * or with a stack handle from another thread (in multithreaded apps). */ -stacklet_handle stacklet_switch(stacklet_thread_handle thrd, - stacklet_handle target); +stacklet_handle stacklet_switch(stacklet_handle target); /* Delete a stack handle without resuming it at all. * (This works even if the stack handle is of a different thread) */ -void stacklet_destroy(stacklet_thread_handle thrd, stacklet_handle target); +void stacklet_destroy(stacklet_handle target); /* stacklet_handle _stacklet_switch_to_copy(stacklet_handle) --- later */ _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit