From: Dag Sverre Seljebotn Date: Tue, 19 May 2009 16:05:29 +0000 (+0200) Subject: Big merge of -devel X-Git-Tag: 0.12.alpha0~296 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=20fe9ab6392241549946094f4d30ad0806c3c8e6;p=cython.git Big merge of -devel --- 20fe9ab6392241549946094f4d30ad0806c3c8e6 diff --cc Cython/Compiler/Code.py index 19554839,48fbbd01..3f10cd8b --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@@ -6,9 -5,9 +6,10 @@@ import r import codecs import Naming import Options -from Cython.Utils import open_new_file, open_source_file +import StringEncoding +from Cython import Utils from PyrexTypes import py_object_type, typecast + import PyrexTypes from TypeSlots import method_coexist from Scanning import SourceDescriptor from Cython.StringIOTree import StringIOTree @@@ -302,10 -211,9 +301,12 @@@ class GlobalState(object) # check if constants are already added). # In time, hopefully the literals etc. will be # supplied directly instead. + # + # const_cname_counter int global counter for constant identifiers + # + # parts {string:CCodeWriter} + # interned_strings # consts @@@ -319,24 -227,40 +320,44 @@@ directives = {} - def __init__(self, rootwriter, emit_linenums=False): + code_layout = [ + 'h_code', + 'utility_code_proto', + 'type_declarations', + 'module_declarations', + 'typeinfo', + 'before_global_var', + 'global_var', ++ 'decls', + 'all_the_rest', + 'utility_code_def' + ] + + + def __init__(self, writer, emit_linenums=False): self.filename_table = {} self.filename_list = [] self.input_file_contents = {} - self.used_utility_code = set() + self.utility_codes = set() self.declared_cnames = {} - self.pystring_table_needed = False self.in_utility_code_generation = False self.emit_linenums = emit_linenums + self.parts = {} + self.const_cname_counter = 1 + self.string_const_index = {} + self.int_const_index = {} + self.py_constants = [] + - def initwriters(self, rootwriter): - self.utilprotowriter = rootwriter.new_writer() - self.utildefwriter = rootwriter.new_writer() - self.decls_writer = rootwriter.new_writer() + assert writer.globalstate is None + writer.globalstate = self + self.rootwriter = writer + + def initialize_main_c_code(self): + rootwriter = self.rootwriter + for part in self.code_layout: + self.parts[part] = rootwriter.insertion_point() + - self.decls_writer = rootwriter.new_writer() self.pystring_table = rootwriter.new_writer() self.init_cached_builtins_writer = rootwriter.new_writer() self.initwriter = rootwriter.new_writer() @@@ -354,6 -278,38 +375,33 @@@ self.cleanupwriter.putln("") self.cleanupwriter.putln("static void __Pyx_CleanupGlobals(void) {") - self.pystring_table.putln("") - self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" % - Naming.stringtab_cname) - - + # + # utility_code_def + # + code = self.parts['utility_code_def'] + if self.emit_linenums: + code.write('\n#line 1 "cython_utility"\n') + code.putln("") + code.putln("/* Runtime support code */") + code.putln("") + code.putln("static void %s(void) {" % Naming.fileinit_cname) + code.putln("%s = %s;" % + (Naming.filetable_cname, Naming.filenames_cname)) + code.putln("}") + + def finalize_main_c_code(self): + self.close_global_decls() + + # + # utility_code_def + # + code = self.parts['utility_code_def'] + code.put(PyrexTypes.type_conversion_functions) + code.putln("") + + def __getitem__(self, key): + return self.parts[key] + # # Global constants, interned objects, etc. # @@@ -393,158 -356,8 +438,162 @@@ code.insert(self.cleanupwriter) def put_pyobject_decl(self, entry): - self.decls_writer.putln("static PyObject *%s;" % entry.cname) + self['global_var'].putln("static PyObject *%s;" % entry.cname) + # constant handling at code generation time + + def get_int_const(self, str_value, longness=False): + longness = bool(longness or Utils.long_literal(str_value)) + try: + c = self.int_const_index[(str_value, longness)] + except KeyError: + c = self.new_int_const(str_value, longness) + return c + + def get_py_const(self, type): + # create a new Python object constant + return self.new_py_const(type) + + def get_string_const(self, text): + # return a C string constant, creating a new one if necessary + if text.is_unicode: + byte_string = text.utf8encode() + else: + byte_string = text.byteencode() + try: + c = self.string_const_index[byte_string] + except KeyError: + c = self.new_string_const(text, byte_string) + return c + + def get_py_string_const(self, text, identifier=None): + # return a Python string constant, creating a new one if necessary + c_string = self.get_string_const(text) + py_string = c_string.get_py_string_const(text.encoding, identifier) + return py_string + + def new_string_const(self, text, byte_string): + cname = self.new_string_const_cname(text) + c = StringConst(cname, text, byte_string) + self.string_const_index[byte_string] = c + return c + + def new_int_const(self, value, longness): + cname = self.new_int_const_cname(value, longness) + c = IntConst(cname, value, longness) + self.int_const_index[(value, longness)] = c + return c + + def new_py_const(self, type): + cname = self.new_const_cname() + c = PyObjectConst(cname, type) + self.py_constants.append(c) + return c + + def new_string_const_cname(self, value, intern=None): + # Create a new globally-unique nice name for a C string constant. + if len(value) < 20 and nice_identifier(value): + return "%s%s" % (Naming.const_prefix, value) + else: + return self.new_const_cname() + + def new_int_const_cname(self, value, longness): + if longness: + value += 'L' + cname = "%s%s" % (Naming.interned_num_prefix, value) + cname = cname.replace('-', 'neg_').replace('.','_') + return cname + + def new_const_cname(self, prefix=''): + n = self.const_cname_counter + self.const_cname_counter += 1 + return "%s%s%d" % (Naming.const_prefix, prefix, n) + + def add_cached_builtin_decl(self, entry): + if Options.cache_builtins: + if self.should_declare(entry.cname, entry): + interned_cname = self.get_py_string_const(entry.name, True).cname + self.put_pyobject_decl(entry) + self.init_cached_builtins_writer.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % ( + entry.cname, + Naming.builtins_cname, + interned_cname, + entry.cname, + self.init_cached_builtins_writer.error_goto(entry.pos))) + + def generate_const_declarations(self): + self.generate_string_constants() + self.generate_int_constants() + self.generate_object_constant_decls() + + def generate_object_constant_decls(self): + consts = [ (len(c.cname), c.cname, c) + for c in self.py_constants ] + consts.sort() ++ decls_writer = self.parts['decls'] + for _, cname, c in consts: - self.decls_writer.putln( ++ decls_writer.putln( + "static %s;" % c.type.declaration_code(cname)) + + def generate_string_constants(self): + c_consts = [ (len(c.cname), c.cname, c) + for c in self.string_const_index.itervalues() ] + c_consts.sort() + py_strings = [] ++ ++ decls_writer = self.parts['decls'] + for _, cname, c in c_consts: - self.decls_writer.putln('static char %s[] = "%s";' % ( ++ decls_writer.putln('static char %s[] = "%s";' % ( + cname, c.escaped_value)) + if c.py_strings is not None: + for py_string in c.py_strings.itervalues(): + py_strings.append((c.cname, len(py_string.cname), py_string)) + + if py_strings: + import Nodes + self.use_utility_code(Nodes.init_string_tab_utility_code) + + py_strings.sort() + self.pystring_table.putln("") + self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" % + Naming.stringtab_cname) + for c_cname, _, py_string in py_strings: - self.decls_writer.putln( ++ decls_writer.putln( + "static PyObject *%s;" % py_string.cname) + self.pystring_table.putln( + "{&%s, %s, sizeof(%s), %d, %d, %d}," % ( + py_string.cname, + c_cname, + c_cname, + py_string.unicode, + py_string.intern, + py_string.identifier + )) + self.pystring_table.putln("{0, 0, 0, 0, 0, 0}") + self.pystring_table.putln("};") + + self.initwriter.putln( + "if (__Pyx_InitStrings(%s) < 0) %s;" % ( + Naming.stringtab_cname, + self.initwriter.error_goto(self.module_pos))) + + def generate_int_constants(self): + consts = [ (len(c.value), c.value, c.is_long, c) + for c in self.int_const_index.itervalues() ] + consts.sort() ++ decls_writer = self.parts['decls'] + for _, value, longness, c in consts: + cname = c.cname - self.decls_writer.putln("static PyObject *%s;" % cname) ++ decls_writer.putln("static PyObject *%s;" % cname) + if longness: + function = '%s = PyLong_FromString((char *)"%s", 0, 0); %s;' + else: + function = "%s = PyInt_FromLong(%s); %s;" + self.initwriter.putln(function % ( + cname, + value, + self.initwriter.error_goto_if_null(cname, self.module_pos))) + # The functions below are there in a transition phase only # and will be deprecated. They are called from Nodes.BlockNode. # The copy&paste duplication is intentional in order to be able @@@ -687,11 -511,10 +699,13 @@@ class CCodeWriter(object) # generation (labels and temps state etc.) # globalstate GlobalState contains state global for a C file (input file info, # utility code, declared constants etc.) - # emit_linenums boolean whether or not to write #line pragmas + # emit_linenums boolean whether or not to write #line pragmas + # + # pyclass_stack list used during recursive code generation to pass information + # about the current class one is in + globalstate = None + def __init__(self, create_from=None, buffer=None, copy_formatting=False, emit_linenums=None): if buffer is None: buffer = StringIOTree() self.buffer = buffer @@@ -785,29 -604,7 +796,29 @@@ def exit_cfunc_scope(self): self.funcstate = None + # constant handling + + def get_py_num(self, str_value, longness): + return self.globalstate.get_int_const(str_value, longness).cname + + def get_string_const(self, text): + return self.globalstate.get_string_const(text).cname + + def get_py_string_const(self, text, identifier=None): + return self.globalstate.get_py_string_const(text, identifier).cname + + def get_argument_default_const(self, type): + return self.globalstate.get_py_const(type).cname + + def intern(self, text): + return self.get_py_string_const(text) + + def intern_identifier(self, text): + return self.get_py_string_const(text, True) + + # code generation + - def putln(self, code = ""): + def putln(self, code = "", safe=False): if self.marker and self.bol: self.emit_marker() if self.emit_linenums and self.last_marker_line != 0: diff --cc Cython/Compiler/ExprNodes.py index c456f262,cb59255e..04de0848 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@@ -878,8 -1041,19 +885,18 @@@ class ImagNode(AtomicExprNode) return complex(0.0, self.value) def analyse_types(self, env): - self.type = py_object_type - self.is_temp = 1 + self.type.create_declaration_utility_code(env) + + def coerce_to(self, dst_type, env): + # Arrange for a Python version of the number to be pre-allocated + # when coercing to a Python type. + if dst_type.is_pyobject: + self.is_temp = 1 + self.type = PyrexTypes.py_object_type - self.gil_check(env) + # We still need to perform normal coerce_to processing on the + # result, because we might be coercing to an extension type, + # in which case a type test node will be needed. - return AtomicNewTempExprNode.coerce_to(self, dst_type, env) ++ return AtomicExprNode.coerce_to(self, dst_type, env) gil_message = "Constructing complex number" @@@ -5128,13 -5177,14 +5219,13 @@@ class CoerceToPyTypeNode(CoercionNode) def __init__(self, arg, env): CoercionNode.__init__(self, arg) self.type = py_object_type - self.gil_check(env) self.is_temp = 1 - if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env): + if not arg.type.create_to_py_utility_code(env): error(arg.pos, "Cannot convert '%s' to Python object" % arg.type) - + gil_message = "Converting to Python object" - + def coerce_to_boolean(self, env): return self.arg.coerce_to_boolean(env).coerce_to_temp(env) diff --cc Cython/Compiler/Main.py index a07ec2e4,7b8b7efd..cc7999e2 --- a/Cython/Compiler/Main.py +++ b/Cython/Compiler/Main.py @@@ -124,7 -123,8 +124,8 @@@ class Context(object) IntroduceBufferAuxiliaryVars(self), _check_c_declarations, AnalyseExpressionsTransform(self), - FlattenBuiltinTypeCreation(), + OptimizeBuiltinCalls(), + ConstantFolding(), IterationTransform(), SwitchTransform(), FinalOptimizePhase(self), diff --cc Cython/Compiler/ModuleNode.py index 93829b8f,32be4c71..7822b941 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@@ -237,23 -244,35 +239,31 @@@ class ModuleNode(Nodes.Node, Nodes.Bloc def generate_c_code(self, env, options, result): modules = self.referenced_modules + if Options.annotate or options.annotate: - code = Annotate.AnnotationCCodeWriter() + emit_linenums = False + rootwriter = Annotate.AnnotationCCodeWriter() else: - code = Code.CCodeWriter(emit_linenums=options.emit_linenums) - h_code = code.insertion_point() + emit_linenums = options.emit_linenums + rootwriter = Code.CCodeWriter(emit_linenums=emit_linenums) + globalstate = Code.GlobalState(rootwriter, emit_linenums) + globalstate.initialize_main_c_code() + h_code = globalstate['h_code'] + self.generate_module_preamble(env, modules, h_code) - code.globalstate.module_pos = self.pos - code.globalstate.directives = self.directives + globalstate.module_pos = self.pos + globalstate.directives = self.directives - code.globalstate.use_utility_code(refcount_utility_code) + globalstate.use_utility_code(refcount_utility_code) + code = globalstate['before_global_var'] code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name) + code.putln("int %s%s = %s;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'), int(Options.embed))) code.putln("") code.putln("/* Implementation of %s */" % env.qualified_name) - self.generate_const_definitions(env, code) - self.generate_interned_num_decls(env, code) - self.generate_interned_string_decls(env, code) - self.generate_py_string_decls(env, code) - code.globalstate.insert_global_var_declarations_into(code) + code = globalstate['all_the_rest'] self.generate_cached_builtins_decls(env, code) self.body.generate_function_definitions(env, code) @@@ -1805,14 -1838,13 +1826,17 @@@ env.module_cname, Naming.builtins_cname, code.error_goto(self.pos))) - if Options.embed: - __main__name = code.globalstate.get_py_string_const( - EncodedString("__main__"), identifier=True) - code.putln( - 'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % ( - env.module_cname, - __main__name.cname, - code.error_goto(self.pos))) ++ ++ ++ __main__name = code.globalstate.get_py_string_const( ++ EncodedString("__main__"), identifier=True) + code.putln("if (%s%s) {" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))) + code.putln( + 'if (__Pyx_SetAttrString(%s, "__name__", %s) < 0) %s;' % ( + env.module_cname, - self.__main__cname, ++ __main__name.cname, + code.error_goto(self.pos))) + code.putln("}") if Options.pre_import is not None: code.putln( '%s = PyImport_AddModule(__Pyx_NAMESTR("%s"));' % ( diff --cc tests/errors/nogil.pyx index e3a5b6d3,570aeb14..841e5487 --- a/tests/errors/nogil.pyx +++ b/tests/errors/nogil.pyx @@@ -82,14 -82,14 +82,14 @@@ _ERRORS = u"" 6: 6: Assignment of Python object not allowed without gil 4: 5: Function declared nogil has Python locals or temporaries 11: 5: Function with Python return type cannot be declared nogil -15: 5: Calling gil-requiring function without gil -24: 9: Calling gil-requiring function without gil +15: 5: Calling gil-requiring function not allowed without gil +24: 9: Calling gil-requiring function not allowed without gil 26:12: Assignment of Python object not allowed without gil - 28: 8: Constructing complex number not allowed without gil + 28:16: Constructing complex number not allowed without gil 29:12: Accessing Python global or builtin not allowed without gil 30: 8: Backquote expression not allowed without gil -31:15: Python import not allowed without gil 31:15: Assignment of Python object not allowed without gil +31:15: Python import not allowed without gil 32:13: Python import not allowed without gil 32:25: Constructing Python list not allowed without gil 33:17: Iterating over Python object not allowed without gil diff --cc tests/run/cdef_setitem_T284.pyx index 2f042ae2,2d1971fa..4438e4da --- a/tests/run/cdef_setitem_T284.pyx +++ b/tests/run/cdef_setitem_T284.pyx @@@ -1,18 -1,15 +1,26 @@@ __doc__ = u''' >>> no_cdef() >>> with_cdef() ++<<<<<<< local + +>>> test_list(range(11), -2, None) ++======= + >>> test_list(list(range(11)), -2, None) ++>>>>>>> other [0, 1, 2, 3, 4, 5, 6, 7, 8, None, 10] ++<<<<<<< local + +>>> test_list(range(11), "invalid index", None) ++======= + >>> test_list(list(range(11)), "invalid index", None) #doctest: +ELLIPSIS ++>>>>>>> other Traceback (most recent call last): ... - TypeError: list indices must be integers, not str + TypeError: list indices must be integers... ''' + def no_cdef(): - lst = range(11) + lst = list(range(11)) ob = 10L lst[ob] = -10 dd = {}