@@ -24,6 +24,7 @@ import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
24
24
import 'deferred_load/output_unit.dart' show OutputUnit, deferredPartFileName;
25
25
import 'dump_info_javascript_monitor.dart' ;
26
26
import 'elements/entities.dart' ;
27
+ import 'elements/entity_utils.dart' as entity_utils;
27
28
import 'inferrer/abstract_value_domain.dart' ;
28
29
import 'inferrer/types.dart'
29
30
show GlobalTypeInferenceMemberResult, GlobalTypeInferenceResults;
@@ -663,14 +664,16 @@ class KernelInfoCollector {
663
664
List <ClosureInfo > nestedClosures = < ClosureInfo > [];
664
665
localFunctionInfoCollector.localFunctions.forEach ((key, value) {
665
666
FunctionEntity closureEntity;
667
+ int closureOrder = value.order;
666
668
environment.forEachNestedClosure (memberEntity, (closure) {
667
- if (closure.enclosingClass.name == value.name) {
669
+ if (closure.enclosingClass.name == value.name &&
670
+ (closureOrder-- == 0 )) {
668
671
closureEntity = closure;
669
672
}
670
673
});
671
674
final closureClassEntity = closureEntity.enclosingClass;
672
- final closureInfo =
673
- ClosureInfo ( name: value.name , outputUnit: null , size: null );
675
+ final closureInfo = ClosureInfo (
676
+ name: value.disambiguatedName , outputUnit: null , size: null );
674
677
state.entityToInfo[closureClassEntity] = closureInfo;
675
678
676
679
FunctionEntity callMethod = closedWorld.elementEnvironment
@@ -691,6 +694,32 @@ class KernelInfoCollector {
691
694
}
692
695
}
693
696
697
+ /// Maps JWorld Entity objects to disambiguated names in order to map them
698
+ /// to/from Kernel.
699
+ ///
700
+ /// This is primarily used for naming closure objects, which rely on Entity
701
+ /// object identity to determine uniqueness.
702
+ ///
703
+ /// Note: this relies on the Kernel traversal order to determine order, which
704
+ /// may change in the future.
705
+ class EntityDisambiguator {
706
+ final nameFrequencies = < String , int > {};
707
+ final entityNames = < Entity , String > {};
708
+
709
+ String name (Entity entity) {
710
+ final disambiguatedName = entityNames[entity];
711
+ if (disambiguatedName != null ) {
712
+ return disambiguatedName;
713
+ }
714
+ nameFrequencies[entity.name] = (nameFrequencies[entity.name] ?? - 1 ) + 1 ;
715
+ final order = nameFrequencies[entity.name];
716
+ entityNames[entity] =
717
+ order == 0 ? entity.name : '${entity .name }%${order - 1 }' ;
718
+
719
+ return entityNames[entity];
720
+ }
721
+ }
722
+
694
723
/// Annotates [KernelInfoCollector] with info extracted from closed-world
695
724
/// analysis.
696
725
class DumpInfoAnnotator {
@@ -699,6 +728,7 @@ class DumpInfoAnnotator {
699
728
final JClosedWorld closedWorld;
700
729
final GlobalTypeInferenceResults _globalInferenceResults;
701
730
final DumpInfoTask dumpInfoTask;
731
+ final entityDisambiguator = EntityDisambiguator ();
702
732
703
733
JElementEnvironment get environment => closedWorld.elementEnvironment;
704
734
@@ -901,8 +931,9 @@ class DumpInfoAnnotator {
901
931
}
902
932
903
933
ClosureInfo visitClosureClass (ClassEntity element) {
934
+ final disambiguatedElementName = entityDisambiguator.name (element);
904
935
final kClosureInfos = kernelInfo.state.info.closures
905
- .where ((info) => info.name == element.name )
936
+ .where ((info) => info.name == disambiguatedElementName )
906
937
.toList ();
907
938
assert (
908
939
kClosureInfos.length == 1 ,
@@ -916,7 +947,8 @@ class DumpInfoAnnotator {
916
947
FunctionEntity callMethod = closedWorld.elementEnvironment
917
948
.lookupClassMember (element, Identifiers .call);
918
949
919
- visitFunction (callMethod, element.name);
950
+ final functionInfo = visitFunction (callMethod, disambiguatedElementName);
951
+ if (functionInfo == null ) return null ;
920
952
921
953
kClosureInfo.treeShakenStatus = TreeShakenStatus .Live ;
922
954
return kClosureInfo;
@@ -926,8 +958,8 @@ class DumpInfoAnnotator {
926
958
// not always be valid. Check and validate later.
927
959
FunctionInfo visitFunction (FunctionEntity function, String parentName) {
928
960
int size = dumpInfoTask.sizeOf (function);
929
- // TODO(sigmund): consider adding a small info to represent unreachable
930
- // code here.
961
+ if (size == 0 && ! shouldKeep (function)) return null ;
962
+
931
963
var compareName = function.name;
932
964
if (function.isConstructor) {
933
965
compareName = compareName == ""
@@ -1477,63 +1509,36 @@ class DumpInfoStateData {
1477
1509
1478
1510
class LocalFunctionInfo {
1479
1511
final ir.LocalFunction localFunction;
1480
- final List <ir.TreeNode > hierarchy;
1481
1512
final String name;
1513
+ final int order;
1482
1514
bool isInvoked = false ;
1483
1515
1484
- LocalFunctionInfo ._(this .localFunction, this .hierarchy, this .name);
1485
-
1486
- factory LocalFunctionInfo (ir.LocalFunction localFunction) {
1487
- String name = '' ;
1488
- ir.TreeNode node = localFunction;
1489
- final hierarchy = < ir.TreeNode > [];
1490
- bool inClosure = false ;
1491
- while (node != null ) {
1492
- // Only consider nodes used for resolving a closure's full name.
1493
- if (node is ir.FunctionDeclaration ) {
1494
- hierarchy.add (node);
1495
- name = '_${node .variable .name }' + name;
1496
- inClosure = false ;
1497
- } else if (node is ir.FunctionExpression ) {
1498
- hierarchy.add (node);
1499
- name = (inClosure ? '_' : '_closure' ) + name;
1500
- inClosure = true ;
1501
- } else if (node is ir.Member ) {
1502
- hierarchy.add (node);
1503
- var cleanName = node.toStringInternal ();
1504
- if (cleanName.endsWith ('.' ))
1505
- cleanName = cleanName.substring (0 , cleanName.length - 1 );
1506
- final isFactory = node is ir.Procedure && node.isFactory;
1507
- if (isFactory) {
1508
- cleanName = cleanName.replaceAll ('.' , '\$ ' );
1509
- cleanName = '${node .enclosingClass .toStringInternal ()}_' + cleanName;
1510
- } else {
1511
- cleanName = cleanName.replaceAll ('.' , '_' );
1512
- }
1513
- name = cleanName + name;
1514
- inClosure = false ;
1515
- }
1516
- node = node.parent;
1517
- }
1516
+ LocalFunctionInfo (this .localFunction, this .name, this .order);
1518
1517
1519
- return LocalFunctionInfo ._(localFunction, hierarchy, name);
1520
- }
1518
+ get disambiguatedName => order == 0 ? name : '$name %${order - 1 }' ;
1521
1519
}
1522
1520
1523
1521
class LocalFunctionInfoCollector extends ir.RecursiveVisitor <void > {
1524
1522
final localFunctions = < ir.LocalFunction , LocalFunctionInfo > {};
1523
+ final localFunctionNames = < String , int > {};
1524
+
1525
+ LocalFunctionInfo generateLocalFunctionInfo (ir.LocalFunction localFunction) {
1526
+ final name = _computeClosureName (localFunction);
1527
+ localFunctionNames[name] = (localFunctionNames[name] ?? - 1 ) + 1 ;
1528
+ return LocalFunctionInfo (localFunction, name, localFunctionNames[name]);
1529
+ }
1525
1530
1526
1531
@override
1527
1532
void visitFunctionExpression (ir.FunctionExpression node) {
1528
1533
assert (localFunctions[node] == null );
1529
- localFunctions[node] = LocalFunctionInfo (node);
1534
+ localFunctions[node] = generateLocalFunctionInfo (node);
1530
1535
defaultExpression (node);
1531
1536
}
1532
1537
1533
1538
@override
1534
1539
void visitFunctionDeclaration (ir.FunctionDeclaration node) {
1535
1540
assert (localFunctions[node] == null );
1536
- localFunctions[node] = LocalFunctionInfo (node);
1541
+ localFunctions[node] = generateLocalFunctionInfo (node);
1537
1542
defaultStatement (node);
1538
1543
}
1539
1544
@@ -1544,3 +1549,57 @@ class LocalFunctionInfoCollector extends ir.RecursiveVisitor<void> {
1544
1549
localFunctions[node.localFunction].isInvoked = true ;
1545
1550
}
1546
1551
}
1552
+
1553
+ // Returns a non-unique name for the given closure element.
1554
+ //
1555
+ // Must be kept logically identical to js_model/element_map_impl.dart.
1556
+ String _computeClosureName (ir.TreeNode treeNode) {
1557
+ String reconstructConstructorName (ir.Member node) {
1558
+ String className = node.enclosingClass.name;
1559
+ if (node.name.text == '' ) {
1560
+ return className;
1561
+ } else {
1562
+ return '$className \$ ${node .name }' ;
1563
+ }
1564
+ }
1565
+
1566
+ var parts = < String > [];
1567
+ // First anonymous is called 'closure', outer ones called '' to give a
1568
+ // compound name where increasing nesting level corresponds to extra
1569
+ // underscores.
1570
+ var anonymous = 'closure' ;
1571
+ ir.TreeNode current = treeNode;
1572
+ while (current != null ) {
1573
+ var node = current;
1574
+ if (node is ir.FunctionExpression ) {
1575
+ parts.add (anonymous);
1576
+ anonymous = '' ;
1577
+ } else if (node is ir.FunctionDeclaration ) {
1578
+ String name = node.variable.name;
1579
+ if (name != null && name != "" ) {
1580
+ parts.add (entity_utils.operatorNameToIdentifier (name));
1581
+ } else {
1582
+ parts.add (anonymous);
1583
+ anonymous = '' ;
1584
+ }
1585
+ } else if (node is ir.Class ) {
1586
+ parts.add (node.name);
1587
+ break ;
1588
+ } else if (node is ir.Procedure ) {
1589
+ if (node.kind == ir.ProcedureKind .Factory ) {
1590
+ parts.add (reconstructConstructorName (node));
1591
+ } else {
1592
+ parts.add (entity_utils.operatorNameToIdentifier (node.name.text));
1593
+ }
1594
+ } else if (node is ir.Constructor ) {
1595
+ parts.add (reconstructConstructorName (node));
1596
+ break ;
1597
+ } else if (node is ir.Field ) {
1598
+ // Add the field name for closures in field initializers.
1599
+ String name = node.name? .text;
1600
+ if (name != null ) parts.add (name);
1601
+ }
1602
+ current = current.parent;
1603
+ }
1604
+ return parts.reversed.join ('_' );
1605
+ }
0 commit comments