コード例 #1
0
def generate_constructor_for_class(cl: ClassIR, fn: FuncDecl,
                                   init_fn: Optional[FuncIR], setup_name: str,
                                   vtable_name: str, emitter: Emitter) -> None:
    """Generate a native function that allocates and initializes an instance of a class."""
    emitter.emit_line('{}'.format(native_function_header(fn, emitter)))
    emitter.emit_line('{')
    emitter.emit_line('PyObject *self = {}({});'.format(
        setup_name, emitter.type_struct_name(cl)))
    emitter.emit_line('if (self == NULL)')
    emitter.emit_line('    return NULL;')
    args = ', '.join(['self'] + [REG_PREFIX + arg.name for arg in fn.sig.args])
    if init_fn is not None:
        emitter.emit_line('char res = {}{}{}({});'.format(
            emitter.get_group_prefix(init_fn.decl), NATIVE_PREFIX,
            init_fn.cname(emitter.names), args))
        emitter.emit_line('if (res == 2) {')
        emitter.emit_line('Py_DECREF(self);')
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')

    # If there is a nontrivial ctor that we didn't define, invoke it via tp_init
    elif len(fn.sig.args) > 1:
        emitter.emit_line('int res = {}->tp_init({});'.format(
            emitter.type_struct_name(cl), args))

        emitter.emit_line('if (res < 0) {')
        emitter.emit_line('Py_DECREF(self);')
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')

    emitter.emit_line('return self;')
    emitter.emit_line('}')
コード例 #2
0
ファイル: emitclass.py プロジェクト: JoeCare/mypy-1
def generate_vtable(entries: VTableEntries,
                    vtable_name: str,
                    emitter: Emitter,
                    subtables: List[Tuple[ClassIR, str, str]],
                    shadow: bool) -> None:
    emitter.emit_line('CPyVTableItem {}_scratch[] = {{'.format(vtable_name))
    if subtables:
        emitter.emit_line('/* Array of trait vtables */')
        for trait, table, offset_table in subtables:
            emitter.emit_line(
                '(CPyVTableItem){}, (CPyVTableItem){}, (CPyVTableItem){},'.format(
                    emitter.type_struct_name(trait), table, offset_table))
        emitter.emit_line('/* Start of real vtable */')

    for entry in entries:
        method = entry.shadow_method if shadow and entry.shadow_method else entry.method
        emitter.emit_line('(CPyVTableItem){}{}{},'.format(
            emitter.get_group_prefix(entry.method.decl),
            NATIVE_PREFIX,
            method.cname(emitter.names)))

    # msvc doesn't allow empty arrays; maybe allowing them at all is an extension?
    if not entries:
        emitter.emit_line('NULL')
    emitter.emit_line('};')
    emitter.emit_line('memcpy({name}, {name}_scratch, sizeof({name}));'.format(name=vtable_name))
コード例 #3
0
ファイル: emitclass.py プロジェクト: JoeCare/mypy-1
def generate_class_type_decl(cl: ClassIR, c_emitter: Emitter,
                             external_emitter: Emitter,
                             emitter: Emitter) -> None:
    context = c_emitter.context
    name = emitter.type_struct_name(cl)
    context.declarations[name] = HeaderDeclaration(
        'PyTypeObject *{};'.format(emitter.type_struct_name(cl)),
        needs_export=True)

    # If this is a non-extension class, all we want is the type object decl.
    if not cl.is_ext_class:
        return

    generate_object_struct(cl, external_emitter)
    generate_full = not cl.is_trait and not cl.builtin_base
    if generate_full:
        context.declarations[emitter.native_function_name(cl.ctor)] = HeaderDeclaration(
            '{};'.format(native_function_header(cl.ctor, emitter)),
            needs_export=True,
        )
コード例 #4
0
ファイル: emitwrapper.py プロジェクト: srittau/mypy
def generate_bin_op_both_wrappers(cl: ClassIR,
                                  fn: FuncIR,
                                  fn_rev: FuncIR,
                                  emitter: Emitter,
                                  gen: 'WrapperGenerator') -> None:
    # There's both a forward and a reverse operator method. First
    # check if we should try calling the forward one. If the
    # argument type check fails, fall back to the reverse method.
    #
    # Similar to above, we can't perfectly match Python semantics.
    # In regular Python code you'd return NotImplemented if the
    # operand has the wrong type, but in compiled code we'll never
    # get to execute the type check.
    emitter.emit_line('if (PyObject_IsInstance(obj_left, (PyObject *){})) {{'.format(
        emitter.type_struct_name(cl)))
    gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False)
    gen.emit_call(not_implemented_handler='goto typefail;')
    gen.emit_error_handling()
    emitter.emit_line('}')
    emitter.emit_label('typefail')
    emitter.emit_line('if (PyObject_IsInstance(obj_right, (PyObject *){})) {{'.format(
        emitter.type_struct_name(cl)))
    gen.set_target(fn_rev)
    gen.arg_names = ['right', 'left']
    gen.emit_arg_processing(error=GotoHandler('typefail2'), raise_exception=False)
    gen.emit_call()
    gen.emit_error_handling()
    emitter.emit_line('} else {')
    emitter.emit_line('_Py_IDENTIFIER({});'.format(fn_rev.name))
    emitter.emit_line(
        'return CPy_CallReverseOpMethod(obj_left, obj_right, "{}", &PyId_{});'.format(
            op_methods_to_symbols[fn.name],
            fn_rev.name))
    emitter.emit_line('}')
    emitter.emit_label('typefail2')
    emitter.emit_line('Py_INCREF(Py_NotImplemented);')
    emitter.emit_line('return Py_NotImplemented;')
    gen.finish()
コード例 #5
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('}')
コード例 #6
0
def generate_new_for_trait(cl: ClassIR, func_name: str,
                           emitter: Emitter) -> None:
    emitter.emit_line('static PyObject *')
    emitter.emit_line(
        '{}(PyTypeObject *type, PyObject *args, PyObject *kwds)'.format(
            func_name))
    emitter.emit_line('{')
    emitter.emit_line('if (type != {}) {{'.format(
        emitter.type_struct_name(cl)))
    emitter.emit_line(
        'PyErr_SetString(PyExc_TypeError, '
        '"interpreted classes cannot inherit from compiled traits");')
    emitter.emit_line('} else {')
    emitter.emit_line(
        'PyErr_SetString(PyExc_TypeError, "traits may not be directly created");'
    )
    emitter.emit_line('}')
    emitter.emit_line('return NULL;')
    emitter.emit_line('}')
コード例 #7
0
def generate_new_for_class(cl: ClassIR, func_name: str, vtable_name: str,
                           setup_name: str, emitter: Emitter) -> None:
    emitter.emit_line('static PyObject *')
    emitter.emit_line(
        '{}(PyTypeObject *type, PyObject *args, PyObject *kwds)'.format(
            func_name))
    emitter.emit_line('{')
    # TODO: Check and unbox arguments
    if not cl.allow_interpreted_subclasses:
        emitter.emit_line('if (type != {}) {{'.format(
            emitter.type_struct_name(cl)))
        emitter.emit_line(
            'PyErr_SetString(PyExc_TypeError, "interpreted classes cannot inherit from compiled");'
        )
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')

    emitter.emit_line('return {}(type);'.format(setup_name))
    emitter.emit_line('}')
コード例 #8
0
    def generate_module_def(self, emitter: Emitter, module_name: str,
                            module: ModuleIR) -> None:
        """Emit the PyModuleDef struct for a module and the module init function."""
        # Emit module methods
        module_prefix = emitter.names.private_name(module_name)
        emitter.emit_line(
            'static PyMethodDef {}module_methods[] = {{'.format(module_prefix))
        for fn in module.functions:
            if fn.class_name is not None or fn.name == TOP_LEVEL_NAME:
                continue
            emitter.emit_line((
                '{{"{name}", (PyCFunction){prefix}{cname}, METH_VARARGS | METH_KEYWORDS, '
                'NULL /* docstring */}},').format(name=fn.name,
                                                  cname=fn.cname(
                                                      emitter.names),
                                                  prefix=PREFIX))
        emitter.emit_line('{NULL, NULL, 0, NULL}')
        emitter.emit_line('};')
        emitter.emit_line()

        # Emit module definition struct
        emitter.emit_lines(
            'static struct PyModuleDef {}module = {{'.format(module_prefix),
            'PyModuleDef_HEAD_INIT,', '"{}",'.format(module_name),
            'NULL, /* docstring */',
            '-1,       /* size of per-interpreter state of the module,',
            '             or -1 if the module keeps state in global variables. */',
            '{}module_methods'.format(module_prefix), '};')
        emitter.emit_line()
        # Emit module init function. If we are compiling just one module, this
        # will be the C API init function. If we are compiling 2+ modules, we
        # generate a shared library for the modules and shims that call into
        # the shared library, and in this case we use an internal module
        # initialized function that will be called by the shim.
        if not self.use_shared_lib:
            declaration = 'PyMODINIT_FUNC PyInit_{}(void)'.format(module_name)
        else:
            declaration = 'PyObject *CPyInit_{}(void)'.format(
                exported_name(module_name))
        emitter.emit_lines(declaration, '{')
        # Store the module reference in a static and return it when necessary.
        # This is separate from the *global* reference to the module that will
        # be populated when it is imported by a compiled module. We want that
        # reference to only be populated when the module has been successfully
        # imported, whereas this we want to have to stop a circular import.
        module_static = self.module_internal_static_name(module_name, emitter)

        emitter.emit_lines('if ({}) {{'.format(module_static),
                           'Py_INCREF({});'.format(module_static),
                           'return {};'.format(module_static), '}')

        emitter.emit_lines(
            '{} = PyModule_Create(&{}module);'.format(module_static,
                                                      module_prefix),
            'if (unlikely({} == NULL))'.format(module_static),
            '    return NULL;')
        emitter.emit_line(
            'PyObject *modname = PyObject_GetAttrString((PyObject *){}, "__name__");'
            .format(module_static))

        module_globals = emitter.static_name('globals', module_name)
        emitter.emit_lines(
            '{} = PyModule_GetDict({});'.format(module_globals, module_static),
            'if (unlikely({} == NULL))'.format(module_globals),
            '    return NULL;')

        # HACK: Manually instantiate generated classes here
        for cl in module.classes:
            if cl.is_generated:
                type_struct = emitter.type_struct_name(cl)
                emitter.emit_lines(
                    '{t} = (PyTypeObject *)CPyType_FromTemplate({t}_template, NULL, modname);'
                    .format(t=type_struct))
                emitter.emit_lines('if (unlikely(!{}))'.format(type_struct),
                                   '    return NULL;')

        emitter.emit_lines('if (CPyGlobalsInit() < 0)', '    return NULL;')

        self.generate_top_level_call(module, emitter)

        emitter.emit_lines('Py_DECREF(modname);')

        emitter.emit_line('return {};'.format(module_static))
        emitter.emit_line('}')
コード例 #9
0
def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None:
    """Generate C code for a class.

    This is the main entry point to the module.
    """
    name = cl.name
    name_prefix = cl.name_prefix(emitter.names)

    setup_name = '{}_setup'.format(name_prefix)
    new_name = '{}_new'.format(name_prefix)
    members_name = '{}_members'.format(name_prefix)
    getseters_name = '{}_getseters'.format(name_prefix)
    vtable_name = '{}_vtable'.format(name_prefix)
    traverse_name = '{}_traverse'.format(name_prefix)
    clear_name = '{}_clear'.format(name_prefix)
    dealloc_name = '{}_dealloc'.format(name_prefix)
    methods_name = '{}_methods'.format(name_prefix)
    vtable_setup_name = '{}_trait_vtable_setup'.format(name_prefix)

    fields: Dict[str, str] = OrderedDict()
    fields['tp_name'] = '"{}"'.format(name)

    generate_full = not cl.is_trait and not cl.builtin_base
    needs_getseters = cl.needs_getseters or not cl.is_generated

    if not cl.builtin_base:
        fields['tp_new'] = new_name

    if generate_full:
        fields['tp_dealloc'] = '(destructor){}_dealloc'.format(name_prefix)
        fields['tp_traverse'] = '(traverseproc){}_traverse'.format(name_prefix)
        fields['tp_clear'] = '(inquiry){}_clear'.format(name_prefix)
    if needs_getseters:
        fields['tp_getset'] = getseters_name
    fields['tp_methods'] = methods_name

    def emit_line() -> None:
        emitter.emit_line()

    emit_line()

    # If the class has a method to initialize default attribute
    # values, we need to call it during initialization.
    defaults_fn = cl.get_method('__mypyc_defaults_setup')

    # If there is a __init__ method, we'll use it in the native constructor.
    init_fn = cl.get_method('__init__')

    # Fill out slots in the type object from dunder methods.
    fields.update(generate_slots(cl, SLOT_DEFS, emitter))

    # Fill out dunder methods that live in tables hanging off the side.
    for table_name, type, slot_defs in SIDE_TABLES:
        slots = generate_slots(cl, slot_defs, emitter)
        if slots:
            table_struct_name = generate_side_table_for_class(
                cl, table_name, type, slots, emitter)
            fields['tp_{}'.format(table_name)] = '&{}'.format(
                table_struct_name)

    richcompare_name = generate_richcompare_wrapper(cl, emitter)
    if richcompare_name:
        fields['tp_richcompare'] = richcompare_name

    # If the class inherits from python, make space for a __dict__
    struct_name = cl.struct_name(emitter.names)
    if cl.builtin_base:
        base_size = 'sizeof({})'.format(cl.builtin_base)
    elif cl.is_trait:
        base_size = 'sizeof(PyObject)'
    else:
        base_size = 'sizeof({})'.format(struct_name)
    # Since our types aren't allocated using type() we need to
    # populate these fields ourselves if we want them to have correct
    # values. PyType_Ready will inherit the offsets from tp_base but
    # that isn't what we want.

    # XXX: there is no reason for the __weakref__ stuff to be mixed up with __dict__
    if cl.has_dict:
        # __dict__ lives right after the struct and __weakref__ lives right after that
        # TODO: They should get members in the struct instead of doing this nonsense.
        weak_offset = '{} + sizeof(PyObject *)'.format(base_size)
        emitter.emit_lines(
            'PyMemberDef {}[] = {{'.format(members_name),
            '{{"__dict__", T_OBJECT_EX, {}, 0, NULL}},'.format(base_size),
            '{{"__weakref__", T_OBJECT_EX, {}, 0, NULL}},'.format(weak_offset),
            '{0}',
            '};',
        )

        fields['tp_members'] = members_name
        fields['tp_basicsize'] = '{} + 2*sizeof(PyObject *)'.format(base_size)
        fields['tp_dictoffset'] = base_size
        fields['tp_weaklistoffset'] = weak_offset
    else:
        fields['tp_basicsize'] = base_size

    if generate_full:
        # Declare setup method that allocates and initializes an object. type is the
        # type of the class being initialized, which could be another class if there
        # is an interpreted subclass.
        emitter.emit_line(
            'static PyObject *{}(PyTypeObject *type);'.format(setup_name))
        assert cl.ctor is not None
        emitter.emit_line(native_function_header(cl.ctor, emitter) + ';')

        emit_line()
        generate_new_for_class(cl, new_name, vtable_name, setup_name, emitter)
        emit_line()
        generate_traverse_for_class(cl, traverse_name, emitter)
        emit_line()
        generate_clear_for_class(cl, clear_name, emitter)
        emit_line()
        generate_dealloc_for_class(cl, dealloc_name, clear_name, emitter)
        emit_line()

        if cl.allow_interpreted_subclasses:
            shadow_vtable_name: Optional[str] = generate_vtables(
                cl,
                vtable_setup_name + "_shadow",
                vtable_name + "_shadow",
                emitter,
                shadow=True)
            emit_line()
        else:
            shadow_vtable_name = None
        vtable_name = generate_vtables(cl,
                                       vtable_setup_name,
                                       vtable_name,
                                       emitter,
                                       shadow=False)
        emit_line()
    if needs_getseters:
        generate_getseter_declarations(cl, emitter)
        emit_line()
        generate_getseters_table(cl, getseters_name, emitter)
        emit_line()

    if cl.is_trait:
        generate_new_for_trait(cl, new_name, emitter)

    generate_methods_table(cl, methods_name, emitter)
    emit_line()

    flags = [
        'Py_TPFLAGS_DEFAULT', 'Py_TPFLAGS_HEAPTYPE', 'Py_TPFLAGS_BASETYPE'
    ]
    if generate_full:
        flags.append('Py_TPFLAGS_HAVE_GC')
    if cl.has_method('__call__') and emitter.use_vectorcall():
        fields['tp_vectorcall_offset'] = 'offsetof({}, vectorcall)'.format(
            cl.struct_name(emitter.names))
        flags.append('_Py_TPFLAGS_HAVE_VECTORCALL')
    fields['tp_flags'] = ' | '.join(flags)

    emitter.emit_line("static PyTypeObject {}_template_ = {{".format(
        emitter.type_struct_name(cl)))
    emitter.emit_line("PyVarObject_HEAD_INIT(NULL, 0)")
    for field, value in fields.items():
        emitter.emit_line(".{} = {},".format(field, value))
    emitter.emit_line("};")
    emitter.emit_line(
        "static PyTypeObject *{t}_template = &{t}_template_;".format(
            t=emitter.type_struct_name(cl)))

    emitter.emit_line()
    if generate_full:
        generate_setup_for_class(cl, setup_name, defaults_fn, vtable_name,
                                 shadow_vtable_name, emitter)
        emitter.emit_line()
        generate_constructor_for_class(cl, cl.ctor, init_fn, setup_name,
                                       vtable_name, emitter)
        emitter.emit_line()
    if needs_getseters:
        generate_getseters(cl, emitter)
コード例 #10
0
    def generate_module_def(self, emitter: Emitter, module_name: str,
                            module: ModuleIR) -> None:
        """Emit the PyModuleDef struct for a module and the module init function."""
        # Emit module methods
        module_prefix = emitter.names.private_name(module_name)
        emitter.emit_line(
            f'static PyMethodDef {module_prefix}module_methods[] = {{')
        for fn in module.functions:
            if fn.class_name is not None or fn.name == TOP_LEVEL_NAME:
                continue
            name = short_id_from_name(fn.name, fn.decl.shortname, fn.line)
            if is_fastcall_supported(fn, emitter.capi_version):
                flag = 'METH_FASTCALL'
            else:
                flag = 'METH_VARARGS'
            emitter.emit_line((
                '{{"{name}", (PyCFunction){prefix}{cname}, {flag} | METH_KEYWORDS, '
                'NULL /* docstring */}},').format(name=name,
                                                  cname=fn.cname(
                                                      emitter.names),
                                                  prefix=PREFIX,
                                                  flag=flag))
        emitter.emit_line('{NULL, NULL, 0, NULL}')
        emitter.emit_line('};')
        emitter.emit_line()

        # Emit module definition struct
        emitter.emit_lines(
            f'static struct PyModuleDef {module_prefix}module = {{',
            'PyModuleDef_HEAD_INIT,', f'"{module_name}",',
            'NULL, /* docstring */',
            '-1,       /* size of per-interpreter state of the module,',
            '             or -1 if the module keeps state in global variables. */',
            f'{module_prefix}module_methods', '};')
        emitter.emit_line()
        # Emit module init function. If we are compiling just one module, this
        # will be the C API init function. If we are compiling 2+ modules, we
        # generate a shared library for the modules and shims that call into
        # the shared library, and in this case we use an internal module
        # initialized function that will be called by the shim.
        if not self.use_shared_lib:
            declaration = f'PyMODINIT_FUNC PyInit_{module_name}(void)'
        else:
            declaration = f'PyObject *CPyInit_{exported_name(module_name)}(void)'
        emitter.emit_lines(declaration, '{')
        emitter.emit_line('PyObject* modname = NULL;')
        # Store the module reference in a static and return it when necessary.
        # This is separate from the *global* reference to the module that will
        # be populated when it is imported by a compiled module. We want that
        # reference to only be populated when the module has been successfully
        # imported, whereas this we want to have to stop a circular import.
        module_static = self.module_internal_static_name(module_name, emitter)

        emitter.emit_lines(f'if ({module_static}) {{',
                           f'Py_INCREF({module_static});',
                           f'return {module_static};', '}')

        emitter.emit_lines(
            f'{module_static} = PyModule_Create(&{module_prefix}module);',
            f'if (unlikely({module_static} == NULL))', '    goto fail;')
        emitter.emit_line(
            'modname = PyObject_GetAttrString((PyObject *){}, "__name__");'.
            format(module_static))

        module_globals = emitter.static_name('globals', module_name)
        emitter.emit_lines(
            f'{module_globals} = PyModule_GetDict({module_static});',
            f'if (unlikely({module_globals} == NULL))', '    goto fail;')

        # HACK: Manually instantiate generated classes here
        type_structs: List[str] = []
        for cl in module.classes:
            type_struct = emitter.type_struct_name(cl)
            type_structs.append(type_struct)
            if cl.is_generated:
                emitter.emit_lines(
                    '{t} = (PyTypeObject *)CPyType_FromTemplate('
                    '(PyObject *){t}_template, NULL, modname);'.format(
                        t=type_struct))
                emitter.emit_lines(f'if (unlikely(!{type_struct}))',
                                   '    goto fail;')

        emitter.emit_lines('if (CPyGlobalsInit() < 0)', '    goto fail;')

        self.generate_top_level_call(module, emitter)

        emitter.emit_lines('Py_DECREF(modname);')

        emitter.emit_line(f'return {module_static};')
        emitter.emit_lines('fail:', f'Py_CLEAR({module_static});',
                           'Py_CLEAR(modname);')
        for name, typ in module.final_names:
            static_name = emitter.static_name(name, module_name)
            emitter.emit_dec_ref(static_name, typ, is_xdec=True)
            undef = emitter.c_undefined_value(typ)
            emitter.emit_line(f'{static_name} = {undef};')
        # the type objects returned from CPyType_FromTemplate are all new references
        # so we have to decref them
        for t in type_structs:
            emitter.emit_line(f'Py_CLEAR({t});')
        emitter.emit_line('return NULL;')
        emitter.emit_line('}')