Commit 64275702 authored by Stefan Behnel's avatar Stefan Behnel

major cleanup, move argument default value caching to code generation phase

parent 0e92b4fc
...@@ -214,6 +214,16 @@ class IntConst(object): ...@@ -214,6 +214,16 @@ class IntConst(object):
self.value = value self.value = value
self.is_long = is_long self.is_long = is_long
class PyObjectConst(object):
"""Global info about a generic constant held by GlobalState.
"""
# cname string
# type PyrexType
def __init__(self, cname, type):
self.cname = cname
self.type = type
possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
...@@ -321,6 +331,7 @@ class GlobalState(object): ...@@ -321,6 +331,7 @@ class GlobalState(object):
self.const_cname_counter = 1 self.const_cname_counter = 1
self.string_const_index = {} self.string_const_index = {}
self.int_const_index = {} self.int_const_index = {}
self.py_constants = []
def initwriters(self, rootwriter): def initwriters(self, rootwriter):
self.utilprotowriter = rootwriter.new_writer() self.utilprotowriter = rootwriter.new_writer()
...@@ -394,6 +405,10 @@ class GlobalState(object): ...@@ -394,6 +405,10 @@ class GlobalState(object):
c = self.new_int_const(str_value, longness) c = self.new_int_const(str_value, longness)
return c 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): def get_string_const(self, text):
# return a C string constant, creating a new one if necessary # return a C string constant, creating a new one if necessary
if text.is_unicode: if text.is_unicode:
...@@ -424,6 +439,12 @@ class GlobalState(object): ...@@ -424,6 +439,12 @@ class GlobalState(object):
self.int_const_index[(value, longness)] = c self.int_const_index[(value, longness)] = c
return 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): def new_string_const_cname(self, value, intern=None):
# Create a new globally-unique nice name for a C string constant. # Create a new globally-unique nice name for a C string constant.
if len(value) < 20 and nice_identifier(value): if len(value) < 20 and nice_identifier(value):
...@@ -458,6 +479,15 @@ class GlobalState(object): ...@@ -458,6 +479,15 @@ class GlobalState(object):
def generate_const_declarations(self): def generate_const_declarations(self):
self.generate_string_constants() self.generate_string_constants()
self.generate_int_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()
for _, cname, c in consts:
self.decls_writer.putln(
"static %s;" % c.type.declaration_code(cname))
def generate_string_constants(self): def generate_string_constants(self):
c_consts = [ (len(c.cname), c.cname, c) c_consts = [ (len(c.cname), c.cname, c)
...@@ -762,6 +792,9 @@ class CCodeWriter(object): ...@@ -762,6 +792,9 @@ class CCodeWriter(object):
def get_py_string_const(self, text, identifier=None): def get_py_string_const(self, text, identifier=None):
return self.globalstate.get_py_string_const(text, identifier).cname 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): def intern(self, text):
return self.get_py_string_const(text) return self.get_py_string_const(text)
......
...@@ -255,10 +255,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -255,10 +255,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("") code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name) 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.insert_global_var_declarations_into(code)
...@@ -663,13 +659,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -663,13 +659,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
" 'cdef extern from' block") " 'cdef extern from' block")
else: else:
last_entry = enum_values[-1] last_entry = enum_values[-1]
# this does not really generate code, just builds the result value
for value_entry in enum_values: for value_entry in enum_values:
if value_entry.value == value_entry.name: if value_entry.value_node is not None:
value_entry.value_node.generate_evaluation_code(code)
for value_entry in enum_values:
if value_entry.value_node is None:
value_code = value_entry.cname value_code = value_entry.cname
else: else:
value_code = ("%s = %s" % ( value_code = ("%s = %s" % (
value_entry.cname, value_entry.cname,
value_entry.value)) value_entry.value_node.result()))
if value_entry is not last_entry: if value_entry is not last_entry:
value_code += "," value_code += ","
code.putln(value_code) code.putln(value_code)
...@@ -761,9 +762,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -761,9 +762,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
entry.type.typeptr_cname) entry.type.typeptr_cname)
code.put_var_declarations(env.var_entries, static = 1, code.put_var_declarations(env.var_entries, static = 1,
dll_linkage = "DL_EXPORT", definition = definition) dll_linkage = "DL_EXPORT", definition = definition)
if definition:
code.put_var_declarations(env.default_entries, static = 1,
definition = definition)
def generate_cfunction_predeclarations(self, env, code, definition): def generate_cfunction_predeclarations(self, env, code, definition):
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
...@@ -1702,19 +1700,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1702,19 +1700,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put_decref_clear(Naming.empty_tuple, code.put_decref_clear(Naming.empty_tuple,
PyrexTypes.py_object_type, PyrexTypes.py_object_type,
nanny=False) nanny=False)
for entry in env.pynum_entries: # for entry in env.pynum_entries:
code.put_decref_clear(entry.cname, # code.put_decref_clear(entry.cname,
PyrexTypes.py_object_type, # PyrexTypes.py_object_type,
nanny=False) # nanny=False)
for entry in env.all_pystring_entries: # for entry in env.all_pystring_entries:
if entry.is_interned: # if entry.is_interned:
code.put_decref_clear(entry.pystring_cname, # code.put_decref_clear(entry.pystring_cname,
PyrexTypes.py_object_type, # PyrexTypes.py_object_type,
nanny=False) # nanny=False)
for entry in env.default_entries: # for entry in env.default_entries:
if entry.type.is_pyobject and entry.used: # if entry.type.is_pyobject and entry.used:
code.putln("Py_DECREF(%s); %s = 0;" % ( # code.putln("Py_DECREF(%s); %s = 0;" % (
code.entry_as_pyobject(entry), entry.cname)) # code.entry_as_pyobject(entry), entry.cname))
code.putln("Py_INCREF(Py_None); return Py_None;") code.putln("Py_INCREF(Py_None); return Py_None;")
code.putln('}') code.putln('}')
......
...@@ -302,38 +302,6 @@ class CompilerDirectivesNode(Node): ...@@ -302,38 +302,6 @@ class CompilerDirectivesNode(Node):
class BlockNode(object): class BlockNode(object):
# Mixin class for nodes representing a declaration block. # Mixin class for nodes representing a declaration block.
def generate_const_definitions(self, env, code):
if env.const_entries:
for entry in env.const_entries:
if not entry.is_interned:
code.globalstate.add_const_definition(entry)
def generate_interned_string_decls(self, env, code):
entries = env.global_scope().new_interned_string_entries
if entries:
for entry in entries:
code.globalstate.add_interned_string_decl(entry)
del entries[:]
def generate_py_string_decls(self, env, code):
if env is None:
return # earlier error
entries = env.pystring_entries
if entries:
for entry in entries:
if not entry.is_interned:
code.globalstate.add_py_string_decl(entry)
def generate_interned_num_decls(self, env, code):
# Flush accumulated interned nums from the global scope
# and generate declarations for them.
genv = env.global_scope()
entries = genv.interned_nums
if entries:
for entry in entries:
code.globalstate.add_interned_num_decl(entry)
del entries[:]
def generate_cached_builtins_decls(self, env, code): def generate_cached_builtins_decls(self, env, code):
entries = env.global_scope().undeclared_cached_builtins entries = env.global_scope().undeclared_cached_builtins
for entry in entries: for entry in entries:
...@@ -609,8 +577,7 @@ class CArgDeclNode(Node): ...@@ -609,8 +577,7 @@ class CArgDeclNode(Node):
# declarator CDeclaratorNode # declarator CDeclaratorNode
# not_none boolean Tagged with 'not None' # not_none boolean Tagged with 'not None'
# default ExprNode or None # default ExprNode or None
# default_entry Symtab.Entry Entry for the variable holding the default value # default_value PyObjectConst constant for default value
# default_result_code string cname or code fragment for default value
# is_self_arg boolean Is the "self" arg of an extension type method # is_self_arg boolean Is the "self" arg of an extension type method
# is_kw_only boolean Is a keyword-only argument # is_kw_only boolean Is a keyword-only argument
...@@ -620,6 +587,7 @@ class CArgDeclNode(Node): ...@@ -620,6 +587,7 @@ class CArgDeclNode(Node):
is_generic = 1 is_generic = 1
type = None type = None
name_declarator = None name_declarator = None
default_value = None
def analyse(self, env, nonempty = 0): def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ### #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
...@@ -641,16 +609,15 @@ class CArgDeclNode(Node): ...@@ -641,16 +609,15 @@ class CArgDeclNode(Node):
else: else:
return self.name_declarator, self.type return self.name_declarator, self.type
def prepare_default_result_code(self, code): def calculate_default_value_code(self, code):
if self.default: if self.default_value is None:
if self.default.is_literal: if self.default:
# FIXME: IS IT OK TO CALL THIS HERE??? if self.default.is_literal:
self.default.generate_evaluation_code(code) # will not output any code, just assign the result_code
self.default_result_code = self.default.result() self.default.generate_evaluation_code(code)
if self.default.type != self.type and not self.type.is_int: return self.type.cast_code(self.default.result())
self.default_result_code = self.type.cast_code(self.default_result_code) self.default_value = code.get_argument_default_const(self.type)
else: return self.default_value
self.default_result_code = self.default_entry.cname
def annotate(self, code): def annotate(self, code):
if self.default: if self.default:
...@@ -944,11 +911,9 @@ class CEnumDefItemNode(StatNode): ...@@ -944,11 +911,9 @@ class CEnumDefItemNode(StatNode):
if not self.value.type.is_int: if not self.value.type.is_int:
self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
self.value.analyse_const_expression(env) self.value.analyse_const_expression(env)
value = self.value.get_constant_result_code()
else:
value = self.name
entry = env.declare_const(self.name, enum_entry.type, entry = env.declare_const(self.name, enum_entry.type,
value, self.pos, cname = self.cname, visibility = enum_entry.visibility) self.value, self.pos, cname = self.cname,
visibility = enum_entry.visibility)
enum_entry.enum_values.append(entry) enum_entry.enum_values.append(entry)
...@@ -997,14 +962,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -997,14 +962,7 @@ class FuncDefNode(StatNode, BlockNode):
if not hasattr(arg, 'default_entry'): if not hasattr(arg, 'default_entry'):
arg.default.analyse_types(env) arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, genv) arg.default = arg.default.coerce_to(arg.type, genv)
if arg.default.is_literal: arg.default.allocate_temps(genv)
arg.default_entry = arg.default
else:
arg.default.allocate_temps(genv)
arg.default_entry = genv.add_default_value(arg.type)
if arg.type.is_pyobject:
arg.default_entry.init = 0
arg.default_entry.used = 1
else: else:
error(arg.pos, error(arg.pos,
"This argument cannot have a default value") "This argument cannot have a default value")
...@@ -1042,13 +1000,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1042,13 +1000,7 @@ class FuncDefNode(StatNode, BlockNode):
# ----- Top-level constants used by this function # ----- Top-level constants used by this function
code.mark_pos(self.pos) code.mark_pos(self.pos)
self.generate_interned_num_decls(lenv, code)
self.generate_interned_string_decls(lenv, code)
self.generate_py_string_decls(lenv, code)
self.generate_cached_builtins_decls(lenv, code) self.generate_cached_builtins_decls(lenv, code)
#code.putln("")
#code.put_var_declarations(lenv.const_entries, static = 1)
self.generate_const_definitions(lenv, code)
# ----- Function header # ----- Function header
code.putln("") code.putln("")
if self.py_func: if self.py_func:
...@@ -1244,14 +1196,15 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1244,14 +1196,15 @@ class FuncDefNode(StatNode, BlockNode):
if not default.is_literal: if not default.is_literal:
default.generate_evaluation_code(code) default.generate_evaluation_code(code)
default.make_owned_reference(code) default.make_owned_reference(code)
result = default.result_as(arg.type)
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
arg.default_entry.cname, arg.calculate_default_value_code(code),
default.result_as(arg.default_entry.type))) result))
if default.is_temp and default.type.is_pyobject: if arg.type.is_pyobject:
code.putln("%s = 0;" % default.result()) code.put_giveref(default.result())
default.generate_post_assignment_code(code)
default.free_temps(code) default.free_temps(code)
code.put_var_giveref(arg.default_entry)
# For Python class methods, create and store function object # For Python class methods, create and store function object
if self.assmt: if self.assmt:
self.assmt.generate_execution_code(code) self.assmt.generate_execution_code(code)
...@@ -1438,9 +1391,9 @@ class CFuncDefNode(FuncDefNode): ...@@ -1438,9 +1391,9 @@ class CFuncDefNode(FuncDefNode):
def generate_argument_declarations(self, env, code): def generate_argument_declarations(self, env, code):
for arg in self.args: for arg in self.args:
if arg.default: if arg.default:
arg.prepare_default_result_code(code) result = arg.calculate_default_value_code(code)
code.putln('%s = %s;' % ( code.putln('%s = %s;' % (
arg.type.declaration_code(arg.cname), arg.default_result_code)) arg.type.declaration_code(arg.cname), result))
def generate_keyword_list(self, code): def generate_keyword_list(self, code):
pass pass
...@@ -1881,9 +1834,7 @@ class DefNode(FuncDefNode): ...@@ -1881,9 +1834,7 @@ class DefNode(FuncDefNode):
code.putln("PyObject *%s = 0;" % arg.hdr_cname) code.putln("PyObject *%s = 0;" % arg.hdr_cname)
else: else:
code.put_var_declaration(arg.entry) code.put_var_declaration(arg.entry)
if arg.default:
arg.prepare_default_result_code(code)
def generate_keyword_list(self, code): def generate_keyword_list(self, code):
if self.signature_has_generic_args() and \ if self.signature_has_generic_args() and \
self.signature_has_nongeneric_args(): self.signature_has_nongeneric_args():
...@@ -2143,7 +2094,7 @@ class DefNode(FuncDefNode): ...@@ -2143,7 +2094,7 @@ class DefNode(FuncDefNode):
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
arg.entry.cname, arg.entry.cname,
arg.default_result_code)) arg.calculate_default_value_code(code)))
def generate_stararg_init_code(self, max_positional_args, code): def generate_stararg_init_code(self, max_positional_args, code):
if self.starstar_arg: if self.starstar_arg:
...@@ -2185,7 +2136,7 @@ class DefNode(FuncDefNode): ...@@ -2185,7 +2136,7 @@ class DefNode(FuncDefNode):
default_args = [] default_args = []
for i, arg in enumerate(all_args): for i, arg in enumerate(all_args):
if arg.default and arg.type.is_pyobject: if arg.default and arg.type.is_pyobject:
default_value = arg.default_result_code default_value = arg.calculate_default_value_code(code)
if arg.type is not PyrexTypes.py_object_type: if arg.type is not PyrexTypes.py_object_type:
default_value = "(PyObject*)"+default_value default_value = "(PyObject*)"+default_value
default_args.append((i, default_value)) default_args.append((i, default_value))
...@@ -2331,7 +2282,7 @@ class DefNode(FuncDefNode): ...@@ -2331,7 +2282,7 @@ class DefNode(FuncDefNode):
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
arg.entry.cname, arg.entry.cname,
arg.default_result_code)) arg.calculate_default_value_code(code)))
code.putln('}') code.putln('}')
def generate_argument_conversion_code(self, code): def generate_argument_conversion_code(self, code):
...@@ -2582,7 +2533,6 @@ class PyClassDefNode(ClassDefNode): ...@@ -2582,7 +2533,6 @@ class PyClassDefNode(ClassDefNode):
#self.target.release_target_temp(env) #self.target.release_target_temp(env)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.generate_py_string_decls(self.scope, code)
self.body.generate_function_definitions(self.scope, code) self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code): def generate_execution_code(self, code):
...@@ -2716,7 +2666,6 @@ class CClassDefNode(ClassDefNode): ...@@ -2716,7 +2666,6 @@ class CClassDefNode(ClassDefNode):
self.body.analyse_expressions(scope) self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.generate_py_string_decls(self.entry.type.scope, code)
if self.body: if self.body:
self.body.generate_function_definitions( self.body.generate_function_definitions(
self.entry.type.scope, code) self.entry.type.scope, code)
......
...@@ -296,7 +296,7 @@ class Scope(object): ...@@ -296,7 +296,7 @@ class Scope(object):
def qualify_name(self, name): def qualify_name(self, name):
return "%s.%s" % (self.qualified_name, name) return "%s.%s" % (self.qualified_name, name)
def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'): def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
# Add an entry for a named constant. # Add an entry for a named constant.
if not cname: if not cname:
...@@ -306,7 +306,7 @@ class Scope(object): ...@@ -306,7 +306,7 @@ class Scope(object):
cname = self.mangle(Naming.enum_prefix, name) cname = self.mangle(Naming.enum_prefix, name)
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_const = 1 entry.is_const = 1
entry.value = value entry.value_node = value
return entry return entry
def declare_type(self, name, type, pos, def declare_type(self, name, type, pos,
...@@ -683,9 +683,7 @@ class ModuleScope(Scope): ...@@ -683,9 +683,7 @@ class ModuleScope(Scope):
# method_table_cname string C name of method table # method_table_cname string C name of method table
# doc string Module doc string # doc string Module doc string
# doc_cname string C name of module doc string # doc_cname string C name of module doc string
# const_counter integer Counter for naming constants (PS: MOVED TO GLOBAL)
# utility_code_list [(UtilityCode, string)] Queuing utility codes for forwarding to Code.py # utility_code_list [(UtilityCode, string)] Queuing utility codes for forwarding to Code.py
# default_entries [Entry] Function argument default entries
# python_include_files [string] Standard Python headers to be included # python_include_files [string] Standard Python headers to be included
# include_files [string] Other C headers to be included # include_files [string] Other C headers to be included
# string_to_entry {string : Entry} Map string const to entry # string_to_entry {string : Entry} Map string const to entry
...@@ -697,9 +695,6 @@ class ModuleScope(Scope): ...@@ -697,9 +695,6 @@ class ModuleScope(Scope):
# included_files [string] Cython sources included with 'include' # included_files [string] Cython sources included with 'include'
# pxd_file_loaded boolean Corresponding .pxd file has been processed # pxd_file_loaded boolean Corresponding .pxd file has been processed
# cimported_modules [ModuleScope] Modules imported with cimport # cimported_modules [ModuleScope] Modules imported with cimport
# new_interned_string_entries [Entry] New interned strings waiting to be declared
# interned_nums [int/long] Interned numeric constants
# all_pystring_entries [Entry] Python string consts from all scopes
# types_imported {PyrexType : 1} Set of types for which import code generated # types_imported {PyrexType : 1} Set of types for which import code generated
# has_import_star boolean Module contains import * # has_import_star boolean Module contains import *
...@@ -723,20 +718,14 @@ class ModuleScope(Scope): ...@@ -723,20 +718,14 @@ class ModuleScope(Scope):
self.doc = "" self.doc = ""
self.doc_cname = Naming.moddoc_cname self.doc_cname = Naming.moddoc_cname
self.utility_code_list = [] self.utility_code_list = []
self.default_entries = []
self.module_entries = {} self.module_entries = {}
self.python_include_files = ["Python.h", "structmember.h"] self.python_include_files = ["Python.h", "structmember.h"]
self.include_files = [] self.include_files = []
self.type_names = dict(outer_scope.type_names) self.type_names = dict(outer_scope.type_names)
self.pxd_file_loaded = 0 self.pxd_file_loaded = 0
self.cimported_modules = [] self.cimported_modules = []
self.new_interned_string_entries = []
self.interned_nums = []
self.interned_objs = []
self.all_pystring_entries = []
self.types_imported = {} self.types_imported = {}
self.included_files = [] self.included_files = []
self.pynum_entries = []
self.has_extern_class = 0 self.has_extern_class = 0
self.cached_builtins = [] self.cached_builtins = []
self.undeclared_cached_builtins = [] self.undeclared_cached_builtins = []
...@@ -869,22 +858,6 @@ class ModuleScope(Scope): ...@@ -869,22 +858,6 @@ class ModuleScope(Scope):
if not entry: if not entry:
self.declare_var(name, py_object_type, pos) self.declare_var(name, py_object_type, pos)
def add_default_value(self, type):
# Add an entry for holding a function argument
# default value.
cname = self.new_const_cname()
entry = Entry("", cname, type)
self.default_entries.append(entry)
return entry
def new_const_cname(self):
global const_counter
# Create a new globally-unique name for a constant.
prefix=''
n = const_counter
const_counter = n + 1
return "%s%s%d" % (Naming.const_prefix, prefix, n)
def use_utility_code(self, new_code, name=None): def use_utility_code(self, new_code, name=None):
if new_code is not None: if new_code is not None:
self.utility_code_list.append((new_code, name)) self.utility_code_list.append((new_code, name))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment