Commit 9c1bf4c5 authored by Robert Bradshaw's avatar Robert Bradshaw

Interned integer constants, created at module load time.

For example, in the SAGE source we have

1158 PyInt_FromLong(0)
 776 PyInt_FromLong(1)
 258 PyInt_FromLong(2)
  33 PyInt_FromLong(3)
  21 PyInt_FromLong(10)

and a thousand or so others... Who knows how many of these are in loops too.
parent cbcbdc0c
...@@ -596,6 +596,24 @@ class CharNode(ConstNode): ...@@ -596,6 +596,24 @@ class CharNode(ConstNode):
class IntNode(ConstNode): class IntNode(ConstNode):
type = PyrexTypes.c_long_type type = PyrexTypes.c_long_type
def analyse_types(self, env):
self.entry = env.get_py_num(self.value)
def coerce_to(self, dst_type, env):
# Arrange for a Python version of the string to be pre-allocated
# when coercing to a Python type.
if dst_type.is_pyobject:
self.type = PyrexTypes.py_object_type
# 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 ConstNode.coerce_to(self, dst_type, env)
def calculate_result_code(self):
if self.type.is_pyobject:
return self.entry.cname
else:
return str(self.value)
class FloatNode(ConstNode): class FloatNode(ConstNode):
type = PyrexTypes.c_double_type type = PyrexTypes.c_double_type
...@@ -2323,6 +2341,8 @@ unop_node_classes = { ...@@ -2323,6 +2341,8 @@ unop_node_classes = {
def unop_node(pos, operator, operand): def unop_node(pos, operator, operand):
# Construct unnop node of appropriate class for # Construct unnop node of appropriate class for
# given operator. # given operator.
if isinstance(operand, IntNode) and operator == '-':
return IntNode(pos = operand.pos, value = -int(operand.value))
return unop_node_classes[operator](pos, return unop_node_classes[operator](pos,
operator = operator, operator = operator,
operand = operand) operand = operand)
...@@ -2744,7 +2764,7 @@ class BoolBinopNode(ExprNode): ...@@ -2744,7 +2764,7 @@ class BoolBinopNode(ExprNode):
if self.type.is_pyobject: if self.type.is_pyobject:
test_result = self.temp_bool.result_code test_result = self.temp_bool.result_code
code.putln( code.putln(
"%s = PyObject_IsTrue(%s); %s" % ( "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
test_result, test_result,
self.operand1.py_result(), self.operand1.py_result(),
code.error_goto_if_neg(test_result, self.pos))) code.error_goto_if_neg(test_result, self.pos)))
......
...@@ -125,6 +125,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -125,6 +125,7 @@ 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_const_definitions(env, code)
self.generate_interned_num_decls(env, code)
self.generate_interned_name_decls(env, code) self.generate_interned_name_decls(env, code)
self.generate_py_string_decls(env, code) self.generate_py_string_decls(env, code)
self.generate_cached_builtins_decls(env, code) self.generate_cached_builtins_decls(env, code)
...@@ -1238,6 +1239,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1238,6 +1239,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.error_goto(self.pos))); code.error_goto(self.pos)));
def generate_intern_code(self, env, code): def generate_intern_code(self, env, code):
for entry in env.pynum_entries:
code.putln("%s = PyInt_FromLong(%s); %s;" % (
entry.cname,
entry.init,
code.error_goto_if_null(entry.cname, self.pos)))
if env.intern_map: if env.intern_map:
env.use_utility_code(Nodes.init_intern_tab_utility_code); env.use_utility_code(Nodes.init_intern_tab_utility_code);
code.putln( code.putln(
......
...@@ -21,6 +21,7 @@ pymethdef_prefix = pyrex_prefix + "mdef_" ...@@ -21,6 +21,7 @@ pymethdef_prefix = pyrex_prefix + "mdef_"
methtab_prefix = pyrex_prefix + "methods_" methtab_prefix = pyrex_prefix + "methods_"
memtab_prefix = pyrex_prefix + "members_" memtab_prefix = pyrex_prefix + "members_"
interned_prefix = pyrex_prefix + "n_" interned_prefix = pyrex_prefix + "n_"
interned_num_prefix = pyrex_prefix + "num_"
objstruct_prefix = pyrex_prefix + "obj_" objstruct_prefix = pyrex_prefix + "obj_"
typeptr_prefix = pyrex_prefix + "ptype_" typeptr_prefix = pyrex_prefix + "ptype_"
prop_set_prefix = pyrex_prefix + "setprop_" prop_set_prefix = pyrex_prefix + "setprop_"
......
...@@ -115,6 +115,18 @@ class BlockNode: ...@@ -115,6 +115,18 @@ class BlockNode:
for entry in entries: for entry in entries:
code.putln( code.putln(
"static PyObject *%s;" % entry.pystring_cname) "static PyObject *%s;" % entry.pystring_cname)
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:
code.putln("")
for entry in entries:
code.putln(
"static PyObject *%s;" % entry.cname)
del entries[:]
def generate_cached_builtins_decls(self, env, code): def generate_cached_builtins_decls(self, env, code):
entries = env.builtin_scope().undeclared_cached_entries entries = env.builtin_scope().undeclared_cached_entries
...@@ -556,6 +568,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -556,6 +568,7 @@ class FuncDefNode(StatNode, BlockNode):
# Code for nested function definitions would go here # Code for nested function definitions would go here
# if we supported them, which we probably won't. # if we supported them, which we probably won't.
# ----- Top-level constants used by this function # ----- Top-level constants used by this function
self.generate_interned_num_decls(lenv, code)
self.generate_interned_name_decls(lenv, code) self.generate_interned_name_decls(lenv, code)
self.generate_py_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)
......
...@@ -123,6 +123,7 @@ class Scope: ...@@ -123,6 +123,7 @@ class Scope:
# free_temp_entries [Entry] Temp variables currently unused # free_temp_entries [Entry] Temp variables currently unused
# temp_counter integer Counter for naming temp vars # temp_counter integer Counter for naming temp vars
# cname_to_entry {string : Entry} Temp cname to entry mapping # cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping
# pow_function_used boolean The C pow() function is used # pow_function_used boolean The C pow() function is used
# return_type PyrexType or None Return type of function owning scope # return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope # is_py_class_scope boolean Is a Python class scope
...@@ -169,6 +170,7 @@ class Scope: ...@@ -169,6 +170,7 @@ class Scope:
self.cname_to_entry = {} self.cname_to_entry = {}
self.pow_function_used = 0 self.pow_function_used = 0
self.string_to_entry = {} self.string_to_entry = {}
self.num_to_entry = {}
self.pystring_entries = [] self.pystring_entries = []
def __str__(self): def __str__(self):
...@@ -394,6 +396,28 @@ class Scope: ...@@ -394,6 +396,28 @@ class Scope:
entry.pystring_cname = entry.cname + "p" entry.pystring_cname = entry.cname + "p"
self.pystring_entries.append(entry) self.pystring_entries.append(entry)
self.global_scope().all_pystring_entries.append(entry) self.global_scope().all_pystring_entries.append(entry)
def add_py_num(self, value):
# Add an entry for an int constant.
cname = "%s%s" % (Naming.interned_num_prefix, value)
cname = cname.replace('-', 'neg_').replace('.','_')
entry = Entry("", cname, c_long_type, init = value)
entry.used = 1
entry.is_interned = 1
self.const_entries.append(entry)
self.interned_nums.append(entry)
return entry
def get_py_num(self, value):
# Get entry for int constant. Returns an existing
# one if possible, otherwise creates a new one.
genv = self.global_scope()
entry = genv.num_to_entry.get(value)
if not entry:
entry = genv.add_py_num(value)
genv.num_to_entry[value] = entry
genv.pynum_entries.append(entry)
return entry
def new_const_cname(self): def new_const_cname(self):
# Create a new globally-unique name for a constant. # Create a new globally-unique name for a constant.
...@@ -608,8 +632,10 @@ class ModuleScope(Scope): ...@@ -608,8 +632,10 @@ class ModuleScope(Scope):
self.cimported_modules = [] self.cimported_modules = []
self.intern_map = {} self.intern_map = {}
self.interned_names = [] self.interned_names = []
self.interned_nums = []
self.all_pystring_entries = [] self.all_pystring_entries = []
self.types_imported = {} self.types_imported = {}
self.pynum_entries = []
def qualifying_scope(self): def qualifying_scope(self):
return self.parent_module return self.parent_module
......
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