Esempio n. 1
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('}')
Esempio n. 2
0
 def final_definition(
         self, module: str, name: str, typ: RType, emitter: Emitter) -> str:
     static_name = emitter.static_name(name, module)
     # Here we rely on the fact that undefined value and error value are always the same
     if isinstance(typ, RTuple):
         # We need to inline because initializer must be static
         undefined = '{{ {} }}'.format(''.join(emitter.tuple_undefined_value_helper(typ)))
     else:
         undefined = emitter.c_undefined_value(typ)
     return '{}{} = {};'.format(emitter.ctype_spaced(typ), static_name, undefined)
Esempio n. 3
0
def emit_undefined_check(rtype: RType, emitter: Emitter, attr: str,
                         compare: str) -> None:
    if isinstance(rtype, RTuple):
        attr_expr = 'self->{}'.format(attr)
        emitter.emit_line('if ({}) {{'.format(
            emitter.tuple_undefined_check_cond(rtype, attr_expr,
                                               emitter.c_undefined_value,
                                               compare)))
    else:
        emitter.emit_line('if (self->{} {} {}) {{'.format(
            attr, compare, emitter.c_undefined_value(rtype)))
Esempio n. 4
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('}')
Esempio n. 5
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('}')
Esempio n. 6
0
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('}')
Esempio n. 7
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('}')