Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r86928:ce52ed81e2ba Date: 2016-09-07 14:43 +0200 http://bitbucket.org/pypy/pypy/changeset/ce52ed81e2ba/
Log: hg merge boehm-rawrefcount diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py --- a/pypy/module/cpyext/state.py +++ b/pypy/module/cpyext/state.py @@ -1,7 +1,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rffi, lltype from pypy.interpreter.error import OperationError, oefmt -from pypy.interpreter.executioncontext import AsyncAction +from pypy.interpreter import executioncontext from rpython.rtyper.lltypesystem import lltype from rpython.rtyper.annlowlevel import llhelper from rpython.rlib.rdynload import DLLHANDLE @@ -14,8 +14,9 @@ self.reset() self.programname = lltype.nullptr(rffi.CCHARP.TO) self.version = lltype.nullptr(rffi.CCHARP.TO) - pyobj_dealloc_action = PyObjDeallocAction(space) - self.dealloc_trigger = lambda: pyobj_dealloc_action.fire() + if space.config.translation.gc != "boehm": + pyobj_dealloc_action = PyObjDeallocAction(space) + self.dealloc_trigger = lambda: pyobj_dealloc_action.fire() def reset(self): from pypy.module.cpyext.modsupport import PyMethodDef @@ -67,6 +68,11 @@ state.api_lib = str(api.build_bridge(self.space)) else: api.setup_library(self.space) + # + if self.space.config.translation.gc == "boehm": + action = BoehmPyObjDeallocAction(self.space) + self.space.actionflag.register_periodic_action(action, + use_bytecode_counter=True) def install_dll(self, eci): """NOT_RPYTHON @@ -84,8 +90,10 @@ from pypy.module.cpyext.api import init_static_data_translated if we_are_translated(): - rawrefcount.init(llhelper(rawrefcount.RAWREFCOUNT_DEALLOC_TRIGGER, - self.dealloc_trigger)) + if space.config.translation.gc != "boehm": + rawrefcount.init( + llhelper(rawrefcount.RAWREFCOUNT_DEALLOC_TRIGGER, + self.dealloc_trigger)) init_static_data_translated(space) setup_new_method_def(space) @@ -143,15 +151,23 @@ self.extensions[path] = w_copy -class PyObjDeallocAction(AsyncAction): +def _rawrefcount_perform(space): + from pypy.module.cpyext.pyobject import PyObject, decref + while True: + py_obj = rawrefcount.next_dead(PyObject) + if not py_obj: + break + decref(space, py_obj) + +class PyObjDeallocAction(executioncontext.AsyncAction): """An action that invokes _Py_Dealloc() on the dying PyObjects. """ + def perform(self, executioncontext, frame): + _rawrefcount_perform(self.space) +class BoehmPyObjDeallocAction(executioncontext.PeriodicAsyncAction): + # This variant is used with Boehm, which doesn't have the explicit + # callback. Instead we must periodically check ourselves. def perform(self, executioncontext, frame): - from pypy.module.cpyext.pyobject import PyObject, decref - - while True: - py_obj = rawrefcount.next_dead(PyObject) - if not py_obj: - break - decref(self.space, py_obj) + if we_are_translated(): + _rawrefcount_perform(self.space) diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py --- a/rpython/rlib/rawrefcount.py +++ b/rpython/rlib/rawrefcount.py @@ -4,10 +4,11 @@ # This is meant for pypy's cpyext module, but is a generally # useful interface over our GC. XXX "pypy" should be removed here # -import sys, weakref -from rpython.rtyper.lltypesystem import lltype, llmemory +import sys, weakref, py +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.rlib import rgc @@ -229,6 +230,11 @@ v_p, v_ob = hop.inputargs(*hop.args_r) hop.exception_cannot_occur() hop.genop(name, [_unspec_p(hop, v_p), _unspec_ob(hop, v_ob)]) + # + if hop.rtyper.annotator.translator.config.translation.gc == "boehm": + c_func = hop.inputconst(lltype.typeOf(func_boehm_eci), + func_boehm_eci) + hop.genop('direct_call', [c_func]) class Entry(ExtRegistryEntry): @@ -281,3 +287,10 @@ v_ob = hop.genop('gc_rawrefcount_next_dead', [], resulttype = llmemory.Address) return _spec_ob(hop, v_ob) + +src_dir = py.path.local(__file__).dirpath() / 'src' +boehm_eci = ExternalCompilationInfo( + post_include_bits = [(src_dir / 'boehm-rawrefcount.h').read()], + separate_module_files = [(src_dir / 'boehm-rawrefcount.c')], +) +func_boehm_eci = rffi.llexternal_use_eci(boehm_eci) diff --git a/rpython/rlib/src/boehm-rawrefcount.c b/rpython/rlib/src/boehm-rawrefcount.c new file mode 100644 --- /dev/null +++ b/rpython/rlib/src/boehm-rawrefcount.c @@ -0,0 +1,281 @@ +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <gc/gc.h> +#include <gc/gc_mark.h> + +#ifdef TEST_BOEHM_RAWREFCOUNT +# define RPY_EXTERN /* nothing */ +#else +# include "common_header.h" +#endif + + +#define REFCNT_FROM_PYPY (LONG_MAX / 4 + 1) + +typedef struct pypy_header0 gcobj_t; /* opaque here */ + +#ifndef _WIN32 +typedef intptr_t Py_ssize_t; +#else +typedef long Py_ssize_t; +#endif + +/* this is the first two words of the PyObject structure used in + pypy/module/cpyext */ +typedef struct { + Py_ssize_t ob_refcnt; + Py_ssize_t ob_pypy_link; +} pyobj_t; + +struct link_s { + pyobj_t *pyobj; /* NULL if entry unused */ + uintptr_t gcenc; + struct link_s *next_in_bucket; +}; + +#define MARKER_LIST_START ((pyobj_t *)-1) + +static struct link_s **hash_buckets, *hash_list, *hash_free_list; +static uintptr_t hash_mask_bucket; +static intptr_t hash_list_walk_next = -1; + +static uintptr_t hash_get_hash(gcobj_t *gcobj) +{ + assert(gcobj != NULL); + uintptr_t h = (uintptr_t)gcobj; + assert((h & 1) == 0); + h -= (h >> 6); + return h & hash_mask_bucket; +} + +static gcobj_t *decode_gcenc(uintptr_t gcenc) +{ + if (gcenc & 1) + gcenc = ~gcenc; + return (gcobj_t *)gcenc; +} + +static void hash_link(struct link_s *lnk) +{ + uintptr_t h = hash_get_hash(decode_gcenc(lnk->gcenc)); + lnk->next_in_bucket = hash_buckets[h]; + hash_buckets[h] = lnk; +} + +static void boehm_is_about_to_collect(void); + +static void hash_grow_table(void) +{ + static int rec = 0; + assert(!rec); /* recursive hash_grow_table() */ + rec = 1; + + if (hash_buckets == NULL) + GC_set_start_callback(boehm_is_about_to_collect); + + uintptr_t i, num_buckets = (hash_mask_bucket + 1) * 2; + if (num_buckets < 16) num_buckets = 16; + assert((num_buckets & (num_buckets - 1)) == 0); /* power of two */ + + /* The new hash_buckets: an array of pointers to struct link_s, of + length a power of two, used as a dictionary hash table. It is + not allocated with Boehm because there is no point in Boehm looking + in it. + */ + struct link_s **new_buckets = calloc(num_buckets, sizeof(struct link_s *)); + assert(new_buckets); + + /* The new hash_list: the array of all struct link_s. Their order + is irrelevant. There is a GC_register_finalizer() on the 'gcenc' + field, so we don't move the array; instead we allocate a new array + to use in addition to the old one. There are a total of 2 to 4 + times as many 'struct link_s' as the length of 'buckets'. + */ + uintptr_t num_list = num_buckets * 2; + struct link_s *new_list = GC_MALLOC(num_list * sizeof(struct link_s)); + for (i = num_list; i-- > 1; ) { + new_list[i].next_in_bucket = hash_free_list; + hash_free_list = &new_list[i]; + } + /* list[0] is abused to store a pointer to the previous list and + the length of the current list */ + struct link_s *old_list = hash_list; + new_list[0].next_in_bucket = old_list; + new_list[0].gcenc = num_list; + new_list[0].pyobj = MARKER_LIST_START; + + hash_list = new_list; + free(hash_buckets); + hash_buckets = new_buckets; + hash_mask_bucket = num_buckets - 1; + hash_list_walk_next = hash_mask_bucket; + + /* re-add all old 'struct link_s' to the hash_buckets */ + struct link_s *plist = old_list; + while (plist != NULL) { + uintptr_t count = plist[0].gcenc; + for (i = 1; i < count; i++) { + if (plist[i].gcenc != 0) + hash_link(&plist[i]); + } + plist = plist[0].next_in_bucket; + } + GC_reachable_here(old_list); + + rec = 0; +} + +static void hash_add_entry(gcobj_t *gcobj, pyobj_t *pyobj) +{ + if (hash_free_list == NULL) { + hash_grow_table(); + } + assert(pyobj->ob_pypy_link == 0); + + struct link_s *lnk = hash_free_list; + hash_free_list = lnk->next_in_bucket; + lnk->pyobj = pyobj; + lnk->gcenc = (uintptr_t)gcobj; + pyobj->ob_pypy_link = (Py_ssize_t)lnk; + + hash_link(lnk); + + if (GC_base(gcobj) == NULL) { + /* 'gcobj' is probably a prebuilt object - it makes no */ + /* sense to register it then, and it crashes Boehm in */ + /* quite obscure ways */ + } + else { + int j = GC_general_register_disappearing_link( + (void **)&lnk->gcenc, gcobj); + assert(j == GC_SUCCESS); + } +} + +static pyobj_t *hash_get_entry(gcobj_t *gcobj) +{ + if (hash_buckets == NULL) + return NULL; + uintptr_t h = hash_get_hash(gcobj); + struct link_s *lnk = hash_buckets[h]; + while (lnk != NULL) { + assert(lnk->pyobj != NULL); + if (decode_gcenc(lnk->gcenc) == gcobj) + return lnk->pyobj; + lnk = lnk->next_in_bucket; + } + return NULL; +} + + +RPY_EXTERN +/*pyobj_t*/void *gc_rawrefcount_next_dead(void) +{ + while (hash_list_walk_next >= 0) { + struct link_s *p, **pp = &hash_buckets[hash_list_walk_next]; + while (1) { + p = *pp; + if (p == NULL) + break; + assert(p->pyobj != NULL); + if (p->gcenc == 0) { + /* quadratic time on the number of links from the same + bucket chain, but it should be small with very high + probability */ + pyobj_t *result = p->pyobj; +#ifdef TEST_BOEHM_RAWREFCOUNT + printf("next_dead: %p\n", result); +#endif + assert(result->ob_refcnt == REFCNT_FROM_PYPY); + p->pyobj = NULL; + *pp = p->next_in_bucket; + p->next_in_bucket = hash_free_list; + hash_free_list = p; + return result; + } + else { + assert(p->gcenc != ~(uintptr_t)0); + pp = &p->next_in_bucket; + } + } + hash_list_walk_next--; + } + return NULL; +} + +RPY_EXTERN +void gc_rawrefcount_create_link_pypy(/*gcobj_t*/void *gcobj, + /*pyobj_t*/void *pyobj) +{ + gcobj_t *gcobj1 = (gcobj_t *)gcobj; + pyobj_t *pyobj1 = (pyobj_t *)pyobj; + + assert(pyobj1->ob_pypy_link == 0); + /*assert(pyobj1->ob_refcnt >= REFCNT_FROM_PYPY);*/ + /*^^^ could also be fixed just after the call to create_link_pypy()*/ + + hash_add_entry(gcobj1, pyobj1); +} + +RPY_EXTERN +/*pyobj_t*/void *gc_rawrefcount_from_obj(/*gcobj_t*/void *gcobj) +{ + return hash_get_entry((gcobj_t *)gcobj); +} + +RPY_EXTERN +/*gcobj_t*/void *gc_rawrefcount_to_obj(/*pyobj_t*/void *pyobj) +{ + pyobj_t *pyobj1 = (pyobj_t *)pyobj; + + if (pyobj1->ob_pypy_link == 0) + return NULL; + + struct link_s *lnk = (struct link_s *)pyobj1->ob_pypy_link; + assert(lnk->pyobj == pyobj1); + + gcobj_t *g = decode_gcenc(lnk->gcenc); + assert(g != NULL); + return g; +} + +static void boehm_is_about_to_collect(void) +{ + struct link_s *plist = hash_list; + uintptr_t gcenc_union = 0; + while (plist != NULL) { + uintptr_t i, count = plist[0].gcenc; + for (i = 1; i < count; i++) { + if (plist[i].gcenc == 0) + continue; + + pyobj_t *p = plist[i].pyobj; + assert(p != NULL); + assert(p->ob_refcnt >= REFCNT_FROM_PYPY); + +#ifdef TEST_BOEHM_RAWREFCOUNT + printf("plist[%d].gcenc: %p ", (int)i, plist[i].gcenc); +#endif + + if ((plist[i].gcenc & 1) ^ (p->ob_refcnt == REFCNT_FROM_PYPY)) { + /* ob_refcnt > FROM_PYPY: non-zero regular refcnt, + the gc obj must stay alive. decode gcenc. + ---OR--- + ob_refcnt == FROM_PYPY: no refs from C code, the + gc obj must not (necessarily) stay alive. encode gcenc. + */ + plist[i].gcenc = ~plist[i].gcenc; + } + gcenc_union |= plist[i].gcenc; +#ifdef TEST_BOEHM_RAWREFCOUNT + printf("-> %p\n", plist[i].gcenc); +#endif + } + plist = plist[0].next_in_bucket; + } + if (gcenc_union & 1) /* if there is at least one item potentially dead */ + hash_list_walk_next = hash_mask_bucket; +} diff --git a/rpython/rlib/src/boehm-rawrefcount.h b/rpython/rlib/src/boehm-rawrefcount.h new file mode 100644 --- /dev/null +++ b/rpython/rlib/src/boehm-rawrefcount.h @@ -0,0 +1,24 @@ + +/* Missing: + OP_GC_RAWREFCOUNT_INIT(callback, r): the callback is not supported here + OP_GC_RAWREFCOUNT_CREATE_LINK_PYOBJ(): not implemented, maybe not needed +*/ + +#define OP_GC_RAWREFCOUNT_CREATE_LINK_PYPY(gcobj, pyobj, r) \ + gc_rawrefcount_create_link_pypy(gcobj, pyobj) + +#define OP_GC_RAWREFCOUNT_FROM_OBJ(gcobj, r) \ + r = gc_rawrefcount_from_obj(gcobj) + +#define OP_GC_RAWREFCOUNT_TO_OBJ(pyobj, r) \ + r = gc_rawrefcount_to_obj(pyobj) + +#define OP_GC_RAWREFCOUNT_NEXT_DEAD(r) \ + r = gc_rawrefcount_next_dead() + + +RPY_EXTERN void gc_rawrefcount_create_link_pypy(/*gcobj_t*/void *gcobj, + /*pyobj_t*/void *pyobj); +RPY_EXTERN /*pyobj_t*/void *gc_rawrefcount_from_obj(/*gcobj_t*/void *gcobj); +RPY_EXTERN /*gcobj_t*/void *gc_rawrefcount_to_obj(/*pyobj_t*/void *pyobj); +RPY_EXTERN /*pyobj_t*/void *gc_rawrefcount_next_dead(void); diff --git a/rpython/rlib/test/test_rawrefcount.py b/rpython/rlib/test/test_rawrefcount.py --- a/rpython/rlib/test/test_rawrefcount.py +++ b/rpython/rlib/test/test_rawrefcount.py @@ -266,3 +266,52 @@ t, cbuilder = self.compile(entry_point) data = cbuilder.cmdexec('hi there') assert data.startswith('OK!\n') + + +class TestBoehmTranslated(StandaloneTests): + + def test_full_translation(self): + + def make_ob(): + p = W_Root(42) + ob = lltype.malloc(PyObjectS, flavor='raw', zero=True) + rawrefcount.create_link_pypy(p, ob) + ob.c_ob_refcnt += REFCNT_FROM_PYPY + assert rawrefcount.from_obj(PyObject, p) == ob + assert rawrefcount.to_obj(W_Root, ob) == p + return ob + + prebuilt_p = W_Root(-42) + prebuilt_ob = lltype.malloc(PyObjectS, flavor='raw', zero=True, + immortal=True) + + def entry_point(argv): + rawrefcount.create_link_pypy(prebuilt_p, prebuilt_ob) + prebuilt_ob.c_ob_refcnt += REFCNT_FROM_PYPY + oblist = [make_ob() for i in range(50)] + rgc.collect() + deadlist = [] + while True: + ob = rawrefcount.next_dead(PyObject) + if not ob: break + deadlist.append(ob) + if len(deadlist) == 0: + print "no dead object" + return 1 + if len(deadlist) < 30: + print "not enough dead objects" + return 1 + for ob in deadlist: + if ob not in oblist: + print "unexpected value for dead pointer" + return 1 + oblist.remove(ob) + print "OK!" + lltype.free(ob, flavor='raw') + return 0 + + self.config = get_combined_translation_config(translating=True) + self.config.translation.gc = "boehm" + t, cbuilder = self.compile(entry_point) + data = cbuilder.cmdexec('hi there') + assert data.startswith('OK!\n') diff --git a/rpython/rlib/test/test_rawrefcount_boehm.py b/rpython/rlib/test/test_rawrefcount_boehm.py new file mode 100644 --- /dev/null +++ b/rpython/rlib/test/test_rawrefcount_boehm.py @@ -0,0 +1,230 @@ +import itertools, os, subprocess +from hypothesis import given, strategies +from rpython.tool.udir import udir + + +TEST_CODE = r""" +#define TEST_BOEHM_RAWREFCOUNT +#include "boehm-rawrefcount.c" + +static gcobj_t *alloc_gcobj(void) /* for tests */ +{ + gcobj_t *g = GC_MALLOC(1000); + printf("gc obj: %p\n", g); + return g; +} + +static pyobj_t *alloc_pyobj(void) /* for tests */ +{ + pyobj_t *p = malloc(1000); + p->ob_refcnt = 1; + p->ob_pypy_link = 0; + printf("py obj: %p\n", p); + return p; +} + +static void decref(pyobj_t *p) /* for tests */ +{ + p->ob_refcnt--; + if (p->ob_refcnt == 0) { + printf("decref to zero: %p\n", p); + free(p); + } + assert(p->ob_refcnt >= REFCNT_FROM_PYPY || + p->ob_refcnt < REFCNT_FROM_PYPY * 0.99); +} + +void run_test(void); /* forward declaration, produced by the test */ + +int main(void) +{ + run_test(); + while (gc_rawrefcount_next_dead() != NULL) + ; + return 0; +} +""" + + +operations = strategies.sampled_from([ + 'new_pyobj', + 'new_gcobj', + 'create_link', + 'from_obj', + 'to_obj', + 'forget_pyobj', + 'forget_gcobj', + 'collect', + 'dead', + ]) + + +@strategies.composite +def make_code(draw): + code = [] + pyobjs = [] + gcobjs = [] + num_gcobj = itertools.count() + num_pyobj = itertools.count() + links_g2p = {} + links_p2g = {} + + def new_gcobj(): + varname = 'g%d' % next(num_gcobj) + code.append('gcobj_t *volatile %s = alloc_gcobj();' % varname) + gcobjs.append(varname) + return varname + + def new_pyobj(): + varname = 'p%d' % next(num_pyobj) + code.append('pyobj_t *%s = alloc_pyobj();' % varname) + pyobjs.append(varname) + return varname + + for op in draw(strategies.lists(operations, average_size=250)): + if op == 'new_gcobj': + new_gcobj() + elif op == 'new_pyobj': + new_pyobj() + elif op == 'create_link': + gvars = [varname for varname in gcobjs if varname not in links_g2p] + if gvars == []: + gvars.append(new_gcobj()) + pvars = [varname for varname in pyobjs if varname not in links_p2g] + if pvars == []: + pvars.append(new_pyobj()) + gvar = draw(strategies.sampled_from(gvars)) + pvar = draw(strategies.sampled_from(pvars)) + code.append(r'printf("create_link %%p-%%p\n", %s, %s); ' + % (gvar, pvar) + + "%s->ob_refcnt += REFCNT_FROM_PYPY; " % pvar + + "gc_rawrefcount_create_link_pypy(%s, %s);" + % (gvar, pvar)) + links_g2p[gvar] = pvar + links_p2g[pvar] = gvar + elif op == 'from_obj': + if gcobjs: + prnt = False + gvar = draw(strategies.sampled_from(gcobjs)) + if gvar not in links_g2p: + check = "== NULL" + elif links_g2p[gvar] in pyobjs: + check = "== %s" % (links_g2p[gvar],) + else: + check = "!= NULL" + prnt = True + code.append("assert(gc_rawrefcount_from_obj(%s) %s);" + % (gvar, check)) + if prnt: + code.append(r'printf("link %%p-%%p\n", %s, ' + 'gc_rawrefcount_from_obj(%s));' % (gvar, gvar)) + elif op == 'to_obj': + if pyobjs: + prnt = False + pvar = draw(strategies.sampled_from(pyobjs)) + if pvar not in links_p2g: + check = "== NULL" + elif links_p2g[pvar] in gcobjs: + check = "== %s" % (links_p2g[pvar],) + else: + check = "!= NULL" + prnt = True + code.append("assert(gc_rawrefcount_to_obj(%s) %s);" + % (pvar, check)) + if prnt: + code.append(r'printf("link %%p-%%p\n", ' + 'gc_rawrefcount_to_obj(%s), %s);' % (pvar, pvar)) + elif op == 'forget_pyobj': + if pyobjs: + index = draw(strategies.sampled_from(range(len(pyobjs)))) + pvar = pyobjs.pop(index) + code.append(r'printf("-p%%p\n", %s); ' % pvar + + "decref(%s); %s = NULL;" % (pvar, pvar)) + elif op == 'forget_gcobj': + if gcobjs: + index = draw(strategies.sampled_from(range(len(gcobjs)))) + gvar = gcobjs.pop(index) + code.append(r'printf("-g%%p\n", %s); ' % gvar + + "%s = NULL;" % (gvar,)) + elif op == 'collect': + code.append("GC_gcollect();") + elif op == 'dead': + code.append('gc_rawrefcount_next_dead();') + else: + assert False, op + + return '\n'.join(code) + + +@given(make_code()) +def test_random(code): + filename = str(udir.join("test-rawrefcount-boehm.c")) + with open(filename, "w") as f: + print >> f, TEST_CODE + print >> f, 'void run_test(void) {' + print >> f, code + print >> f, '}' + + srcdir = os.path.dirname(os.path.dirname( + os.path.abspath(os.path.join(__file__)))) + srcdir = os.path.join(srcdir, 'src') + + err = os.system("cd '%s' && gcc -Werror -lgc -I%s -o test-rawrefcount-boehm" + " test-rawrefcount-boehm.c" % (udir, srcdir)) + assert err == 0 + p = subprocess.Popen("./test-rawrefcount-boehm", stdout=subprocess.PIPE, + cwd=str(udir)) + stdout, _ = p.communicate() + assert p.wait() == 0 + + gcobjs = {} + pyobjs = {} + links_p2g = {} + links_g2p = {} + for line in stdout.splitlines(): + if line.startswith('py obj: '): + p = line[8:] + assert not pyobjs.get(p) + pyobjs[p] = True + assert p not in links_p2g + elif line.startswith('gc obj: '): + g = line[8:] + assert not gcobjs.get(g) + gcobjs[g] = True + if g in links_g2p: del links_g2p[g] + elif line.startswith('-p'): + p = line[2:] + assert pyobjs[p] == True + pyobjs[p] = False + elif line.startswith('-g'): + g = line[2:] + assert gcobjs[g] == True + gcobjs[g] = False + elif line.startswith('decref to zero: '): + p = line[16:] + assert pyobjs[p] == False + assert p not in links_p2g + del pyobjs[p] + elif line.startswith('create_link '): + g, p = line[12:].split('-') + assert g in gcobjs + assert p in pyobjs + assert g not in links_g2p + assert p not in links_p2g + links_g2p[g] = p + links_p2g[p] = g + elif line.startswith('link '): + g, p = line[5:].split('-') + assert g in gcobjs + assert p in pyobjs + assert links_g2p[g] == p + assert links_p2g[p] == g + elif line.startswith('plist['): + pass + elif line.startswith('next_dead: '): + p = line[11:] + assert pyobjs[p] == False + del pyobjs[p] + del links_p2g[p] + else: + assert False, repr(line) 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 @@ -497,6 +497,7 @@ 'gc_rawrefcount_create_link_pyobj': LLOp(), 'gc_rawrefcount_from_obj': LLOp(sideeffects=False), 'gc_rawrefcount_to_obj': LLOp(sideeffects=False), + 'gc_rawrefcount_next_dead': LLOp(), # ------- JIT & GC interaction, only for some GCs ---------- _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit