Esempio n. 1
0
 def annotate_walker_functions(self, getfn):
     self.incr_stack_ptr = getfn(self.root_walker.incr_stack,
                                 [annmodel.SomeInteger()],
                                 SomeAddress(),
                                 inline=True)
     self.decr_stack_ptr = getfn(self.root_walker.decr_stack,
                                 [annmodel.SomeInteger()],
                                 SomeAddress(),
                                 inline=True)
Esempio n. 2
0
    def need_stacklet_support(self, gctransformer, getfn):
        from rpython.annotator import model as annmodel
        from rpython.rlib import _stacklet_asmgcc
        # stacklet support: BIG HACK for rlib.rstacklet
        _stacklet_asmgcc._asmstackrootwalker = self  # as a global! argh
        _stacklet_asmgcc.complete_destrptr(gctransformer)

        #
        def gc_detach_callback_pieces():
            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
            result = llmemory.NULL
            framedata = anchor.address[1]
            while framedata != anchor:
                next = framedata.address[1]
                if self.belongs_to_current_thread(framedata):
                    # detach it
                    prev = framedata.address[0]
                    prev.address[1] = next
                    next.address[0] = prev
                    # update the global stack counter
                    rffi.stackcounter.stacks_counter -= 1
                    # reattach framedata into the singly-linked list 'result'
                    framedata.address[0] = rffi.cast(llmemory.Address, -1)
                    framedata.address[1] = result
                    result = framedata
                framedata = next
            return result

        #
        def gc_reattach_callback_pieces(pieces):
            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
            while pieces != llmemory.NULL:
                framedata = pieces
                pieces = pieces.address[1]
                # attach 'framedata' into the normal doubly-linked list
                following = anchor.address[1]
                following.address[0] = framedata
                framedata.address[1] = following
                anchor.address[1] = framedata
                framedata.address[0] = anchor
                # update the global stack counter
                rffi.stackcounter.stacks_counter += 1

        #
        s_addr = SomeAddress()
        s_None = annmodel.s_None
        self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces,
                                                   [], s_addr)
        self.gc_reattach_callback_pieces_ptr = getfn(
            gc_reattach_callback_pieces, [s_addr], s_None)
Esempio n. 3
0
    def need_stacklet_support(self, gctransformer, getfn):
        shadow_stack_pool = self.shadow_stack_pool
        SHADOWSTACKREF = get_shadowstackref(self, gctransformer)

        def gc_shadowstackref_new():
            ssref = shadow_stack_pool.allocate(SHADOWSTACKREF)
            return lltype.cast_opaque_ptr(llmemory.GCREF, ssref)

        def gc_shadowstackref_context(gcref):
            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
            return ssref.context

        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)

        def gc_forget_current_state():
            shadow_stack_pool.forget_current_state()

        def gc_restore_state_from(gcref):
            ssref = lltype.cast_opaque_ptr(lltype.Ptr(SHADOWSTACKREF), gcref)
            shadow_stack_pool.restore_state_from(ssref)

        def gc_start_fresh_new_state():
            shadow_stack_pool.start_fresh_new_state()

        s_gcref = SomePtr(llmemory.GCREF)
        s_addr = SomeAddress()
        self.gc_shadowstackref_new_ptr = getfn(gc_shadowstackref_new, [],
                                               s_gcref,
                                               minimal_transform=False)
        self.gc_shadowstackref_context_ptr = getfn(gc_shadowstackref_context,
                                                   [s_gcref],
                                                   s_addr,
                                                   inline=True)
        self.gc_save_current_state_away_ptr = getfn(gc_save_current_state_away,
                                                    [s_gcref, s_addr],
                                                    annmodel.s_None,
                                                    inline=True)
        self.gc_forget_current_state_ptr = getfn(gc_forget_current_state, [],
                                                 annmodel.s_None,
                                                 inline=True)
        self.gc_restore_state_from_ptr = getfn(gc_restore_state_from,
                                               [s_gcref],
                                               annmodel.s_None,
                                               inline=True)
        self.gc_start_fresh_new_state_ptr = getfn(gc_start_fresh_new_state, [],
                                                  annmodel.s_None,
                                                  inline=True)
Esempio n. 4
0
def test_rtype_nongc_object():
    class TestClass(object):
        _alloc_flavor_ = "raw"

        def __init__(self, a):
            self.a = a

        def method1(self):
            return self.a

    def malloc_and_free(a):
        ci = TestClass(a)
        b = ci.method1()
        free_non_gc_object(ci)
        return b

    a = RPythonAnnotator()
    #does not raise:
    s = a.build_types(malloc_and_free, [SomeAddress()])
    assert isinstance(s, SomeAddress)
    rtyper = RPythonTyper(a)
    rtyper.specialize()
Esempio n. 5
0
def ann_cast_int_to_adr(s):
    return SomeAddress()
Esempio n. 6
0
def ann_cast_ptr_to_adr(s):
    from rpython.rtyper.llannotation import SomeInteriorPtr
    assert not isinstance(s, SomeInteriorPtr)
    return SomeAddress()
Esempio n. 7
0
 def compute_annotation(self):
     from rpython.rtyper.llannotation import SomeAddress
     return SomeAddress()
Esempio n. 8
0
def ann_raw_malloc(s_size, s_zero=None):
    assert isinstance(s_size, SomeInteger)  # XXX add noneg...?
    assert s_zero is None or isinstance(s_zero, SomeBool)
    return SomeAddress()
Esempio n. 9
0
    def need_thread_support(self, gctransformer, getfn):
        # Threads supported "out of the box" by the rest of the code.
        # The whole code in this function is only there to support
        # fork()ing in a multithreaded process :-(
        # For this, we need to handle gc_thread_start and gc_thread_die
        # to record the mapping {thread_id: stack_start}, and
        # gc_thread_before_fork and gc_thread_after_fork to get rid of
        # all ASM_FRAMEDATA structures that do no belong to the current
        # thread after a fork().
        from rpython.rlib import rthread
        from rpython.memory.support import AddressDict
        from rpython.memory.support import copy_without_null_values
        from rpython.annotator import model as annmodel
        gcdata = self.gcdata

        def get_aid():
            """Return the thread identifier, cast to an (opaque) address."""
            return llmemory.cast_int_to_adr(rthread.get_ident())

        def thread_start():
            value = llmemory.cast_int_to_adr(llop.stack_current(lltype.Signed))
            gcdata.aid2stack.setitem(get_aid(), value)

        thread_start._always_inline_ = True

        def thread_setup():
            gcdata.aid2stack = AddressDict()
            gcdata.dead_threads_count = 0
            # to also register the main thread's stack
            thread_start()

        thread_setup._always_inline_ = True

        def thread_die():
            gcdata.aid2stack.setitem(get_aid(), llmemory.NULL)
            # from time to time, rehash the dictionary to remove
            # old NULL entries
            gcdata.dead_threads_count += 1
            if (gcdata.dead_threads_count & 511) == 0:
                copy = copy_without_null_values(gcdata.aid2stack)
                gcdata.aid2stack.delete()
                gcdata.aid2stack = copy

        def belongs_to_current_thread(framedata):
            # xxx obscure: the answer is Yes if, as a pointer, framedata
            # lies between the start of the current stack and the top of it.
            stack_start = gcdata.aid2stack.get(get_aid(), llmemory.NULL)
            ll_assert(stack_start != llmemory.NULL,
                      "current thread not found in gcdata.aid2stack!")
            stack_stop = llmemory.cast_int_to_adr(
                llop.stack_current(lltype.Signed))
            return (stack_start <= framedata <= stack_stop
                    or stack_start >= framedata >= stack_stop)

        self.belongs_to_current_thread = belongs_to_current_thread

        def thread_before_fork():
            # before fork(): collect all ASM_FRAMEDATA structures that do
            # not belong to the current thread, and move them out of the
            # way, i.e. out of the main circular doubly linked list.
            detached_pieces = llmemory.NULL
            anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
            initialframedata = anchor.address[1]
            while initialframedata != anchor:  # while we have not looped back
                if not belongs_to_current_thread(initialframedata):
                    # Unlink it
                    prev = initialframedata.address[0]
                    next = initialframedata.address[1]
                    prev.address[1] = next
                    next.address[0] = prev
                    # Link it to the singly linked list 'detached_pieces'
                    initialframedata.address[0] = detached_pieces
                    detached_pieces = initialframedata
                    rffi.stackcounter.stacks_counter -= 1
                # Then proceed to the next piece of stack
                initialframedata = initialframedata.address[1]
            return detached_pieces

        def thread_after_fork(result_of_fork, detached_pieces):
            if result_of_fork == 0:
                # We are in the child process.  Assumes that only the
                # current thread survived.  All the detached_pieces
                # are pointers in other stacks, so have likely been
                # freed already by the multithreaded library.
                # Nothing more for us to do.
                pass
            else:
                # We are still in the parent process.  The fork() may
                # have succeeded or not, but that's irrelevant here.
                # We need to reattach the detached_pieces now, to the
                # circular doubly linked list at 'gcrootanchor'.  The
                # order is not important.
                anchor = llmemory.cast_ptr_to_adr(gcrootanchor)
                while detached_pieces != llmemory.NULL:
                    reattach = detached_pieces
                    detached_pieces = detached_pieces.address[0]
                    a_next = anchor.address[1]
                    reattach.address[0] = anchor
                    reattach.address[1] = a_next
                    anchor.address[1] = reattach
                    a_next.address[0] = reattach
                    rffi.stackcounter.stacks_counter += 1

        self.thread_setup = thread_setup
        self.thread_start_ptr = getfn(thread_start, [],
                                      annmodel.s_None,
                                      inline=True)
        self.thread_die_ptr = getfn(thread_die, [], annmodel.s_None)
        self.thread_before_fork_ptr = getfn(thread_before_fork, [],
                                            SomeAddress())
        self.thread_after_fork_ptr = getfn(
            thread_after_fork,
            [annmodel.SomeInteger(), SomeAddress()], annmodel.s_None)
        #
        # check that the order of the need_*() is correct for us: if we
        # need both threads and stacklets, need_thread_support() must be
        # called first, to initialize self.belongs_to_current_thread.
        assert not hasattr(self, 'gc_detach_callback_pieces_ptr')
Esempio n. 10
0
    def need_thread_support(self, gctransformer, getfn):
        from rpython.rlib import rthread  # xxx fish
        gcdata = self.gcdata
        # the interfacing between the threads and the GC is done via
        # two completely ad-hoc operations at the moment:
        # gc_thread_run and gc_thread_die.  See docstrings below.

        shadow_stack_pool = self.shadow_stack_pool
        SHADOWSTACKREF = get_shadowstackref(self, gctransformer)

        # this is a dict {tid: SHADOWSTACKREF}, where the tid for the
        # current thread may be missing so far
        gcdata.thread_stacks = None
        shadow_stack_pool.has_threads = True

        # Return the thread identifier, as an integer.
        get_tid = rthread.get_ident

        def thread_setup():
            tid = get_tid()
            gcdata.main_tid = tid
            gcdata.active_tid = tid

        def thread_run():
            """Called whenever the current thread (re-)acquired the GIL.
            This should ensure that the shadow stack installed in
            gcdata.root_stack_top/root_stack_base is the one corresponding
            to the current thread.
            No GC operation here, e.g. no mallocs or storing in a dict!

            Note that here specifically we don't call rthread.get_ident(),
            but rthread.get_or_make_ident().  We are possibly in a fresh
            new thread, so we need to be careful.
            """
            tid = rthread.get_or_make_ident()
            if gcdata.active_tid != tid:
                switch_shadow_stacks(tid)

        def thread_die():
            """Called just before the final GIL release done by a dying
            thread.  After a thread_die(), no more gc operation should
            occur in this thread.
            """
            tid = get_tid()
            if tid == gcdata.main_tid:
                return  # ignore calls to thread_die() in the main thread
                # (which can occur after a fork()).
            # we need to switch somewhere else, so go to main_tid
            gcdata.active_tid = gcdata.main_tid
            thread_stacks = gcdata.thread_stacks
            new_ref = thread_stacks[gcdata.active_tid]
            try:
                del thread_stacks[tid]
            except KeyError:
                pass
            # no more GC operation from here -- switching shadowstack!
            shadow_stack_pool.forget_current_state()
            shadow_stack_pool.restore_state_from(new_ref)

        def switch_shadow_stacks(new_tid):
            # we have the wrong shadowstack right now, but it should not matter
            thread_stacks = gcdata.thread_stacks
            try:
                if thread_stacks is None:
                    gcdata.thread_stacks = thread_stacks = {}
                    raise KeyError
                new_ref = thread_stacks[new_tid]
            except KeyError:
                new_ref = lltype.nullptr(SHADOWSTACKREF)
            try:
                old_ref = thread_stacks[gcdata.active_tid]
            except KeyError:
                # first time we ask for a SHADOWSTACKREF for this active_tid
                old_ref = shadow_stack_pool.allocate(SHADOWSTACKREF)
                thread_stacks[gcdata.active_tid] = old_ref
            #
            # no GC operation from here -- switching shadowstack!
            shadow_stack_pool.save_current_state_away(old_ref)
            if new_ref:
                shadow_stack_pool.restore_state_from(new_ref)
            else:
                shadow_stack_pool.start_fresh_new_state()
            # done
            #
            gcdata.active_tid = new_tid

        switch_shadow_stacks._dont_inline_ = True

        def thread_after_fork(result_of_fork, opaqueaddr):
            # we don't need a thread_before_fork in this case, so
            # opaqueaddr == NULL.  This is called after fork().
            if result_of_fork == 0:
                # We are in the child process.  Assumes that only the
                # current thread survived, so frees the shadow stacks
                # of all the other ones.
                gcdata.thread_stacks = None
                # Finally, reset the stored thread IDs, in case it
                # changed because of fork().  Also change the main
                # thread to the current one (because there is not any
                # other left).
                tid = get_tid()
                gcdata.main_tid = tid
                gcdata.active_tid = tid

        self.thread_setup = thread_setup
        self.thread_run_ptr = getfn(thread_run, [],
                                    annmodel.s_None,
                                    minimal_transform=False)
        self.thread_die_ptr = getfn(thread_die, [],
                                    annmodel.s_None,
                                    minimal_transform=False)
        # no thread_before_fork_ptr here
        self.thread_after_fork_ptr = getfn(
            thread_after_fork,
            [annmodel.SomeInteger(), SomeAddress()],
            annmodel.s_None,
            minimal_transform=False)
Esempio n. 11
0
def ann_raw_malloc(s_size):
    assert isinstance(s_size, SomeInteger)  # XXX add noneg...?
    return SomeAddress()