@@ -65,7 +65,6 @@ import 'package:front_end/src/api_unstable/dart2js.dart'
6565 show $0, $9, $A, $Z, $_, $a, $z;
6666
6767import '../common_elements.dart' show CommonElements;
68- import '../elements/entities.dart' show FunctionEntity;
6968import '../elements/types.dart' ;
7069import '../js/js.dart' as js;
7170import '../js_emitter/code_emitter_task.dart' show Emitter;
@@ -261,19 +260,20 @@ class TypeReferenceFinalizerImpl implements TypeReferenceFinalizer {
261260 }
262261
263262 void _updateReferences () {
264- js.Expression loadTypeCall (TypeRecipe recipe) {
265- FunctionEntity helperElement = _commonElements.findType;
263+ js.Expression helperAccess =
264+ _emitter.staticFunctionAccess (_commonElements.findType);
265+
266+ js.Expression loadTypeCall (TypeRecipe recipe, String helperLocal) {
266267 js.Expression recipeExpression =
267268 _recipeEncoder.encodeGroundRecipe (_emitter, recipe);
268- js.Expression helper = _emitter.staticFunctionAccess (helperElement);
269- return js.js (r'#(#)' , [helper, recipeExpression]);
269+ return js.js (r'#(#)' , [helperLocal ?? helperAccess, recipeExpression]);
270270 }
271271
272272 // Emit generate-at-use references.
273273 for (_ReferenceSet referenceSet in _referencesByRecipe.values) {
274274 if (referenceSet.generateAtUse) {
275275 TypeRecipe recipe = referenceSet.recipe;
276- js.Expression reference = loadTypeCall (recipe);
276+ js.Expression reference = loadTypeCall (recipe, null );
277277 for (TypeReference ref in referenceSet._references) {
278278 ref.value = reference;
279279 }
@@ -287,23 +287,43 @@ class TypeReferenceFinalizerImpl implements TypeReferenceFinalizer {
287287 // are grouped together.
288288 referenceSetsUsingProperties.sort ((a, b) => a.name.compareTo (b.name));
289289
290+ // We can generate a literal with calls to H.findType (minified to typically
291+ // e.g. H.xy) or cache H.findType in a local in a scope created by an IIFE.
292+ // Doing so saves 2-3 bytes per entry, but with an overhead of 30+ bytes for
293+ // the IIFE. So it is smaller to use the IIFE only for over 10 or so types.
294+ const minUseIIFE = 10 ;
295+ String helperLocal =
296+ referenceSetsUsingProperties.length < minUseIIFE ? null : 'findType' ;
297+
290298 List <js.Property > properties = [];
291299 for (_ReferenceSet referenceSet in referenceSetsUsingProperties) {
292300 TypeRecipe recipe = referenceSet.recipe;
293301 var propertyName = js.string (referenceSet.propertyName);
294- properties.add (js.Property (propertyName, loadTypeCall (recipe)));
302+ properties
303+ .add (js.Property (propertyName, loadTypeCall (recipe, helperLocal)));
295304 var access = js.js ('#.#' , [typesHolderLocalName, propertyName]);
296305 for (TypeReference ref in referenceSet._references) {
297306 ref.value = access;
298307 }
299308 }
300- var initializer = js.ObjectInitializer (properties, isOneLiner: false );
301309
302- var function = js.js (r'function rtii(){return #}' , initializer);
303- _resource.value = js.js (r'var # = #()' , [
304- js.VariableDeclaration (typesHolderLocalName),
305- js.Parentheses (function)
306- ]);
310+ if (properties.isEmpty) {
311+ // We don't have a deferred statement sequence. "0;" is the smallest we
312+ // can do with an expression statement.
313+ // TODO(sra): Add deferred expression statement sequences.
314+ _resource.value = js.js ('0' );
315+ } else {
316+ js.Expression initializer =
317+ js.ObjectInitializer (properties, isOneLiner: false );
318+ if (helperLocal != null ) {
319+ // A named IIFE helps attribute startup time in profiling.
320+ var function = js.js (r'function rtii(){var # = #; return #}' ,
321+ [js.VariableDeclaration (helperLocal), helperAccess, initializer]);
322+ initializer = js.js ('#()' , js.Parentheses (function));
323+ }
324+ _resource.value = js.js (r'var # = #' ,
325+ [js.VariableDeclaration (typesHolderLocalName), initializer]);
326+ }
307327 }
308328
309329 // This is a top-level local name in the generated JavaScript top-level
0 commit comments