Beispiel #1
0
    def handle_method_call(self, env, node, call_node):
        """
        Resolve an extension method of a static (C++/Cython-like) vtable:

            typedef {
                double (*method1)(double);
                ...
            } vtab_struct;

            vtab_struct *vtab = *(vtab_struct **) (((char *) obj) + vtab_offset)
            void *method = vtab[index]
        """
        # Make the object we call the method on clone-able
        node.value = nodes.CloneableNode(node.value)

        ext_type = node.value.type
        offset = ext_type.vtab_offset

        vtable_struct = ext_type.vtab_type.to_struct()
        vtable_struct_type = vtable_struct.ref()

        vtab_struct_pointer_pointer = nodes.value_at_offset(
            node.value, offset, vtable_struct_type.pointer())
        vtab_struct_pointer = nodes.DereferenceNode(
            vtab_struct_pointer_pointer)

        vmethod = nodes.StructAttribute(vtab_struct_pointer, node.attr,
                                        ast.Load(), vtable_struct_type)

        # Insert first argument 'self' in args list
        args = call_node.args
        args.insert(0, nodes.CloneNode(node.value))
        result = nodes.NativeFunctionCallNode(node.type, vmethod, args)

        return result
Beispiel #2
0
def get_closure_scope(func_signature, func_obj):
    """
    Retrieve the closure from the NumbaFunction from the func_closure
    attribute.

        func_signature:
            signature of closure function

        func_obj:
            LLVM Value referencing the closure function as a Python object
    """
    closure_scope_type = func_signature.args[0]
    offset = numbawrapper.numbafunc_closure_field_offset
    closure = nodes.LLVMValueRefNode(void.pointer(), func_obj)
    closure = nodes.CoercionNode(closure, char.pointer())
    closure_field = nodes.pointer_add(closure, nodes.const(offset, size_t))
    closure_field = nodes.CoercionNode(closure_field,
                                       closure_scope_type.pointer())
    closure_scope = nodes.DereferenceNode(closure_field)
    return closure_scope
Beispiel #3
0
    def handle_method_call(self, env, node, call_node):
        """
        Resolve an extension method of a dynamic hash-based vtable:

            PyCustomSlots_Table ***vtab_slot = (((char *) obj) + vtab_offset)
            lookup_virtual_method(*vtab_slot)

        We may cache (*vtab_slot), but we may not cache (**vtab_slot), since
        compilations may regenerate the table.

        However, we could *preload* (**vtab_slot), where function calls
        invalidate the preload, if we were so inclined.
        """
        # Make the object we call the method on clone-able
        node.value = nodes.CloneableNode(node.value)

        ext_type = node.ext_type
        func_signature = node.type  #typesystem.extmethod_to_function(node.type)
        offset = ext_type.vtab_offset

        # __________________________________________________________________
        # Retrieve vtab

        vtab_ppp = nodes.value_at_offset(node.value, offset,
                                         void.pointer().pointer())
        vtab_struct_pp = nodes.DereferenceNode(vtab_ppp)

        # __________________________________________________________________
        # Calculate pre-hash

        prehash = virtual.hash_signature(func_signature, func_signature.name)
        prehash_node = nodes.ConstNode(prehash, uint64)

        # __________________________________________________________________
        # Retrieve method pointer

        # A method is always present when it was given a static signature,
        # e.g. @double(double)
        always_present = node.attr in ext_type.vtab_type.methodnames
        args = [vtab_struct_pp, prehash_node]

        # lookup_impl = NumbaVirtualLookup()
        lookup_impl = DebugVirtualLookup()
        ptr = lookup_impl.lookup(env, always_present, node, args)
        vmethod = ptr.coerce(func_signature.pointer())
        vmethod = vmethod.cloneable

        # __________________________________________________________________
        # Call method pointer

        # Insert first argument 'self' in args list
        args = call_node.args
        args.insert(0, nodes.CloneNode(node.value))
        method_call = nodes.NativeFunctionCallNode(func_signature, vmethod,
                                                   args)

        # __________________________________________________________________
        # Generate fallback

        # TODO: Subclassing!
        # if not always_present:
        #     # TODO: Enable this path and generate a phi for the result
        #     # Generate object call
        #     obj_args = [nodes.CoercionNode(arg, object_) for arg in args]
        #     obj_args.append(nodes.NULL)
        #     object_call = function_util.external_call(
        #         env.context, env.crnt.llvm_module,
        #         'PyObject_CallMethodObjArgs', obj_args)
        #
        #     # if vmethod != NULL: vmethod(obj, ...)
        #     # else: obj.method(...)
        #     method_call = nodes.if_else(
        #         ast.NotEq(),
        #         vmethod.clone, nodes.NULL,
        #         lhs=method_call, rhs=object_call)

        return method_call