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):
self.value = value
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
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
......@@ -321,6 +331,7 @@ class GlobalState(object):
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()
......@@ -394,6 +405,10 @@ class GlobalState(object):
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:
......@@ -424,6 +439,12 @@ class GlobalState(object):
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):
......@@ -458,6 +479,15 @@ class GlobalState(object):
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()
for _, cname, c in consts:
self.decls_writer.putln(
"static %s;" % c.type.declaration_code(cname))
def generate_string_constants(self):
c_consts = [ (len(c.cname), c.cname, c)
......@@ -762,6 +792,9 @@ class CCodeWriter(object):
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)
......
......@@ -255,10 +255,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
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)
......@@ -663,13 +659,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
" 'cdef extern from' block")
else:
last_entry = enum_values[-1]
# this does not really generate code, just builds the result value
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
else:
value_code = ("%s = %s" % (
value_entry.cname,
value_entry.value))
value_entry.value_node.result()))
if value_entry is not last_entry:
value_code += ","
code.putln(value_code)
......@@ -761,9 +762,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
entry.type.typeptr_cname)
code.put_var_declarations(env.var_entries, static = 1,
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):
for entry in env.cfunc_entries:
......@@ -1702,19 +1700,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put_decref_clear(Naming.empty_tuple,
PyrexTypes.py_object_type,
nanny=False)
for entry in env.pynum_entries:
code.put_decref_clear(entry.cname,
PyrexTypes.py_object_type,
nanny=False)
for entry in env.all_pystring_entries:
if entry.is_interned:
code.put_decref_clear(entry.pystring_cname,
PyrexTypes.py_object_type,
nanny=False)
for entry in env.default_entries:
if entry.type.is_pyobject and entry.used:
code.putln("Py_DECREF(%s); %s = 0;" % (
code.entry_as_pyobject(entry), entry.cname))
# for entry in env.pynum_entries:
# code.put_decref_clear(entry.cname,
# PyrexTypes.py_object_type,
# nanny=False)
# for entry in env.all_pystring_entries:
# if entry.is_interned:
# code.put_decref_clear(entry.pystring_cname,
# PyrexTypes.py_object_type,
# nanny=False)
# for entry in env.default_entries:
# if entry.type.is_pyobject and entry.used:
# code.putln("Py_DECREF(%s); %s = 0;" % (
# code.entry_as_pyobject(entry), entry.cname))
code.putln("Py_INCREF(Py_None); return Py_None;")
code.putln('}')
......
......@@ -302,38 +302,6 @@ class CompilerDirectivesNode(Node):
class BlockNode(object):
# 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):
entries = env.global_scope().undeclared_cached_builtins
for entry in entries:
......@@ -609,8 +577,7 @@ class CArgDeclNode(Node):
# declarator CDeclaratorNode
# not_none boolean Tagged with 'not None'
# default ExprNode or None
# default_entry Symtab.Entry Entry for the variable holding the default value
# default_result_code string cname or code fragment for default value
# default_value PyObjectConst constant for default value
# is_self_arg boolean Is the "self" arg of an extension type method
# is_kw_only boolean Is a keyword-only argument
......@@ -620,6 +587,7 @@ class CArgDeclNode(Node):
is_generic = 1
type = None
name_declarator = None
default_value = None
def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
......@@ -641,16 +609,15 @@ class CArgDeclNode(Node):
else:
return self.name_declarator, self.type
def prepare_default_result_code(self, code):
def calculate_default_value_code(self, code):
if self.default_value is None:
if self.default:
if self.default.is_literal:
# FIXME: IS IT OK TO CALL THIS HERE???
# will not output any code, just assign the result_code
self.default.generate_evaluation_code(code)
self.default_result_code = self.default.result()
if self.default.type != self.type and not self.type.is_int:
self.default_result_code = self.type.cast_code(self.default_result_code)
else:
self.default_result_code = self.default_entry.cname
return self.type.cast_code(self.default.result())
self.default_value = code.get_argument_default_const(self.type)
return self.default_value
def annotate(self, code):
if self.default:
......@@ -944,11 +911,9 @@ class CEnumDefItemNode(StatNode):
if not self.value.type.is_int:
self.value = self.value.coerce_to(PyrexTypes.c_int_type, 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,
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)
......@@ -997,14 +962,7 @@ class FuncDefNode(StatNode, BlockNode):
if not hasattr(arg, 'default_entry'):
arg.default.analyse_types(env)
arg.default = arg.default.coerce_to(arg.type, genv)
if arg.default.is_literal:
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:
error(arg.pos,
"This argument cannot have a default value")
......@@ -1042,13 +1000,7 @@ class FuncDefNode(StatNode, BlockNode):
# ----- Top-level constants used by this function
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)
#code.putln("")
#code.put_var_declarations(lenv.const_entries, static = 1)
self.generate_const_definitions(lenv, code)
# ----- Function header
code.putln("")
if self.py_func:
......@@ -1244,14 +1196,15 @@ class FuncDefNode(StatNode, BlockNode):
if not default.is_literal:
default.generate_evaluation_code(code)
default.make_owned_reference(code)
result = default.result_as(arg.type)
code.putln(
"%s = %s;" % (
arg.default_entry.cname,
default.result_as(arg.default_entry.type)))
if default.is_temp and default.type.is_pyobject:
code.putln("%s = 0;" % default.result())
arg.calculate_default_value_code(code),
result))
if arg.type.is_pyobject:
code.put_giveref(default.result())
default.generate_post_assignment_code(code)
default.free_temps(code)
code.put_var_giveref(arg.default_entry)
# For Python class methods, create and store function object
if self.assmt:
self.assmt.generate_execution_code(code)
......@@ -1438,9 +1391,9 @@ class CFuncDefNode(FuncDefNode):
def generate_argument_declarations(self, env, code):
for arg in self.args:
if arg.default:
arg.prepare_default_result_code(code)
result = arg.calculate_default_value_code(code)
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):
pass
......@@ -1881,8 +1834,6 @@ class DefNode(FuncDefNode):
code.putln("PyObject *%s = 0;" % arg.hdr_cname)
else:
code.put_var_declaration(arg.entry)
if arg.default:
arg.prepare_default_result_code(code)
def generate_keyword_list(self, code):
if self.signature_has_generic_args() and \
......@@ -2143,7 +2094,7 @@ class DefNode(FuncDefNode):
code.putln(
"%s = %s;" % (
arg.entry.cname,
arg.default_result_code))
arg.calculate_default_value_code(code)))
def generate_stararg_init_code(self, max_positional_args, code):
if self.starstar_arg:
......@@ -2185,7 +2136,7 @@ class DefNode(FuncDefNode):
default_args = []
for i, arg in enumerate(all_args):
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:
default_value = "(PyObject*)"+default_value
default_args.append((i, default_value))
......@@ -2331,7 +2282,7 @@ class DefNode(FuncDefNode):
code.putln(
"%s = %s;" % (
arg.entry.cname,
arg.default_result_code))
arg.calculate_default_value_code(code)))
code.putln('}')
def generate_argument_conversion_code(self, code):
......@@ -2582,7 +2533,6 @@ class PyClassDefNode(ClassDefNode):
#self.target.release_target_temp(env)
def generate_function_definitions(self, env, code):
self.generate_py_string_decls(self.scope, code)
self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code):
......@@ -2716,7 +2666,6 @@ class CClassDefNode(ClassDefNode):
self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code):
self.generate_py_string_decls(self.entry.type.scope, code)
if self.body:
self.body.generate_function_definitions(
self.entry.type.scope, code)
......
......@@ -306,7 +306,7 @@ class Scope(object):
cname = self.mangle(Naming.enum_prefix, name)
entry = self.declare(name, cname, type, pos, visibility)
entry.is_const = 1
entry.value = value
entry.value_node = value
return entry
def declare_type(self, name, type, pos,
......@@ -683,9 +683,7 @@ class ModuleScope(Scope):
# method_table_cname string C name of method table
# doc string 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
# default_entries [Entry] Function argument default entries
# python_include_files [string] Standard Python headers to be included
# include_files [string] Other C headers to be included
# string_to_entry {string : Entry} Map string const to entry
......@@ -697,9 +695,6 @@ class ModuleScope(Scope):
# included_files [string] Cython sources included with 'include'
# pxd_file_loaded boolean Corresponding .pxd file has been processed
# 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
# has_import_star boolean Module contains import *
......@@ -723,20 +718,14 @@ class ModuleScope(Scope):
self.doc = ""
self.doc_cname = Naming.moddoc_cname
self.utility_code_list = []
self.default_entries = []
self.module_entries = {}
self.python_include_files = ["Python.h", "structmember.h"]
self.include_files = []
self.type_names = dict(outer_scope.type_names)
self.pxd_file_loaded = 0
self.cimported_modules = []
self.new_interned_string_entries = []
self.interned_nums = []
self.interned_objs = []
self.all_pystring_entries = []
self.types_imported = {}
self.included_files = []
self.pynum_entries = []
self.has_extern_class = 0
self.cached_builtins = []
self.undeclared_cached_builtins = []
......@@ -869,22 +858,6 @@ class ModuleScope(Scope):
if not entry:
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):
if new_code is not None:
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