Extract ModularEmitterImpl superclass from EmitterImpl

Change-Id: I7e7a87743d24e5da6401937b3983a358062a2296
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101523
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 49cc060..f28aa79 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -935,27 +935,15 @@
         : _disambiguateGlobalMember(element);
   }
 
-  /// Returns a JavaScript property name used to store the member [element] on
-  /// one of the global objects.
-  ///
-  /// Should be used together with [globalObjectForMember], which denotes the
-  /// object on which the returned property name should be used.
+  @override
   jsAst.Name globalPropertyNameForMember(MemberEntity element) =>
       _disambiguateGlobalMember(element);
 
-  /// Returns a JavaScript property name used to store the class [element] on
-  /// one of the global objects.
-  ///
-  /// Should be used together with [globalObjectForClass], which denotes the
-  /// object on which the returned property name should be used.
+  @override
   jsAst.Name globalPropertyNameForClass(ClassEntity element) =>
       _disambiguateGlobalType(element);
 
-  /// Returns a JavaScript property name used to store the type (typedef)
-  /// [element] on one of the global objects.
-  ///
-  /// Should be used together with [globalObjectForType], which denotes the
-  /// object on which the returned property name should be used.
+  @override
   jsAst.Name globalPropertyNameForType(Entity element) =>
       _disambiguateGlobalType(element);
 
@@ -1553,10 +1541,23 @@
     return globalObjectForLibrary(element.library);
   }
 
+  @override
+  jsAst.VariableUse readGlobalObjectForMember(MemberEntity element) {
+    if (_isPropertyOfStaticStateHolder(element)) {
+      return new jsAst.VariableUse(staticStateHolder);
+    }
+    return readGlobalObjectForLibrary(element.library);
+  }
+
   String globalObjectForClass(ClassEntity element) {
     return globalObjectForLibrary(element.library);
   }
 
+  @override
+  jsAst.VariableUse readGlobalObjectForClass(ClassEntity element) {
+    return readGlobalObjectForLibrary(element.library);
+  }
+
   String globalObjectForType(Entity element) {
     if (element is TypedefEntity) {
       return globalObjectForLibrary(element.library);
@@ -1564,6 +1565,14 @@
     return globalObjectForClass(element);
   }
 
+  @override
+  jsAst.VariableUse readGlobalObjectForType(Entity element) {
+    if (element is TypedefEntity) {
+      return readGlobalObjectForLibrary(element.library);
+    }
+    return readGlobalObjectForClass(element);
+  }
+
   /// Returns the [reservedGlobalObjectNames] for [library].
   String globalObjectForLibrary(LibraryEntity library) {
     if (library == _commonElements.interceptorsLibrary) return 'J';
@@ -1581,6 +1590,7 @@
     return new jsAst.VariableUse(globalObjectForLibrary(library));
   }
 
+  @override
   jsAst.Name lazyInitializerName(FieldEntity element) {
     assert(element.isTopLevel || element.isStatic);
     jsAst.Name name = _disambiguateGlobal<MemberEntity>(
@@ -1588,6 +1598,7 @@
     return name;
   }
 
+  @override
   jsAst.Name staticClosureName(FunctionEntity element) {
     assert(element.isTopLevel || element.isStatic);
     String enclosing =
@@ -2335,9 +2346,48 @@
 
 /// Namer interface that can be used in modular code generation.
 abstract class ModularNamer {
-  /// Returns a variable use of the [reservedGlobalObjectNames] for [library].
+  /// Returns a variable use for accessing [library].
+  ///
+  /// This is one of the [reservedGlobalObjectNames]
   jsAst.VariableUse readGlobalObjectForLibrary(LibraryEntity library);
 
+  /// Returns a variable use for accessing the class [element].
+  ///
+  /// This is one of the [reservedGlobalObjectNames]
+  jsAst.VariableUse readGlobalObjectForClass(ClassEntity element);
+
+  /// Returns a variable use for accessing the type [element].
+  ///
+  /// This is one of the [reservedGlobalObjectNames]
+  jsAst.VariableUse readGlobalObjectForType(Entity element);
+
+  /// Returns a variable use for accessing the member [element].
+  ///
+  /// This is either the [staticStateHolder] or one of the
+  /// [reservedGlobalObjectNames]
+  jsAst.VariableUse readGlobalObjectForMember(MemberEntity element);
+
+  /// Returns a JavaScript property name used to store the class [element] on
+  /// one of the global objects.
+  ///
+  /// Should be used together with [globalObjectForClass], which denotes the
+  /// object on which the returned property name should be used.
+  jsAst.Name globalPropertyNameForClass(ClassEntity element);
+
+  /// Returns a JavaScript property name used to store the member [element] on
+  /// one of the global objects.
+  ///
+  /// Should be used together with [globalObjectForMember], which denotes the
+  /// object on which the returned property name should be used.
+  jsAst.Name globalPropertyNameForMember(MemberEntity element);
+
+  /// Returns a JavaScript property name used to store the type (typedef)
+  /// [element] on one of the global objects.
+  ///
+  /// Should be used together with [globalObjectForType], which denotes the
+  /// object on which the returned property name should be used.
+  jsAst.Name globalPropertyNameForType(Entity element);
+
   /// Returns the name for the instance field that holds runtime type arguments
   /// on generic classes.
   jsAst.Name get rtiFieldJsName;
@@ -2387,8 +2437,6 @@
   /// collisions.
   jsAst.Name nameForGetInterceptor(Iterable<ClassEntity> classes);
 
-  jsAst.Name operatorIsType(DartType type);
-
   /// Returns the runtime name for [element].
   ///
   /// This name is used as the basis for deriving `is` and `as` property names
@@ -2429,10 +2477,19 @@
   /// [element].
   jsAst.Name operatorIs(ClassEntity element);
 
+  /// Return the name of the `isX` property for classes that implement [type].
+  jsAst.Name operatorIsType(DartType type);
+
   /// Returns the name of the `asX` function for classes that implement the
   /// generic class [element].
   jsAst.Name substitutionName(ClassEntity element);
 
+  /// Returns the name of the lazy initializer for the static field [element].
+  jsAst.Name lazyInitializerName(FieldEntity element);
+
+  /// Returns the name of the closure of the static method [element].
+  jsAst.Name staticClosureName(FunctionEntity element);
+
   /// Returns the label name for [label] used as a break target.
   String breakLabelName(LabelDefinition label) {
     return '\$${label.labelName}\$${label.target.nestingLevel}';
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index b04b3cb..99a79d1 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -168,7 +168,7 @@
   jsAst.Expression isolateLazyInitializerAccess(covariant FieldEntity element);
 
   /// Returns the closure expression of a static function.
-  jsAst.Expression isolateStaticClosureAccess(covariant FunctionEntity element);
+  jsAst.Expression staticClosureAccess(covariant FunctionEntity element);
 
   /// Returns the JS constructor of the given element.
   ///
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index c82d0aa..a2095b5 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -16,21 +16,98 @@
 import '../../elements/entities.dart';
 import '../../io/source_information.dart';
 import '../../js/js.dart' as js;
-import '../../js_backend/js_backend.dart' show Namer;
+import '../../js_backend/js_backend.dart' show ModularNamer, Namer;
 import '../../js_backend/runtime_types.dart';
 import '../../options.dart';
 import '../../universe/codegen_world_builder.dart' show CodegenWorld;
 import '../../world.dart' show JClosedWorld;
-import '../js_emitter.dart' show Emitter;
+import '../js_emitter.dart' show Emitter, ModularEmitter;
 import '../model.dart';
 import '../program_builder/program_builder.dart' show ProgramBuilder;
 import 'model_emitter.dart';
 
-class EmitterImpl implements Emitter {
+class ModularEmitterImpl implements ModularEmitter {
+  final ModularNamer _namer;
+
+  ModularEmitterImpl(this._namer);
+
+  js.PropertyAccess globalPropertyAccessForClass(ClassEntity element) {
+    js.Name name = _namer.globalPropertyNameForClass(element);
+    js.PropertyAccess pa =
+        new js.PropertyAccess(_namer.readGlobalObjectForClass(element), name);
+    return pa;
+  }
+
+  js.PropertyAccess globalPropertyAccessForType(Entity element) {
+    js.Name name = _namer.globalPropertyNameForType(element);
+    js.PropertyAccess pa =
+        new js.PropertyAccess(_namer.readGlobalObjectForType(element), name);
+    return pa;
+  }
+
+  js.PropertyAccess globalPropertyAccessForMember(MemberEntity element) {
+    js.Name name = _namer.globalPropertyNameForMember(element);
+    js.PropertyAccess pa =
+        new js.PropertyAccess(_namer.readGlobalObjectForMember(element), name);
+    return pa;
+  }
+
+  @override
+  js.PropertyAccess constructorAccess(ClassEntity element) {
+    return globalPropertyAccessForClass(element);
+  }
+
+  @override
+  js.Expression isolateLazyInitializerAccess(FieldEntity element) {
+    return new js.PropertyAccess(_namer.readGlobalObjectForMember(element),
+        _namer.lazyInitializerName(element));
+  }
+
+  @override
+  js.PropertyAccess staticFunctionAccess(FunctionEntity element) {
+    return globalPropertyAccessForMember(element);
+  }
+
+  @override
+  js.PropertyAccess staticFieldAccess(FieldEntity element) {
+    return globalPropertyAccessForMember(element);
+  }
+
+  @override
+  js.PropertyAccess prototypeAccess(ClassEntity element,
+      {bool hasBeenInstantiated}) {
+    js.Expression constructor =
+        hasBeenInstantiated ? constructorAccess(element) : typeAccess(element);
+    return js.js('#.prototype', constructor);
+  }
+
+  js.Expression typeAccess(Entity element) {
+    return globalPropertyAccessForType(element);
+  }
+
+  @override
+  js.Expression staticClosureAccess(FunctionEntity element) {
+    return new js.Call(
+        new js.PropertyAccess(_namer.readGlobalObjectForMember(element),
+            _namer.staticClosureName(element)),
+        const []);
+  }
+
+  @override
+  js.Expression constantReference(ConstantValue constant) {
+    throw new UnimplementedError("ModularEmitter.constantReference");
+  }
+
+  @override
+  js.Expression generateEmbeddedGlobalAccess(String global) {
+    throw new UnimplementedError("ModularEmitter.generateEmbeddedGlobalAccess");
+  }
+}
+
+class EmitterImpl extends ModularEmitterImpl implements Emitter {
   final DiagnosticReporter _reporter;
   final JClosedWorld _closedWorld;
   final RuntimeTypesEncoder _rtiEncoder;
-  final Namer namer;
   ModelEmitter _emitter;
 
   @override
@@ -41,12 +118,13 @@
       this._reporter,
       CompilerOutput outputProvider,
       DumpInfoTask dumpInfoTask,
-      this.namer,
+      Namer namer,
       this._closedWorld,
       this._rtiEncoder,
       SourceInformationStrategy sourceInformationStrategy,
       CompilerTask task,
-      bool shouldGenerateSourceMap) {
+      bool shouldGenerateSourceMap)
+      : super(namer) {
     _emitter = new ModelEmitter(
         options,
         _reporter,
@@ -62,6 +140,9 @@
   }
 
   @override
+  Namer get _namer => super._namer;
+
+  @override
   int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld) {
     Program program = programBuilder.buildProgram();
     if (retainDataForTesting) {
@@ -70,53 +151,12 @@
     return _emitter.emitProgram(program, codegenWorld);
   }
 
-  js.PropertyAccess globalPropertyAccessForMember(MemberEntity element) {
-    js.Name name = namer.globalPropertyNameForMember(element);
-    js.PropertyAccess pa = new js.PropertyAccess(
-        new js.VariableUse(namer.globalObjectForMember(element)), name);
-    return pa;
-  }
-
-  js.PropertyAccess globalPropertyAccessForClass(ClassEntity element) {
-    js.Name name = namer.globalPropertyNameForClass(element);
-    js.PropertyAccess pa = new js.PropertyAccess(
-        new js.VariableUse(namer.globalObjectForClass(element)), name);
-    return pa;
-  }
-
-  js.PropertyAccess globalPropertyAccessForType(Entity element) {
-    js.Name name = namer.globalPropertyNameForType(element);
-    js.PropertyAccess pa = new js.PropertyAccess(
-        new js.VariableUse(namer.globalObjectForType(element)), name);
-    return pa;
-  }
-
-  @override
-  js.PropertyAccess staticFieldAccess(FieldEntity element) {
-    return globalPropertyAccessForMember(element);
-  }
-
-  @override
-  js.PropertyAccess staticFunctionAccess(FunctionEntity element) {
-    return globalPropertyAccessForMember(element);
-  }
-
-  @override
-  js.PropertyAccess constructorAccess(ClassEntity element) {
-    return globalPropertyAccessForClass(element);
-  }
-
   @override
   js.Expression interceptorClassAccess(ClassEntity element) {
     return globalPropertyAccessForClass(element);
   }
 
   @override
-  js.Expression typeAccess(Entity element) {
-    return globalPropertyAccessForType(element);
-  }
-
-  @override
   bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
     return _emitter.isConstantInlinedOrAlreadyEmitted(constant);
   }
@@ -143,27 +183,6 @@
   }
 
   @override
-  js.Expression isolateLazyInitializerAccess(FieldEntity element) {
-    return js.js('#.#', [
-      namer.globalObjectForMember(element),
-      namer.lazyInitializerName(element)
-    ]);
-  }
-
-  @override
-  js.Expression isolateStaticClosureAccess(FunctionEntity element) {
-    return _emitter.generateStaticClosureAccess(element);
-  }
-
-  @override
-  js.PropertyAccess prototypeAccess(ClassEntity element,
-      {bool hasBeenInstantiated}) {
-    js.Expression constructor =
-        hasBeenInstantiated ? constructorAccess(element) : typeAccess(element);
-    return js.js('#.prototype', constructor);
-  }
-
-  @override
   js.Expression interceptorPrototypeAccess(ClassEntity e) {
     return js.js('#.prototype', interceptorClassAccess(e));
   }
@@ -176,7 +195,7 @@
         return js.js.expressionTemplateYielding(typeAccess(objectClass));
 
       case JsBuiltin.isCheckPropertyToJsConstructorName:
-        int isPrefixLength = namer.operatorIsPrefix.length;
+        int isPrefixLength = _namer.operatorIsPrefix.length;
         return js.js.expressionTemplateFor('#.substring($isPrefixLength)');
 
       case JsBuiltin.isFunctionType:
@@ -203,7 +222,7 @@
       case JsBuiltin.isSubtype:
         // TODO(floitsch): move this closer to where is-check properties are
         // built.
-        String isPrefix = namer.operatorIsPrefix;
+        String isPrefix = _namer.operatorIsPrefix;
         return js.js.expressionTemplateFor("('$isPrefix' + #) in #.prototype");
 
       case JsBuiltin.isGivenTypeRti:
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 8dcae67..5d3f455 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -155,17 +155,10 @@
     return _constantOrdering.compare(a, b);
   }
 
-  js.Expression generateStaticClosureAccess(FunctionEntity element) {
-    return js.js('#.#()', [
-      _namer.globalObjectForMember(element),
-      _namer.staticClosureName(element)
-    ]);
-  }
-
   js.Expression generateConstantReference(ConstantValue value) {
     if (value.isFunction) {
       FunctionConstantValue functionConstant = value;
-      return generateStaticClosureAccess(functionConstant.element);
+      return _emitter.staticClosureAccess(functionConstant.element);
     }
 
     // We are only interested in the "isInlined" part, but it does not hurt to
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3072911..80e28c7 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2641,7 +2641,7 @@
     assert(element.isFunction || element.isField);
     if (element.isFunction) {
       push(_emitter
-          .isolateStaticClosureAccess(element)
+          .staticClosureAccess(element)
           .withSourceInformation(node.sourceInformation));
       _registry.registerStaticUse(new StaticUse.staticTearOff(element));
     } else {