示例#1
0
def generate_methods_table(cl: ClassIR, name: str, emitter: Emitter) -> None:
    emitter.emit_line('static PyMethodDef {}[] = {{'.format(name))
    for fn in cl.methods.values():
        if fn.decl.is_prop_setter or fn.decl.is_prop_getter:
            continue
        emitter.emit_line('{{"{}",'.format(fn.name))
        emitter.emit_line(' (PyCFunction){}{},'.format(PREFIX,
                                                       fn.cname(
                                                           emitter.names)))
        if use_fastcall(emitter.capi_version):
            flags = ['METH_FASTCALL']
        else:
            flags = ['METH_VARARGS']
        flags.append('METH_KEYWORDS')
        if fn.decl.kind == FUNC_STATICMETHOD:
            flags.append('METH_STATIC')
        elif fn.decl.kind == FUNC_CLASSMETHOD:
            flags.append('METH_CLASS')

        emitter.emit_line(' {}, NULL}},'.format(' | '.join(flags)))

    # Provide a default __getstate__ and __setstate__
    if not cl.has_method('__setstate__') and not cl.has_method('__getstate__'):
        emitter.emit_lines(
            '{"__setstate__", (PyCFunction)CPyPickle_SetState, METH_O, NULL},',
            '{"__getstate__", (PyCFunction)CPyPickle_GetState, METH_NOARGS, NULL},',
        )

    emitter.emit_line('{NULL}  /* Sentinel */')
    emitter.emit_line('};')
示例#2
0
def generate_richcompare_wrapper(cl: ClassIR, emitter: Emitter) -> Optional[str]:
    """Generates a wrapper for richcompare dunder methods."""
    # Sort for determinism on Python 3.5
    matches = sorted([name for name in RICHCOMPARE_OPS if cl.has_method(name)])
    if not matches:
        return None

    name = '{}_RichCompare_{}'.format(DUNDER_PREFIX, cl.name_prefix(emitter.names))
    emitter.emit_line(
        'static PyObject *{name}(PyObject *obj_lhs, PyObject *obj_rhs, int op) {{'.format(
            name=name)
    )
    emitter.emit_line('switch (op) {')
    for func in matches:
        emitter.emit_line('case {}: {{'.format(RICHCOMPARE_OPS[func]))
        method = cl.get_method(func)
        assert method is not None
        generate_wrapper_core(method, emitter, arg_names=['lhs', 'rhs'])
        emitter.emit_line('}')
    emitter.emit_line('}')

    emitter.emit_line('Py_INCREF(Py_NotImplemented);')
    emitter.emit_line('return Py_NotImplemented;')

    emitter.emit_line('}')

    return name
示例#3
0
def specialize_parent_vtable(cls: ClassIR, parent: ClassIR) -> VTableEntries:
    """Generate the part of a vtable corresponding to a parent class or trait"""
    updated = []
    for entry in parent.vtable_entries:
        if isinstance(entry, VTableMethod):
            # Find the original method corresponding to this vtable entry.
            # (This may not be the method in the entry, if it was overridden.)
            orig_parent_method = entry.cls.get_method(entry.name)
            assert orig_parent_method
            method_cls = cls.get_method_and_class(entry.name)
            if method_cls:
                child_method, defining_cls = method_cls
                # TODO: emit a wrapper for __init__ that raises or something
                if (is_same_method_signature(orig_parent_method.sig, child_method.sig)
                        or orig_parent_method.name == '__init__'):
                    entry = VTableMethod(entry.cls, entry.name, child_method, entry.shadow_method)
                else:
                    entry = VTableMethod(entry.cls, entry.name,
                                         defining_cls.glue_methods[(entry.cls, entry.name)],
                                         entry.shadow_method)
        else:
            # If it is an attribute from a trait, we need to find out
            # the real class it got mixed in at and point to that.
            if parent.is_trait:
                _, origin_cls = cls.attr_details(entry.name)
                entry = VTableAttr(origin_cls, entry.name, entry.is_setter)
        updated.append(entry)
    return updated
示例#4
0
def setup_env_class(builder: IRBuilder) -> ClassIR:
    """Generate a class representing a function environment.

    Note that the variables in the function environment are not
    actually populated here. This is because when the environment
    class is generated, the function environment has not yet been
    visited. This behavior is allowed so that when the compiler visits
    nested functions, it can use the returned ClassIR instance to
    figure out free variables it needs to access.  The remaining
    attributes of the environment class are populated when the
    environment registers are loaded.

    Return a ClassIR representing an environment for a function
    containing a nested function.
    """
    env_class = ClassIR('{}_env'.format(builder.fn_info.namespaced_name()),
                        builder.module_name,
                        is_generated=True)
    env_class.attributes[SELF_NAME] = RInstance(env_class)
    if builder.fn_info.is_nested:
        # If the function is nested, its environment class must contain an environment
        # attribute pointing to its encapsulating functions' environment class.
        env_class.attributes[ENV_ATTR_NAME] = RInstance(
            builder.fn_infos[-2].env_class)
    env_class.mro = [env_class]
    builder.fn_info.env_class = env_class
    builder.classes.append(env_class)
    return env_class
示例#5
0
def generate_getseter_declarations(cl: ClassIR, emitter: Emitter) -> None:
    if not cl.is_trait:
        for attr in cl.attributes:
            emitter.emit_line('static PyObject *')
            emitter.emit_line('{}({} *self, void *closure);'.format(
                getter_name(cl, attr, emitter.names),
                cl.struct_name(emitter.names)))
            emitter.emit_line('static int')
            emitter.emit_line(
                '{}({} *self, PyObject *value, void *closure);'.format(
                    setter_name(cl, attr, emitter.names),
                    cl.struct_name(emitter.names)))

    for prop in cl.properties:
        # Generate getter declaration
        emitter.emit_line('static PyObject *')
        emitter.emit_line('{}({} *self, void *closure);'.format(
            getter_name(cl, prop, emitter.names),
            cl.struct_name(emitter.names)))

        # Generate property setter declaration if a setter exists
        if cl.properties[prop][1]:
            emitter.emit_line('static int')
            emitter.emit_line(
                '{}({} *self, PyObject *value, void *closure);'.format(
                    setter_name(cl, prop, emitter.names),
                    cl.struct_name(emitter.names)))
示例#6
0
def generate_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None:
    for attr, rtype in cl.attributes.items():
        attr_field = emitter.attr(attr)

        # Native getter
        emitter.emit_line('{}{}({} *self)'.format(
            emitter.ctype_spaced(rtype),
            native_getter_name(cl, attr, emitter.names),
            cl.struct_name(emitter.names)))
        emitter.emit_line('{')
        if rtype.is_refcounted:
            emit_undefined_check(rtype, emitter, attr_field, '==')
            emitter.emit_lines(
                'PyErr_SetString(PyExc_AttributeError, "attribute {} of {} undefined");'
                .format(repr(attr), repr(cl.name)), '} else {')
            emitter.emit_inc_ref('self->{}'.format(attr_field), rtype)
            emitter.emit_line('}')
        emitter.emit_line('return self->{};'.format(attr_field))
        emitter.emit_line('}')
        emitter.emit_line()
        # Native setter
        emitter.emit_line('bool {}({} *self, {}value)'.format(
            native_setter_name(cl, attr, emitter.names),
            cl.struct_name(emitter.names), emitter.ctype_spaced(rtype)))
        emitter.emit_line('{')
        if rtype.is_refcounted:
            emit_undefined_check(rtype, emitter, attr_field, '!=')
            emitter.emit_dec_ref('self->{}'.format(attr_field), rtype)
            emitter.emit_line('}')
        # This steal the reference to src, so we don't need to increment the arg
        emitter.emit_lines('self->{} = value;'.format(attr_field), 'return 1;',
                           '}')
        emitter.emit_line()
示例#7
0
文件: emitclass.py 项目: alanhdu/mypy
def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None:
    seen_attrs: Set[Tuple[str, RType]] = set()
    lines: List[str] = []
    lines += ['typedef struct {',
              'PyObject_HEAD',
              'CPyVTableItem *vtable;']
    if cl.has_method('__call__') and emitter.use_vectorcall():
        lines.append('vectorcallfunc vectorcall;')
    for base in reversed(cl.base_mro):
        if not base.is_trait:
            for attr, rtype in base.attributes.items():
                if (attr, rtype) not in seen_attrs:
                    lines.append('{}{};'.format(emitter.ctype_spaced(rtype),
                                                emitter.attr(attr)))
                    seen_attrs.add((attr, rtype))

                    if isinstance(rtype, RTuple):
                        emitter.declare_tuple_struct(rtype)

    lines.append('}} {};'.format(cl.struct_name(emitter.names)))
    lines.append('')
    emitter.context.declarations[cl.struct_name(emitter.names)] = HeaderDeclaration(
        lines,
        is_type=True
    )
示例#8
0
def generate_getter(cl: ClassIR,
                    attr: str,
                    rtype: RType,
                    emitter: Emitter) -> None:
    attr_field = emitter.attr(attr)
    emitter.emit_line('static PyObject *')
    emitter.emit_line('{}({} *self, void *closure)'.format(getter_name(cl, attr, emitter.names),
                                                           cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    attr_expr = f'self->{attr_field}'

    # HACK: Don't consider refcounted values as always defined, since it's possible to
    #       access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted
    #       values is benign.
    always_defined = cl.is_always_defined(attr) and not rtype.is_refcounted

    if not always_defined:
        emitter.emit_undefined_attr_check(rtype, attr_expr, '==', unlikely=True)
        emitter.emit_line('PyErr_SetString(PyExc_AttributeError,')
        emitter.emit_line('    "attribute {} of {} undefined");'.format(repr(attr),
                                                                        repr(cl.name)))
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')
    emitter.emit_inc_ref(f'self->{attr_field}', rtype)
    emitter.emit_box(f'self->{attr_field}', 'retval', rtype, declare_dest=True)
    emitter.emit_line('return retval;')
    emitter.emit_line('}')
示例#9
0
    def setUp(self) -> None:
        self.env = Environment()
        self.n = self.env.add_local(Var('n'), int_rprimitive)
        self.m = self.env.add_local(Var('m'), int_rprimitive)
        self.k = self.env.add_local(Var('k'), int_rprimitive)
        self.l = self.env.add_local(Var('l'), list_rprimitive)  # noqa
        self.ll = self.env.add_local(Var('ll'), list_rprimitive)
        self.o = self.env.add_local(Var('o'), object_rprimitive)
        self.o2 = self.env.add_local(Var('o2'), object_rprimitive)
        self.d = self.env.add_local(Var('d'), dict_rprimitive)
        self.b = self.env.add_local(Var('b'), bool_rprimitive)
        self.t = self.env.add_local(Var('t'),
                                    RTuple([int_rprimitive, bool_rprimitive]))
        self.tt = self.env.add_local(
            Var('tt'),
            RTuple(
                [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive]))
        ir = ClassIR('A', 'mod')
        ir.attributes = OrderedDict([('x', bool_rprimitive),
                                     ('y', int_rprimitive)])
        compute_vtable(ir)
        ir.mro = [ir]
        self.r = self.env.add_local(Var('r'), RInstance(ir))

        self.context = EmitterContext(NameGenerator([['mod']]))
        self.emitter = Emitter(self.context, self.env)
        self.declarations = Emitter(self.context, self.env)
        self.visitor = FunctionEmitterVisitor(self.emitter, self.declarations,
                                              'prog.py', 'prog')
示例#10
0
    def setUp(self) -> None:
        self.env = Environment()
        self.n = self.env.add_local(Var('n'), int_rprimitive)
        self.m = self.env.add_local(Var('m'), int_rprimitive)
        self.k = self.env.add_local(Var('k'), int_rprimitive)
        self.l = self.env.add_local(Var('l'), list_rprimitive)  # noqa
        self.ll = self.env.add_local(Var('ll'), list_rprimitive)
        self.o = self.env.add_local(Var('o'), object_rprimitive)
        self.o2 = self.env.add_local(Var('o2'), object_rprimitive)
        self.d = self.env.add_local(Var('d'), dict_rprimitive)
        self.b = self.env.add_local(Var('b'), bool_rprimitive)
        self.s1 = self.env.add_local(Var('s1'), short_int_rprimitive)
        self.s2 = self.env.add_local(Var('s2'), short_int_rprimitive)
        self.i32 = self.env.add_local(Var('i32'), int32_rprimitive)
        self.i32_1 = self.env.add_local(Var('i32_1'), int32_rprimitive)
        self.i64 = self.env.add_local(Var('i64'), int64_rprimitive)
        self.i64_1 = self.env.add_local(Var('i64_1'), int64_rprimitive)
        self.ptr = self.env.add_local(Var('ptr'), pointer_rprimitive)
        self.t = self.env.add_local(Var('t'),
                                    RTuple([int_rprimitive, bool_rprimitive]))
        self.tt = self.env.add_local(
            Var('tt'),
            RTuple(
                [RTuple([int_rprimitive, bool_rprimitive]), bool_rprimitive]))
        ir = ClassIR('A', 'mod')
        ir.attributes = OrderedDict([('x', bool_rprimitive),
                                     ('y', int_rprimitive)])
        compute_vtable(ir)
        ir.mro = [ir]
        self.r = self.env.add_local(Var('r'), RInstance(ir))

        self.context = EmitterContext(NameGenerator([['mod']]))
示例#11
0
def setup_generator_class(builder: IRBuilder) -> ClassIR:
    name = '{}_gen'.format(builder.fn_info.namespaced_name())

    generator_class_ir = ClassIR(name, builder.module_name, is_generated=True)
    generator_class_ir.attributes[ENV_ATTR_NAME] = RInstance(builder.fn_info.env_class)
    generator_class_ir.mro = [generator_class_ir]

    builder.classes.append(generator_class_ir)
    builder.fn_info.generator_class = GeneratorClass(generator_class_ir)
    return generator_class_ir
示例#12
0
def setup_callable_class(builder: IRBuilder) -> None:
    """Generates a callable class representing a nested function or a function within a
    non-extension class and sets up the 'self' variable for that class.

    This takes the most recently visited function and returns a ClassIR to represent that
    function. Each callable class contains an environment attribute with points to another
    ClassIR representing the environment class where some of its variables can be accessed.
    Note that its '__call__' method is not yet implemented, and is implemented in the
    add_call_to_callable_class function.

    Returns a newly constructed ClassIR representing the callable class for the nested
    function.
    """

    # Check to see that the name has not already been taken. If so, rename the class. We allow
    # multiple uses of the same function name because this is valid in if-else blocks. Example:
    #     if True:
    #         def foo():          ---->    foo_obj()
    #             return True
    #     else:
    #         def foo():          ---->    foo_obj_0()
    #             return False
    name = base_name = '{}_obj'.format(builder.fn_info.namespaced_name())
    count = 0
    while name in builder.callable_class_names:
        name = base_name + '_' + str(count)
        count += 1
    builder.callable_class_names.add(name)

    # Define the actual callable class ClassIR, and set its environment to point at the
    # previously defined environment class.
    callable_class_ir = ClassIR(name, builder.module_name, is_generated=True)

    # The functools @wraps decorator attempts to call setattr on nested functions, so
    # we create a dict for these nested functions.
    # https://github.com/python/cpython/blob/3.7/Lib/functools.py#L58
    if builder.fn_info.is_nested:
        callable_class_ir.has_dict = True

    # If the enclosing class doesn't contain nested (which will happen if
    # this is a toplevel lambda), don't set up an environment.
    if builder.fn_infos[-2].contains_nested:
        callable_class_ir.attributes[ENV_ATTR_NAME] = RInstance(
            builder.fn_infos[-2].env_class
        )
    callable_class_ir.mro = [callable_class_ir]
    builder.fn_info.callable_class = ImplicitClass(callable_class_ir)
    builder.classes.append(callable_class_ir)

    # Add a 'self' variable to the callable class' environment, and store that variable in a
    # register to be accessed later.
    self_target = add_self_to_env(builder.environment, callable_class_ir)
    builder.fn_info.callable_class.self_reg = builder.read(self_target, builder.fn_info.fitem.line)
示例#13
0
def generate_setter(cl: ClassIR,
                    attr: str,
                    rtype: RType,
                    emitter: Emitter) -> None:
    attr_field = emitter.attr(attr)
    emitter.emit_line('static int')
    emitter.emit_line('{}({} *self, PyObject *value, void *closure)'.format(
        setter_name(cl, attr, emitter.names),
        cl.struct_name(emitter.names)))
    emitter.emit_line('{')

    deletable = cl.is_deletable(attr)
    if not deletable:
        emitter.emit_line('if (value == NULL) {')
        emitter.emit_line('PyErr_SetString(PyExc_AttributeError,')
        emitter.emit_line('    "{} object attribute {} cannot be deleted");'.format(repr(cl.name),
                                                                                    repr(attr)))
        emitter.emit_line('return -1;')
        emitter.emit_line('}')

    # HACK: Don't consider refcounted values as always defined, since it's possible to
    #       access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted
    #       values is benign.
    always_defined = cl.is_always_defined(attr) and not rtype.is_refcounted

    if rtype.is_refcounted:
        attr_expr = f'self->{attr_field}'
        if not always_defined:
            emitter.emit_undefined_attr_check(rtype, attr_expr, '!=')
        emitter.emit_dec_ref('self->{}'.format(attr_field), rtype)
        if not always_defined:
            emitter.emit_line('}')

    if deletable:
        emitter.emit_line('if (value != NULL) {')

    if rtype.is_unboxed:
        emitter.emit_unbox('value', 'tmp', rtype, error=ReturnHandler('-1'), declare_dest=True)
    elif is_same_type(rtype, object_rprimitive):
        emitter.emit_line('PyObject *tmp = value;')
    else:
        emitter.emit_cast('value', 'tmp', rtype, declare_dest=True)
        emitter.emit_lines('if (!tmp)',
                           '    return -1;')
    emitter.emit_inc_ref('tmp', rtype)
    emitter.emit_line(f'self->{attr_field} = tmp;')
    if deletable:
        emitter.emit_line('} else')
        emitter.emit_line('    self->{} = {};'.format(attr_field,
                                                      emitter.c_undefined_value(rtype)))
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
示例#14
0
文件: classdef.py 项目: srittau/mypy
def check_deletable_declaration(builder: IRBuilder, cl: ClassIR, line: int) -> None:
    for attr in cl.deletable:
        if attr not in cl.attributes:
            if not cl.has_attr(attr):
                builder.error('Attribute "{}" not defined'.format(attr), line)
                continue
            for base in cl.mro:
                if attr in base.property_types:
                    builder.error('Cannot make property "{}" deletable'.format(attr), line)
                    break
            else:
                _, base = cl.attr_details(attr)
                builder.error(('Attribute "{}" not defined in "{}" ' +
                               '(defined in "{}")').format(attr, cl.name, base.name), line)
示例#15
0
def declare_native_getters_and_setters(cl: ClassIR, emitter: Emitter) -> None:
    decls = emitter.context.declarations
    for attr, rtype in cl.attributes.items():
        getter_name = native_getter_name(cl, attr, emitter.names)
        setter_name = native_setter_name(cl, attr, emitter.names)
        decls[getter_name] = HeaderDeclaration(
            '{}{}({} *self);'.format(emitter.ctype_spaced(rtype), getter_name,
                                     cl.struct_name(emitter.names)),
            needs_export=True,
        )
        decls[setter_name] = HeaderDeclaration(
            'bool {}({} *self, {}value);'.format(
                native_setter_name(cl, attr, emitter.names),
                cl.struct_name(emitter.names), emitter.ctype_spaced(rtype)),
            needs_export=True,
        )
示例#16
0
def generate_bin_op_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
    """Generates a wrapper for a native binary dunder method.

    The same wrapper that handles the forward method (e.g. __add__) also handles
    the corresponding reverse method (e.g. __radd__), if defined.

    Both arguments and the return value are PyObject *.
    """
    gen = WrapperGenerator(cl, emitter)
    gen.set_target(fn)
    gen.arg_names = ['left', 'right']
    wrapper_name = gen.wrapper_name()

    gen.emit_header()
    if fn.name not in reverse_op_methods and fn.name in reverse_op_method_names:
        # There's only a reverse operator method.
        generate_bin_op_reverse_only_wrapper(emitter, gen)
    else:
        rmethod = reverse_op_methods[fn.name]
        fn_rev = cl.get_method(rmethod)
        if fn_rev is None:
            # There's only a forward operator method.
            generate_bin_op_forward_only_wrapper(fn, emitter, gen)
        else:
            # There's both a forward and a reverse operator method.
            generate_bin_op_both_wrappers(cl, fn, fn_rev, emitter, gen)
    return wrapper_name
示例#17
0
    def get_attr_expr(self, obj: str, op: Union[GetAttr, SetAttr],
                      decl_cl: ClassIR) -> str:
        """Generate attribute accessor for normal (non-property) access.

        This either has a form like obj->attr_name for attributes defined in non-trait
        classes, and *(obj + attr_offset) for attributes defined by traits. We also
        insert all necessary C casts here.
        """
        cast = '({} *)'.format(op.class_type.struct_name(self.emitter.names))
        if decl_cl.is_trait and op.class_type.class_ir.is_trait:
            # For pure trait access find the offset first, offsets
            # are ordered by attribute position in the cl.attributes dict.
            # TODO: pre-calculate the mapping to make this faster.
            trait_attr_index = list(decl_cl.attributes).index(op.attr)
            # TODO: reuse these names somehow?
            offset = self.emitter.temp_name()
            self.declarations.emit_line('size_t {};'.format(offset))
            self.emitter.emit_line('{} = {};'.format(
                offset, 'CPy_FindAttrOffset({}, {}, {})'.format(
                    self.emitter.type_struct_name(decl_cl),
                    '({}{})->vtable'.format(cast, obj),
                    trait_attr_index,
                )))
            attr_cast = '({} *)'.format(
                self.ctype(op.class_type.attr_type(op.attr)))
            return '*{}((char *){} + {})'.format(attr_cast, obj, offset)
        else:
            # Cast to something non-trait. Note: for this to work, all struct
            # members for non-trait classes must obey monotonic linear growth.
            if op.class_type.class_ir.is_trait:
                assert not decl_cl.is_trait
                cast = '({} *)'.format(decl_cl.struct_name(self.emitter.names))
            return '({}{})->{}'.format(cast, obj, self.emitter.attr(op.attr))
示例#18
0
def generate_setter(cl: ClassIR, attr: str, rtype: RType,
                    emitter: Emitter) -> None:
    attr_field = emitter.attr(attr)
    emitter.emit_line('static int')
    emitter.emit_line('{}({} *self, PyObject *value, void *closure)'.format(
        setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    if rtype.is_refcounted:
        attr_expr = 'self->{}'.format(attr_field)
        emitter.emit_undefined_attr_check(rtype, attr_expr, '!=')
        emitter.emit_dec_ref('self->{}'.format(attr_field), rtype)
        emitter.emit_line('}')
    emitter.emit_line('if (value != NULL) {')
    if rtype.is_unboxed:
        emitter.emit_unbox('value',
                           'tmp',
                           rtype,
                           custom_failure='return -1;',
                           declare_dest=True)
    elif is_same_type(rtype, object_rprimitive):
        emitter.emit_line('PyObject *tmp = value;')
    else:
        emitter.emit_cast('value', 'tmp', rtype, declare_dest=True)
        emitter.emit_lines('if (!tmp)', '    return -1;')
    emitter.emit_inc_ref('tmp', rtype)
    emitter.emit_line('self->{} = tmp;'.format(attr_field))
    emitter.emit_line('} else')
    emitter.emit_line('    self->{} = {};'.format(
        attr_field, emitter.c_undefined_value(rtype)))
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
示例#19
0
def deserialize_modules(data: Dict[str, JsonDict],
                        ctx: DeserMaps) -> Dict[str, ModuleIR]:
    """Deserialize a collection of modules.

    The modules can contain dependencies on each other.

    Arguments:
        data: A dict containing the modules to deserialize.
        ctx: The deserialization maps to use and to populate.
             They are populated with information from the deserialized
             modules and as a precondition must have been populated by
             deserializing any dependencies of the modules being deserialized
             (outside of dependencies between the modules themselves).

    Returns a map containing the deserialized modules.
    """
    for mod in data.values():
        # First create ClassIRs for every class so that we can construct types and whatnot
        for cls in mod['classes']:
            ir = ClassIR(cls['name'], cls['module_name'])
            assert ir.fullname not in ctx.classes, "Class %s already in map" % ir.fullname
            ctx.classes[ir.fullname] = ir

    for mod in data.values():
        # Then deserialize all of the functions so that methods are available
        # to the class deserialization.
        for method in mod['functions']:
            func = FuncIR.deserialize(method, ctx)
            assert func.decl.fullname not in ctx.functions, (
                "Method %s already in map" % func.decl.fullname)
            ctx.functions[func.decl.fullname] = func

    return {k: ModuleIR.deserialize(v, ctx) for k, v in data.items()}
示例#20
0
def analyze_always_defined_attrs_in_class(cl: ClassIR,
                                          seen: Set[ClassIR]) -> None:
    if cl in seen:
        return

    seen.add(cl)

    if (cl.is_trait or cl.inherits_python or cl.allow_interpreted_subclasses
            or cl.builtin_base is not None or cl.children is None
            or cl.is_serializable()):
        # Give up -- we can't enforce that attributes are always defined.
        return

    # First analyze all base classes. Track seen classes to avoid duplicate work.
    for base in cl.mro[1:]:
        analyze_always_defined_attrs_in_class(base, seen)

    m = cl.get_method('__init__')
    if m is None:
        cl._always_initialized_attrs = cl.attrs_with_defaults.copy()
        cl._sometimes_initialized_attrs = cl.attrs_with_defaults.copy()
        return
    self_reg = m.arg_regs[0]
    cfg = get_cfg(m.blocks)
    dirty = analyze_self_leaks(m.blocks, self_reg, cfg)
    maybe_defined = analyze_maybe_defined_attrs_in_init(
        m.blocks, self_reg, cl.attrs_with_defaults, cfg)
    all_attrs: Set[str] = set()
    for base in cl.mro:
        all_attrs.update(base.attributes)
    maybe_undefined = analyze_maybe_undefined_attrs_in_init(
        m.blocks,
        self_reg,
        initial_undefined=all_attrs - cl.attrs_with_defaults,
        cfg=cfg)

    always_defined = find_always_defined_attributes(m.blocks, self_reg,
                                                    all_attrs, maybe_defined,
                                                    maybe_undefined, dirty)
    always_defined = {a for a in always_defined if not cl.is_deletable(a)}

    cl._always_initialized_attrs = always_defined
    if dump_always_defined:
        print(cl.name, sorted(always_defined))
    cl._sometimes_initialized_attrs = find_sometimes_defined_attributes(
        m.blocks, self_reg, maybe_defined, dirty)

    mark_attr_initialiation_ops(m.blocks, self_reg, maybe_defined, dirty)

    # Check if __init__ can run unpredictable code (leak 'self').
    any_dirty = False
    for b in m.blocks:
        for i, op in enumerate(b.ops):
            if dirty.after[b, i] and not isinstance(op, Return):
                any_dirty = True
                break
    cl.init_self_leak = any_dirty
示例#21
0
文件: emitclass.py 项目: alanhdu/mypy
def generate_setup_for_class(cl: ClassIR,
                             func_name: str,
                             defaults_fn: Optional[FuncIR],
                             vtable_name: str,
                             shadow_vtable_name: Optional[str],
                             emitter: Emitter) -> None:
    """Generate a native function that allocates an instance of a class."""
    emitter.emit_line('static PyObject *')
    emitter.emit_line('{}(PyTypeObject *type)'.format(func_name))
    emitter.emit_line('{')
    emitter.emit_line('{} *self;'.format(cl.struct_name(emitter.names)))
    emitter.emit_line('self = ({struct} *)type->tp_alloc(type, 0);'.format(
        struct=cl.struct_name(emitter.names)))
    emitter.emit_line('if (self == NULL)')
    emitter.emit_line('    return NULL;')

    if shadow_vtable_name:
        emitter.emit_line('if (type != {}) {{'.format(emitter.type_struct_name(cl)))
        emitter.emit_line('self->vtable = {};'.format(shadow_vtable_name))
        emitter.emit_line('} else {')
        emitter.emit_line('self->vtable = {};'.format(vtable_name))
        emitter.emit_line('}')
    else:
        emitter.emit_line('self->vtable = {};'.format(vtable_name))

    if cl.has_method('__call__') and emitter.use_vectorcall():
        name = cl.method_decl('__call__').cname(emitter.names)
        emitter.emit_line('self->vectorcall = {}{};'.format(PREFIX, name))

    for base in reversed(cl.base_mro):
        for attr, rtype in base.attributes.items():
            emitter.emit_line('self->{} = {};'.format(
                emitter.attr(attr), emitter.c_undefined_value(rtype)))

    # Initialize attributes to default values, if necessary
    if defaults_fn is not None:
        emitter.emit_lines(
            'if ({}{}((PyObject *)self) == 0) {{'.format(
                NATIVE_PREFIX, defaults_fn.cname(emitter.names)),
            'Py_DECREF(self);',
            'return NULL;',
            '}')

    emitter.emit_line('return (PyObject *)self;')
    emitter.emit_line('}')
示例#22
0
def generate_setter(cl: ClassIR, attr: str, rtype: RType,
                    emitter: Emitter) -> None:
    attr_field = emitter.attr(attr)
    emitter.emit_line('static int')
    emitter.emit_line('{}({} *self, PyObject *value, void *closure)'.format(
        setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)))
    emitter.emit_line('{')

    deletable = cl.is_deletable(attr)
    if not deletable:
        emitter.emit_line('if (value == NULL) {')
        emitter.emit_line('PyErr_SetString(PyExc_AttributeError,')
        emitter.emit_line(
            '    "{} object attribute {} cannot be deleted");'.format(
                repr(cl.name), repr(attr)))
        emitter.emit_line('return -1;')
        emitter.emit_line('}')

    if rtype.is_refcounted:
        attr_expr = 'self->{}'.format(attr_field)
        emitter.emit_undefined_attr_check(rtype, attr_expr, '!=')
        emitter.emit_dec_ref('self->{}'.format(attr_field), rtype)
        emitter.emit_line('}')

    if deletable:
        emitter.emit_line('if (value != NULL) {')
    if rtype.is_unboxed:
        emitter.emit_unbox('value',
                           'tmp',
                           rtype,
                           error=ReturnHandler('-1'),
                           declare_dest=True)
    elif is_same_type(rtype, object_rprimitive):
        emitter.emit_line('PyObject *tmp = value;')
    else:
        emitter.emit_cast('value', 'tmp', rtype, declare_dest=True)
        emitter.emit_lines('if (!tmp)', '    return -1;')
    emitter.emit_inc_ref('tmp', rtype)
    emitter.emit_line('self->{} = tmp;'.format(attr_field))
    if deletable:
        emitter.emit_line('} else')
        emitter.emit_line('    self->{} = {};'.format(
            attr_field, emitter.c_undefined_value(rtype)))
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
示例#23
0
def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
    fields = OrderedDict()  # type: Dict[str, str]
    # Sort for determinism on Python 3.5
    for name, (slot, generator) in sorted(table.items()):
        method_cls = cl.get_method_and_class(name)
        if method_cls and (method_cls[1] == cl or name in ALWAYS_FILL):
            fields[slot] = generator(cl, method_cls[0], emitter)

    return fields
示例#24
0
def generate_side_table_for_class(cl: ClassIR, name: str, type: str,
                                  slots: Dict[str, str],
                                  emitter: Emitter) -> Optional[str]:
    name = '{}_{}'.format(cl.name_prefix(emitter.names), name)
    emitter.emit_line('static {} {} = {{'.format(type, name))
    for field, value in slots.items():
        emitter.emit_line(".{} = {},".format(field, value))
    emitter.emit_line("};")
    return name
示例#25
0
def generate_dealloc_for_class(cl: ClassIR, dealloc_func_name: str,
                               clear_func_name: str, emitter: Emitter) -> None:
    emitter.emit_line('static void')
    emitter.emit_line('{}({} *self)'.format(dealloc_func_name,
                                            cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    emitter.emit_line('PyObject_GC_UnTrack(self);')
    emitter.emit_line('{}(self);'.format(clear_func_name))
    emitter.emit_line('Py_TYPE(self)->tp_free((PyObject *)self);')
    emitter.emit_line('}')
示例#26
0
def build_type_map(mapper: Mapper, modules: List[MypyFile], graph: Graph,
                   types: Dict[Expression, Type], options: CompilerOptions,
                   errors: Errors) -> None:
    # Collect all classes defined in everything we are compiling
    classes = []
    for module in modules:
        module_classes = [
            node for node in module.defs if isinstance(node, ClassDef)
        ]
        classes.extend([(module, cdef) for cdef in module_classes])

    # Collect all class mappings so that we can bind arbitrary class name
    # references even if there are import cycles.
    for module, cdef in classes:
        class_ir = ClassIR(cdef.name,
                           module.fullname,
                           is_trait(cdef),
                           is_abstract=cdef.info.is_abstract)
        class_ir.is_ext_class = is_extension_class(cdef)
        if class_ir.is_ext_class:
            class_ir.deletable = cdef.info.deletable_attributes[:]
        # If global optimizations are disabled, turn of tracking of class children
        if not options.global_opts:
            class_ir.children = None
        mapper.type_to_ir[cdef.info] = class_ir

    # Populate structural information in class IR for extension classes.
    for module, cdef in classes:
        with catch_errors(module.path, cdef.line):
            if mapper.type_to_ir[cdef.info].is_ext_class:
                prepare_class_def(module.path, module.fullname, cdef, errors,
                                  mapper)
            else:
                prepare_non_ext_class_def(module.path, module.fullname, cdef,
                                          errors, mapper)

    # Collect all the functions also. We collect from the symbol table
    # so that we can easily pick out the right copy of a function that
    # is conditionally defined.
    for module in modules:
        for func in get_module_func_defs(module):
            prepare_func_def(module.fullname, None, func, mapper)
示例#27
0
def compute_vtable(cls: ClassIR) -> None:
    """Compute the vtable structure for a class."""
    if cls.vtable is not None: return

    if not cls.is_generated:
        cls.has_dict = any(x.inherits_python for x in cls.mro)

    for t in cls.mro[1:]:
        # Make sure all ancestors are processed first
        compute_vtable(t)
        # Merge attributes from traits into the class
        if not t.is_trait:
            continue
        for name, typ in t.attributes.items():
            if not cls.is_trait and not any(name in b.attributes for b in cls.base_mro):
                cls.attributes[name] = typ

    cls.vtable = {}
    if cls.base:
        assert cls.base.vtable is not None
        cls.vtable.update(cls.base.vtable)
        cls.vtable_entries = specialize_parent_vtable(cls, cls.base)

    # Include the vtable from the parent classes, but handle method overrides.
    entries = cls.vtable_entries

    # Traits need to have attributes in the vtable, since the
    # attributes can be at different places in different classes, but
    # regular classes can just directly get them.
    if cls.is_trait:
        # Traits also need to pull in vtable entries for non-trait
        # parent classes explicitly.
        for t in cls.mro:
            for attr in t.attributes:
                if attr in cls.vtable:
                    continue
                cls.vtable[attr] = len(entries)
                entries.append(VTableAttr(t, attr, is_setter=False))
                entries.append(VTableAttr(t, attr, is_setter=True))

    all_traits = [t for t in cls.mro if t.is_trait]

    for t in [cls] + cls.traits:
        for fn in itertools.chain(t.methods.values()):
            # TODO: don't generate a new entry when we overload without changing the type
            if fn == cls.get_method(fn.name):
                cls.vtable[fn.name] = len(entries)
                # If the class contains a glue method referring to itself, that is a
                # shadow glue method to support interpreted subclasses.
                shadow = cls.glue_methods.get((cls, fn.name))
                entries.append(VTableMethod(t, fn.name, fn, shadow))

    # Compute vtables for all of the traits that the class implements
    if not cls.is_trait:
        for trait in all_traits:
            compute_vtable(trait)
            cls.trait_vtables[trait] = specialize_parent_vtable(cls, trait)
示例#28
0
def generate_clear_for_class(cl: ClassIR, func_name: str,
                             emitter: Emitter) -> None:
    emitter.emit_line('static int')
    emitter.emit_line('{}({} *self)'.format(func_name,
                                            cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    for base in reversed(cl.base_mro):
        for attr, rtype in base.attributes.items():
            emitter.emit_gc_clear('self->{}'.format(emitter.attr(attr)), rtype)
    if cl.has_dict:
        struct_name = cl.struct_name(emitter.names)
        # __dict__ lives right after the struct and __weakref__ lives right after that
        emitter.emit_gc_clear(
            '*((PyObject **)((char *)self + sizeof({})))'.format(struct_name),
            object_rprimitive)
        emitter.emit_gc_clear(
            '*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({})))'.
            format(struct_name), object_rprimitive)
    emitter.emit_line('return 0;')
    emitter.emit_line('}')
示例#29
0
 def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> 'ModuleIR':
     return ModuleIR(
         data['fullname'],
         data['imports'],
         [
             ctx.functions[FuncDecl.get_name_from_json(f['decl'])]
             for f in data['functions']
         ],
         [ClassIR.deserialize(c, ctx) for c in data['classes']],
         [(k, deserialize_type(t, ctx)) for k, t in data['final_names']],
     )
示例#30
0
def generate_traverse_for_class(cl: ClassIR, func_name: str,
                                emitter: Emitter) -> None:
    """Emit function that performs cycle GC traversal of an instance."""
    emitter.emit_line('static int')
    emitter.emit_line('{}({} *self, visitproc visit, void *arg)'.format(
        func_name, cl.struct_name(emitter.names)))
    emitter.emit_line('{')
    for base in reversed(cl.base_mro):
        for attr, rtype in base.attributes.items():
            emitter.emit_gc_visit('self->{}'.format(emitter.attr(attr)), rtype)
    if cl.has_dict:
        struct_name = cl.struct_name(emitter.names)
        # __dict__ lives right after the struct and __weakref__ lives right after that
        emitter.emit_gc_visit(
            '*((PyObject **)((char *)self + sizeof({})))'.format(struct_name),
            object_rprimitive)
        emitter.emit_gc_visit(
            '*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({})))'.
            format(struct_name), object_rprimitive)
    emitter.emit_line('return 0;')
    emitter.emit_line('}')