@@ -250,6 +250,29 @@ function installTearOff(
250
250
}
251
251
}
252
252
253
+ function installStaticTearOff(
254
+ container, getterName,
255
+ requiredParameterCount, optionalParameterDefaultValues,
256
+ callNames, funsOrNames, funType, applyIndex) {
257
+ // TODO(sra): Specialize installTearOff for static methods. It might be
258
+ // possible to handle some very common simple cases directly.
259
+ return installTearOff(
260
+ container, getterName, true, false,
261
+ requiredParameterCount, optionalParameterDefaultValues,
262
+ callNames, funsOrNames, funType, applyIndex);
263
+ }
264
+
265
+ function installInstanceTearOff(
266
+ container, getterName, isIntercepted,
267
+ requiredParameterCount, optionalParameterDefaultValues,
268
+ callNames, funsOrNames, funType, applyIndex) {
269
+ // TODO(sra): Specialize installTearOff for instance methods.
270
+ return installTearOff(
271
+ container, getterName, false, isIntercepted,
272
+ requiredParameterCount, optionalParameterDefaultValues,
273
+ callNames, funsOrNames, funType, applyIndex);
274
+ }
275
+
253
276
// Instead of setting the interceptor tags directly we use this update
254
277
// function. This makes it easier for deferred fragments to contribute to the
255
278
// embedded global.
@@ -292,14 +315,21 @@ function updateHolder(holder, newHolder) {
292
315
return holder;
293
316
}
294
317
318
+ // TODO(sra): Minify properties of 'hunkHelpers'.
319
+ var #hunkHelpers = {
320
+ installStaticTearOff: installStaticTearOff,
321
+ installInstanceTearOff: installInstanceTearOff,
322
+ };
323
+
295
324
// Every deferred hunk (i.e. fragment) is a function that we can invoke to
296
325
// initialize it. At this moment it contributes its data to the main hunk.
297
326
function initializeDeferredHunk(hunk) {
298
327
// Update the typesOffset for the next deferred library.
299
328
typesOffset = #embeddedTypes.length;
300
329
301
330
// TODO(floitsch): extend natives.
302
- hunk(inherit, inheritMany, mixin, lazy, makeConstList, convertToFastObject, installTearOff,
331
+ hunk(inherit, inheritMany, mixin, lazy, makeConstList, convertToFastObject,
332
+ hunkHelpers,
303
333
setFunctionNamesIfNecessary, updateHolder, updateTypes,
304
334
setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
305
335
#embeddedGlobalsObject, holders, #staticState);
@@ -326,7 +356,7 @@ if (#hasSoftDeferredClasses) {
326
356
#deferredGlobal[#softId](
327
357
holders, #embeddedGlobalsObject, #staticState,
328
358
inherit, inheritMany, mixin,
329
- installTearOff );
359
+ hunkHelpers );
330
360
if (o != null) {
331
361
// TODO(29574): should we do something different for Firefox?
332
362
// If we recommend that the program triggers the load by itself before
@@ -425,7 +455,7 @@ const String directAccessTestExpression = r'''
425
455
/// This template is used for Dart 2.
426
456
const String deferredBoilerplateDart2 = '''
427
457
function(inherit, inheritMany, mixin, lazy, makeConstList, convertToFastObject,
428
- installTearOff , setFunctionNamesIfNecessary, updateHolder, updateTypes,
458
+ hunkHelpers , setFunctionNamesIfNecessary, updateHolder, updateTypes,
429
459
setOrUpdateInterceptorsByTag, setOrUpdateLeafTags,
430
460
#embeddedGlobalsObject, holdersList, #staticState) {
431
461
@@ -476,7 +506,7 @@ const String softDeferredBoilerplate = '''
476
506
#deferredGlobal[#softId] =
477
507
function(holdersList, #embeddedGlobalsObject, #staticState,
478
508
inherit, inheritMany, mixin,
479
- installTearOff ) {
509
+ hunkHelpers ) {
480
510
481
511
// Installs the holders as local variables.
482
512
#installHoldersAsLocals;
@@ -532,6 +562,8 @@ class FragmentEmitter {
532
562
emitHolders (program.holders, fragment, initializeEmptyHolders: true );
533
563
534
564
js.Statement mainCode = js.js.statement (mainBoilerplate, {
565
+ // TODO(29455): 'hunkHelpers' displaces other names, so don't minify it.
566
+ 'hunkHelpers' : js.VariableDeclaration ('hunkHelpers' , allowRename: false ),
535
567
'directAccessTestExpression' : js.js (directAccessTestExpression),
536
568
'cyclicThrow' : backend.emitter
537
569
.staticFunctionAccess (_closedWorld.commonElements.cyclicThrowHelper),
@@ -1204,75 +1236,6 @@ class FragmentEmitter {
1204
1236
}
1205
1237
}
1206
1238
1207
- /// Emits the statement that installs a tear off for a method.
1208
- ///
1209
- /// Tear-offs might be passed to `Function.apply` which means that all
1210
- /// calling-conventions (with or without optional positional/named arguments)
1211
- /// are possible. As such, the tear-off needs enough information to fill in
1212
- /// missing parameters.
1213
- js.Statement emitInstallTearOff (js.Expression container, DartMethod method) {
1214
- List <js.Name > callNames = [];
1215
- List <js.Expression > funsOrNames = [];
1216
-
1217
- /// Adds the stub-method's code or name to the [funsOrNames] array.
1218
- ///
1219
- /// Static methods don't need stub-methods except for tear-offs. As such,
1220
- /// they are not emitted in the prototype, but directly passed here.
1221
- ///
1222
- /// Instance-methods install the stub-methods in their prototype, and we
1223
- /// use string-based redirections to find them there.
1224
- void addFunOrName (StubMethod stubMethod) {
1225
- if (method.isStatic) {
1226
- funsOrNames.add (stubMethod.code);
1227
- } else {
1228
- funsOrNames.add (js.quoteName (stubMethod.name));
1229
- }
1230
- }
1231
-
1232
- callNames.add (method.callName);
1233
- // The first entry in the funsOrNames-array must be a string.
1234
- funsOrNames.add (js.quoteName (method.name));
1235
- for (ParameterStubMethod stubMethod in method.parameterStubs) {
1236
- callNames.add (stubMethod.callName);
1237
- addFunOrName (stubMethod);
1238
- }
1239
-
1240
- js.ArrayInitializer callNameArray =
1241
- new js.ArrayInitializer (callNames.map (js.quoteName).toList ());
1242
- js.ArrayInitializer funsOrNamesArray = new js.ArrayInitializer (funsOrNames);
1243
-
1244
- bool isIntercepted = false ;
1245
- if (method is InstanceMethod ) {
1246
- isIntercepted = method.isIntercepted;
1247
- }
1248
- int requiredParameterCount = 0 ;
1249
- js.Expression optionalParameterDefaultValues = new js.LiteralNull ();
1250
- if (method.canBeApplied) {
1251
- requiredParameterCount = method.requiredParameterCount;
1252
- optionalParameterDefaultValues =
1253
- _encodeOptionalParameterDefaultValues (method);
1254
- }
1255
-
1256
- var applyIndex = js.number (method.applyIndex);
1257
-
1258
- return js.js.statement ('''
1259
- installTearOff(#container, #getterName, #isStatic, #isIntercepted,
1260
- #requiredParameterCount, #optionalParameterDefaultValues,
1261
- #callNames, #funsOrNames, #funType, #applyIndex)''' , {
1262
- "container" : container,
1263
- "getterName" : js.quoteName (method.tearOffName),
1264
- // 'Truthy' values are ok for `isStatic` and `isIntercepted`.
1265
- "isStatic" : js.number (method.isStatic ? 1 : 0 ),
1266
- "isIntercepted" : js.number (isIntercepted ? 1 : 0 ),
1267
- "requiredParameterCount" : js.number (requiredParameterCount),
1268
- "optionalParameterDefaultValues" : optionalParameterDefaultValues,
1269
- "callNames" : callNameArray,
1270
- "funsOrNames" : funsOrNamesArray,
1271
- "funType" : method.functionType,
1272
- "applyIndex" : applyIndex,
1273
- });
1274
- }
1275
-
1276
1239
/// Wraps the statement in a named function to that it shows up as a unit in
1277
1240
/// profiles.
1278
1241
// TODO(sra): Should this be conditional?
@@ -1292,6 +1255,100 @@ class FragmentEmitter {
1292
1255
/// Emits the section that installs tear-off getters.
1293
1256
js.Statement emitInstallTearOffs (Fragment fragment,
1294
1257
{bool softDeferred = false }) {
1258
+ var aliasForInstallStaticTearOff;
1259
+ var aliasForInstallInstanceTearOff;
1260
+
1261
+ /// Emits the statement that installs a tear off for a method.
1262
+ ///
1263
+ /// Tear-offs might be passed to `Function.apply` which means that all
1264
+ /// calling-conventions (with or without optional positional/named
1265
+ /// arguments) are possible. As such, the tear-off needs enough information
1266
+ /// to fill in missing parameters.
1267
+ js.Statement emitInstallTearOff (
1268
+ js.Expression container, DartMethod method) {
1269
+ List <js.Name > callNames = [];
1270
+ List <js.Expression > funsOrNames = [];
1271
+
1272
+ /// Adds the stub-method's code or name to the [funsOrNames] array.
1273
+ ///
1274
+ /// Static methods don't need stub-methods except for tear-offs. As such,
1275
+ /// they are not emitted in the prototype, but directly passed here.
1276
+ ///
1277
+ /// Instance-methods install the stub-methods in their prototype, and we
1278
+ /// use string-based redirections to find them there.
1279
+ void addFunOrName (StubMethod stubMethod) {
1280
+ if (method.isStatic) {
1281
+ funsOrNames.add (stubMethod.code);
1282
+ } else {
1283
+ funsOrNames.add (js.quoteName (stubMethod.name));
1284
+ }
1285
+ }
1286
+
1287
+ callNames.add (method.callName);
1288
+ // The first entry in the funsOrNames-array must be a string.
1289
+ funsOrNames.add (js.quoteName (method.name));
1290
+ for (ParameterStubMethod stubMethod in method.parameterStubs) {
1291
+ callNames.add (stubMethod.callName);
1292
+ addFunOrName (stubMethod);
1293
+ }
1294
+
1295
+ js.ArrayInitializer callNameArray =
1296
+ new js.ArrayInitializer (callNames.map (js.quoteName).toList ());
1297
+ js.ArrayInitializer funsOrNamesArray =
1298
+ new js.ArrayInitializer (funsOrNames);
1299
+
1300
+ bool isIntercepted = false ;
1301
+ if (method is InstanceMethod ) {
1302
+ isIntercepted = method.isIntercepted;
1303
+ }
1304
+
1305
+ int requiredParameterCount = 0 ;
1306
+ js.Expression optionalParameterDefaultValues = new js.LiteralNull ();
1307
+ if (method.canBeApplied) {
1308
+ requiredParameterCount = method.requiredParameterCount;
1309
+ optionalParameterDefaultValues =
1310
+ _encodeOptionalParameterDefaultValues (method);
1311
+ }
1312
+
1313
+ var applyIndex = js.number (method.applyIndex);
1314
+
1315
+ if (method.isStatic) {
1316
+ aliasForInstallStaticTearOff ?? = '_static' ;
1317
+ return js.js.statement ('''
1318
+ #install(#container, #getterName,
1319
+ #requiredParameterCount, #optionalParameterDefaultValues,
1320
+ #callNames, #funsOrNames, #funType, #applyIndex)''' , {
1321
+ "install" : aliasForInstallStaticTearOff,
1322
+ "container" : container,
1323
+ "getterName" : js.quoteName (method.tearOffName),
1324
+ "requiredParameterCount" : js.number (requiredParameterCount),
1325
+ "optionalParameterDefaultValues" : optionalParameterDefaultValues,
1326
+ "callNames" : callNameArray,
1327
+ "funsOrNames" : funsOrNamesArray,
1328
+ "funType" : method.functionType,
1329
+ "applyIndex" : applyIndex,
1330
+ });
1331
+ } else {
1332
+ aliasForInstallInstanceTearOff ?? = '_instance' ;
1333
+ return js.js.statement ('''
1334
+ #install(#container, #getterName, #isIntercepted,
1335
+ #requiredParameterCount, #optionalParameterDefaultValues,
1336
+ #callNames, #funsOrNames, #funType, #applyIndex)''' , {
1337
+ "install" : aliasForInstallInstanceTearOff,
1338
+ "container" : container,
1339
+ "getterName" : js.quoteName (method.tearOffName),
1340
+ // 'Truthy' values are ok for `isIntercepted`.
1341
+ "isIntercepted" : js.number (isIntercepted ? 1 : 0 ),
1342
+ "requiredParameterCount" : js.number (requiredParameterCount),
1343
+ "optionalParameterDefaultValues" : optionalParameterDefaultValues,
1344
+ "callNames" : callNameArray,
1345
+ "funsOrNames" : funsOrNamesArray,
1346
+ "funType" : method.functionType,
1347
+ "applyIndex" : applyIndex,
1348
+ });
1349
+ }
1350
+ }
1351
+
1295
1352
List <js.Statement > inits = [];
1296
1353
js.Expression temp;
1297
1354
@@ -1325,6 +1382,23 @@ class FragmentEmitter {
1325
1382
}
1326
1383
}
1327
1384
}
1385
+
1386
+ List <js.VariableInitialization > locals = [];
1387
+ if (aliasForInstallStaticTearOff != null ) {
1388
+ locals.add (js.VariableInitialization (
1389
+ js.VariableDeclaration (aliasForInstallStaticTearOff),
1390
+ js.js ('hunkHelpers.installStaticTearOff' )));
1391
+ }
1392
+ if (aliasForInstallInstanceTearOff != null ) {
1393
+ locals.add (js.VariableInitialization (
1394
+ js.VariableDeclaration (aliasForInstallInstanceTearOff),
1395
+ js.js ('hunkHelpers.installInstanceTearOff' )));
1396
+ }
1397
+ if (locals.isNotEmpty) {
1398
+ inits.insert (
1399
+ 0 , js.ExpressionStatement (js.VariableDeclarationList (locals)));
1400
+ }
1401
+
1328
1402
return wrapPhase ('installTearOffs' , inits);
1329
1403
}
1330
1404
0 commit comments