diff options
Diffstat (limited to 'Cython/Compiler/Code.py')
-rw-r--r-- | Cython/Compiler/Code.py | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index a27908486..6b1e374ae 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -1020,6 +1020,7 @@ class GlobalState(object): self.num_const_index = {} self.py_constants = [] self.cached_cmethods = {} + self.code_objects = {} writer.set_global_state(self) self.rootwriter = writer @@ -1132,6 +1133,69 @@ class GlobalState(object): def get_cached_constants_writer(self): return self.parts['cached_constants'] + def get_pycode_object_cname(self, func_name, func_node, obj_type): + if func_node in self.code_objects: + return self.code_objects[func_node] + + code_object_cname = self.code_objects[func_node] = self.get_py_const( + obj_type, 'codeobj', cleanup_level=2).cname + + code = self.get_cached_constants_writer() + code.mark_pos(func_node.pos) + + func_name = code.intern_identifier(func_name) + # FIXME: better way to get the module file path at module init time? Encoding to use? + file_path = StringEncoding.bytes_literal(func_node.pos[0].get_filenametable_entry().encode('utf8'), 'utf8') + file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True) + + flags = [] + if func_node.star_arg: + flags.append('CO_VARARGS') + if func_node.starstar_arg: + flags.append('CO_VARKEYWORDS') + + args = list(func_node.args) + num_kwonly_args = func_node.num_kwonly_args if func_node.entry.type.is_pyobject else 0 + local_vars = [arg for arg in func_node.local_scope.var_entries if arg.name] + varnames = [ + code.intern_identifier(arg.name) + for arg in args + local_vars] + + varnames_cname = Naming.quick_temp_cname + code.putln("{") + code.putln("PyObject* %s = PyTuple_New(%d); %s" % ( + varnames_cname, + len(varnames), + code.error_goto_if_null(varnames_cname, func_node.pos))) + code.put_gotref(varnames_cname) + + for i, varname in enumerate(varnames): + code.putln("Py_INCREF(%s); PyTuple_SET_ITEM(%s, %d, %s);" % (varname, varnames_cname, i, varname)) + + code.putln("%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s);" % ( + code_object_cname, + len(func_node.args) - num_kwonly_args, # argcount + num_kwonly_args, # kwonlyargcount (Py3 only) + len(varnames), # nlocals + '|'.join(flags) or '0', # flags + Naming.empty_bytes, # code + Naming.empty_tuple, # consts + Naming.empty_tuple, # names (FIXME) + varnames_cname, # varnames + Naming.empty_tuple, # freevars (FIXME) + Naming.empty_tuple, # cellvars (FIXME) + file_path_const, # filename + func_name, # name + func_node.pos[1], # firstlineno + Naming.empty_bytes, # lnotab + )) + + code.put_decref_clear(varnames_cname, obj_type) + code.putln(code.error_goto_if_null(code_object_cname, func_node.pos)) + code.putln("}") + + return code_object_cname + def get_int_const(self, str_value, longness=False): py_type = longness and 'long' or 'int' try: @@ -1646,6 +1710,9 @@ class CCodeWriter(object): def get_py_const(self, type, prefix='', cleanup_level=None): return self.globalstate.get_py_const(type, prefix, cleanup_level).cname + def get_pycode_object_const(self, func_name, def_node, obj_type): + return self.globalstate.get_pycode_object_cname(func_name, def_node, obj_type) + def get_string_const(self, text): return self.globalstate.get_string_const(text).cname |