@@ -32,13 +32,12 @@ import 'nullable_inference.dart';
3232import 'property_model.dart' ;
3333import 'type_table.dart' ;
3434
35- class ProgramCompiler extends Object
35+ class ProgramCompiler extends ComputeOnceConstantVisitor <js_ast. Expression >
3636 with SharedCompiler <Library , Class , InterfaceType , FunctionNode >
3737 implements
3838 StatementVisitor <js_ast.Statement >,
3939 ExpressionVisitor <js_ast.Expression >,
40- DartTypeVisitor <js_ast.Expression >,
41- ConstantVisitor <js_ast.Expression > {
40+ DartTypeVisitor <js_ast.Expression > {
4241 final SharedCompilerOptions _options;
4342
4443 /// Maps a library URI import, that is not in [_libraries] , to the
@@ -62,6 +61,16 @@ class ProgramCompiler extends Object
6261 /// Let variables collected for the given function.
6362 List <js_ast.TemporaryId > _letVariables;
6463
64+ final _constTable = js_ast.TemporaryId ("CT" );
65+
66+ // Constant getters used to populate the constant table.
67+ final _constLazyAccessors = List <js_ast.Method >();
68+
69+ /// Tracks the index in [moduleItems] where the const table must be inserted.
70+ /// Required for SDK builds due to internal circular dependencies.
71+ /// E.g., dart.constList depends on JSArray.
72+ int _constTableInsertionIndex = 0 ;
73+
6574 /// The class that is emitting its base class or mixin references, otherwise
6675 /// null.
6776 ///
@@ -185,6 +194,9 @@ class ProgramCompiler extends Object
185194 /// as targets for continue and break.
186195 final _switchLabelStates = HashMap <Statement , _SwitchLabelState >();
187196
197+ /// Maps Kernel constants to their JS aliases.
198+ final constAliasCache = HashMap <Constant , js_ast.Expression >();
199+
188200 final Class _jsArrayClass;
189201 final Class _privateSymbolClass;
190202 final Class _linkedHashMapImplClass;
@@ -287,6 +299,11 @@ class ProgramCompiler extends Object
287299 _pendingClasses.addAll (l.classes);
288300 }
289301
302+ // TODO(markzipan): Don't emit this when compiling the SDK.
303+ moduleItems
304+ .add (js.statement ("const # = Object.create(null);" , [_constTable]));
305+ _constTableInsertionIndex = moduleItems.length;
306+
290307 // Add implicit dart:core dependency so it is first.
291308 emitLibraryName (_coreTypes.coreLibrary);
292309
@@ -297,6 +314,15 @@ class ProgramCompiler extends Object
297314 // This is done by forward declaring items.
298315 libraries.forEach (_emitLibrary);
299316
317+ // This can cause problems if it's ever true during the SDK build, as it's
318+ // emitted before dart.defineLazy.
319+ if (_constLazyAccessors.isNotEmpty) {
320+ var constTableBody = runtimeStatement (
321+ 'defineLazy(#, { # })' , [_constTable, _constLazyAccessors]);
322+ moduleItems.insert (_constTableInsertionIndex, constTableBody);
323+ _constLazyAccessors.clear ();
324+ }
325+
300326 moduleItems.addAll (afterClassDefItems);
301327 afterClassDefItems.clear ();
302328
@@ -445,6 +471,11 @@ class ProgramCompiler extends Object
445471
446472 moduleItems.add (_emitClassDeclaration (c));
447473
474+ // The const table depends on dart.defineLazy, so emit it after the SDK.
475+ if (isSdkInternalRuntime (_currentLibrary)) {
476+ _constTableInsertionIndex = moduleItems.length;
477+ }
478+
448479 _currentClass = savedClass;
449480 _types.thisType = savedClass? .thisType;
450481 _currentLibrary = savedLibrary;
@@ -2083,12 +2114,11 @@ class ProgramCompiler extends Object
20832114 }
20842115
20852116 js_ast.Fun _emitStaticFieldInitializer (Field field) {
2086- return js_ast.Fun (
2087- [],
2088- js_ast.Block (_withLetScope (() => [
2089- js_ast.Return (
2090- _visitInitializer (field.initializer, field.annotations))
2091- ])));
2117+ return js_ast.Fun ([], js_ast.Block (_withLetScope (() {
2118+ return [
2119+ js_ast.Return (_visitInitializer (field.initializer, field.annotations))
2120+ ];
2121+ })));
20922122 }
20932123
20942124 List <js_ast.Statement > _withLetScope (List <js_ast.Statement > visitBody ()) {
@@ -3101,6 +3131,9 @@ class ProgramCompiler extends Object
31013131
31023132 js_ast.Expression _visitExpression (Expression e) {
31033133 if (e == null ) return null ;
3134+ if (e is ConstantExpression ) {
3135+ return visitConstant (e.constant);
3136+ }
31043137 var result = e.accept (this ) as js_ast.Expression ;
31053138 result.sourceInformation ?? = _nodeStart (e);
31063139 return result;
@@ -3780,7 +3813,15 @@ class ProgramCompiler extends Object
37803813
37813814 @override
37823815 js_ast.Expression visitConstantExpression (ConstantExpression node) =>
3783- node.constant.accept (this ) as js_ast.Expression ;
3816+ visitConstant (node.constant);
3817+
3818+ @override
3819+ js_ast.Expression canonicalizeConstObject (js_ast.Expression expr) {
3820+ if (isSdkInternalRuntime (_currentLibrary)) {
3821+ return super .canonicalizeConstObject (expr);
3822+ }
3823+ return runtimeCall ('const(#)' , [expr]);
3824+ }
37843825
37853826 @override
37863827 js_ast.Expression visitVariableGet (VariableGet node) {
@@ -4725,7 +4766,7 @@ class ProgramCompiler extends Object
47254766 if (isFromEnvironmentInvocation (_coreTypes, node)) {
47264767 var value = _constants.evaluate (node);
47274768 if (value is PrimitiveConstant ) {
4728- return value. accept ( this ) as js_ast. Expression ;
4769+ return visitConstant (value) ;
47294770 }
47304771 }
47314772
@@ -4864,7 +4905,7 @@ class ProgramCompiler extends Object
48644905 node.accept (this );
48654906 if (node is ConstantExpression ) {
48664907 var list = node.constant as ListConstant ;
4867- entries.addAll (list.entries.map (_visitConstant ));
4908+ entries.addAll (list.entries.map (visitConstant ));
48684909 } else if (node is ListLiteral ) {
48694910 entries.addAll (node.expressions.map (_visitExpression));
48704911 }
@@ -4886,7 +4927,7 @@ class ProgramCompiler extends Object
48864927 node.accept (this );
48874928 if (node is ConstantExpression ) {
48884929 var set = node.constant as SetConstant ;
4889- entries.addAll (set .entries.map (_visitConstant ));
4930+ entries.addAll (set .entries.map (visitConstant ));
48904931 } else if (node is SetLiteral ) {
48914932 entries.addAll (node.expressions.map (_visitExpression));
48924933 }
@@ -4909,8 +4950,8 @@ class ProgramCompiler extends Object
49094950 if (node is ConstantExpression ) {
49104951 var map = node.constant as MapConstant ;
49114952 for (var entry in map.entries) {
4912- entries.add (_visitConstant (entry.key));
4913- entries.add (_visitConstant (entry.value));
4953+ entries.add (visitConstant (entry.key));
4954+ entries.add (visitConstant (entry.value));
49144955 }
49154956 } else if (node is MapLiteral ) {
49164957 for (var entry in node.entries) {
@@ -5032,11 +5073,7 @@ class ProgramCompiler extends Object
50325073 js_ast.Expression visitListLiteral (ListLiteral node) {
50335074 var elementType = node.typeArgument;
50345075 var elements = _visitExpressionList (node.expressions);
5035- // TODO(markzipan): remove const check when we use front-end const eval
5036- if (! node.isConst) {
5037- return _emitList (elementType, elements);
5038- }
5039- return _emitConstList (elementType, elements);
5076+ return _emitList (elementType, elements);
50405077 }
50415078
50425079 js_ast.Expression _emitList (
@@ -5270,8 +5307,48 @@ class ProgramCompiler extends Object
52705307 findAnnotation (node, test), 'name' ) as String ;
52715308 }
52725309
5273- js_ast.Expression _visitConstant (Constant node) =>
5274- node.accept (this ) as js_ast.Expression ;
5310+ @override
5311+ js_ast.Expression cacheConst (js_ast.Expression jsExpr) {
5312+ if (isSdkInternalRuntime (_currentLibrary)) {
5313+ return super .cacheConst (jsExpr);
5314+ }
5315+ return jsExpr;
5316+ }
5317+
5318+ @override
5319+ js_ast.Expression visitConstant (Constant node) {
5320+ if (node is TearOffConstant ) {
5321+ // JS() or JS interop functions should not be lazily loaded.
5322+ if (node.procedure.isExternal || _isInForeignJS) {
5323+ return _emitStaticTarget (node.procedure);
5324+ }
5325+ }
5326+ if (isSdkInternalRuntime (_currentLibrary) || node is PrimitiveConstant ) {
5327+ return super .visitConstant (node);
5328+ }
5329+ var constAlias = constAliasCache[node];
5330+ if (constAlias != null ) {
5331+ return constAlias;
5332+ }
5333+ var constAliasString = "C${constAliasCache .length }" ;
5334+ var constAliasProperty = propertyName (constAliasString);
5335+ var constAliasId = js_ast.TemporaryId (constAliasString);
5336+ var constAccessor =
5337+ js.call ("# || #.#" , [constAliasId, _constTable, constAliasProperty]);
5338+ constAliasCache[node] = constAccessor;
5339+ var constJs = super .visitConstant (node);
5340+ moduleItems.add (js.statement ('let #;' , [constAliasId]));
5341+
5342+ var func = js_ast.Fun (
5343+ [],
5344+ js_ast.Block ([
5345+ js.statement ("return # = #;" , [constAliasId, constJs])
5346+ ]));
5347+ var accessor = js_ast.Method (constAliasProperty, func, isGetter: true );
5348+ _constLazyAccessors.add (accessor);
5349+ return constAccessor;
5350+ }
5351+
52755352 @override
52765353 js_ast.Expression visitNullConstant (NullConstant node) =>
52775354 js_ast.LiteralNull ();
@@ -5324,25 +5401,26 @@ class ProgramCompiler extends Object
53245401 js_ast.Expression visitMapConstant (MapConstant node) {
53255402 var entries = [
53265403 for (var e in node.entries) ...[
5327- _visitConstant (e.key),
5328- _visitConstant (e.value),
5404+ visitConstant (e.key),
5405+ visitConstant (e.value),
53295406 ],
53305407 ];
53315408 return _emitConstMap (node.keyType, node.valueType, entries);
53325409 }
53335410
53345411 @override
53355412 js_ast.Expression visitListConstant (ListConstant node) => _emitConstList (
5336- node.typeArgument, node.entries.map (_visitConstant ).toList ());
5413+ node.typeArgument, node.entries.map (visitConstant ).toList ());
53375414
53385415 @override
53395416 js_ast.Expression visitSetConstant (SetConstant node) => _emitConstSet (
5340- node.typeArgument, node.entries.map (_visitConstant ).toList ());
5417+ node.typeArgument, node.entries.map (visitConstant ).toList ());
53415418
53425419 @override
53435420 js_ast.Expression visitInstanceConstant (InstanceConstant node) {
5421+ _declareBeforeUse (node.classNode);
53445422 entryToProperty (MapEntry <Reference , Constant > entry) {
5345- var constant = entry.value. accept ( this ) as js_ast. Expression ;
5423+ var constant = visitConstant ( entry.value) ;
53465424 var member = entry.key.asField;
53475425 return js_ast.Property (
53485426 _emitMemberName (member.name.name, member: member), constant);
@@ -5359,20 +5437,22 @@ class ProgramCompiler extends Object
53595437 }
53605438
53615439 @override
5362- js_ast.Expression visitTearOffConstant (TearOffConstant node) =>
5363- _emitStaticGet (node.procedure);
5440+ js_ast.Expression visitTearOffConstant (TearOffConstant node) {
5441+ _declareBeforeUse (node.procedure.enclosingClass);
5442+ return _emitStaticGet (node.procedure);
5443+ }
53645444
53655445 @override
53665446 js_ast.Expression visitTypeLiteralConstant (TypeLiteralConstant node) =>
53675447 _emitTypeLiteral (node.type);
53685448
53695449 @override
53705450 js_ast.Expression visitPartialInstantiationConstant (
5371- PartialInstantiationConstant node) =>
5372- runtimeCall ('gbind(#, #)' , [
5373- _visitConstant (node.tearOffConstant),
5374- node.types.map (_emitType).toList ()
5375- ]);
5451+ PartialInstantiationConstant node) =>
5452+ runtimeCall ('gbind(#, #)' , [
5453+ visitConstant (node.tearOffConstant),
5454+ node.types.map (_emitType).toList ()
5455+ ]);
53765456
53775457 @override
53785458 js_ast.Expression visitUnevaluatedConstant (UnevaluatedConstant node) =>
0 commit comments