Decouple startup emitter from compiler/backend

Change-Id: I5220cbf6c6ce6369787b2eed33e952dc694128a5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101294
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0073f8c..dc1a2b4 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -658,7 +658,7 @@
     processor.extractJsInteropAnnotations(library);
     Uri uri = library.canonicalUri;
     if (uri == Uris.dart_html) {
-      htmlLibraryIsLoaded = true;
+      _backendUsageBuilder.registerHtmlIsLoaded();
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index 09ce162..ad3877c 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -53,6 +53,10 @@
 
   /// `true` if `noSuchMethod` is used.
   bool get isNoSuchMethodUsed;
+
+  /// `true` if the `dart:html` is loaded.
+  // TODO(johnniwinther): This is always `true` with the CFE.
+  bool get isHtmlLoaded;
 }
 
 abstract class BackendUsageBuilder {
@@ -90,6 +94,9 @@
   /// `true` if `noSuchMethod` is used.
   bool isNoSuchMethodUsed;
 
+  /// Register that `dart:html` is loaded.
+  void registerHtmlIsLoaded();
+
   BackendUsage close();
 }
 
@@ -122,6 +129,8 @@
   @override
   bool isNoSuchMethodUsed = false;
 
+  bool isHtmlLoaded = false;
+
   BackendUsageBuilderImpl(this._frontendStrategy);
 
   KCommonElements get _commonElements => _frontendStrategy.commonElements;
@@ -261,6 +270,11 @@
   }
 
   @override
+  void registerHtmlIsLoaded() {
+    isHtmlLoaded = true;
+  }
+
+  @override
   BackendUsage close() {
     return new BackendUsageImpl(
         globalFunctionDependencies: _globalFunctionDependencies,
@@ -273,7 +287,8 @@
         runtimeTypeUses: _runtimeTypeUses,
         isFunctionApplyUsed: isFunctionApplyUsed,
         isMirrorsUsed: isMirrorsUsed,
-        isNoSuchMethodUsed: isNoSuchMethodUsed);
+        isNoSuchMethodUsed: isNoSuchMethodUsed,
+        isHtmlLoaded: isHtmlLoaded);
   }
 }
 
@@ -311,6 +326,9 @@
   @override
   final bool isNoSuchMethodUsed;
 
+  @override
+  final bool isHtmlLoaded;
+
   BackendUsageImpl(
       {Set<FunctionEntity> globalFunctionDependencies,
       Set<ClassEntity> globalClassDependencies,
@@ -322,7 +340,8 @@
       Set<RuntimeTypeUse> runtimeTypeUses,
       this.isFunctionApplyUsed,
       this.isMirrorsUsed,
-      this.isNoSuchMethodUsed})
+      this.isNoSuchMethodUsed,
+      this.isHtmlLoaded})
       : this._globalFunctionDependencies = globalFunctionDependencies,
         this._globalClassDependencies = globalClassDependencies,
         this._helperFunctionsUsed = helperFunctionsUsed,
@@ -349,6 +368,7 @@
     bool isFunctionApplyUsed = source.readBool();
     bool isMirrorsUsed = source.readBool();
     bool isNoSuchMethodUsed = source.readBool();
+    bool isHtmlLoaded = source.readBool();
     source.end(tag);
     return new BackendUsageImpl(
         globalFunctionDependencies: globalFunctionDependencies,
@@ -361,7 +381,8 @@
         requiresPreamble: requiresPreamble,
         isFunctionApplyUsed: isFunctionApplyUsed,
         isMirrorsUsed: isMirrorsUsed,
-        isNoSuchMethodUsed: isNoSuchMethodUsed);
+        isNoSuchMethodUsed: isNoSuchMethodUsed,
+        isHtmlLoaded: isHtmlLoaded);
   }
 
   @override
@@ -382,6 +403,7 @@
     sink.writeBool(isFunctionApplyUsed);
     sink.writeBool(isMirrorsUsed);
     sink.writeBool(isNoSuchMethodUsed);
+    sink.writeBool(isHtmlLoaded);
     sink.end(tag);
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 8976841..b596d65 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -24,7 +24,7 @@
 
 /// Generates the JavaScript expressions for constants.
 ///
-/// It uses a given [constantReferenceGenerator] to reference nested constants
+/// It uses a given [_constantReferenceGenerator] to reference nested constants
 /// (if there are some). It is hence up to that function to decide which
 /// constants should be inlined or not.
 class ConstantEmitter implements ConstantValueVisitor<jsAst.Expression, Null> {
@@ -39,11 +39,11 @@
   final RuntimeTypesNeed _rtiNeed;
   final RuntimeTypesEncoder _rtiEncoder;
   final JFieldAnalysis _fieldAnalysis;
-  final CodeEmitterTask _task;
-  final _ConstantReferenceGenerator constantReferenceGenerator;
-  final _ConstantListGenerator makeConstantList;
+  final Emitter _emitter;
+  final _ConstantReferenceGenerator _constantReferenceGenerator;
+  final _ConstantListGenerator _makeConstantList;
 
-  /// The given [constantReferenceGenerator] function must, when invoked with a
+  /// The given [_constantReferenceGenerator] function must, when invoked with a
   /// constant, either return a reference or return its literal expression if it
   /// can be inlined.
   ConstantEmitter(
@@ -53,11 +53,9 @@
       this._rtiNeed,
       this._rtiEncoder,
       this._fieldAnalysis,
-      this._task,
-      this.constantReferenceGenerator,
-      this.makeConstantList);
-
-  Emitter get _emitter => _task.emitter;
+      this._emitter,
+      this._constantReferenceGenerator,
+      this._makeConstantList);
 
   /// Constructs a literal expression that evaluates to the constant. Uses a
   /// canonical name unless the constant can be emitted multiple times (as for
@@ -176,10 +174,10 @@
   @override
   jsAst.Expression visitList(ListConstantValue constant, [_]) {
     List<jsAst.Expression> elements = constant.entries
-        .map(constantReferenceGenerator)
+        .map(_constantReferenceGenerator)
         .toList(growable: false);
     jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements);
-    jsAst.Expression value = makeConstantList(array);
+    jsAst.Expression value = _makeConstantList(array);
     return maybeAddTypeArguments(constant, constant.type, value);
   }
 
@@ -195,7 +193,7 @@
     }
 
     List<jsAst.Expression> arguments = <jsAst.Expression>[
-      constantReferenceGenerator(constant.entries),
+      _constantReferenceGenerator(constant.entries),
     ];
 
     if (_rtiNeed.classNeedsTypeArguments(classElement)) {
@@ -221,7 +219,7 @@
         // Keys in literal maps must be emitted in place.
         jsAst.Literal keyExpression = _visit(key);
         jsAst.Expression valueExpression =
-            constantReferenceGenerator(constant.values[i]);
+            _constantReferenceGenerator(constant.values[i]);
         properties.add(new jsAst.Property(keyExpression, valueExpression));
       }
       return new jsAst.ObjectInitializer(properties);
@@ -231,9 +229,9 @@
       List<jsAst.Expression> data = <jsAst.Expression>[];
       for (int i = 0; i < constant.keys.length; i++) {
         jsAst.Expression keyExpression =
-            constantReferenceGenerator(constant.keys[i]);
+            _constantReferenceGenerator(constant.keys[i]);
         jsAst.Expression valueExpression =
-            constantReferenceGenerator(constant.values[i]);
+            _constantReferenceGenerator(constant.values[i]);
         data.add(keyExpression);
         data.add(valueExpression);
       }
@@ -259,11 +257,11 @@
         arguments.add(jsMap());
       } else if (field.name ==
           constant_system.JavaScriptMapConstant.KEYS_NAME) {
-        arguments.add(constantReferenceGenerator(constant.keyList));
+        arguments.add(_constantReferenceGenerator(constant.keyList));
       } else if (field.name ==
           constant_system.JavaScriptMapConstant.PROTO_VALUE) {
         assert(constant.protoValue != null);
-        arguments.add(constantReferenceGenerator(constant.protoValue));
+        arguments.add(_constantReferenceGenerator(constant.protoValue));
       } else if (field.name ==
           constant_system.JavaScriptMapConstant.JS_DATA_NAME) {
         arguments.add(jsGeneralMap());
@@ -353,7 +351,7 @@
       FieldAnalysisData fieldData = _fieldAnalysis.getFieldData(field);
       if (fieldData.isElided) return;
       if (!fieldData.isInitializedInAllocator) {
-        fields.add(constantReferenceGenerator(constant.fields[field]));
+        fields.add(_constantReferenceGenerator(constant.fields[field]));
       }
     });
     if (_rtiNeed.classNeedsTypeArguments(constant.type.element)) {
@@ -368,7 +366,7 @@
     ClassEntity cls =
         _commonElements.getInstantiationClass(constant.typeArguments.length);
     List<jsAst.Expression> fields = <jsAst.Expression>[
-      constantReferenceGenerator(constant.function),
+      _constantReferenceGenerator(constant.function),
       _reifiedTypeArguments(constant, constant.typeArguments)
     ];
     jsAst.Expression constructor = _emitter.constructorAccess(cls);
@@ -412,6 +410,6 @@
   @override
   jsAst.Expression visitDeferredGlobal(DeferredGlobalConstantValue constant,
       [_]) {
-    return constantReferenceGenerator(constant.referenced);
+    return _constantReferenceGenerator(constant.referenced);
   }
 }
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 67fd3bd..74afc24 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -34,11 +34,11 @@
   TypeTestRegistry typeTestRegistry;
   NativeEmitter _nativeEmitter;
   MetadataCollector metadataCollector;
-  final EmitterFactory _emitterFactory;
   Emitter _emitter;
-  final Compiler compiler;
+  final Compiler _compiler;
+  final bool _generateSourceMap;
 
-  JavaScriptBackend get backend => compiler.backend;
+  JavaScriptBackend get _backend => _compiler.backend;
 
   @deprecated
   // This field should be removed. It's currently only needed for dump-info and
@@ -47,11 +47,8 @@
   /// Contains a list of all classes that are emitted.
   Set<ClassEntity> neededClasses;
 
-  CodeEmitterTask(Compiler compiler, bool generateSourceMap)
-      : compiler = compiler,
-        _emitterFactory = startup_js_emitter.EmitterFactory(
-            generateSourceMap: generateSourceMap),
-        super(compiler.measurer);
+  CodeEmitterTask(this._compiler, this._generateSourceMap)
+      : super(_compiler.measurer);
 
   NativeEmitter get nativeEmitter {
     assert(
@@ -70,33 +67,40 @@
   @override
   String get name => 'Code emitter';
 
-  /// Returns true, if the emitter supports reflection.
-  bool get supportsReflection => _emitterFactory.supportsReflection;
-
   void _finalizeRti(CodegenInputs codegen, CodegenWorld codegenWorld) {
     // Compute the required type checks to know which classes need a
     // 'is$' method.
     typeTestRegistry.computeRequiredTypeChecks(
-        backend.rtiChecksBuilder, codegenWorld);
+        _backend.rtiChecksBuilder, codegenWorld);
     // Compute the classes needed by RTI.
     typeTestRegistry.computeRtiNeededClasses(
-        codegen.rtiSubstitutions, backend.generatedCode.keys);
+        codegen.rtiSubstitutions, _backend.generatedCode.keys);
   }
 
   /// Creates the [Emitter] for this task.
   void createEmitter(Namer namer, JClosedWorld closedWorld) {
     measure(() {
       _nativeEmitter =
-          new NativeEmitter(this, closedWorld, backend.nativeCodegenEnqueuer);
-      _emitter = _emitterFactory.createEmitter(this, namer, closedWorld);
+          new NativeEmitter(this, closedWorld, _backend.nativeCodegenEnqueuer);
+      _emitter = new startup_js_emitter.EmitterImpl(
+          _compiler.options,
+          _compiler.reporter,
+          _compiler.outputProvider,
+          _compiler.dumpInfoTask,
+          namer,
+          closedWorld,
+          _backend.rtiEncoder,
+          _backend.sourceInformationStrategy,
+          this,
+          _generateSourceMap);
       metadataCollector = new MetadataCollector(
-          compiler.options,
-          compiler.reporter,
+          _compiler.options,
+          _compiler.reporter,
           _emitter,
-          backend.rtiEncoder,
+          _backend.rtiEncoder,
           closedWorld.elementEnvironment);
       typeTestRegistry = new TypeTestRegistry(
-          compiler.options, closedWorld.elementEnvironment);
+          _compiler.options, closedWorld.elementEnvironment);
     });
   }
 
@@ -109,13 +113,13 @@
     return measure(() {
       _finalizeRti(codegen, codegenWorld);
       ProgramBuilder programBuilder = new ProgramBuilder(
-          compiler.options,
-          compiler.reporter,
+          _compiler.options,
+          _compiler.reporter,
           closedWorld.elementEnvironment,
           closedWorld.commonElements,
           closedWorld.outputUnitData,
           codegenWorld,
-          backend.nativeCodegenEnqueuer,
+          _backend.nativeCodegenEnqueuer,
           closedWorld.backendUsage,
           closedWorld.nativeData,
           closedWorld.rtiNeed,
@@ -124,18 +128,18 @@
           typeTestRegistry.rtiChecks,
           codegen.rtiEncoder,
           codegen.oneShotInterceptorData,
-          backend.customElementsCodegenAnalysis,
-          backend.generatedCode,
+          _backend.customElementsCodegenAnalysis,
+          _backend.generatedCode,
           namer,
           this,
           closedWorld,
           closedWorld.fieldAnalysis,
           inferredData,
-          backend.sourceInformationStrategy,
+          _backend.sourceInformationStrategy,
           closedWorld.sorter,
           typeTestRegistry.rtiNeededClasses,
           closedWorld.elementEnvironment.mainFunction);
-      int size = emitter.emitProgram(programBuilder, codegenWorld);
+      int size = emitter.emitProgram(programBuilder, codegen, codegenWorld);
       // TODO(floitsch): we shouldn't need the `neededClasses` anymore.
       neededClasses = programBuilder.collector.neededClasses;
       return size;
@@ -143,21 +147,13 @@
   }
 }
 
-abstract class EmitterFactory {
-  /// Returns true, if the emitter supports reflection.
-  bool get supportsReflection;
-
-  /// Create the [Emitter] for the emitter [task] that uses the given [namer].
-  Emitter createEmitter(
-      CodeEmitterTask task, Namer namer, JClosedWorld closedWorld);
-}
-
 abstract class Emitter {
   Program get programForTesting;
 
   /// Uses the [programBuilder] to generate a model of the program, emits
   /// the program, and returns the size of the generated output.
-  int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld);
+  int emitProgram(ProgramBuilder programBuilder, CodegenInputs codegen,
+      CodegenWorld codegenWorld);
 
   /// Returns the JS function that must be invoked to get the value of the
   /// lazily initialized static.
@@ -208,55 +204,3 @@
   /// Returns the size of the code generated for a given output [unit].
   int generatedSize(OutputUnit unit);
 }
-
-abstract class EmitterBase implements Emitter {
-  @override
-  Program programForTesting;
-  Namer get namer;
-
-  jsAst.PropertyAccess globalPropertyAccessForMember(MemberEntity element) {
-    jsAst.Name name = namer.globalPropertyNameForMember(element);
-    jsAst.PropertyAccess pa = new jsAst.PropertyAccess(
-        new jsAst.VariableUse(namer.globalObjectForMember(element)), name);
-    return pa;
-  }
-
-  jsAst.PropertyAccess globalPropertyAccessForClass(ClassEntity element) {
-    jsAst.Name name = namer.globalPropertyNameForClass(element);
-    jsAst.PropertyAccess pa = new jsAst.PropertyAccess(
-        new jsAst.VariableUse(namer.globalObjectForClass(element)), name);
-    return pa;
-  }
-
-  jsAst.PropertyAccess globalPropertyAccessForType(Entity element) {
-    jsAst.Name name = namer.globalPropertyNameForType(element);
-    jsAst.PropertyAccess pa = new jsAst.PropertyAccess(
-        new jsAst.VariableUse(namer.globalObjectForType(element)), name);
-    return pa;
-  }
-
-  @override
-  jsAst.PropertyAccess staticFieldAccess(FieldEntity element) {
-    return globalPropertyAccessForMember(element);
-  }
-
-  @override
-  jsAst.PropertyAccess staticFunctionAccess(FunctionEntity element) {
-    return globalPropertyAccessForMember(element);
-  }
-
-  @override
-  jsAst.PropertyAccess constructorAccess(ClassEntity element) {
-    return globalPropertyAccessForClass(element);
-  }
-
-  @override
-  jsAst.Expression interceptorClassAccess(ClassEntity element) {
-    return globalPropertyAccessForClass(element);
-  }
-
-  @override
-  jsAst.Expression typeAccess(Entity element) {
-    return globalPropertyAccessForType(element);
-  }
-}
diff --git a/pkg/compiler/lib/src/js_emitter/headers.dart b/pkg/compiler/lib/src/js_emitter/headers.dart
index 9af8ea1..adc0060 100644
--- a/pkg/compiler/lib/src/js_emitter/headers.dart
+++ b/pkg/compiler/lib/src/js_emitter/headers.dart
@@ -4,12 +4,12 @@
 
 library dart2js.js_emitter.headers;
 
-import '../compiler.dart' show Compiler;
+import '../options.dart';
 
-String generatedBy(Compiler compiler, {String flavor: ""}) {
+String generatedBy(CompilerOptions options, {String flavor: ""}) {
   String suffix = '';
-  if (compiler.options.hasBuildId) {
-    suffix = ' version: ${compiler.options.buildId}';
+  if (options.hasBuildId) {
+    suffix = ' version: ${options.buildId}';
   }
   if (flavor != "") flavor = " ($flavor)";
   return '// Generated by dart2js$flavor, '
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 5d47b13..f595f07 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -7,60 +7,114 @@
 import 'package:js_runtime/shared/embedded_names.dart'
     show JsBuiltin, METADATA, TYPES;
 
+import '../../../compiler_new.dart';
 import '../../common.dart';
-import '../../compiler.dart' show Compiler;
+import '../../common/tasks.dart';
 import '../../constants/values.dart' show ConstantValue;
 import '../../deferred_load.dart' show OutputUnit;
+import '../../dump_info.dart';
 import '../../elements/entities.dart';
+import '../../io/source_information.dart';
 import '../../js/js.dart' as js;
-import '../../js_backend/js_backend.dart' show JavaScriptBackend, Namer;
+import '../../js_backend/js_backend.dart' show CodegenInputs, 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 CodeEmitterTask, NativeEmitter;
-import '../js_emitter.dart' as emitterTask show EmitterBase, EmitterFactory;
+import '../js_emitter.dart' show Emitter;
 import '../model.dart';
 import '../program_builder/program_builder.dart' show ProgramBuilder;
 import 'model_emitter.dart';
 
-class EmitterFactory implements emitterTask.EmitterFactory {
-  final bool generateSourceMap;
-
-  EmitterFactory({this.generateSourceMap});
-
-  @override
-  bool get supportsReflection => false;
-
-  @override
-  Emitter createEmitter(
-      CodeEmitterTask task, Namer namer, JClosedWorld closedWorld) {
-    return new Emitter(task.compiler, namer, task.nativeEmitter, closedWorld,
-        task, generateSourceMap);
-  }
-}
-
-class Emitter extends emitterTask.EmitterBase {
-  final Compiler _compiler;
+class EmitterImpl implements Emitter {
+  final DiagnosticReporter _reporter;
   final JClosedWorld _closedWorld;
-  @override
+  final RuntimeTypesEncoder _rtiEncoder;
   final Namer namer;
-  final ModelEmitter _emitter;
-
-  JavaScriptBackend get _backend => _compiler.backend;
-
-  Emitter(this._compiler, this.namer, NativeEmitter nativeEmitter,
-      this._closedWorld, CodeEmitterTask task, bool shouldGenerateSourceMap)
-      : _emitter = new ModelEmitter(_compiler, namer, nativeEmitter,
-            _closedWorld, task, shouldGenerateSourceMap);
-
-  DiagnosticReporter get reporter => _compiler.reporter;
+  ModelEmitter _emitter;
 
   @override
-  int emitProgram(ProgramBuilder programBuilder, CodegenWorld codegenWorld) {
+  Program programForTesting;
+
+  EmitterImpl(
+      CompilerOptions options,
+      this._reporter,
+      CompilerOutput outputProvider,
+      DumpInfoTask dumpInfoTask,
+      this.namer,
+      this._closedWorld,
+      this._rtiEncoder,
+      SourceInformationStrategy sourceInformationStrategy,
+      CompilerTask task,
+      bool shouldGenerateSourceMap) {
+    _emitter = new ModelEmitter(
+        options,
+        _reporter,
+        outputProvider,
+        dumpInfoTask,
+        namer,
+        _closedWorld,
+        task,
+        this,
+        sourceInformationStrategy,
+        _rtiEncoder,
+        shouldGenerateSourceMap);
+  }
+
+  @override
+  int emitProgram(ProgramBuilder programBuilder, CodegenInputs codegen,
+      CodegenWorld codegenWorld) {
     Program program = programBuilder.buildProgram();
     if (retainDataForTesting) {
       programForTesting = program;
     }
-    return _emitter.emitProgram(program, codegenWorld);
+    return _emitter.emitProgram(program, codegen, 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
@@ -127,19 +181,19 @@
         return js.js.expressionTemplateFor('#.substring($isPrefixLength)');
 
       case JsBuiltin.isFunctionType:
-        return _backend.rtiEncoder.templateForIsFunctionType;
+        return _rtiEncoder.templateForIsFunctionType;
 
       case JsBuiltin.isFutureOrType:
-        return _backend.rtiEncoder.templateForIsFutureOrType;
+        return _rtiEncoder.templateForIsFutureOrType;
 
       case JsBuiltin.isVoidType:
-        return _backend.rtiEncoder.templateForIsVoidType;
+        return _rtiEncoder.templateForIsVoidType;
 
       case JsBuiltin.isDynamicType:
-        return _backend.rtiEncoder.templateForIsDynamicType;
+        return _rtiEncoder.templateForIsDynamicType;
 
       case JsBuiltin.isJsInteropTypeArgument:
-        return _backend.rtiEncoder.templateForIsJsInteropTypeArgument;
+        return _rtiEncoder.templateForIsJsInteropTypeArgument;
 
       case JsBuiltin.rawRtiToJsConstructorName:
         return js.js.expressionTemplateFor("#.name");
@@ -166,7 +220,7 @@
         return js.js.expressionTemplateFor("$typesAccess[#]");
 
       default:
-        reporter.internalError(
+        _reporter.internalError(
             NO_LOCATION_SPANNABLE, "Unhandled Builtin: $builtin");
         return null;
     }
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 1d5c23d..7781d54 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -569,40 +569,48 @@
 ///
 /// This class is stateless and can be reused for different fragments.
 class FragmentEmitter {
-  final Compiler compiler;
-  final Namer namer;
-  final JavaScriptBackend backend;
-  final ConstantEmitter constantEmitter;
-  final ModelEmitter modelEmitter;
+  final CompilerOptions _options;
+  final DumpInfoTask _dumpInfoTask;
+  final Namer _namer;
+  final ConstantEmitter _constantEmitter;
+  final ModelEmitter _modelEmitter;
   final JClosedWorld _closedWorld;
+  final CodegenInputs _codegen;
   final CodegenWorld _codegenWorld;
 
   js.Name _call0Name, _call1Name, _call2Name;
   js.Name get call0Name =>
-      _call0Name ??= namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX0);
+      _call0Name ??= _namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX0);
   js.Name get call1Name =>
-      _call1Name ??= namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX1);
+      _call1Name ??= _namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX1);
   js.Name get call2Name =>
-      _call2Name ??= namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX2);
+      _call2Name ??= _namer.getNameForJsGetName(null, JsGetName.CALL_PREFIX2);
 
-  FragmentEmitter(this.compiler, this.namer, this.backend, this.constantEmitter,
-      this.modelEmitter, this._closedWorld, this._codegenWorld);
+  FragmentEmitter(
+      this._options,
+      this._dumpInfoTask,
+      this._namer,
+      this._constantEmitter,
+      this._modelEmitter,
+      this._closedWorld,
+      this._codegen,
+      this._codegenWorld);
 
   js.Expression generateEmbeddedGlobalAccess(String global) =>
-      modelEmitter.generateEmbeddedGlobalAccess(global);
+      _modelEmitter.generateEmbeddedGlobalAccess(global);
 
   js.Expression generateConstantReference(ConstantValue value) =>
-      modelEmitter.generateConstantReference(value);
+      _modelEmitter.generateConstantReference(value);
 
   js.Expression classReference(Class cls) {
     return js.js('#.#', [cls.holder.name, cls.name]);
   }
 
   void registerEntityAst(Entity entity, js.Node code, {LibraryEntity library}) {
-    compiler.dumpInfoTask.registerEntityAst(entity, code);
+    _dumpInfoTask.registerEntityAst(entity, code);
     // TODO(sigmund): stop recoding associations twice, dump-info already
     // has library to element dependencies to recover this data.
-    if (library != null) compiler.dumpInfoTask.registerEntityAst(library, code);
+    if (library != null) _dumpInfoTask.registerEntityAst(library, code);
   }
 
   js.Statement emitMainFragment(
@@ -621,33 +629,30 @@
       // TODO(29455): 'hunkHelpers' displaces other names, so don't minify it.
       'hunkHelpers': js.VariableDeclaration('hunkHelpers', allowRename: false),
       'directAccessTestExpression': js.js(directAccessTestExpression),
-      'cyclicThrow': backend.emitterTask.emitter
+      'cyclicThrow': _codegen.emitter
           .staticFunctionAccess(_closedWorld.commonElements.cyclicThrowHelper),
-      'operatorIsPrefix': js.string(namer.operatorIsPrefix),
+      'operatorIsPrefix': js.string(_namer.operatorIsPrefix),
       'tearOffCode': new js.Block(buildTearOffCode(
-          compiler.options,
-          backend.emitterTask.emitter,
-          backend.namer,
-          _closedWorld.commonElements)),
+          _options, _codegen.emitter, _namer, _closedWorld.commonElements)),
       'embeddedTypes': generateEmbeddedGlobalAccess(TYPES),
       'embeddedInterceptorTags':
           generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG),
       'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS),
       'embeddedGlobalsObject': js.js("init"),
       'staticStateDeclaration': new js.VariableDeclaration(
-          namer.staticStateHolder,
+          _namer.staticStateHolder,
           allowRename: false),
-      'staticState': js.js('#', namer.staticStateHolder),
+      'staticState': js.js('#', _namer.staticStateHolder),
       'constantHolderReference': buildConstantHolderReference(program),
       'holders': holderCode.statements,
-      'callName': js.string(namer.callNameField),
-      'stubName': js.string(namer.stubNameField),
-      'argumentCount': js.string(namer.requiredParameterField),
-      'defaultArgumentValues': js.string(namer.defaultValuesField),
+      'callName': js.string(_namer.callNameField),
+      'stubName': js.string(_namer.stubNameField),
+      'argumentCount': js.string(_namer.requiredParameterField),
+      'defaultArgumentValues': js.string(_namer.defaultValuesField),
       'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
       'hasSoftDeferredClasses': program.hasSoftDeferredClasses,
       'softId': js.string(softDeferredId),
-      'isTrackingAllocations': compiler.options.experimentalTrackAllocations,
+      'isTrackingAllocations': _options.experimentalTrackAllocations,
       'prototypes': emitPrototypes(fragment),
       'inheritance': emitInheritance(fragment),
       'aliases': emitInstanceMethodAliases(fragment),
@@ -660,7 +665,7 @@
           ? emitNativeSupport(fragment)
           : new js.EmptyStatement(),
       'jsInteropSupport': jsInteropAnalysis.buildJsInteropBootstrap(
-              _codegenWorld, _closedWorld.nativeData, namer) ??
+              _codegenWorld, _closedWorld.nativeData, _namer) ??
           new js.EmptyStatement(),
       'invokeMain': fragment.invokeMain,
 
@@ -675,7 +680,7 @@
           'softId': js.string(softDeferredId),
           // TODO(floitsch): don't just reference 'init'.
           'embeddedGlobalsObject': new js.Parameter('init'),
-          'staticState': new js.Parameter(namer.staticStateHolder),
+          'staticState': new js.Parameter(_namer.staticStateHolder),
           'installHoldersAsLocals':
               emitInstallHoldersAsLocals(nonStaticStateHolders),
           'prototypes': emitPrototypes(fragment, softDeferred: true),
@@ -766,7 +771,7 @@
     js.Expression code = js.js(deferredBoilerplateDart2, {
       // TODO(floitsch): don't just reference 'init'.
       'embeddedGlobalsObject': new js.Parameter('init'),
-      'staticState': new js.Parameter(namer.staticStateHolder),
+      'staticState': new js.Parameter(_namer.staticStateHolder),
       'holders': holderCode.statements,
       'deferredHoldersList': new js.ArrayInitializer(holderCode.activeHolders
           .map((holder) => js.js("#", holder.name))
@@ -782,10 +787,10 @@
       'lazyStatics': lazyInitializers,
       'types': deferredTypes,
       'nativeSupport': nativeSupport,
-      'typesOffset': namer.typesOffsetName,
+      'typesOffset': _namer.typesOffsetName,
     });
 
-    if (compiler.options.experimentStartupFunctions) {
+    if (_options.experimentStartupFunctions) {
       code = js.Parentheses(code);
     }
     return code;
@@ -918,7 +923,7 @@
 
     if (cls.isSoftDeferred) {
       statements.add(js.js.statement('softDef(this)'));
-    } else if (compiler.options.experimentalTrackAllocations) {
+    } else if (_options.experimentalTrackAllocations) {
       String qualifiedName =
           "${cls.element.library.canonicalUri}:${cls.element.name}";
       statements.add(js.js.statement('allocations["$qualifiedName"] = true'));
@@ -963,7 +968,7 @@
           assignment = js.js('#.# = #', [
             thisRef,
             field.name,
-            constantEmitter.generate(constant),
+            _constantEmitter.generate(constant),
           ]);
         }
         ++chainLength;
@@ -982,7 +987,7 @@
       js.Parameter parameter = new js.Parameter('t${parameters.length}');
       parameters.add(parameter);
       statements.add(js.js.statement(
-          '#.# = #', [thisRef, namer.rtiFieldJsName, parameter.name]));
+          '#.# = #', [thisRef, _namer.rtiFieldJsName, parameter.name]));
     }
 
     return js.js('function #(#) { # }', [name, parameters, statements]);
@@ -1050,7 +1055,7 @@
       // TODO(sra): What is this doing? Document or remove.
       properties
           .add(js.Property(js.string("constructor"), classReference(cls)));
-      properties.add(js.Property(namer.operatorIs(cls.element), js.number(1)));
+      properties.add(js.Property(_namer.operatorIs(cls.element), js.number(1)));
     }
 
     allMethods.forEach((Method method) {
@@ -1068,13 +1073,13 @@
 
       // Closures taking exactly one argument are common.
       properties.add(js.Property(
-          js.string(namer.callCatchAllName), js.quoteName(call1Name)));
+          js.string(_namer.callCatchAllName), js.quoteName(call1Name)));
       properties.add(
-          js.Property(js.string(namer.requiredParameterField), js.number(1)));
+          js.Property(js.string(_namer.requiredParameterField), js.number(1)));
 
       // Most closures have no optional arguments.
       properties.add(js.Property(
-          js.string(namer.defaultValuesField), new js.LiteralNull()));
+          js.string(_namer.defaultValuesField), new js.LiteralNull()));
     }
 
     return new js.ObjectInitializer(properties);
@@ -1110,7 +1115,7 @@
       js.Expression fieldName = js.quoteName(field.name);
       code = js.js(template, fieldName);
     }
-    js.Name getterName = namer.deriveGetterName(field.accessorName);
+    js.Name getterName = _namer.deriveGetterName(field.accessorName);
     return new StubMethod(getterName, code);
   }
 
@@ -1135,7 +1140,7 @@
       code = js.js(template, fieldName);
     }
 
-    js.Name setterName = namer.deriveSetterName(field.accessorName);
+    js.Name setterName = _namer.deriveSetterName(field.accessorName);
     return new StubMethod(setterName, code);
   }
 
@@ -1184,12 +1189,12 @@
           js.Name applyName = method.applyIndex == 0
               ? method.name
               : method.parameterStubs[method.applyIndex - 1].name;
-          properties[js.string(namer.callCatchAllName)] =
+          properties[js.string(_namer.callCatchAllName)] =
               js.quoteName(applyName);
         }
         // Common case of '1' is stored on the Closure class.
         if (method.requiredParameterCount != 1 || forceAdd) {
-          properties[js.string(namer.requiredParameterField)] =
+          properties[js.string(_namer.requiredParameterField)] =
               js.number(method.requiredParameterCount);
         }
 
@@ -1198,7 +1203,7 @@
         // Default values property of `null` is stored on the common JS
         // superclass.
         if (defaultValues is! js.LiteralNull || forceAdd) {
-          properties[js.string(namer.defaultValuesField)] = defaultValues;
+          properties[js.string(_namer.defaultValuesField)] = defaultValues;
         }
       }
     }
@@ -1583,9 +1588,9 @@
       var assignment = js.js.statement('#.# = #', [
         constant.holder.name,
         constant.name,
-        constantEmitter.generate(constant.value)
+        _constantEmitter.generate(constant.value)
       ]);
-      compiler.dumpInfoTask.registerConstantAst(constant.value, assignment);
+      _dumpInfoTask.registerConstantAst(constant.value, assignment);
       assignments.add(assignment);
       if (constant.value.isList) hasList = true;
     }
@@ -1804,7 +1809,7 @@
     // TODO(floitsch): this should probably be on a per-fragment basis.
     nativeClassesNeedingUnmangledName.forEach((element) {
       names.add(new js.Property(
-          js.quoteName(namer.className(element)), js.string(element.name)));
+          js.quoteName(_namer.className(element)), js.string(element.name)));
     });
 
     return new js.Property(
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 6a2038d..f02e6a1 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
@@ -31,47 +31,51 @@
 
 import '../../../compiler_new.dart';
 import '../../common.dart';
-import '../../compiler.dart' show Compiler;
+import '../../common/tasks.dart';
 import '../../constants/values.dart'
     show ConstantValue, FunctionConstantValue, NullConstantValue;
 import '../../common_elements.dart' show CommonElements;
+import '../../dump_info.dart';
 import '../../elements/entities.dart';
 import '../../hash/sha1.dart' show Hasher;
 import '../../io/code_output.dart';
 import '../../io/location_provider.dart' show LocationCollector;
+import '../../io/source_information.dart';
 import '../../io/source_map_builder.dart' show SourceMapBuilder;
 import '../../js/js.dart' as js;
 import '../../js_backend/js_backend.dart'
-    show JavaScriptBackend, Namer, ConstantEmitter, StringBackedName;
+    show CodegenInputs, Namer, ConstantEmitter, StringBackedName;
 import '../../js_backend/js_interop_analysis.dart' as jsInteropAnalysis;
+import '../../js_backend/runtime_types.dart';
+import '../../options.dart';
 import '../../universe/codegen_world_builder.dart' show CodegenWorld;
 import '../../world.dart';
 import '../code_emitter_task.dart';
 import '../constant_ordering.dart' show ConstantOrdering;
 import '../headers.dart';
-import '../js_emitter.dart' show NativeEmitter;
 import '../js_emitter.dart' show buildTearOffCode, NativeGenerator;
 import '../model.dart';
 
 part 'fragment_emitter.dart';
 
 class ModelEmitter {
-  final Compiler compiler;
-  final Namer namer;
-  final CodeEmitterTask task;
-  ConstantEmitter constantEmitter;
-  final NativeEmitter nativeEmitter;
-  final bool shouldGenerateSourceMap;
+  final CompilerOptions _options;
+  final DiagnosticReporter _reporter;
+  final CompilerOutput _outputProvider;
+  final DumpInfoTask _dumpInfoTask;
+  final Namer _namer;
+  final CompilerTask _task;
+  ConstantEmitter _constantEmitter;
+  final bool _shouldGenerateSourceMap;
   final JClosedWorld _closedWorld;
   final ConstantOrdering _constantOrdering;
+  final SourceInformationStrategy _sourceInformationStrategy;
 
   // The full code that is written to each hunk part-file.
   final Map<Fragment, CodeOutput> outputBuffers = {};
 
   Set<Fragment> omittedFragments = Set();
 
-  JavaScriptBackend get backend => compiler.backend;
-
   /// For deferred loading we communicate the initializers via this global var.
   static const String deferredInitializersGlobal =
       r"$__dart_deferred_initializers__";
@@ -81,23 +85,31 @@
 
   static const String typeNameProperty = r"builtin$cls";
 
-  ModelEmitter(this.compiler, this.namer, this.nativeEmitter, this._closedWorld,
-      this.task, this.shouldGenerateSourceMap)
+  ModelEmitter(
+      this._options,
+      this._reporter,
+      this._outputProvider,
+      this._dumpInfoTask,
+      this._namer,
+      this._closedWorld,
+      this._task,
+      Emitter emitter,
+      this._sourceInformationStrategy,
+      RuntimeTypesEncoder rtiEncoder,
+      this._shouldGenerateSourceMap)
       : _constantOrdering = new ConstantOrdering(_closedWorld.sorter) {
-    this.constantEmitter = new ConstantEmitter(
-        compiler.options,
+    this._constantEmitter = new ConstantEmitter(
+        _options,
         _closedWorld.commonElements,
         _closedWorld.elementEnvironment,
         _closedWorld.rtiNeed,
-        compiler.backend.rtiEncoder,
+        rtiEncoder,
         _closedWorld.fieldAnalysis,
-        task,
+        emitter,
         this.generateConstantReference,
         constantListGenerator);
   }
 
-  DiagnosticReporter get reporter => compiler.reporter;
-
   js.Expression constantListGenerator(js.Expression array) {
     // TODO(floitsch): remove hard-coded name.
     return js.js('makeConstList(#)', [array]);
@@ -135,7 +147,7 @@
 
     // Sorting by the long name clusters constants with the same constructor
     // which compresses a tiny bit better.
-    int r = namer.constantLongName(a).compareTo(namer.constantLongName(b));
+    int r = _namer.constantLongName(a).compareTo(_namer.constantLongName(b));
     if (r != 0) return r;
 
     // Resolve collisions in the long name by using a structural order.
@@ -144,8 +156,8 @@
 
   js.Expression generateStaticClosureAccess(FunctionEntity element) {
     return js.js('#.#()', [
-      namer.globalObjectForMember(element),
-      namer.staticClosureName(element)
+      _namer.globalObjectForMember(element),
+      _namer.staticClosureName(element)
     ]);
   }
 
@@ -158,19 +170,27 @@
     // We are only interested in the "isInlined" part, but it does not hurt to
     // test for the other predicates.
     if (isConstantInlinedOrAlreadyEmitted(value)) {
-      return constantEmitter.generate(value);
+      return _constantEmitter.generate(value);
     }
     return js.js('#.#',
-        [namer.globalObjectForConstant(value), namer.constantName(value)]);
+        [_namer.globalObjectForConstant(value), _namer.constantName(value)]);
   }
 
-  int emitProgram(Program program, CodegenWorld codegenWorld) {
+  int emitProgram(
+      Program program, CodegenInputs codegen, CodegenWorld codegenWorld) {
     MainFragment mainFragment = program.fragments.first;
     List<DeferredFragment> deferredFragments =
         new List<DeferredFragment>.from(program.deferredFragments);
 
-    FragmentEmitter fragmentEmitter = new FragmentEmitter(compiler, namer,
-        backend, constantEmitter, this, _closedWorld, codegenWorld);
+    FragmentEmitter fragmentEmitter = new FragmentEmitter(
+        _options,
+        _dumpInfoTask,
+        _namer,
+        _constantEmitter,
+        this,
+        _closedWorld,
+        codegen,
+        codegenWorld);
 
     var deferredLoadingState = new DeferredLoadingState();
     js.Statement mainCode =
@@ -211,14 +231,14 @@
     writeMainFragment(mainFragment, mainCode,
         isSplit: program.deferredFragments.isNotEmpty ||
             program.hasSoftDeferredClasses ||
-            compiler.options.experimentalTrackAllocations);
+            _options.experimentalTrackAllocations);
 
     if (_closedWorld.backendUsage.requiresPreamble &&
-        !backend.htmlLibraryIsLoaded) {
-      reporter.reportHintMessage(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
+        !_closedWorld.backendUsage.isHtmlLoaded) {
+      _reporter.reportHintMessage(NO_LOCATION_SPANNABLE, MessageKind.PREAMBLE);
     }
 
-    if (compiler.options.deferredMapUri != null) {
+    if (_options.deferredMapUri != null) {
       writeDeferredMap();
     }
 
@@ -232,13 +252,13 @@
     flavor.write('fast startup emitter');
     // TODO(johnniwinther): Remove this flavor.
     flavor.write(', strong');
-    if (compiler.options.trustPrimitives) flavor.write(', trust primitives');
-    if (compiler.options.omitImplicitChecks) flavor.write(', omit checks');
-    if (compiler.options.laxRuntimeTypeToString) {
+    if (_options.trustPrimitives) flavor.write(', trust primitives');
+    if (_options.omitImplicitChecks) flavor.write(', omit checks');
+    if (_options.laxRuntimeTypeToString) {
       flavor.write(', lax runtime type');
     }
-    if (compiler.options.useContentSecurityPolicy) flavor.write(', CSP');
-    return new js.Comment(generatedBy(compiler, flavor: '$flavor'));
+    if (_options.useContentSecurityPolicy) flavor.write(', CSP');
+    return new js.Comment(generatedBy(_options, flavor: '$flavor'));
   }
 
   /// Writes all deferred fragment's code into files.
@@ -272,15 +292,15 @@
       {bool isSplit}) {
     LocationCollector locationCollector;
     List<CodeOutputListener> codeOutputListeners;
-    if (shouldGenerateSourceMap) {
-      task.measureSubtask('source-maps', () {
+    if (_shouldGenerateSourceMap) {
+      _task.measureSubtask('source-maps', () {
         locationCollector = new LocationCollector();
         codeOutputListeners = <CodeOutputListener>[locationCollector];
       });
     }
 
     CodeOutput mainOutput = new StreamCodeOutput(
-        compiler.outputProvider.createOutputSink('', 'js', OutputType.js),
+        _outputProvider.createOutputSink('', 'js', OutputType.js),
         codeOutputListeners);
     outputBuffers[fragment] = mainOutput;
 
@@ -292,29 +312,29 @@
     ]);
 
     mainOutput.addBuffer(js.createCodeBuffer(
-        program, compiler.options, backend.sourceInformationStrategy,
-        monitor: compiler.dumpInfoTask));
+        program, _options, _sourceInformationStrategy,
+        monitor: _dumpInfoTask));
 
-    if (shouldGenerateSourceMap) {
-      task.measureSubtask('source-maps', () {
+    if (_shouldGenerateSourceMap) {
+      _task.measureSubtask('source-maps', () {
         mainOutput.add(SourceMapBuilder.generateSourceMapTag(
-            compiler.options.sourceMapUri, compiler.options.outputUri));
+            _options.sourceMapUri, _options.outputUri));
       });
     }
 
     mainOutput.close();
 
-    if (shouldGenerateSourceMap) {
-      task.measureSubtask('source-maps', () {
+    if (_shouldGenerateSourceMap) {
+      _task.measureSubtask('source-maps', () {
         SourceMapBuilder.outputSourceMap(
             mainOutput,
             locationCollector,
-            namer.createMinifiedGlobalNameMap(),
-            namer.createMinifiedInstanceNameMap(),
+            _namer.createMinifiedGlobalNameMap(),
+            _namer.createMinifiedInstanceNameMap(),
             '',
-            compiler.options.sourceMapUri,
-            compiler.options.outputUri,
-            compiler.outputProvider);
+            _options.sourceMapUri,
+            _options.outputUri,
+            _outputProvider);
       });
     }
   }
@@ -330,8 +350,8 @@
     outputListeners.add(hasher);
 
     LocationCollector locationCollector;
-    if (shouldGenerateSourceMap) {
-      task.measureSubtask('source-maps', () {
+    if (_shouldGenerateSourceMap) {
+      _task.measureSubtask('source-maps', () {
         locationCollector = new LocationCollector();
         outputListeners.add(locationCollector);
       });
@@ -340,8 +360,8 @@
     String hunkPrefix = fragment.outputFileName;
 
     CodeOutput output = new StreamCodeOutput(
-        compiler.outputProvider
-            .createOutputSink(hunkPrefix, deferredExtension, OutputType.jsPart),
+        _outputProvider.createOutputSink(
+            hunkPrefix, deferredExtension, OutputType.jsPart),
         outputListeners);
 
     outputBuffers[fragment] = output;
@@ -362,8 +382,8 @@
     ]);
 
     output.addBuffer(js.createCodeBuffer(
-        program, compiler.options, backend.sourceInformationStrategy,
-        monitor: compiler.dumpInfoTask));
+        program, _options, _sourceInformationStrategy,
+        monitor: _dumpInfoTask));
 
     // Make a unique hash of the code (before the sourcemaps are added)
     // This will be used to retrieve the initializing function from the global
@@ -374,11 +394,11 @@
     output.add('\n${deferredInitializersGlobal}["$hash"] = '
         '${deferredInitializersGlobal}.current');
 
-    if (shouldGenerateSourceMap) {
-      task.measureSubtask('source-maps', () {
+    if (_shouldGenerateSourceMap) {
+      _task.measureSubtask('source-maps', () {
         Uri mapUri, partUri;
-        Uri sourceMapUri = compiler.options.sourceMapUri;
-        Uri outputUri = compiler.options.outputUri;
+        Uri sourceMapUri = _options.sourceMapUri;
+        Uri outputUri = _options.outputUri;
         String partName = "$hunkPrefix.$partExtension";
         String hunkFileName = "$hunkPrefix.$deferredExtension";
 
@@ -386,21 +406,19 @@
           String mapFileName = hunkFileName + ".map";
           List<String> mapSegments = sourceMapUri.pathSegments.toList();
           mapSegments[mapSegments.length - 1] = mapFileName;
-          mapUri =
-              compiler.options.sourceMapUri.replace(pathSegments: mapSegments);
+          mapUri = _options.sourceMapUri.replace(pathSegments: mapSegments);
         }
 
         if (outputUri != null) {
           List<String> partSegments = outputUri.pathSegments.toList();
           partSegments[partSegments.length - 1] = hunkFileName;
-          partUri =
-              compiler.options.outputUri.replace(pathSegments: partSegments);
+          partUri = _options.outputUri.replace(pathSegments: partSegments);
         }
 
         output.add(SourceMapBuilder.generateSourceMapTag(mapUri, partUri));
         output.close();
         SourceMapBuilder.outputSourceMap(output, locationCollector, {}, {},
-            partName, mapUri, partUri, compiler.outputProvider);
+            partName, mapUri, partUri, _outputProvider);
       });
     } else {
       output.close();
@@ -420,11 +438,11 @@
     mapping["_comment"] = "This mapping shows which compiled `.js` files are "
         "needed for a given deferred library import.";
     mapping.addAll(_closedWorld.outputUnitData.computeDeferredMap(
-        compiler.options, _closedWorld.elementEnvironment,
+        _options, _closedWorld.elementEnvironment,
         omittedUnits:
             omittedFragments.map((fragemnt) => fragemnt.outputUnit).toSet()));
-    compiler.outputProvider.createOutputSink(
-        compiler.options.deferredMapUri.path, '', OutputType.deferredMap)
+    _outputProvider.createOutputSink(
+        _options.deferredMapUri.path, '', OutputType.deferredMap)
       ..add(const JsonEncoder.withIndent("  ").convert(mapping))
       ..close();
   }
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index a9c3bfe..1a9544f 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -267,7 +267,8 @@
         runtimeTypeUses: runtimeTypeUses,
         isFunctionApplyUsed: backendUsage.isFunctionApplyUsed,
         isMirrorsUsed: backendUsage.isMirrorsUsed,
-        isNoSuchMethodUsed: backendUsage.isNoSuchMethodUsed);
+        isNoSuchMethodUsed: backendUsage.isNoSuchMethodUsed,
+        isHtmlLoaded: backendUsage.isHtmlLoaded);
   }
 
   NativeBasicData _convertNativeBasicData(