Skip to content

Commit 82ce38f

Browse files
SanjitKalmsullivan
authored andcommitted
Cache enum attributes (mypyc/mypyc#672)
Add enum attributes to the global cache/treats the as final to speed up attribute lookup (since we don't need to do a py_get_attr every time we lookup an enum attribute, whose value will never change).
1 parent 148a1d0 commit 82ce38f

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

mypyc/genops.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,7 +1315,8 @@ def add_to_non_ext_dict(self, key: str, val: Value, line: int) -> None:
13151315
self.primitive_op(dict_set_item_op, [self.non_ext_info.dict, key_unicode, val], line)
13161316

13171317
def add_non_ext_class_attr(self, lvalue: NameExpr,
1318-
stmt: AssignmentStmt, class_ir: ClassIR) -> None:
1318+
stmt: AssignmentStmt, cdef: ClassDef,
1319+
attr_to_cache: List[Lvalue]) -> None:
13191320
"""
13201321
Add a class attribute to __annotations__ of a non-extension class. If the
13211322
attribute is assigned to a value, it is also added to __dict__.
@@ -1332,7 +1333,12 @@ def add_non_ext_class_attr(self, lvalue: NameExpr,
13321333
# Only add the attribute to the __dict__ if the assignment is of the form:
13331334
# x: type = value (don't add attributes of the form 'x: type' to the __dict__).
13341335
if not isinstance(stmt.rvalue, TempNode):
1335-
self.add_to_non_ext_dict(lvalue.name, self.accept(stmt.rvalue), stmt.line)
1336+
rvalue = self.accept(stmt.rvalue)
1337+
self.add_to_non_ext_dict(lvalue.name, rvalue, stmt.line)
1338+
# We cache enum attributes to speed up enum attribute lookup since they
1339+
# are final.
1340+
if cdef.info.bases and cdef.info.bases[0].type.fullname() == 'enum.Enum':
1341+
attr_to_cache.append(lvalue)
13361342

13371343
def setup_non_ext_dict(self, cdef: ClassDef, bases: Value) -> Value:
13381344
"""
@@ -1367,6 +1373,14 @@ def setup_non_ext_dict(self, cdef: ClassDef, bases: Value) -> Value:
13671373

13681374
return non_ext_dict
13691375

1376+
def cache_class_attrs(self, attrs_to_cache: List[Lvalue], cdef: ClassDef) -> None:
1377+
"""Add class attributes to be cached to the global cache"""
1378+
typ = self.load_native_type_object(cdef.fullname)
1379+
for lval in attrs_to_cache:
1380+
assert isinstance(lval, NameExpr)
1381+
rval = self.py_get_attr(typ, lval.name, cdef.line)
1382+
self.init_final_static(lval, rval, cdef.fullname)
1383+
13701384
def visit_class_def(self, cdef: ClassDef) -> None:
13711385
ir = self.mapper.type_to_ir[cdef.info]
13721386
# Currently, we only create non-extension classes for classes that are
@@ -1382,9 +1396,10 @@ def visit_class_def(self, cdef: ClassDef) -> None:
13821396
# because dataclasses uses it to determine which attributes to compute on.
13831397
# TODO: Maybe generate more precise types for annotations
13841398
non_ext_anns = self.primitive_op(new_dict_op, [], cdef.line)
1385-
13861399
self.non_ext_info = NonExtClassInfo(non_ext_dict, non_ext_bases, non_ext_anns)
13871400

1401+
attrs_to_cache = [] # type: List[Lvalue]
1402+
13881403
for stmt in cdef.defs.body:
13891404
if isinstance(stmt, OverloadedFuncDef) and stmt.is_property:
13901405
if not ir.is_ext_class:
@@ -1415,7 +1430,7 @@ def visit_class_def(self, cdef: ClassDef) -> None:
14151430
stmt.line)
14161431
continue
14171432
if not ir.is_ext_class:
1418-
self.add_non_ext_class_attr(lvalue, stmt, ir)
1433+
self.add_non_ext_class_attr(lvalue, stmt, cdef, attrs_to_cache)
14191434
continue
14201435
# Variable declaration with no body
14211436
if isinstance(stmt.rvalue, TempNode):
@@ -1451,6 +1466,9 @@ def visit_class_def(self, cdef: ClassDef) -> None:
14511466
[self.load_globals_dict(), self.load_static_unicode(cdef.name),
14521467
non_ext_class], cdef.line)
14531468

1469+
# Cache any cachable class attributes
1470+
self.cache_class_attrs(attrs_to_cache, cdef)
1471+
14541472
# Set this attribute back to None until the next non-extension class is visited.
14551473
self.non_ext_info = None
14561474

@@ -2724,10 +2742,14 @@ def get_final_ref(self, expr: MemberExpr) -> Optional[Tuple[str, Var, bool]]:
27242742
if isinstance(expr.expr, RefExpr) and isinstance(expr.expr.node, TypeInfo):
27252743
# a class attribute
27262744
sym = expr.expr.node.get(expr.name)
2727-
if sym and isinstance(sym.node, Var) and sym.node.is_final:
2728-
final_var = sym.node
2729-
fullname = '{}.{}'.format(sym.node.info.fullname(), final_var.name())
2730-
native = expr.expr.node.module_name in self.modules
2745+
if sym and isinstance(sym.node, Var):
2746+
# Enum attribute are treated as final since they are added to the global cache
2747+
expr_fullname = expr.expr.node.bases[0].type.fullname()
2748+
is_final = sym.node.is_final or expr_fullname == 'enum.Enum'
2749+
if is_final:
2750+
final_var = sym.node
2751+
fullname = '{}.{}'.format(sym.node.info.fullname(), final_var.name())
2752+
native = expr.expr.node.module_name in self.modules
27312753
elif self.is_module_member_expr(expr):
27322754
# a module attribute
27332755
if isinstance(expr.node, Var) and expr.node.is_final:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy