Version 1.21.0-dev.4.0

Merge 93e55dbe6e14b40197a74176388fdcf65a0a059a into dev
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..96325ae
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,16 @@
+# Defines the Chromium style for automatic reformatting.
+# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+BasedOnStyle: Chromium
+
+# Keep up to 2 blank lines. More blank lines are removed.
+MaxEmptyLinesToKeep: 2
+
+# clang-format doesn't seem to do a good job of this for longer comments.
+ReflowComments: 'false'
+
+# We have lots of these. Though we need to put them all in curly braces,
+# clang-format can't do that.
+AllowShortIfStatementsOnASingleLine: 'true'
+
+# Put escaped newlines into the rightmost column.
+AlignEscapedNewlinesLeft: false
diff --git a/.packages b/.packages
index 4dbf1a4..3c252bb1 100644
--- a/.packages
+++ b/.packages
@@ -35,6 +35,7 @@
 dev_compiler:pkg/dev_compiler/lib
 expect:pkg/expect/lib
 fixnum:third_party/pkg/fixnum/lib
+front_end:pkg/front_end/lib
 func:third_party/pkg/func/lib
 glob:third_party/pkg/glob/lib
 html:third_party/pkg/html/lib
diff --git a/.travis.yml b/.travis.yml
index 246ca09..ef84927 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -70,6 +70,7 @@
   - if [[ -z "$TEST" ]]; then ./tool/presubmit.sh ; fi
   - if [[ "$TEST" == coverage ]]; then ./tool/build_sdk.sh && ./tool/coverage.sh ; fi
   - if [[ "$TEST" == node ]]; then ./tool/node_test.sh ; fi
+  - if [[ "$TEST" == package ]]; then ./tool/build_sdk.sh && ./tool/build_pkgs.sh ; fi
 env:
   - ANALYZER=master
   - ANALYZER=master DDC_BROWSERS=Firefox
@@ -77,11 +78,10 @@
   - ANALYZER=master CXX=g++
   - ANALYZER=master CXX=clang++
   - TEST=coverage
+  - TEST=package
 matrix:
   allow_failures:
     - env: TEST=node
-    - env: ANALYZER=master DDC_BROWSERS=ChromeCanaryTravis
-    - env: ANALYZER=master DDC_BROWSERS=Firefox
     - env: ANALYZER=master CXX=g++
 notifications:
   email:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69f85c2..a9e4b6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,19 @@
 ## 1.21.0
+
+### Language
+
+* Don't warn about switch case fallthrough if the case ends in a `rethrow`
+  statement.
+* Also don't warn if the entire switch case is wrapped in braces - as long as
+  the block ends with a `break`, `continue`, `rethrow`, `return` or `throw`.
+* Allow `=` as well as `:` as separator for named parameter default values.
+
 ### Core library changes
 
 * `dart:core`: `Set.difference` now takes a `Set<Object>` as argument.
 
-### Language
-
-* Allow `=` as well as `:` as separator for named parameter default values.
+* `dart:developer`:
+  * The service protocol http server can now be controlled from Dart code.
 
 ## 1.20.1 - 2016-10-13
 
diff --git a/DEPS b/DEPS
index cb26a1e..3bfa76e 100644
--- a/DEPS
+++ b/DEPS
@@ -37,7 +37,7 @@
 
   # Revisions of /third_party/* dependencies.
   "args_tag": "@0.13.5",
-  "async_tag": "@1.11.2",
+  "async_tag": "@1.11.3",
   "barback-0.13.0_rev": "@34853",
   "barback-0.14.0_rev": "@36398",
   "barback-0.14.1_rev": "@38525",
@@ -61,7 +61,7 @@
   "fixnum_tag": "@0.10.5",
   "func_tag": "@0.1.0",
   "glob_tag": "@1.1.3",
-  "html_tag" : "@0.13.0",
+  "html_tag" : "@0.13.1",
   "http_multi_server_tag" : "@2.0.2",
   "http_parser_tag" : "@3.0.2",
   "http_tag" : "@0.11.3+9",
@@ -104,8 +104,8 @@
   "smoke_tag" : "@v0.3.6+2",
   "source_map_stack_trace_tag": "@1.1.3",
   "source_maps-0.9.4_rev": "@38524",
-  "source_maps_tag": "@0.10.1+1",
-  "source_span_tag": "@1.2.3",
+  "source_maps_tag": "@0.10.1+2",
+  "source_span_tag": "@1.2.4",
   "stack_trace_tag": "@1.6.6",
   "stream_channel_tag": "@1.5.0",
   "string_scanner_tag": "@1.0.0",
@@ -121,7 +121,7 @@
   "WebCore_rev": "@a86fe28efadcfc781f836037a80f27e22a5dad17",
   "when_tag": "@0.2.0+2",
   "which_tag": "@0.1.3+1",
-  "yaml_tag": "@2.1.10",
+  "yaml_tag": "@2.1.12",
   "zlib_rev": "@c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f",
 }
 
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index f3c2d98..2f69d0a 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -8195,11 +8195,11 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class AnalysisErrorSeverity implements Enum {
-  static const INFO = const AnalysisErrorSeverity._("INFO");
+  static const AnalysisErrorSeverity INFO = const AnalysisErrorSeverity._("INFO");
 
-  static const WARNING = const AnalysisErrorSeverity._("WARNING");
+  static const AnalysisErrorSeverity WARNING = const AnalysisErrorSeverity._("WARNING");
 
-  static const ERROR = const AnalysisErrorSeverity._("ERROR");
+  static const AnalysisErrorSeverity ERROR = const AnalysisErrorSeverity._("ERROR");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -8256,21 +8256,21 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class AnalysisErrorType implements Enum {
-  static const CHECKED_MODE_COMPILE_TIME_ERROR = const AnalysisErrorType._("CHECKED_MODE_COMPILE_TIME_ERROR");
+  static const AnalysisErrorType CHECKED_MODE_COMPILE_TIME_ERROR = const AnalysisErrorType._("CHECKED_MODE_COMPILE_TIME_ERROR");
 
-  static const COMPILE_TIME_ERROR = const AnalysisErrorType._("COMPILE_TIME_ERROR");
+  static const AnalysisErrorType COMPILE_TIME_ERROR = const AnalysisErrorType._("COMPILE_TIME_ERROR");
 
-  static const HINT = const AnalysisErrorType._("HINT");
+  static const AnalysisErrorType HINT = const AnalysisErrorType._("HINT");
 
-  static const LINT = const AnalysisErrorType._("LINT");
+  static const AnalysisErrorType LINT = const AnalysisErrorType._("LINT");
 
-  static const STATIC_TYPE_WARNING = const AnalysisErrorType._("STATIC_TYPE_WARNING");
+  static const AnalysisErrorType STATIC_TYPE_WARNING = const AnalysisErrorType._("STATIC_TYPE_WARNING");
 
-  static const STATIC_WARNING = const AnalysisErrorType._("STATIC_WARNING");
+  static const AnalysisErrorType STATIC_WARNING = const AnalysisErrorType._("STATIC_WARNING");
 
-  static const SYNTACTIC_ERROR = const AnalysisErrorType._("SYNTACTIC_ERROR");
+  static const AnalysisErrorType SYNTACTIC_ERROR = const AnalysisErrorType._("SYNTACTIC_ERROR");
 
-  static const TODO = const AnalysisErrorType._("TODO");
+  static const AnalysisErrorType TODO = const AnalysisErrorType._("TODO");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -8610,25 +8610,25 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class AnalysisService implements Enum {
-  static const FOLDING = const AnalysisService._("FOLDING");
+  static const AnalysisService FOLDING = const AnalysisService._("FOLDING");
 
-  static const HIGHLIGHTS = const AnalysisService._("HIGHLIGHTS");
+  static const AnalysisService HIGHLIGHTS = const AnalysisService._("HIGHLIGHTS");
 
-  static const IMPLEMENTED = const AnalysisService._("IMPLEMENTED");
+  static const AnalysisService IMPLEMENTED = const AnalysisService._("IMPLEMENTED");
 
   /**
    * This service is not currently implemented and will become a
    * GeneralAnalysisService in a future release.
    */
-  static const INVALIDATE = const AnalysisService._("INVALIDATE");
+  static const AnalysisService INVALIDATE = const AnalysisService._("INVALIDATE");
 
-  static const NAVIGATION = const AnalysisService._("NAVIGATION");
+  static const AnalysisService NAVIGATION = const AnalysisService._("NAVIGATION");
 
-  static const OCCURRENCES = const AnalysisService._("OCCURRENCES");
+  static const AnalysisService OCCURRENCES = const AnalysisService._("OCCURRENCES");
 
-  static const OUTLINE = const AnalysisService._("OUTLINE");
+  static const AnalysisService OUTLINE = const AnalysisService._("OUTLINE");
 
-  static const OVERRIDES = const AnalysisService._("OVERRIDES");
+  static const AnalysisService OVERRIDES = const AnalysisService._("OVERRIDES");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -9445,9 +9445,9 @@
    * the invocation and the parameterNames, parameterTypes, and
    * requiredParameterCount attributes are defined.
    */
-  static const ARGUMENT_LIST = const CompletionSuggestionKind._("ARGUMENT_LIST");
+  static const CompletionSuggestionKind ARGUMENT_LIST = const CompletionSuggestionKind._("ARGUMENT_LIST");
 
-  static const IMPORT = const CompletionSuggestionKind._("IMPORT");
+  static const CompletionSuggestionKind IMPORT = const CompletionSuggestionKind._("IMPORT");
 
   /**
    * The element identifier should be inserted at the completion location. For
@@ -9455,7 +9455,7 @@
    * suggestions of this kind, the element attribute is defined and the
    * completion field is the element's identifier.
    */
-  static const IDENTIFIER = const CompletionSuggestionKind._("IDENTIFIER");
+  static const CompletionSuggestionKind IDENTIFIER = const CompletionSuggestionKind._("IDENTIFIER");
 
   /**
    * The element is being invoked at the completion location. For example,
@@ -9463,24 +9463,24 @@
    * element attribute is defined and the completion field is the element's
    * identifier.
    */
-  static const INVOCATION = const CompletionSuggestionKind._("INVOCATION");
+  static const CompletionSuggestionKind INVOCATION = const CompletionSuggestionKind._("INVOCATION");
 
   /**
    * A keyword is being suggested. For suggestions of this kind, the completion
    * is the keyword.
    */
-  static const KEYWORD = const CompletionSuggestionKind._("KEYWORD");
+  static const CompletionSuggestionKind KEYWORD = const CompletionSuggestionKind._("KEYWORD");
 
   /**
    * A named argument for the current callsite is being suggested. For
    * suggestions of this kind, the completion is the named argument identifier
    * including a trailing ':' and space.
    */
-  static const NAMED_ARGUMENT = const CompletionSuggestionKind._("NAMED_ARGUMENT");
+  static const CompletionSuggestionKind NAMED_ARGUMENT = const CompletionSuggestionKind._("NAMED_ARGUMENT");
 
-  static const OPTIONAL_ARGUMENT = const CompletionSuggestionKind._("OPTIONAL_ARGUMENT");
+  static const CompletionSuggestionKind OPTIONAL_ARGUMENT = const CompletionSuggestionKind._("OPTIONAL_ARGUMENT");
 
-  static const PARAMETER = const CompletionSuggestionKind._("PARAMETER");
+  static const CompletionSuggestionKind PARAMETER = const CompletionSuggestionKind._("PARAMETER");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10015,57 +10015,57 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class ElementKind implements Enum {
-  static const CLASS = const ElementKind._("CLASS");
+  static const ElementKind CLASS = const ElementKind._("CLASS");
 
-  static const CLASS_TYPE_ALIAS = const ElementKind._("CLASS_TYPE_ALIAS");
+  static const ElementKind CLASS_TYPE_ALIAS = const ElementKind._("CLASS_TYPE_ALIAS");
 
-  static const COMPILATION_UNIT = const ElementKind._("COMPILATION_UNIT");
+  static const ElementKind COMPILATION_UNIT = const ElementKind._("COMPILATION_UNIT");
 
-  static const CONSTRUCTOR = const ElementKind._("CONSTRUCTOR");
+  static const ElementKind CONSTRUCTOR = const ElementKind._("CONSTRUCTOR");
 
-  static const ENUM = const ElementKind._("ENUM");
+  static const ElementKind ENUM = const ElementKind._("ENUM");
 
-  static const ENUM_CONSTANT = const ElementKind._("ENUM_CONSTANT");
+  static const ElementKind ENUM_CONSTANT = const ElementKind._("ENUM_CONSTANT");
 
-  static const FIELD = const ElementKind._("FIELD");
+  static const ElementKind FIELD = const ElementKind._("FIELD");
 
-  static const FILE = const ElementKind._("FILE");
+  static const ElementKind FILE = const ElementKind._("FILE");
 
-  static const FUNCTION = const ElementKind._("FUNCTION");
+  static const ElementKind FUNCTION = const ElementKind._("FUNCTION");
 
-  static const FUNCTION_TYPE_ALIAS = const ElementKind._("FUNCTION_TYPE_ALIAS");
+  static const ElementKind FUNCTION_TYPE_ALIAS = const ElementKind._("FUNCTION_TYPE_ALIAS");
 
-  static const GETTER = const ElementKind._("GETTER");
+  static const ElementKind GETTER = const ElementKind._("GETTER");
 
-  static const LABEL = const ElementKind._("LABEL");
+  static const ElementKind LABEL = const ElementKind._("LABEL");
 
-  static const LIBRARY = const ElementKind._("LIBRARY");
+  static const ElementKind LIBRARY = const ElementKind._("LIBRARY");
 
-  static const LOCAL_VARIABLE = const ElementKind._("LOCAL_VARIABLE");
+  static const ElementKind LOCAL_VARIABLE = const ElementKind._("LOCAL_VARIABLE");
 
-  static const METHOD = const ElementKind._("METHOD");
+  static const ElementKind METHOD = const ElementKind._("METHOD");
 
-  static const PARAMETER = const ElementKind._("PARAMETER");
+  static const ElementKind PARAMETER = const ElementKind._("PARAMETER");
 
-  static const PREFIX = const ElementKind._("PREFIX");
+  static const ElementKind PREFIX = const ElementKind._("PREFIX");
 
-  static const SETTER = const ElementKind._("SETTER");
+  static const ElementKind SETTER = const ElementKind._("SETTER");
 
-  static const TOP_LEVEL_VARIABLE = const ElementKind._("TOP_LEVEL_VARIABLE");
+  static const ElementKind TOP_LEVEL_VARIABLE = const ElementKind._("TOP_LEVEL_VARIABLE");
 
-  static const TYPE_PARAMETER = const ElementKind._("TYPE_PARAMETER");
+  static const ElementKind TYPE_PARAMETER = const ElementKind._("TYPE_PARAMETER");
 
   /**
    * Deprecated: support for tests was removed.
    */
-  static const UNIT_TEST_GROUP = const ElementKind._("UNIT_TEST_GROUP");
+  static const ElementKind UNIT_TEST_GROUP = const ElementKind._("UNIT_TEST_GROUP");
 
   /**
    * Deprecated: support for tests was removed.
    */
-  static const UNIT_TEST_TEST = const ElementKind._("UNIT_TEST_TEST");
+  static const ElementKind UNIT_TEST_TEST = const ElementKind._("UNIT_TEST_TEST");
 
-  static const UNKNOWN = const ElementKind._("UNKNOWN");
+  static const ElementKind UNKNOWN = const ElementKind._("UNKNOWN");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10255,13 +10255,13 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class ExecutableKind implements Enum {
-  static const CLIENT = const ExecutableKind._("CLIENT");
+  static const ExecutableKind CLIENT = const ExecutableKind._("CLIENT");
 
-  static const EITHER = const ExecutableKind._("EITHER");
+  static const ExecutableKind EITHER = const ExecutableKind._("EITHER");
 
-  static const NOT_EXECUTABLE = const ExecutableKind._("NOT_EXECUTABLE");
+  static const ExecutableKind NOT_EXECUTABLE = const ExecutableKind._("NOT_EXECUTABLE");
 
-  static const SERVER = const ExecutableKind._("SERVER");
+  static const ExecutableKind SERVER = const ExecutableKind._("SERVER");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10313,7 +10313,7 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class ExecutionService implements Enum {
-  static const LAUNCH_DATA = const ExecutionService._("LAUNCH_DATA");
+  static const ExecutionService LAUNCH_DATA = const ExecutionService._("LAUNCH_DATA");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10360,9 +10360,9 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class FileKind implements Enum {
-  static const LIBRARY = const FileKind._("LIBRARY");
+  static const FileKind LIBRARY = const FileKind._("LIBRARY");
 
-  static const PART = const FileKind._("PART");
+  static const FileKind PART = const FileKind._("PART");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10414,15 +10414,15 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class FoldingKind implements Enum {
-  static const COMMENT = const FoldingKind._("COMMENT");
+  static const FoldingKind COMMENT = const FoldingKind._("COMMENT");
 
-  static const CLASS_MEMBER = const FoldingKind._("CLASS_MEMBER");
+  static const FoldingKind CLASS_MEMBER = const FoldingKind._("CLASS_MEMBER");
 
-  static const DIRECTIVES = const FoldingKind._("DIRECTIVES");
+  static const FoldingKind DIRECTIVES = const FoldingKind._("DIRECTIVES");
 
-  static const DOCUMENTATION_COMMENT = const FoldingKind._("DOCUMENTATION_COMMENT");
+  static const FoldingKind DOCUMENTATION_COMMENT = const FoldingKind._("DOCUMENTATION_COMMENT");
 
-  static const TOP_LEVEL_DECLARATION = const FoldingKind._("TOP_LEVEL_DECLARATION");
+  static const FoldingKind TOP_LEVEL_DECLARATION = const FoldingKind._("TOP_LEVEL_DECLARATION");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10599,7 +10599,7 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class GeneralAnalysisService implements Enum {
-  static const ANALYZED_FILES = const GeneralAnalysisService._("ANALYZED_FILES");
+  static const GeneralAnalysisService ANALYZED_FILES = const GeneralAnalysisService._("ANALYZED_FILES");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -10840,298 +10840,298 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class HighlightRegionType implements Enum {
-  static const ANNOTATION = const HighlightRegionType._("ANNOTATION");
+  static const HighlightRegionType ANNOTATION = const HighlightRegionType._("ANNOTATION");
 
-  static const BUILT_IN = const HighlightRegionType._("BUILT_IN");
+  static const HighlightRegionType BUILT_IN = const HighlightRegionType._("BUILT_IN");
 
-  static const CLASS = const HighlightRegionType._("CLASS");
+  static const HighlightRegionType CLASS = const HighlightRegionType._("CLASS");
 
-  static const COMMENT_BLOCK = const HighlightRegionType._("COMMENT_BLOCK");
+  static const HighlightRegionType COMMENT_BLOCK = const HighlightRegionType._("COMMENT_BLOCK");
 
-  static const COMMENT_DOCUMENTATION = const HighlightRegionType._("COMMENT_DOCUMENTATION");
+  static const HighlightRegionType COMMENT_DOCUMENTATION = const HighlightRegionType._("COMMENT_DOCUMENTATION");
 
-  static const COMMENT_END_OF_LINE = const HighlightRegionType._("COMMENT_END_OF_LINE");
+  static const HighlightRegionType COMMENT_END_OF_LINE = const HighlightRegionType._("COMMENT_END_OF_LINE");
 
-  static const CONSTRUCTOR = const HighlightRegionType._("CONSTRUCTOR");
+  static const HighlightRegionType CONSTRUCTOR = const HighlightRegionType._("CONSTRUCTOR");
 
-  static const DIRECTIVE = const HighlightRegionType._("DIRECTIVE");
+  static const HighlightRegionType DIRECTIVE = const HighlightRegionType._("DIRECTIVE");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const DYNAMIC_TYPE = const HighlightRegionType._("DYNAMIC_TYPE");
+  static const HighlightRegionType DYNAMIC_TYPE = const HighlightRegionType._("DYNAMIC_TYPE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const DYNAMIC_LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_DECLARATION");
+  static const HighlightRegionType DYNAMIC_LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const DYNAMIC_LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_REFERENCE");
+  static const HighlightRegionType DYNAMIC_LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("DYNAMIC_LOCAL_VARIABLE_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const DYNAMIC_PARAMETER_DECLARATION = const HighlightRegionType._("DYNAMIC_PARAMETER_DECLARATION");
+  static const HighlightRegionType DYNAMIC_PARAMETER_DECLARATION = const HighlightRegionType._("DYNAMIC_PARAMETER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const DYNAMIC_PARAMETER_REFERENCE = const HighlightRegionType._("DYNAMIC_PARAMETER_REFERENCE");
+  static const HighlightRegionType DYNAMIC_PARAMETER_REFERENCE = const HighlightRegionType._("DYNAMIC_PARAMETER_REFERENCE");
 
-  static const ENUM = const HighlightRegionType._("ENUM");
+  static const HighlightRegionType ENUM = const HighlightRegionType._("ENUM");
 
-  static const ENUM_CONSTANT = const HighlightRegionType._("ENUM_CONSTANT");
+  static const HighlightRegionType ENUM_CONSTANT = const HighlightRegionType._("ENUM_CONSTANT");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const FIELD = const HighlightRegionType._("FIELD");
+  static const HighlightRegionType FIELD = const HighlightRegionType._("FIELD");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const FIELD_STATIC = const HighlightRegionType._("FIELD_STATIC");
+  static const HighlightRegionType FIELD_STATIC = const HighlightRegionType._("FIELD_STATIC");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const FUNCTION = const HighlightRegionType._("FUNCTION");
+  static const HighlightRegionType FUNCTION = const HighlightRegionType._("FUNCTION");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const FUNCTION_DECLARATION = const HighlightRegionType._("FUNCTION_DECLARATION");
+  static const HighlightRegionType FUNCTION_DECLARATION = const HighlightRegionType._("FUNCTION_DECLARATION");
 
-  static const FUNCTION_TYPE_ALIAS = const HighlightRegionType._("FUNCTION_TYPE_ALIAS");
+  static const HighlightRegionType FUNCTION_TYPE_ALIAS = const HighlightRegionType._("FUNCTION_TYPE_ALIAS");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const GETTER_DECLARATION = const HighlightRegionType._("GETTER_DECLARATION");
+  static const HighlightRegionType GETTER_DECLARATION = const HighlightRegionType._("GETTER_DECLARATION");
 
-  static const IDENTIFIER_DEFAULT = const HighlightRegionType._("IDENTIFIER_DEFAULT");
+  static const HighlightRegionType IDENTIFIER_DEFAULT = const HighlightRegionType._("IDENTIFIER_DEFAULT");
 
-  static const IMPORT_PREFIX = const HighlightRegionType._("IMPORT_PREFIX");
+  static const HighlightRegionType IMPORT_PREFIX = const HighlightRegionType._("IMPORT_PREFIX");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_FIELD_DECLARATION = const HighlightRegionType._("INSTANCE_FIELD_DECLARATION");
+  static const HighlightRegionType INSTANCE_FIELD_DECLARATION = const HighlightRegionType._("INSTANCE_FIELD_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_FIELD_REFERENCE = const HighlightRegionType._("INSTANCE_FIELD_REFERENCE");
+  static const HighlightRegionType INSTANCE_FIELD_REFERENCE = const HighlightRegionType._("INSTANCE_FIELD_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_GETTER_DECLARATION = const HighlightRegionType._("INSTANCE_GETTER_DECLARATION");
+  static const HighlightRegionType INSTANCE_GETTER_DECLARATION = const HighlightRegionType._("INSTANCE_GETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_GETTER_REFERENCE = const HighlightRegionType._("INSTANCE_GETTER_REFERENCE");
+  static const HighlightRegionType INSTANCE_GETTER_REFERENCE = const HighlightRegionType._("INSTANCE_GETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_METHOD_DECLARATION = const HighlightRegionType._("INSTANCE_METHOD_DECLARATION");
+  static const HighlightRegionType INSTANCE_METHOD_DECLARATION = const HighlightRegionType._("INSTANCE_METHOD_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_METHOD_REFERENCE = const HighlightRegionType._("INSTANCE_METHOD_REFERENCE");
+  static const HighlightRegionType INSTANCE_METHOD_REFERENCE = const HighlightRegionType._("INSTANCE_METHOD_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_SETTER_DECLARATION = const HighlightRegionType._("INSTANCE_SETTER_DECLARATION");
+  static const HighlightRegionType INSTANCE_SETTER_DECLARATION = const HighlightRegionType._("INSTANCE_SETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INSTANCE_SETTER_REFERENCE = const HighlightRegionType._("INSTANCE_SETTER_REFERENCE");
+  static const HighlightRegionType INSTANCE_SETTER_REFERENCE = const HighlightRegionType._("INSTANCE_SETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const INVALID_STRING_ESCAPE = const HighlightRegionType._("INVALID_STRING_ESCAPE");
+  static const HighlightRegionType INVALID_STRING_ESCAPE = const HighlightRegionType._("INVALID_STRING_ESCAPE");
 
-  static const KEYWORD = const HighlightRegionType._("KEYWORD");
+  static const HighlightRegionType KEYWORD = const HighlightRegionType._("KEYWORD");
 
-  static const LABEL = const HighlightRegionType._("LABEL");
+  static const HighlightRegionType LABEL = const HighlightRegionType._("LABEL");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const LIBRARY_NAME = const HighlightRegionType._("LIBRARY_NAME");
+  static const HighlightRegionType LIBRARY_NAME = const HighlightRegionType._("LIBRARY_NAME");
 
-  static const LITERAL_BOOLEAN = const HighlightRegionType._("LITERAL_BOOLEAN");
+  static const HighlightRegionType LITERAL_BOOLEAN = const HighlightRegionType._("LITERAL_BOOLEAN");
 
-  static const LITERAL_DOUBLE = const HighlightRegionType._("LITERAL_DOUBLE");
+  static const HighlightRegionType LITERAL_DOUBLE = const HighlightRegionType._("LITERAL_DOUBLE");
 
-  static const LITERAL_INTEGER = const HighlightRegionType._("LITERAL_INTEGER");
+  static const HighlightRegionType LITERAL_INTEGER = const HighlightRegionType._("LITERAL_INTEGER");
 
-  static const LITERAL_LIST = const HighlightRegionType._("LITERAL_LIST");
+  static const HighlightRegionType LITERAL_LIST = const HighlightRegionType._("LITERAL_LIST");
 
-  static const LITERAL_MAP = const HighlightRegionType._("LITERAL_MAP");
+  static const HighlightRegionType LITERAL_MAP = const HighlightRegionType._("LITERAL_MAP");
 
-  static const LITERAL_STRING = const HighlightRegionType._("LITERAL_STRING");
+  static const HighlightRegionType LITERAL_STRING = const HighlightRegionType._("LITERAL_STRING");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const LOCAL_FUNCTION_DECLARATION = const HighlightRegionType._("LOCAL_FUNCTION_DECLARATION");
+  static const HighlightRegionType LOCAL_FUNCTION_DECLARATION = const HighlightRegionType._("LOCAL_FUNCTION_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const LOCAL_FUNCTION_REFERENCE = const HighlightRegionType._("LOCAL_FUNCTION_REFERENCE");
+  static const HighlightRegionType LOCAL_FUNCTION_REFERENCE = const HighlightRegionType._("LOCAL_FUNCTION_REFERENCE");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const LOCAL_VARIABLE = const HighlightRegionType._("LOCAL_VARIABLE");
+  static const HighlightRegionType LOCAL_VARIABLE = const HighlightRegionType._("LOCAL_VARIABLE");
 
-  static const LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("LOCAL_VARIABLE_DECLARATION");
+  static const HighlightRegionType LOCAL_VARIABLE_DECLARATION = const HighlightRegionType._("LOCAL_VARIABLE_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("LOCAL_VARIABLE_REFERENCE");
+  static const HighlightRegionType LOCAL_VARIABLE_REFERENCE = const HighlightRegionType._("LOCAL_VARIABLE_REFERENCE");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const METHOD = const HighlightRegionType._("METHOD");
+  static const HighlightRegionType METHOD = const HighlightRegionType._("METHOD");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const METHOD_DECLARATION = const HighlightRegionType._("METHOD_DECLARATION");
+  static const HighlightRegionType METHOD_DECLARATION = const HighlightRegionType._("METHOD_DECLARATION");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const METHOD_DECLARATION_STATIC = const HighlightRegionType._("METHOD_DECLARATION_STATIC");
+  static const HighlightRegionType METHOD_DECLARATION_STATIC = const HighlightRegionType._("METHOD_DECLARATION_STATIC");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const METHOD_STATIC = const HighlightRegionType._("METHOD_STATIC");
+  static const HighlightRegionType METHOD_STATIC = const HighlightRegionType._("METHOD_STATIC");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const PARAMETER = const HighlightRegionType._("PARAMETER");
+  static const HighlightRegionType PARAMETER = const HighlightRegionType._("PARAMETER");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const SETTER_DECLARATION = const HighlightRegionType._("SETTER_DECLARATION");
+  static const HighlightRegionType SETTER_DECLARATION = const HighlightRegionType._("SETTER_DECLARATION");
 
   /**
    * Only for version 1 of highlight.
    */
-  static const TOP_LEVEL_VARIABLE = const HighlightRegionType._("TOP_LEVEL_VARIABLE");
+  static const HighlightRegionType TOP_LEVEL_VARIABLE = const HighlightRegionType._("TOP_LEVEL_VARIABLE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const PARAMETER_DECLARATION = const HighlightRegionType._("PARAMETER_DECLARATION");
+  static const HighlightRegionType PARAMETER_DECLARATION = const HighlightRegionType._("PARAMETER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const PARAMETER_REFERENCE = const HighlightRegionType._("PARAMETER_REFERENCE");
+  static const HighlightRegionType PARAMETER_REFERENCE = const HighlightRegionType._("PARAMETER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_FIELD_DECLARATION = const HighlightRegionType._("STATIC_FIELD_DECLARATION");
+  static const HighlightRegionType STATIC_FIELD_DECLARATION = const HighlightRegionType._("STATIC_FIELD_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_GETTER_DECLARATION = const HighlightRegionType._("STATIC_GETTER_DECLARATION");
+  static const HighlightRegionType STATIC_GETTER_DECLARATION = const HighlightRegionType._("STATIC_GETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_GETTER_REFERENCE = const HighlightRegionType._("STATIC_GETTER_REFERENCE");
+  static const HighlightRegionType STATIC_GETTER_REFERENCE = const HighlightRegionType._("STATIC_GETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_METHOD_DECLARATION = const HighlightRegionType._("STATIC_METHOD_DECLARATION");
+  static const HighlightRegionType STATIC_METHOD_DECLARATION = const HighlightRegionType._("STATIC_METHOD_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_METHOD_REFERENCE = const HighlightRegionType._("STATIC_METHOD_REFERENCE");
+  static const HighlightRegionType STATIC_METHOD_REFERENCE = const HighlightRegionType._("STATIC_METHOD_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_SETTER_DECLARATION = const HighlightRegionType._("STATIC_SETTER_DECLARATION");
+  static const HighlightRegionType STATIC_SETTER_DECLARATION = const HighlightRegionType._("STATIC_SETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const STATIC_SETTER_REFERENCE = const HighlightRegionType._("STATIC_SETTER_REFERENCE");
+  static const HighlightRegionType STATIC_SETTER_REFERENCE = const HighlightRegionType._("STATIC_SETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_FUNCTION_DECLARATION = const HighlightRegionType._("TOP_LEVEL_FUNCTION_DECLARATION");
+  static const HighlightRegionType TOP_LEVEL_FUNCTION_DECLARATION = const HighlightRegionType._("TOP_LEVEL_FUNCTION_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_FUNCTION_REFERENCE = const HighlightRegionType._("TOP_LEVEL_FUNCTION_REFERENCE");
+  static const HighlightRegionType TOP_LEVEL_FUNCTION_REFERENCE = const HighlightRegionType._("TOP_LEVEL_FUNCTION_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_GETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_GETTER_DECLARATION");
+  static const HighlightRegionType TOP_LEVEL_GETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_GETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_GETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_GETTER_REFERENCE");
+  static const HighlightRegionType TOP_LEVEL_GETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_GETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_SETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_SETTER_DECLARATION");
+  static const HighlightRegionType TOP_LEVEL_SETTER_DECLARATION = const HighlightRegionType._("TOP_LEVEL_SETTER_DECLARATION");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_SETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_SETTER_REFERENCE");
+  static const HighlightRegionType TOP_LEVEL_SETTER_REFERENCE = const HighlightRegionType._("TOP_LEVEL_SETTER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const TOP_LEVEL_VARIABLE_DECLARATION = const HighlightRegionType._("TOP_LEVEL_VARIABLE_DECLARATION");
+  static const HighlightRegionType TOP_LEVEL_VARIABLE_DECLARATION = const HighlightRegionType._("TOP_LEVEL_VARIABLE_DECLARATION");
 
-  static const TYPE_NAME_DYNAMIC = const HighlightRegionType._("TYPE_NAME_DYNAMIC");
+  static const HighlightRegionType TYPE_NAME_DYNAMIC = const HighlightRegionType._("TYPE_NAME_DYNAMIC");
 
-  static const TYPE_PARAMETER = const HighlightRegionType._("TYPE_PARAMETER");
+  static const HighlightRegionType TYPE_PARAMETER = const HighlightRegionType._("TYPE_PARAMETER");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const UNRESOLVED_INSTANCE_MEMBER_REFERENCE = const HighlightRegionType._("UNRESOLVED_INSTANCE_MEMBER_REFERENCE");
+  static const HighlightRegionType UNRESOLVED_INSTANCE_MEMBER_REFERENCE = const HighlightRegionType._("UNRESOLVED_INSTANCE_MEMBER_REFERENCE");
 
   /**
    * Only for version 2 of highlight.
    */
-  static const VALID_STRING_ESCAPE = const HighlightRegionType._("VALID_STRING_ESCAPE");
+  static const HighlightRegionType VALID_STRING_ESCAPE = const HighlightRegionType._("VALID_STRING_ESCAPE");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -12145,13 +12145,13 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class LinkedEditSuggestionKind implements Enum {
-  static const METHOD = const LinkedEditSuggestionKind._("METHOD");
+  static const LinkedEditSuggestionKind METHOD = const LinkedEditSuggestionKind._("METHOD");
 
-  static const PARAMETER = const LinkedEditSuggestionKind._("PARAMETER");
+  static const LinkedEditSuggestionKind PARAMETER = const LinkedEditSuggestionKind._("PARAMETER");
 
-  static const TYPE = const LinkedEditSuggestionKind._("TYPE");
+  static const LinkedEditSuggestionKind TYPE = const LinkedEditSuggestionKind._("TYPE");
 
-  static const VARIABLE = const LinkedEditSuggestionKind._("VARIABLE");
+  static const LinkedEditSuggestionKind VARIABLE = const LinkedEditSuggestionKind._("VARIABLE");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -13425,23 +13425,23 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class RefactoringKind implements Enum {
-  static const CONVERT_GETTER_TO_METHOD = const RefactoringKind._("CONVERT_GETTER_TO_METHOD");
+  static const RefactoringKind CONVERT_GETTER_TO_METHOD = const RefactoringKind._("CONVERT_GETTER_TO_METHOD");
 
-  static const CONVERT_METHOD_TO_GETTER = const RefactoringKind._("CONVERT_METHOD_TO_GETTER");
+  static const RefactoringKind CONVERT_METHOD_TO_GETTER = const RefactoringKind._("CONVERT_METHOD_TO_GETTER");
 
-  static const EXTRACT_LOCAL_VARIABLE = const RefactoringKind._("EXTRACT_LOCAL_VARIABLE");
+  static const RefactoringKind EXTRACT_LOCAL_VARIABLE = const RefactoringKind._("EXTRACT_LOCAL_VARIABLE");
 
-  static const EXTRACT_METHOD = const RefactoringKind._("EXTRACT_METHOD");
+  static const RefactoringKind EXTRACT_METHOD = const RefactoringKind._("EXTRACT_METHOD");
 
-  static const INLINE_LOCAL_VARIABLE = const RefactoringKind._("INLINE_LOCAL_VARIABLE");
+  static const RefactoringKind INLINE_LOCAL_VARIABLE = const RefactoringKind._("INLINE_LOCAL_VARIABLE");
 
-  static const INLINE_METHOD = const RefactoringKind._("INLINE_METHOD");
+  static const RefactoringKind INLINE_METHOD = const RefactoringKind._("INLINE_METHOD");
 
-  static const MOVE_FILE = const RefactoringKind._("MOVE_FILE");
+  static const RefactoringKind MOVE_FILE = const RefactoringKind._("MOVE_FILE");
 
-  static const RENAME = const RefactoringKind._("RENAME");
+  static const RefactoringKind RENAME = const RefactoringKind._("RENAME");
 
-  static const SORT_MEMBERS = const RefactoringKind._("SORT_MEMBERS");
+  static const RefactoringKind SORT_MEMBERS = const RefactoringKind._("SORT_MEMBERS");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -13762,11 +13762,11 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class RefactoringMethodParameterKind implements Enum {
-  static const REQUIRED = const RefactoringMethodParameterKind._("REQUIRED");
+  static const RefactoringMethodParameterKind REQUIRED = const RefactoringMethodParameterKind._("REQUIRED");
 
-  static const POSITIONAL = const RefactoringMethodParameterKind._("POSITIONAL");
+  static const RefactoringMethodParameterKind POSITIONAL = const RefactoringMethodParameterKind._("POSITIONAL");
 
-  static const NAMED = const RefactoringMethodParameterKind._("NAMED");
+  static const RefactoringMethodParameterKind NAMED = const RefactoringMethodParameterKind._("NAMED");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -13948,7 +13948,7 @@
   /**
    * A minor code problem. No example, because it is not used yet.
    */
-  static const INFO = const RefactoringProblemSeverity._("INFO");
+  static const RefactoringProblemSeverity INFO = const RefactoringProblemSeverity._("INFO");
 
   /**
    * A minor code problem. For example names of local variables should be camel
@@ -13956,7 +13956,7 @@
    * with an upper case is OK from the language point of view, but it is nice
    * to warn the user.
    */
-  static const WARNING = const RefactoringProblemSeverity._("WARNING");
+  static const RefactoringProblemSeverity WARNING = const RefactoringProblemSeverity._("WARNING");
 
   /**
    * The refactoring technically can be performed, but there is a logical
@@ -13969,14 +13969,14 @@
    * the name conflict might be expected, and the user wants to fix it
    * afterwards.
    */
-  static const ERROR = const RefactoringProblemSeverity._("ERROR");
+  static const RefactoringProblemSeverity ERROR = const RefactoringProblemSeverity._("ERROR");
 
   /**
    * A fatal error, which prevents performing the refactoring. For example the
    * name of a local variable being extracted is not a valid identifier, or
    * selection is not a valid expression.
    */
-  static const FATAL = const RefactoringProblemSeverity._("FATAL");
+  static const RefactoringProblemSeverity FATAL = const RefactoringProblemSeverity._("FATAL");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -14237,93 +14237,93 @@
    * satisfied because the content of the file changed before the requested
    * results could be computed.
    */
-  static const CONTENT_MODIFIED = const RequestErrorCode._("CONTENT_MODIFIED");
+  static const RequestErrorCode CONTENT_MODIFIED = const RequestErrorCode._("CONTENT_MODIFIED");
 
   /**
    * A request specified a FilePath which does not match a file in an analysis
    * root, or the requested operation is not available for the file.
    */
-  static const FILE_NOT_ANALYZED = const RequestErrorCode._("FILE_NOT_ANALYZED");
+  static const RequestErrorCode FILE_NOT_ANALYZED = const RequestErrorCode._("FILE_NOT_ANALYZED");
 
   /**
    * An "edit.format" request specified a FilePath which does not match a Dart
    * file in an analysis root.
    */
-  static const FORMAT_INVALID_FILE = const RequestErrorCode._("FORMAT_INVALID_FILE");
+  static const RequestErrorCode FORMAT_INVALID_FILE = const RequestErrorCode._("FORMAT_INVALID_FILE");
 
   /**
    * An "edit.format" request specified a file that contains syntax errors.
    */
-  static const FORMAT_WITH_ERRORS = const RequestErrorCode._("FORMAT_WITH_ERRORS");
+  static const RequestErrorCode FORMAT_WITH_ERRORS = const RequestErrorCode._("FORMAT_WITH_ERRORS");
 
   /**
    * An "analysis.getErrors" request specified a FilePath which does not match
    * a file currently subject to analysis.
    */
-  static const GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
+  static const RequestErrorCode GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
 
   /**
    * An "analysis.getNavigation" request specified a FilePath which does not
    * match a file currently subject to analysis.
    */
-  static const GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
+  static const RequestErrorCode GET_NAVIGATION_INVALID_FILE = const RequestErrorCode._("GET_NAVIGATION_INVALID_FILE");
 
   /**
    * An "analysis.getReachableSources" request specified a FilePath which does
    * not match a file currently subject to analysis.
    */
-  static const GET_REACHABLE_SOURCES_INVALID_FILE = const RequestErrorCode._("GET_REACHABLE_SOURCES_INVALID_FILE");
+  static const RequestErrorCode GET_REACHABLE_SOURCES_INVALID_FILE = const RequestErrorCode._("GET_REACHABLE_SOURCES_INVALID_FILE");
 
   /**
    * A path passed as an argument to a request (such as analysis.reanalyze) is
    * required to be an analysis root, but isn't.
    */
-  static const INVALID_ANALYSIS_ROOT = const RequestErrorCode._("INVALID_ANALYSIS_ROOT");
+  static const RequestErrorCode INVALID_ANALYSIS_ROOT = const RequestErrorCode._("INVALID_ANALYSIS_ROOT");
 
   /**
    * The context root used to create an execution context does not exist.
    */
-  static const INVALID_EXECUTION_CONTEXT = const RequestErrorCode._("INVALID_EXECUTION_CONTEXT");
+  static const RequestErrorCode INVALID_EXECUTION_CONTEXT = const RequestErrorCode._("INVALID_EXECUTION_CONTEXT");
 
   /**
    * The format of the given file path is invalid, e.g. is not absolute and
    * normalized.
    */
-  static const INVALID_FILE_PATH_FORMAT = const RequestErrorCode._("INVALID_FILE_PATH_FORMAT");
+  static const RequestErrorCode INVALID_FILE_PATH_FORMAT = const RequestErrorCode._("INVALID_FILE_PATH_FORMAT");
 
   /**
    * An "analysis.updateContent" request contained a ChangeContentOverlay
    * object which can't be applied, due to an edit having an offset or length
    * that is out of range.
    */
-  static const INVALID_OVERLAY_CHANGE = const RequestErrorCode._("INVALID_OVERLAY_CHANGE");
+  static const RequestErrorCode INVALID_OVERLAY_CHANGE = const RequestErrorCode._("INVALID_OVERLAY_CHANGE");
 
   /**
    * One of the method parameters was invalid.
    */
-  static const INVALID_PARAMETER = const RequestErrorCode._("INVALID_PARAMETER");
+  static const RequestErrorCode INVALID_PARAMETER = const RequestErrorCode._("INVALID_PARAMETER");
 
   /**
    * A malformed request was received.
    */
-  static const INVALID_REQUEST = const RequestErrorCode._("INVALID_REQUEST");
+  static const RequestErrorCode INVALID_REQUEST = const RequestErrorCode._("INVALID_REQUEST");
 
   /**
    * The "--no-index" flag was passed when the analysis server created, but
    * this API call requires an index to have been generated.
    */
-  static const NO_INDEX_GENERATED = const RequestErrorCode._("NO_INDEX_GENERATED");
+  static const RequestErrorCode NO_INDEX_GENERATED = const RequestErrorCode._("NO_INDEX_GENERATED");
 
   /**
    * An "edit.organizeDirectives" request specified a Dart file that cannot be
    * analyzed. The reason is described in the message.
    */
-  static const ORGANIZE_DIRECTIVES_ERROR = const RequestErrorCode._("ORGANIZE_DIRECTIVES_ERROR");
+  static const RequestErrorCode ORGANIZE_DIRECTIVES_ERROR = const RequestErrorCode._("ORGANIZE_DIRECTIVES_ERROR");
 
   /**
    * Another refactoring request was received during processing of this one.
    */
-  static const REFACTORING_REQUEST_CANCELLED = const RequestErrorCode._("REFACTORING_REQUEST_CANCELLED");
+  static const RequestErrorCode REFACTORING_REQUEST_CANCELLED = const RequestErrorCode._("REFACTORING_REQUEST_CANCELLED");
 
   /**
    * The analysis server has already been started (and hence won't accept new
@@ -14333,25 +14333,25 @@
    * server can only speak to one client at a time so this error will never
    * occur.
    */
-  static const SERVER_ALREADY_STARTED = const RequestErrorCode._("SERVER_ALREADY_STARTED");
+  static const RequestErrorCode SERVER_ALREADY_STARTED = const RequestErrorCode._("SERVER_ALREADY_STARTED");
 
   /**
    * An internal error occurred in the analysis server. Also see the
    * server.error notification.
    */
-  static const SERVER_ERROR = const RequestErrorCode._("SERVER_ERROR");
+  static const RequestErrorCode SERVER_ERROR = const RequestErrorCode._("SERVER_ERROR");
 
   /**
    * An "edit.sortMembers" request specified a FilePath which does not match a
    * Dart file in an analysis root.
    */
-  static const SORT_MEMBERS_INVALID_FILE = const RequestErrorCode._("SORT_MEMBERS_INVALID_FILE");
+  static const RequestErrorCode SORT_MEMBERS_INVALID_FILE = const RequestErrorCode._("SORT_MEMBERS_INVALID_FILE");
 
   /**
    * An "edit.sortMembers" request specified a Dart file that has scan or parse
    * errors.
    */
-  static const SORT_MEMBERS_PARSE_ERRORS = const RequestErrorCode._("SORT_MEMBERS_PARSE_ERRORS");
+  static const RequestErrorCode SORT_MEMBERS_PARSE_ERRORS = const RequestErrorCode._("SORT_MEMBERS_PARSE_ERRORS");
 
   /**
    * An "analysis.setPriorityFiles" request includes one or more files that are
@@ -14360,19 +14360,19 @@
    * This is a legacy error; it will be removed before the API reaches version
    * 1.0.
    */
-  static const UNANALYZED_PRIORITY_FILES = const RequestErrorCode._("UNANALYZED_PRIORITY_FILES");
+  static const RequestErrorCode UNANALYZED_PRIORITY_FILES = const RequestErrorCode._("UNANALYZED_PRIORITY_FILES");
 
   /**
    * A request was received which the analysis server does not recognize, or
    * cannot handle in its current configuration.
    */
-  static const UNKNOWN_REQUEST = const RequestErrorCode._("UNKNOWN_REQUEST");
+  static const RequestErrorCode UNKNOWN_REQUEST = const RequestErrorCode._("UNKNOWN_REQUEST");
 
   /**
    * The analysis server was requested to perform an action on a source that
    * does not exist.
    */
-  static const UNKNOWN_SOURCE = const RequestErrorCode._("UNKNOWN_SOURCE");
+  static const RequestErrorCode UNKNOWN_SOURCE = const RequestErrorCode._("UNKNOWN_SOURCE");
 
   /**
    * The analysis server was requested to perform an action which is not
@@ -14381,7 +14381,7 @@
    * This is a legacy error; it will be removed before the API reaches version
    * 1.0.
    */
-  static const UNSUPPORTED_FEATURE = const RequestErrorCode._("UNSUPPORTED_FEATURE");
+  static const RequestErrorCode UNSUPPORTED_FEATURE = const RequestErrorCode._("UNSUPPORTED_FEATURE");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -14641,38 +14641,38 @@
   /**
    * The declaration of an element.
    */
-  static const DECLARATION = const SearchResultKind._("DECLARATION");
+  static const SearchResultKind DECLARATION = const SearchResultKind._("DECLARATION");
 
   /**
    * The invocation of a function or method.
    */
-  static const INVOCATION = const SearchResultKind._("INVOCATION");
+  static const SearchResultKind INVOCATION = const SearchResultKind._("INVOCATION");
 
   /**
    * A reference to a field, parameter or variable where it is being read.
    */
-  static const READ = const SearchResultKind._("READ");
+  static const SearchResultKind READ = const SearchResultKind._("READ");
 
   /**
    * A reference to a field, parameter or variable where it is being read and
    * written.
    */
-  static const READ_WRITE = const SearchResultKind._("READ_WRITE");
+  static const SearchResultKind READ_WRITE = const SearchResultKind._("READ_WRITE");
 
   /**
    * A reference to an element.
    */
-  static const REFERENCE = const SearchResultKind._("REFERENCE");
+  static const SearchResultKind REFERENCE = const SearchResultKind._("REFERENCE");
 
   /**
    * Some other kind of search result.
    */
-  static const UNKNOWN = const SearchResultKind._("UNKNOWN");
+  static const SearchResultKind UNKNOWN = const SearchResultKind._("UNKNOWN");
 
   /**
    * A reference to a field, parameter or variable where it is being written.
    */
-  static const WRITE = const SearchResultKind._("WRITE");
+  static const SearchResultKind WRITE = const SearchResultKind._("WRITE");
 
   /**
    * A list containing all of the enum values that are defined.
@@ -14730,7 +14730,7 @@
  * Clients may not extend, implement or mix-in this class.
  */
 class ServerService implements Enum {
-  static const STATUS = const ServerService._("STATUS");
+  static const ServerService STATUS = const ServerService._("STATUS");
 
   /**
    * A list containing all of the enum values that are defined.
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index fdef53a..46ea334 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -14,7 +14,10 @@
     hide AnalysisOptions, Element;
 import 'package:analysis_server/src/analysis_logger.dart';
 import 'package:analysis_server/src/channel/channel.dart';
+import 'package:analysis_server/src/computer/new_notifications.dart';
 import 'package:analysis_server/src/context_manager.dart';
+import 'package:analysis_server/src/domains/analysis/navigation.dart';
+import 'package:analysis_server/src/domains/analysis/navigation_dart.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart';
 import 'package:analysis_server/src/operation/operation_queue.dart';
@@ -32,6 +35,10 @@
 import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
 import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart' as nd;
+import 'package:analyzer/src/dart/analysis/file_byte_store.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart' as nd;
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -259,6 +266,11 @@
       new DateTime.now().millisecondsSinceEpoch + 1000;
 
   /**
+   * The content overlay for all analysis drivers.
+   */
+  final nd.FileContentOverlay fileContentOverlay = new nd.FileContentOverlay();
+
+  /**
    * The current state of overlays from the client.  This is used as the
    * content cache for all contexts.
    */
@@ -307,6 +319,8 @@
    */
   PubSummaryManager pubSummaryManager;
 
+  ByteStore byteStore;
+
   /**
    * Initialize a newly created server to receive requests from and send
    * responses to the given [channel].
@@ -341,6 +355,10 @@
         options.finerGrainedInvalidation;
     defaultContextOptions.generateImplicitErrors = false;
     operationQueue = new ServerOperationQueue();
+    byteStore = new MemoryCachingByteStore(
+        new FileByteStore(
+            resourceProvider.getStateLocation('.analysis-driver')),
+        1024);
     if (useSingleContextManager) {
       contextManager = new SingleContextManager(resourceProvider, sdkManager,
           packageResolverProvider, analyzedFilesGlobs, defaultContextOptions);
@@ -352,7 +370,8 @@
           packageMapProvider,
           analyzedFilesGlobs,
           instrumentationService,
-          defaultContextOptions);
+          defaultContextOptions,
+          options.enableNewAnalysisDriver);
     }
     this.fileResolverProvider = fileResolverProvider;
     this.packageResolverProvider = packageResolverProvider;
@@ -412,6 +431,11 @@
   }
 
   /**
+   * A table mapping [Folder]s to the [AnalysisDriver]s associated with them.
+   */
+  Map<Folder, nd.AnalysisDriver> get driverMap => contextManager.driverMap;
+
+  /**
    * Return a table mapping [Folder]s to the [AnalysisContext]s associated with
    * them.
    */
@@ -1086,6 +1110,24 @@
    */
   void setAnalysisSubscriptions(
       Map<AnalysisService, Set<String>> subscriptions) {
+    if (options.enableNewAnalysisDriver) {
+      this.analysisServices = subscriptions;
+      Iterable<nd.AnalysisDriver> drivers = driverMap.values;
+      if (drivers.isNotEmpty) {
+        Set<String> allNewFiles =
+            subscriptions.values.expand((files) => files).toSet();
+        for (String file in allNewFiles) {
+          nd.AnalysisDriver driver = drivers.firstWhere(
+              (driver) => driver.isAddedFile(file),
+              orElse: () => drivers.first);
+          // The result will be produced by the "results" stream with
+          // the fully resolved unit, and processed with sending analysis
+          // notifications as it happens after content changes.
+          driver.getResult(file);
+        }
+      }
+      return;
+    }
     // send notifications for already analyzed sources
     subscriptions.forEach((service, Set<String> newFiles) {
       Set<String> oldFiles = analysisServices[service];
@@ -1175,6 +1217,12 @@
    * Set the priority files to the given [files].
    */
   void setPriorityFiles(String requestId, List<String> files) {
+    if (options.enableNewAnalysisDriver) {
+      driverMap.values.forEach((driver) {
+        driver.priorityFiles = files;
+      });
+      return;
+    }
     // Note: when a file is a priority file, that information needs to be
     // propagated to all contexts that analyze the file, so that all contexts
     // will be able to do incremental resolution of the file.  See
@@ -1294,6 +1342,44 @@
    * Implementation for `analysis.updateContent`.
    */
   void updateContent(String id, Map<String, dynamic> changes) {
+    if (options.enableNewAnalysisDriver) {
+      changes.forEach((file, change) {
+        // Prepare the new contents.
+        String oldContents = fileContentOverlay[file];
+        String newContents;
+        if (change is AddContentOverlay) {
+          newContents = change.content;
+        } else if (change is ChangeContentOverlay) {
+          if (oldContents == null) {
+            // The client may only send a ChangeContentOverlay if there is
+            // already an existing overlay for the source.
+            throw new RequestFailure(new Response(id,
+                error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE,
+                    'Invalid overlay change')));
+          }
+          try {
+            newContents = SourceEdit.applySequence(oldContents, change.edits);
+          } on RangeError {
+            throw new RequestFailure(new Response(id,
+                error: new RequestError(RequestErrorCode.INVALID_OVERLAY_CHANGE,
+                    'Invalid overlay change')));
+          }
+        } else if (change is RemoveContentOverlay) {
+          newContents = null;
+        } else {
+          // Protocol parsing should have ensured that we never get here.
+          throw new AnalysisException('Illegal change type');
+        }
+
+        fileContentOverlay[file] = newContents;
+
+        driverMap.values.forEach((driver) {
+          driver.changeFile(file);
+        });
+        // TODO(scheglov) implement other cases
+      });
+      return;
+    }
     changes.forEach((file, change) {
       ContextSourcePair contextSource = getContextSourcePair(file);
       Source source = contextSource.source;
@@ -1406,6 +1492,10 @@
    * existing analysis context.
    */
   void updateOptions(List<OptionUpdater> optionUpdaters) {
+    if (options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      return;
+    }
     //
     // Update existing contexts.
     //
@@ -1472,6 +1562,10 @@
     });
   }
 
+  bool _hasAnalysisServiceSubscription(AnalysisService service, String file) {
+    return analysisServices[service]?.contains(file) ?? false;
+  }
+
   _scheduleAnalysisImplementedNotification() async {
     Set<String> files = analysisServices[AnalysisService.IMPLEMENTED];
     if (files != null) {
@@ -1549,6 +1643,7 @@
 class AnalysisServerOptions {
   bool enableIncrementalResolutionApi = false;
   bool enableIncrementalResolutionValidation = false;
+  bool enableNewAnalysisDriver = false;
   bool enablePubSummaryManager = false;
   bool finerGrainedInvalidation = false;
   bool noErrorNotification = false;
@@ -1598,6 +1693,56 @@
   ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider);
 
   @override
+  nd.AnalysisDriver addAnalysisDriver(Folder folder, AnalysisOptions options) {
+    SourceFactory sourceFactory;
+    AnalysisOptions analysisOptions;
+    {
+      ContextBuilder builder = createContextBuilder(folder, options);
+      AnalysisContext context = builder.buildContext(folder.path);
+      sourceFactory = context.sourceFactory;
+      analysisOptions = context.analysisOptions;
+      context.dispose();
+    }
+    nd.AnalysisDriver analysisDriver = new nd.AnalysisDriver(
+        new nd.PerformanceLog(io.stdout),
+        resourceProvider,
+        analysisServer.byteStore,
+        analysisServer.fileContentOverlay,
+        sourceFactory,
+        analysisOptions);
+    analysisDriver.name = folder.shortName;
+    analysisDriver.status.listen((status) {
+      // TODO(scheglov) send server status
+    });
+    analysisDriver.results.listen((result) {
+      new_sendErrorNotification(analysisServer, result);
+      CompilationUnit unit = result.unit;
+      if (unit != null) {
+        if (analysisServer._hasAnalysisServiceSubscription(
+            AnalysisService.HIGHLIGHTS, result.path)) {
+          sendAnalysisNotificationHighlights(analysisServer, result.path, unit);
+        }
+        if (analysisServer._hasAnalysisServiceSubscription(
+            AnalysisService.NAVIGATION, result.path)) {
+          NavigationCollectorImpl collector = new NavigationCollectorImpl();
+          computeSimpleDartNavigation(collector, unit);
+          collector.createRegions();
+          var params = new AnalysisNavigationParams(result.path,
+              collector.regions, collector.targets, collector.files);
+          analysisServer.sendNotification(params.toNotification());
+        }
+      }
+      // TODO(scheglov) Implement more notifications.
+      // IMPLEMENTED
+      // OVERRIDES
+      // OCCURRENCES (not used in IDEA)
+      // OUTLINE (not used in IDEA)
+    });
+    analysisServer.driverMap[folder] = analysisDriver;
+    return analysisDriver;
+  }
+
+  @override
   AnalysisContext addContext(Folder folder, AnalysisOptions options) {
     ContextBuilder builder = createContextBuilder(folder, options);
     AnalysisContext context = builder.buildContext(folder.path);
@@ -1612,15 +1757,31 @@
 
   @override
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
-    AnalysisContext context = analysisServer.folderMap[contextFolder];
-    if (context != null) {
-      context.applyChanges(changeSet);
-      analysisServer.schedulePerformAnalysisOperation(context);
-      List<String> flushedFiles = new List<String>();
-      for (Source source in changeSet.removedSources) {
-        flushedFiles.add(source.fullName);
+    if (analysisServer.options.enableNewAnalysisDriver) {
+      nd.AnalysisDriver analysisDriver =
+          analysisServer.driverMap[contextFolder];
+      if (analysisDriver != null) {
+        changeSet.addedSources.forEach((source) {
+          analysisDriver.addFile(source.fullName);
+        });
+        changeSet.changedSources.forEach((source) {
+          analysisDriver.changeFile(source.fullName);
+        });
+        changeSet.removedSources.forEach((source) {
+          analysisDriver.removeFile(source.fullName);
+        });
       }
-      sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
+    } else {
+      AnalysisContext context = analysisServer.folderMap[contextFolder];
+      if (context != null) {
+        context.applyChanges(changeSet);
+        analysisServer.schedulePerformAnalysisOperation(context);
+        List<String> flushedFiles = new List<String>();
+        for (Source source in changeSet.removedSources) {
+          flushedFiles.add(source.fullName);
+        }
+        sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
+      }
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/computer/new_notifications.dart b/pkg/analysis_server/lib/src/computer/new_notifications.dart
new file mode 100644
index 0000000..edbdc62
--- /dev/null
+++ b/pkg/analysis_server/lib/src/computer/new_notifications.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/plugin/protocol/protocol.dart' as protocol;
+import 'package:analysis_server/src/analysis_server.dart' show AnalysisServer;
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+
+void new_sendErrorNotification(
+    AnalysisServer analysisServer, AnalysisResult result) {
+  var serverErrors = <protocol.AnalysisError>[];
+  for (AnalysisError error in result.errors) {
+    serverErrors
+        .add(protocol.newAnalysisError_fromEngine(result.lineInfo, error));
+  }
+  var params = new protocol.AnalysisErrorsParams(result.path, serverErrors);
+  analysisServer.sendNotification(params.toNotification());
+}
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 66977c4..a543ad5 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -24,6 +24,7 @@
 import 'package:analyzer/source/sdk_ext.dart';
 import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/context/context.dart' as context;
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_io.dart';
@@ -90,6 +91,11 @@
   Set<String> _dependencies = new Set<String>();
 
   /**
+   * The analysis driver that was created for the [folder].
+   */
+  AnalysisDriver analysisDriver;
+
+  /**
    * The analysis context that was created for the [folder].
    */
   AnalysisContext context;
@@ -246,6 +252,11 @@
   void set callbacks(ContextManagerCallbacks value);
 
   /**
+   * A table mapping [Folder]s to the [AnalysisDriver]s associated with them.
+   */
+  Map<Folder, AnalysisDriver> get driverMap;
+
+  /**
    * Return the list of excluded paths (folders and files) most recently passed
    * to [setRoots].
    */
@@ -321,6 +332,12 @@
  */
 abstract class ContextManagerCallbacks {
   /**
+   * Create and return a new analysis driver rooted at the given [folder], with
+   * the given analysis [options].
+   */
+  AnalysisDriver addAnalysisDriver(Folder folder, AnalysisOptions options);
+
+  /**
    * Create and return a new analysis context rooted at the given [folder], with
    * the given analysis [options].
    */
@@ -479,6 +496,8 @@
    */
   final InstrumentationService _instrumentationService;
 
+  final bool enableNewAnalysisDriver;
+
   @override
   ContextManagerCallbacks callbacks;
 
@@ -488,11 +507,14 @@
    */
   final ContextInfo rootInfo = new ContextInfo._root();
 
+  @override
+  final Map<Folder, AnalysisDriver> driverMap =
+      new HashMap<Folder, AnalysisDriver>();
+
   /**
    * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
    */
-  @override
-  final Map<Folder, AnalysisContext> folderMap =
+  final Map<Folder, AnalysisContext> _folderMap =
       new HashMap<Folder, AnalysisContext>();
 
   /**
@@ -509,7 +531,8 @@
       this._packageMapProvider,
       this.analyzedFilesGlobs,
       this._instrumentationService,
-      this.defaultContextOptions) {
+      this.defaultContextOptions,
+      this.enableNewAnalysisDriver) {
     absolutePathContext = resourceProvider.absolutePathContext;
     pathContext = resourceProvider.pathContext;
   }
@@ -517,6 +540,14 @@
   @override
   Iterable<AnalysisContext> get analysisContexts => folderMap.values;
 
+  Map<Folder, AnalysisContext> get folderMap {
+    if (enableNewAnalysisDriver) {
+      throw new StateError('Should not be used with the new analysis driver');
+    } else {
+      return _folderMap;
+    }
+  }
+
   @override
   List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
     List<AnalysisContext> contexts = <AnalysisContext>[];
@@ -1033,9 +1064,13 @@
     applyToAnalysisOptions(options, optionMap);
 
     info.setDependencies(dependencies);
-    info.context = callbacks.addContext(folder, options);
-    folderMap[folder] = info.context;
-    info.context.name = folder.path;
+    if (enableNewAnalysisDriver) {
+      info.analysisDriver = callbacks.addAnalysisDriver(folder, options);
+    } else {
+      info.context = callbacks.addContext(folder, options);
+      _folderMap[folder] = info.context;
+      info.context.name = folder.path;
+    }
 
     // Look for pubspec-specified analysis configuration.
     File pubspec;
@@ -1052,13 +1087,21 @@
     }
     if (pubspec != null) {
       File pubSource = resourceProvider.getFile(pubspec.path);
-      setConfiguration(
-          info.context,
-          new AnalysisConfiguration.fromPubspec(
-              pubSource, resourceProvider, disposition.packages));
+      if (enableNewAnalysisDriver) {
+        // TODO(scheglov) implement for the new analysis driver
+      } else {
+        setConfiguration(
+            info.context,
+            new AnalysisConfiguration.fromPubspec(
+                pubSource, resourceProvider, disposition.packages));
+      }
     }
 
-    processOptionsForContext(info, optionMap);
+    if (enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+    } else {
+      processOptionsForContext(info, optionMap);
+    }
 
     return info;
   }
@@ -1336,11 +1379,15 @@
         if (resource is File) {
           File file = resource;
           if (_shouldFileBeAnalyzed(file)) {
-            ChangeSet changeSet = new ChangeSet();
-            Source source = createSourceInContext(info.context, file);
-            changeSet.addedSource(source);
-            callbacks.applyChangesToContext(info.folder, changeSet);
-            info.sources[path] = source;
+            if (enableNewAnalysisDriver) {
+              info.analysisDriver.addFile(path);
+            } else {
+              ChangeSet changeSet = new ChangeSet();
+              Source source = createSourceInContext(info.context, file);
+              changeSet.addedSource(source);
+              callbacks.applyChangesToContext(info.folder, changeSet);
+              info.sources[path] = source;
+            }
           }
         }
         break;
@@ -1377,24 +1424,32 @@
           }
         }
 
-        List<Source> sources = info.context.getSourcesWithFullName(path);
-        if (!sources.isEmpty) {
-          ChangeSet changeSet = new ChangeSet();
-          sources.forEach((Source source) {
-            changeSet.removedSource(source);
-          });
-          callbacks.applyChangesToContext(info.folder, changeSet);
-          info.sources.remove(path);
+        if (enableNewAnalysisDriver) {
+          info.analysisDriver.removeFile(path);
+        } else {
+          List<Source> sources = info.context.getSourcesWithFullName(path);
+          if (!sources.isEmpty) {
+            ChangeSet changeSet = new ChangeSet();
+            sources.forEach((Source source) {
+              changeSet.removedSource(source);
+            });
+            callbacks.applyChangesToContext(info.folder, changeSet);
+            info.sources.remove(path);
+          }
         }
         break;
       case ChangeType.MODIFY:
-        List<Source> sources = info.context.getSourcesWithFullName(path);
-        if (!sources.isEmpty) {
-          ChangeSet changeSet = new ChangeSet();
-          sources.forEach((Source source) {
-            changeSet.changedSource(source);
-          });
-          callbacks.applyChangesToContext(info.folder, changeSet);
+        if (enableNewAnalysisDriver) {
+          info.analysisDriver.changeFile(path);
+        } else {
+          List<Source> sources = info.context.getSourcesWithFullName(path);
+          if (!sources.isEmpty) {
+            ChangeSet changeSet = new ChangeSet();
+            sources.forEach((Source source) {
+              changeSet.changedSource(source);
+            });
+            callbacks.applyChangesToContext(info.folder, changeSet);
+          }
         }
         break;
     }
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index f9ea745..aefb37d 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -102,6 +102,15 @@
 
   @override
   Response handleRequest(Request request) {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      String completionId = (_nextCompletionId++).toString();
+      new Future(() {
+        sendCompletionNotification(completionId, 0, 0, []);
+      });
+      return new CompletionGetSuggestionsResult(completionId)
+          .toResponse(request.id);
+    }
     if (server.searchEngine == null) {
       return new Response.noIndexGenerated(request);
     }
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 7a7a870..1ae3193 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -15,6 +15,16 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
+NavigationCollector computeSimpleDartNavigation(
+    NavigationCollector collector, CompilationUnit unit) {
+  _DartNavigationCollector dartCollector =
+      new _DartNavigationCollector(collector);
+  _DartNavigationComputerVisitor visitor =
+      new _DartNavigationComputerVisitor(dartCollector);
+  unit.accept(visitor);
+  return collector;
+}
+
 /**
  * A computer for navigation regions in a Dart [CompilationUnit].
  */
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 44e9ea7..5906cd1 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -69,23 +69,19 @@
     EditFormatParams params = new EditFormatParams.fromRequest(request);
     String file = params.file;
 
-    ContextSourcePair contextSource = server.getContextSourcePair(file);
-
-    engine.AnalysisContext context = contextSource.context;
-    if (context == null) {
-      return new Response.formatInvalidFile(request);
-    }
-
-    Source source = contextSource.source;
-    engine.TimestampedData<String> contents;
+    String unformattedSource;
     try {
-      contents = context.getContents(source);
+      Source source = server.resourceProvider.getFile(file).createSource();
+      if (server.options.enableNewAnalysisDriver) {
+        unformattedSource = server.fileContentOverlay[file];
+      } else {
+        unformattedSource = server.overlayState.getContents(source);
+      }
+      unformattedSource ??= source.contents.data;
     } catch (e) {
       return new Response.formatInvalidFile(request);
     }
 
-    String unformattedSource = contents.data;
-
     int start = params.selectionOffset;
     int length = params.selectionLength;
 
@@ -135,6 +131,10 @@
   }
 
   Future getAssists(Request request) async {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      return;
+    }
     EditGetAssistsParams params = new EditGetAssistsParams.fromRequest(request);
     ContextSourcePair pair = server.getContextSourcePair(params.file);
     engine.AnalysisContext context = pair.context;
@@ -152,7 +152,11 @@
     server.sendResponse(response);
   }
 
-  getFixes(Request request) async {
+  Future getFixes(Request request) async {
+    if (server.options.enableNewAnalysisDriver) {
+      // TODO(scheglov) implement for the new analysis driver
+      return;
+    }
     var params = new EditGetFixesParams.fromRequest(request);
     String file = params.file;
     int offset = params.offset;
@@ -184,7 +188,7 @@
       }
     }
     // respond
-    return server.sendResponse(
+    server.sendResponse(
         new EditGetFixesResult(errorFixesList).toResponse(request.id));
   }
 
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index 300f7a0..e6607ca 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -13,12 +13,12 @@
 import 'package:analyzer/dart/ast/visitor.dart' as engine;
 import 'package:analyzer/dart/element/element.dart' as engine;
 import 'package:analyzer/dart/element/type.dart' as engine;
+import 'package:analyzer/error/error.dart' as engine;
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart' as engine;
-import 'package:analyzer/src/generated/engine.dart' as engine;
-import 'package:analyzer/error/error.dart' as engine;
 import 'package:analyzer/src/error/codes.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
 import 'package:analyzer/src/generated/source.dart' as engine;
 import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
 
@@ -140,7 +140,8 @@
   }
   int offset = element.nameOffset;
   int length = element.nameLength;
-  if (element is engine.CompilationUnitElement) {
+  if (element is engine.CompilationUnitElement ||
+      (element is engine.LibraryElement && offset < 0)) {
     offset = 0;
     length = 0;
   }
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 3095df8..df6df7b 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -245,6 +245,11 @@
   /**
    * The name of the option used to enable using pub summary manager.
    */
+  static const String ENABLE_NEW_ANALYSIS_DRIVER = 'enable-new-analysis-driver';
+
+  /**
+   * The name of the option used to enable using pub summary manager.
+   */
   static const String ENABLE_PUB_SUMMARY_MANAGER = 'enable-pub-summary-manager';
 
   /**
@@ -383,6 +388,8 @@
         results[ENABLE_INCREMENTAL_RESOLUTION_API];
     analysisServerOptions.enableIncrementalResolutionValidation =
         results[INCREMENTAL_RESOLUTION_VALIDATION];
+    analysisServerOptions.enableNewAnalysisDriver =
+      results[ENABLE_NEW_ANALYSIS_DRIVER];
     analysisServerOptions.enablePubSummaryManager =
         results[ENABLE_PUB_SUMMARY_MANAGER];
     analysisServerOptions.finerGrainedInvalidation =
@@ -532,6 +539,10 @@
         help: "enable validation of incremental resolution results (slow)",
         defaultsTo: false,
         negatable: false);
+    parser.addFlag(ENABLE_NEW_ANALYSIS_DRIVER,
+        help: "enable using new analysis driver",
+        defaultsTo: false,
+        negatable: false);
     parser.addFlag(ENABLE_PUB_SUMMARY_MANAGER,
         help: "enable using summaries for pub cache packages",
         defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index ca243c4..486f724 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -216,6 +216,7 @@
   _SourcePart _methodExpressionPart;
   _SourcePart _methodStatementsPart;
   List<_ReferenceProcessor> _referenceProcessors = [];
+  Set<FunctionBody> _alreadyMadeAsync = new Set<FunctionBody>();
 
   InlineMethodRefactoringImpl(this.searchEngine, this.unit, this.offset) {
     utils = new CorrectionUtils(unit);
@@ -287,6 +288,11 @@
       result = new RefactoringStatus.fatal('Cannot inline operator.');
       return new Future<RefactoringStatus>.value(result);
     }
+    // maybe [a]sync*
+    if (_methodElement.isGenerator) {
+      result = new RefactoringStatus.fatal('Cannot inline a generator.');
+      return new Future<RefactoringStatus>.value(result);
+    }
     // analyze method body
     result.addStatus(_prepareMethodParts());
     // process references
@@ -560,6 +566,33 @@
     if (!_shouldProcess()) {
       return;
     }
+    // If the element being inlined is async, ensure that the function
+    // body that encloses the method is also async.
+    if (ref._methodElement.isAsynchronous) {
+      FunctionBody body = _node.getAncestor((n) => n is FunctionBody);
+      if (body != null) {
+        if (body.isSynchronous) {
+          if (body.isGenerator) {
+            status.addFatalError(
+                'Cannot inline async into sync*.', newLocation_fromNode(_node));
+            return;
+          }
+          if (refElement is ExecutableElement) {
+            var executable = refElement as ExecutableElement;
+            if (!executable.returnType.isDartAsyncFuture) {
+              status.addFatalError(
+                  'Cannot inline async into a function that does not return a Future.',
+                  newLocation_fromNode(_node));
+              return;
+            }
+          }
+          if (ref._alreadyMadeAsync.add(body)) {
+            SourceRange bodyStart = rangeStartLength(body.offset, 0);
+            _addRefEdit(newSourceEdit_range(bodyStart, 'async '));
+          }
+        }
+      }
+    }
     // may be invocation of inline method
     if (nodeParent is MethodInvocation) {
       MethodInvocation invocation = nodeParent;
diff --git a/pkg/analysis_server/lib/src/single_context_manager.dart b/pkg/analysis_server/lib/src/single_context_manager.dart
index 984bc73..fa99c96 100644
--- a/pkg/analysis_server/lib/src/single_context_manager.dart
+++ b/pkg/analysis_server/lib/src/single_context_manager.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/plugin/resolver_provider.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -85,6 +86,11 @@
   ContextManagerCallbacks callbacks;
 
   /**
+   * The analysis driver which analyses everything.
+   */
+  AnalysisDriver analysisDriver;
+
+  /**
    * The context in which everything is being analyzed.
    */
   AnalysisContext context;
@@ -117,6 +123,9 @@
       context == null ? <AnalysisContext>[] : <AnalysisContext>[context];
 
   @override
+  Map<Folder, AnalysisDriver> get driverMap => {contextFolder: analysisDriver};
+
+  @override
   Map<Folder, AnalysisContext> get folderMap => {contextFolder: context};
 
   @override
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 888c2dd..ce0bf7d 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -1801,7 +1802,8 @@
         packageMapProvider,
         analysisFilesGlobs,
         InstrumentationService.NULL_SERVICE,
-        new AnalysisOptionsImpl());
+        new AnalysisOptionsImpl(),
+        false);
     callbacks = new TestContextManagerCallbacks(resourceProvider);
     manager.callbacks = callbacks;
     resourceProvider.newFolder(projPath);
@@ -2655,6 +2657,12 @@
   Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
 
   @override
+  AnalysisDriver addAnalysisDriver(Folder folder, AnalysisOptions options) {
+    // TODO: implement addAnalysisDriver
+    throw new UnimplementedError();
+  }
+
+  @override
   AnalysisContext addContext(Folder folder, AnalysisOptions options) {
     String path = folder.path;
     expect(currentContextPaths, isNot(contains(path)));
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 7c35f5e..bc1d29c 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -66,6 +66,56 @@
     expect(refactoring.isDeclaration, isTrue);
   }
 
+  test_bad_async_intoSyncStar() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  Iterable<Future<int>> foo() sync* {
+    yield test;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // error
+    return _assertConditionsFatal('Cannot inline async into sync*.');
+  }
+
+  test_bad_async_targetIsSync_doesNotReturnFuture() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  double foo() {
+    test;
+    return 1.2;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // error
+    return _assertConditionsFatal(
+        'Cannot inline async into a function that does not return a Future.');
+  }
+
+  test_bad_asyncStar() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Stream<int> test() async* {
+    yield 1;
+    yield 2;
+  }
+  foo() {
+    test();
+  }
+}
+''');
+    _createRefactoring('test() async*');
+    // error
+    return _assertConditionsFatal('Cannot inline a generator.');
+  }
+
   test_bad_cascadeInvocation() async {
     indexTestUnit(r'''
 class A {
@@ -711,6 +761,100 @@
 ''');
   }
 
+  test_getter_async_targetIsAsync() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  Future<int> foo() async {
+    return test;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Future<int> foo() async {
+    return 42;
+  }
+}
+''');
+  }
+
+  test_getter_async_targetIsAsyncStar() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  Stream<int> foo() async {
+    return await test;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Stream<int> foo() async {
+    return await 42;
+  }
+}
+''');
+  }
+
+  test_getter_async_targetIsSync() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  Future<int> foo() {
+    return test;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Future<int> foo() async {
+    return 42;
+  }
+}
+''');
+  }
+
+  test_getter_async_targetIsSync2() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> get test async => 42;
+  Future<int> foo1() {
+    return test;
+  }
+  Future<int> foo2() {
+    return test;
+  }
+}
+''');
+    _createRefactoring('test async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Future<int> foo1() async {
+    return 42;
+  }
+  Future<int> foo2() async {
+    return 42;
+  }
+}
+''');
+  }
+
   test_getter_classMember_instance() {
     indexTestUnit(r'''
 class A {
@@ -803,6 +947,50 @@
     expect(refactoring.inlineAll, false);
   }
 
+  test_method_async() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> test() async => 42;
+  Future<int> foo() {
+    return test();
+  }
+}
+''');
+    _createRefactoring('test() async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Future<int> foo() async {
+    return 42;
+  }
+}
+''');
+  }
+
+  test_method_async2() {
+    indexTestUnit(r'''
+import 'dart:async';
+class A {
+  Future<int> test() async => 42;
+  Future foo() {
+    return [test(), test()];
+  }
+}
+''');
+    _createRefactoring('test() async');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+import 'dart:async';
+class A {
+  Future foo() async {
+    return [42, 42];
+  }
+}
+''');
+  }
+
   test_method_emptyBody() {
     indexTestUnit(r'''
 abstract class A {
diff --git a/pkg/analysis_server/tool/instrumentation/log/log.dart b/pkg/analysis_server/tool/instrumentation/log/log.dart
index 2378c27..37bb4f5 100644
--- a/pkg/analysis_server/tool/instrumentation/log/log.dart
+++ b/pkg/analysis_server/tool/instrumentation/log/log.dart
@@ -8,6 +8,7 @@
 library analysis_server.tool.instrumentation.log.log;
 
 import 'dart:convert';
+import 'dart:math' as math;
 
 import 'package:analyzer/instrumentation/instrumentation.dart';
 
@@ -304,14 +305,21 @@
         if (extraLines.isNotEmpty) {
           logContent[i] = merge(line, extraLines);
         }
+        extraLines.clear();
       } else {
         logContent.removeAt(i);
         extraLines.insert(0, line);
       }
     }
     if (extraLines.isNotEmpty) {
-      throw new StateError(
-          '${extraLines.length} non-entry lines before any entry');
+      int count = math.min(extraLines.length, 10);
+      StringBuffer buffer = new StringBuffer();
+      buffer.writeln('${extraLines.length} non-entry lines before any entry');
+      buffer.writeln('First $count lines:');
+      for (int i = 0; i < count; i++) {
+        buffer.writeln(extraLines[i]);
+      }
+      throw new StateError(buffer.toString());
     }
   }
 
diff --git a/pkg/analysis_server/tool/instrumentation/page/log_page.dart b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
index ad1194d..756b2f4 100644
--- a/pkg/analysis_server/tool/instrumentation/page/log_page.dart
+++ b/pkg/analysis_server/tool/instrumentation/page/log_page.dart
@@ -225,7 +225,11 @@
       sink.writeln('</option>');
     }
     sink.writeln('</select>');
-    sink.writeln('Events $pageStart - ${pageEnd - 1} of ${length - 1}');
+    if (length == 0) {
+      sink.writeln('No matching events');
+    } else {
+      sink.writeln('Events $pageStart - ${pageEnd - 1} of $length');
+    }
     sink.writeln('</div>');
 
     sink.writeln('<div style="float: right">');
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 02855a6..bdde0bc 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -260,7 +260,7 @@
         }));
         String valueString = literalString(value.value);
         writeln(
-            'static const ${value.value} = const $className._($valueString);');
+            'static const $className ${value.value} = const $className._($valueString);');
         writeln();
       }
 
diff --git a/pkg/analysis_server/tool/spec/generate_files b/pkg/analysis_server/tool/spec/generate_files
index ee9e970..c37a385 100755
--- a/pkg/analysis_server/tool/spec/generate_files
+++ b/pkg/analysis_server/tool/spec/generate_files
@@ -51,6 +51,10 @@
 fi
 
 PKG_FILE="${ROOT_DIR}/pkg/analysis_server/.packages"
+if [[ !(-e $PKG_FILE) ]];
+then
+  PKG_FILE="${ROOT_DIR}/.packages"
+fi
 
 DART="${BUILD_DIR}/dart-sdk/bin/dart"
 
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 11c97e8..b6923a0 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -700,4 +700,19 @@
 
   @override
   TypeParameterElement get element;
+
+  /**
+   * Return the type representing the bound associated with this parameter,
+   * or `dynamic` if there was no explicit bound.
+   */
+  DartType get bound;
+
+  /**
+   * An object that can be used to identify this type parameter with `==`.
+   *
+   * Depending on the use, [bound] may also need to be taken into account.
+   * A given type parameter, it may have different bounds in different scopes.
+   * Always consult the bound if that could be relevant.
+   */
+  ElementLocation get definition;
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 6677376..7033335 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -4,33 +4,23 @@
 
 import 'dart:async';
 import 'dart:collection';
-import 'dart:convert';
+import 'dart:typed_data';
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/error/error.dart';
-import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
-import 'package:analyzer/src/dart/scanner/reader.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisEngine, AnalysisOptions, ChangeSet;
-import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/link.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
-import 'package:analyzer/src/summary/summarize_ast.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/util/fast_uri.dart';
-import 'package:convert/convert.dart';
-import 'package:crypto/crypto.dart';
 
 /**
  * This class computes [AnalysisResult]s for Dart files.
@@ -68,8 +58,16 @@
  *
  *
  * TODO(scheglov) Clean up the list of implicitly analyzed files.
+ *
+ * TODO(scheglov) Handle not existing 'dart:x' URIs (while user is typing).
  */
 class AnalysisDriver {
+  /**
+   * The version of data format, should be incremented on every format change.
+   */
+  static const int DATA_VERSION = 1;
+
+  String name;
   final PerformanceLog _logger;
 
   /**
@@ -88,7 +86,7 @@
    * This [ContentCache] is consulted for a file content before reading
    * the content from the file.
    */
-  final ContentCache _contentCache;
+  final FileContentOverlay _contentOverlay;
 
   /**
    * The [SourceFactory] is used to resolve URIs to paths and restore URIs
@@ -102,6 +100,16 @@
   final AnalysisOptions _analysisOptions;
 
   /**
+   * The salt to mix into all hashes used as keys for serialized data.
+   */
+  final Uint32List _salt = new Uint32List(2);
+
+  /**
+   * The current file system state.
+   */
+  FileSystemState _fsState;
+
+  /**
    * The combined unlinked and linked package for the SDK, extracted from
    * the given [_sourceFactory].
    */
@@ -135,28 +143,6 @@
   final _filesToAnalyze = new LinkedHashSet<String>();
 
   /**
-   * Cache of URI resolution. The outer map key is the absolute URI of the
-   * containing file. The inner map key is the URI text of a directive
-   * contained in that file. The inner map value is the [Source] object which
-   * that URI text resolves to.
-   */
-  final _uriResolutionCache = <Uri, Map<String, Source>>{};
-
-  /**
-   * The current file state.
-   *
-   * It maps file paths to the MD5 hash of the file content.
-   */
-  final _fileContentHashMap = <String, String>{};
-
-  /**
-   * The API signatures corresponding to [_fileContentHashMap].
-   *
-   * It maps file paths to the unlinked API signatures.
-   */
-  final _fileApiSignatureMap = <String, String>{};
-
-  /**
    * Mapping from library URIs to the dependency signature of the library.
    */
   final _dependencySignatureMap = <Uri, String>{};
@@ -176,10 +162,19 @@
    */
   AnalysisStatus _currentStatus = AnalysisStatus.IDLE;
 
+  /**
+   * Create a new instance of [AnalysisDriver].
+   *
+   * The given [SourceFactory] is cloned to ensure that it does not contain a
+   * reference to a [AnalysisContext] in which it could have been used.
+   */
   AnalysisDriver(this._logger, this._resourceProvider, this._byteStore,
-      this._contentCache, SourceFactory sourceFactory, this._analysisOptions)
+      this._contentOverlay, SourceFactory sourceFactory, this._analysisOptions)
       : _sourceFactory = sourceFactory.clone() {
+    _fillSalt();
     _sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
+    _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
+        _resourceProvider, _sourceFactory, _analysisOptions, _salt);
   }
 
   /**
@@ -202,7 +197,8 @@
    * Return the [Stream] that produces [AnalysisResult]s for added files.
    *
    * Analysis starts when the client starts listening to the stream, and stops
-   * when the client cancels the subscription.
+   * when the client cancels the subscription. Note that the stream supports
+   * only one single subscriber.
    *
    * When the client starts listening, the analysis state transitions to
    * "analyzing" and an analysis result is produced for every added file prior
@@ -224,6 +220,17 @@
     try {
       PerformanceLogSection analysisSection = null;
       while (true) {
+        // Pump the event queue to allow IO and other asynchronous data
+        // processing while analysis is active. For example Analysis Server
+        // needs to be able to process `updateContent` or `setPriorityFiles`
+        // requests while background analysis is in progress.
+        //
+        // The number of pumpings is arbitrary, might be changed if we see that
+        // analysis or other data processing tasks are starving. Ideally we
+        // would need to be able to set priority of (continuous) asynchronous
+        // tasks.
+        await _pumpEventQueue(128);
+
         await _hasWork.signal;
 
         if (analysisSection == null) {
@@ -233,7 +240,7 @@
         // Verify all changed files one at a time.
         if (_changedFiles.isNotEmpty) {
           String path = _removeFirst(_changedFiles);
-          _verifyApiSignatureOfChangedFile(path);
+          _verifyApiSignature(path);
           // Repeat the processing loop.
           _hasWork.notify();
           continue;
@@ -307,8 +314,10 @@
    * The results of analysis are eventually produced by the [results] stream.
    */
   void addFile(String path) {
-    _explicitFiles.add(path);
-    _filesToAnalyze.add(path);
+    if (AnalysisEngine.isDartFileName(path)) {
+      _explicitFiles.add(path);
+      _filesToAnalyze.add(path);
+    }
     _transitionToAnalyzing();
     _hasWork.notify();
   }
@@ -332,9 +341,11 @@
    * [changeFile] invocation.
    */
   void changeFile(String path) {
-    _changedFiles.add(path);
-    if (_explicitFiles.contains(path)) {
-      _filesToAnalyze.add(path);
+    if (AnalysisEngine.isDartFileName(path)) {
+      _changedFiles.add(path);
+      if (_explicitFiles.contains(path)) {
+        _filesToAnalyze.add(path);
+      }
     }
     _transitionToAnalyzing();
     _hasWork.notify();
@@ -365,6 +376,14 @@
   }
 
   /**
+   * Return `true` if the file with the given [path] was explicitly added
+   * to analysis using [addFile].
+   */
+  bool isAddedFile(String path) {
+    return _explicitFiles.contains(path);
+  }
+
+  /**
    * Remove the file with the given [path] from the list of files to analyze.
    *
    * The [path] must be absolute and normalized.
@@ -408,15 +427,13 @@
    * compute only if [withUnit] is `true`.
    */
   AnalysisResult _computeAnalysisResult(String path, {bool withUnit: false}) {
-    Source source = _sourceForPath(path);
-
     // If we don't need the fully resolved unit, check for the cached result.
     if (!withUnit) {
-      _File file = new _File.forLinking(this, source);
+      FileState file = _fsState.getFile(path);
       // Prepare the key for the cached result.
       String key = _getResolvedUnitKey(file);
       if (key == null) {
-        _logger.run('Compute the dependency hash for $source', () {
+        _logger.run('Compute the dependency hash for $path', () {
           _createLibraryContext(file);
           key = _getResolvedUnitKey(file);
         });
@@ -429,9 +446,9 @@
     }
 
     // We need the fully resolved unit, or the result is not cached.
-    return _logger.run('Compute analysis result for $source', () {
+    return _logger.run('Compute analysis result for $path', () {
       // Still no result, compute and store it.
-      _File file = new _File.forResolution(this, source);
+      FileState file = _verifyApiSignature(path);
       _LibraryContext libraryContext = _createLibraryContext(file);
       AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
       try {
@@ -465,6 +482,7 @@
             file.uri,
             withUnit ? file.content : null,
             file.contentHash,
+            file.lineInfo,
             resolvedUnit,
             errors);
       } finally {
@@ -478,8 +496,7 @@
         AnalysisEngine.instance.createAnalysisContext();
     analysisContext.analysisOptions = _analysisOptions;
 
-    analysisContext.sourceFactory =
-        new SourceFactory((_sourceFactory as SourceFactoryImpl).resolvers);
+    analysisContext.sourceFactory = _sourceFactory.clone();
     analysisContext.resultProvider =
         new InputPackagesResultProvider(analysisContext, libraryContext.store);
     analysisContext
@@ -494,13 +511,13 @@
    * TODO(scheglov) We often don't need [SummaryDataStore], only dependency
    * signature.
    */
-  _LibraryContext _createLibraryContext(_File libraryFile) {
+  _LibraryContext _createLibraryContext(FileState libraryFile) {
     return _logger.run('Create library context', () {
       Map<String, _LibraryNode> nodes = <String, _LibraryNode>{};
       SummaryDataStore store = new SummaryDataStore(const <String>[]);
       store.addBundle(null, _sdkBundle);
 
-      _LibraryNode createLibraryNodes(_File libraryFile) {
+      _LibraryNode createLibraryNodes(FileState libraryFile) {
         Uri libraryUri = libraryFile.uri;
 
         // URIs with the 'dart:' scheme are served from the SDK bundle.
@@ -511,37 +528,25 @@
         String libraryUriStr = libraryUri.toString();
         _LibraryNode node = nodes[libraryUriStr];
         if (node == null) {
-          node = new _LibraryNode(this, nodes, libraryUri);
+          node = new _LibraryNode(this, libraryFile, libraryUri);
           nodes[libraryUriStr] = node;
 
           // Append the defining unit.
-          _ReferencedUris referenced;
           {
-            PackageBundle bundle = libraryFile.unlinked;
-            UnlinkedUnit unlinked = bundle.unlinkedUnits.single;
-            referenced = new _ReferencedUris(unlinked);
-            node.unlinkedBundles.add(bundle);
+            UnlinkedUnit unlinked = libraryFile.unlinked;
             _addToStoreUnlinked(store, libraryUriStr, unlinked);
           }
 
           // Append parts.
-          for (String uri in referenced.parted) {
-            _File file = libraryFile.resolveUri(uri);
-            PackageBundle bundle = file.unlinked;
-            UnlinkedUnit unlinked = bundle.unlinkedUnits.single;
-            node.unlinkedBundles.add(bundle);
-            _addToStoreUnlinked(store, file.uri.toString(), unlinked);
+          for (FileState part in libraryFile.partedFiles) {
+            String partUriStr = part.uri.toString();
+            UnlinkedUnit unlinked = part.unlinked;
+            _addToStoreUnlinked(store, partUriStr, unlinked);
           }
 
           // Create nodes for referenced libraries.
-          for (String uri in referenced.imported) {
-            _File file = libraryFile.resolveUri(uri);
-            createLibraryNodes(file);
-          }
-          for (String uri in referenced.exported) {
-            _File file = libraryFile.resolveUri(uri);
-            createLibraryNodes(file);
-          }
+          libraryFile.importedFiles.forEach(createLibraryNodes);
+          libraryFile.exportedFiles.forEach(createLibraryNodes);
         }
 
         // Done with this node.
@@ -606,10 +611,20 @@
   }
 
   /**
+   * Fill [_salt] with data.
+   */
+  void _fillSalt() {
+    int analysisOptionsSalt = 0;
+    analysisOptionsSalt |= _analysisOptions.strongMode ? (1 << 0) : 0;
+    _salt[0] = DATA_VERSION;
+    _salt[1] = analysisOptionsSalt;
+  }
+
+  /**
    * If we know the result [key] for the [file], try to load the analysis
    * result from the cache. Return `null` if not found.
    */
-  AnalysisResult _getCachedAnalysisResult(_File file, String key) {
+  AnalysisResult _getCachedAnalysisResult(FileState file, String key) {
     List<int> bytes = _byteStore.get(key);
     if (bytes != null) {
       var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
@@ -622,8 +637,8 @@
               error.message,
               error.correction))
           .toList();
-      return new AnalysisResult(
-          file.path, file.uri, null, file.contentHash, null, errors);
+      return new AnalysisResult(file.path, file.uri, null, file.contentHash,
+          file.lineInfo, null, errors);
     }
     return null;
   }
@@ -632,10 +647,11 @@
    * Return the key to store fully resolved results for the [file] into the
    * cache. Return `null` if the dependency signature is not known yet.
    */
-  String _getResolvedUnitKey(_File file) {
+  String _getResolvedUnitKey(FileState file) {
     String dependencyHash = _dependencySignatureMap[file.uri];
     if (dependencyHash != null) {
       ApiSignature signature = new ApiSignature();
+      signature.addUint32List(_salt);
       signature.addString(dependencyHash);
       signature.addString(file.contentHash);
       return '${signature.toHex()}.resolved';
@@ -644,15 +660,6 @@
   }
 
   /**
-   * Return the [Source] for the given [path] in [_sourceFactory].
-   */
-  Source _sourceForPath(String path) {
-    Source fileSource = _resourceProvider.getFile(path).createSource();
-    Uri uri = _sourceFactory.restoreUri(fileSource);
-    return _resourceProvider.getFile(path).createSource(uri);
-  }
-
-  /**
    * Send a notifications to the [status] stream that the driver started
    * analyzing.
    */
@@ -679,27 +686,31 @@
    *
    * TODO(scheglov) I see that adding a local var changes (full) API signature.
    */
-  void _verifyApiSignatureOfChangedFile(String path) {
-    _logger.run('Verify API signature of $path', () {
-      String oldSignature = _fileApiSignatureMap[path];
-      // Compute the new API signature.
-      // _File.forResolution() also updates the content hash in the cache.
-      Source source = _sourceForPath(path);
-      _File newFile = new _File.forResolution(this, source);
-      String newSignature = newFile.unlinked.apiSignature;
-      // If the old API signature is not null, then the file was used to
-      // compute at least one dependency signature. If the new API signature
-      // is different, then potentially all dependency signatures and
-      // resolution results are invalid.
-      if (oldSignature != null && oldSignature != newSignature) {
-        _logger.writeln('API signatures mismatch found for $newFile');
+  FileState _verifyApiSignature(String path) {
+    return _logger.run('Verify API signature of $path', () {
+      FileState file = _fsState.getFile(path);
+      bool apiChanged = file.refresh();
+      if (apiChanged) {
+        _logger.writeln('API signatures mismatch found for $path');
         _dependencySignatureMap.clear();
         _filesToAnalyze.addAll(_explicitFiles);
       }
+      return file;
     });
   }
 
   /**
+   * Returns a [Future] that completes after performing [times] pumpings of
+   * the event queue.
+   */
+  static Future _pumpEventQueue(int times) {
+    if (times == 0) {
+      return new Future.value();
+    }
+    return new Future.delayed(Duration.ZERO, () => _pumpEventQueue(times - 1));
+  }
+
+  /**
    * Remove and return the first item in the given [set].
    */
   static Object/*=T*/ _removeFirst/*<T>*/(LinkedHashSet<Object/*=T*/ > set) {
@@ -744,6 +755,11 @@
   final String contentHash;
 
   /**
+   * Information about lines in the [content].
+   */
+  final LineInfo lineInfo;
+
+  /**
    * The fully resolved compilation unit for the [content].
    */
   final CompilationUnit unit;
@@ -753,8 +769,8 @@
    */
   final List<AnalysisError> errors;
 
-  AnalysisResult(this.path, this.uri, this.content, this.contentHash, this.unit,
-      this.errors);
+  AnalysisResult(this.path, this.uri, this.content, this.contentHash,
+      this.lineInfo, this.unit, this.errors);
 }
 
 /**
@@ -854,194 +870,10 @@
 }
 
 /**
- * Information about a file being analyzed, explicitly or implicitly.
- *
- * It provides a stable, consistent view on its [content], [contentHash],
- * [unlinked] and [unit].
- *
- * A new file can be created either for resolution or for linking.
- *
- * When file is created for linking, it assumes that the file has not been
- * changed since the last time its content was read and hashed. So, this
- * content hash is also used to look for an existing unlinked bundle in the
- * [AnalysisDriver._byteStore]. If any of the caches is empty, the file is
- * created without caching, as for resolution.
- *
- * When file is created for resolution, we always read the content, compute its
- * hash and update [AnalysisDriver._fileContentHashMap], parse the content,
- * compute the unlinked bundle and update [AnalysisDriver._fileApiSignatureMap].
- * It is important to keep these two maps in sync.
- */
-class _File {
-  /**
-   * The driver instance that is used to access [SourceFactory] and caches.
-   */
-  final AnalysisDriver driver;
-
-  /**
-   * The [Source] this [_File] instance represents.
-   */
-  final Source source;
-
-  /**
-   * The [source] content, or `null` if this file is for linking.
-   */
-  final String content;
-
-  /**
-   * The [source] content hash, not `null` even if [content] is `null`.
-   */
-  final String contentHash;
-
-  /**
-   * The unlinked bundle, not `null`.
-   */
-  final PackageBundle unlinked;
-
-  /**
-   * The unresolved unit, not `null` if this file is for resolution.
-   */
-  final CompilationUnit unit;
-
-  /**
-   * Return the file with consistent [content] and [contentHash].
-   */
-  factory _File.forContent(AnalysisDriver driver, Source source) {
-    String path = source.fullName;
-    // Read the content.
-    String content;
-    try {
-      content = driver._contentCache.getContents(source);
-      content ??= source.contents.data;
-    } catch (_) {
-      content = '';
-      // TODO(scheglov) We fail to report URI_DOES_NOT_EXIST.
-      // On one hand we need to provide an unlinked bundle to prevent
-      // analysis context from reading the file (we want it to work
-      // hermetically and handle one one file at a time). OTOH,
-      // ResynthesizerResultProvider happily reports that any source in the
-      // SummaryDataStore has MODIFICATION_TIME `0`. We need to return `-1`
-      // for missing files. Maybe add this feature to SummaryDataStore?
-    }
-    // Compute the content hash.
-    List<int> textBytes = UTF8.encode(content);
-    List<int> hashBytes = md5.convert(textBytes).bytes;
-    String contentHash = hex.encode(hashBytes);
-    driver._fileContentHashMap[path] = contentHash;
-    // Return information about the file content.
-    return new _File._(driver, source, content, contentHash, null, null);
-  }
-
-  factory _File.forLinking(AnalysisDriver driver, Source source) {
-    String path = source.fullName;
-    String contentHash = driver._fileContentHashMap[path];
-    // If we don't have the file content hash, compute it.
-    if (contentHash == null) {
-      _File file = new _File.forContent(driver, source);
-      contentHash = file.contentHash;
-    }
-    // If we have the cached unlinked bundle, use it.
-    {
-      String key = '$contentHash.unlinked';
-      List<int> bytes = driver._byteStore.get(key);
-      if (bytes != null) {
-        PackageBundle unlinked = new PackageBundle.fromBuffer(bytes);
-        _updateApiSignature(driver, path, unlinked.apiSignature);
-        return new _File._(driver, source, null, contentHash, unlinked, null);
-      }
-    }
-    // Otherwise, read the source, parse and build a new unlinked bundle.
-    return new _File.forResolution(driver, source);
-  }
-
-  factory _File.forResolution(AnalysisDriver driver, Source source) {
-    _File file = new _File.forContent(driver, source);
-    String path = file.path;
-    String content = file.content;
-    String contentHash = file.contentHash;
-    // Parse the unit.
-    CompilationUnit unit = _parse(driver, source, content);
-    // Prepare the unlinked bundle.
-    PackageBundle unlinked;
-    {
-      String key = '$contentHash.unlinked';
-      List<int> bytes = driver._byteStore.get(key);
-      if (bytes == null) {
-        driver._logger.run('Create unlinked for $path', () {
-          UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
-          PackageBundleAssembler assembler = new PackageBundleAssembler();
-          assembler.addUnlinkedUnitWithHash(
-              source.uri.toString(), unlinkedUnit, contentHash);
-          bytes = assembler.assemble().toBuffer();
-          driver._byteStore.put(key, bytes);
-        });
-      }
-      unlinked = new PackageBundle.fromBuffer(bytes);
-      _updateApiSignature(driver, path, unlinked.apiSignature);
-    }
-    // Return the full file.
-    return new _File._(driver, source, content, contentHash, unlinked, unit);
-  }
-
-  _File._(this.driver, this.source, this.content, this.contentHash,
-      this.unlinked, this.unit);
-
-  String get path => source.fullName;
-
-  Uri get uri => source.uri;
-
-  /**
-   * Return the [_File] for the [uri] referenced in this file.
-   *
-   * This [_File] can be used only for linking.
-   */
-  _File resolveUri(String uri) {
-    // TODO(scheglov) Consider removing this caching after implementing other
-    // optimizations, e.g. changeFile() optimization.
-    Source uriSource = driver._uriResolutionCache
-        .putIfAbsent(this.uri, () => <String, Source>{})
-        .putIfAbsent(uri, () => driver._sourceFactory.resolveUri(source, uri));
-    return new _File.forLinking(driver, uriSource);
-  }
-
-  @override
-  String toString() => path;
-
-  /**
-   * Return the parsed unresolved [CompilationUnit] for the given [content].
-   */
-  static CompilationUnit _parse(
-      AnalysisDriver driver, Source source, String content) {
-    AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER;
-
-    CharSequenceReader reader = new CharSequenceReader(content);
-    Scanner scanner = new Scanner(source, reader, errorListener);
-    scanner.scanGenericMethodComments = driver._analysisOptions.strongMode;
-    Token token = scanner.tokenize();
-    LineInfo lineInfo = new LineInfo(scanner.lineStarts);
-
-    Parser parser = new Parser(source, errorListener);
-    parser.parseGenericMethodComments = driver._analysisOptions.strongMode;
-    CompilationUnit unit = parser.parseCompilationUnit(token);
-    unit.lineInfo = lineInfo;
-    return unit;
-  }
-
-  static void _updateApiSignature(
-      AnalysisDriver driver, String path, String newSignature) {
-    String oldSignature = driver._fileApiSignatureMap[path];
-    if (oldSignature != null && oldSignature != newSignature) {
-      driver._dependencySignatureMap.clear();
-    }
-    driver._fileApiSignatureMap[path] = newSignature;
-  }
-}
-
-/**
  * TODO(scheglov) document
  */
 class _LibraryContext {
-  final _File file;
+  final FileState file;
   final _LibraryNode node;
   final SummaryDataStore store;
   _LibraryContext(this.file, this.node, this.store);
@@ -1049,78 +881,29 @@
 
 class _LibraryNode {
   final AnalysisDriver driver;
-  final Map<String, _LibraryNode> nodes;
+  final FileState file;
   final Uri uri;
-  final List<PackageBundle> unlinkedBundles = <PackageBundle>[];
 
-  Set<_LibraryNode> transitiveDependencies;
-  List<_LibraryNode> _dependencies;
+  Set<FileState> transitiveDependencies;
   String _dependencySignature;
 
-  _LibraryNode(this.driver, this.nodes, this.uri);
-
-  /**
-   * Retrieve the dependencies of this node.
-   */
-  List<_LibraryNode> get dependencies {
-    if (_dependencies == null) {
-      Set<_LibraryNode> dependencies = new Set<_LibraryNode>();
-
-      void appendDependency(String uriStr) {
-        Uri uri = FastUri.parse(uriStr);
-        if (uri.scheme == 'dart') {
-          // Dependency on the SDK is implicit and always added.
-          // The SDK linked bundle is precomputed before linking packages.
-        } else {
-          if (!uri.isAbsolute) {
-            uri = resolveRelativeUri(this.uri, uri);
-            uriStr = uri.toString();
-          }
-          _LibraryNode node = nodes[uriStr];
-          if (node == null) {
-            throw new StateError('No node for: $uriStr');
-          }
-          dependencies.add(node);
-        }
-      }
-
-      for (PackageBundle unlinkedBundle in unlinkedBundles) {
-        for (UnlinkedUnit unit in unlinkedBundle.unlinkedUnits) {
-          for (UnlinkedImport import in unit.imports) {
-            if (!import.isImplicit) {
-              appendDependency(import.uri);
-            }
-          }
-          for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
-            appendDependency(export.uri);
-          }
-        }
-      }
-
-      _dependencies = dependencies.toList();
-    }
-    return _dependencies;
-  }
+  _LibraryNode(this.driver, this.file, this.uri);
 
   String get dependencySignature {
     return _dependencySignature ??=
         driver._dependencySignatureMap.putIfAbsent(uri, () {
-      computeTransitiveDependencies();
+      ApiSignature signature = new ApiSignature();
+      signature.addUint32List(driver._salt);
+      signature.addString(driver._sdkBundle.apiSignature);
 
       // Add all unlinked API signatures.
-      List<String> signatures = <String>[];
-      signatures.add(driver._sdkBundle.apiSignature);
+      computeTransitiveDependencies();
       transitiveDependencies
-          .map((node) => node.unlinkedBundles)
-          .expand((bundles) => bundles)
-          .map((bundle) => bundle.apiSignature)
-          .forEach(signatures.add);
-      signatures.sort();
+          .map((file) => file.apiSignature)
+          .forEach(signature.addBytes);
 
       // Combine into a single hash.
-      ApiSignature signature = new ApiSignature();
       signature.addString(uri.toString());
-      signatures.forEach(signature.addString);
       return signature.toHex();
     });
   }
@@ -1134,15 +917,15 @@
 
   void computeTransitiveDependencies() {
     if (transitiveDependencies == null) {
-      transitiveDependencies = new Set<_LibraryNode>();
+      transitiveDependencies = new Set<FileState>();
 
-      void appendDependencies(_LibraryNode node) {
-        if (transitiveDependencies.add(node)) {
-          node.dependencies.forEach(appendDependencies);
+      void appendDependencies(FileState file) {
+        if (transitiveDependencies.add(file)) {
+          file.dependencies.forEach(appendDependencies);
         }
       }
 
-      appendDependencies(this);
+      appendDependencies(file);
     }
   }
 
@@ -1178,29 +961,3 @@
     }
   }
 }
-
-/**
- * TODO(scheglov) document
- */
-class _ReferencedUris {
-  bool isLibrary = true;
-  final List<String> imported = <String>[];
-  final List<String> exported = <String>[];
-  final List<String> parted = <String>[];
-
-  factory _ReferencedUris(UnlinkedUnit unit) {
-    _ReferencedUris referenced = new _ReferencedUris._();
-    referenced.parted.addAll(unit.publicNamespace.parts);
-    for (UnlinkedImport import in unit.imports) {
-      if (!import.isImplicit) {
-        referenced.imported.add(import.uri);
-      }
-    }
-    for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
-      referenced.exported.add(export.uri);
-    }
-    return referenced;
-  }
-
-  _ReferencedUris._();
-}
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
new file mode 100644
index 0000000..5ca64c5
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -0,0 +1,349 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/source/source_resource.dart';
+import 'package:analyzer/src/summary/api_signature.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/summarize_ast.dart';
+import 'package:analyzer/src/util/fast_uri.dart';
+import 'package:convert/convert.dart';
+import 'package:crypto/crypto.dart';
+
+/**
+ * [FileContentOverlay] is used to temporary override content of files.
+ */
+class FileContentOverlay {
+  final _map = <String, String>{};
+
+  /**
+   * Return the content of the file with the given [path], or `null` the
+   * overlay does not override the content of the file.
+   *
+   * The [path] must be absolute and normalized.
+   */
+  String operator [](String path) => _map[path];
+
+  /**
+   * Return the new [content] of the file with the given [path].
+   *
+   * The [path] must be absolute and normalized.
+   */
+  void operator []=(String path, String content) {
+    if (content == null) {
+      _map.remove(path);
+    } else {
+      _map[path] = content;
+    }
+  }
+}
+
+/**
+ * Information about a file being analyzed, explicitly or implicitly.
+ *
+ * It provides a consistent view on its properties.
+ *
+ * The properties are not guaranteed to represent the most recent state
+ * of the file system. To update the file to the most recent state, [refresh]
+ * should be called.
+ */
+class FileState {
+  final FileSystemState _fsState;
+
+  /**
+   * The absolute path of the file.
+   */
+  final String path;
+
+  /**
+   * The absolute URI of the file.
+   */
+  final Uri uri;
+
+  Source _source;
+
+  String _content;
+  String _contentHash;
+  LineInfo _lineInfo;
+  UnlinkedUnit _unlinked;
+  List<int> _apiSignature;
+
+  List<FileState> _importedFiles;
+  List<FileState> _exportedFiles;
+  List<FileState> _partedFiles;
+  List<FileState> _dependencies;
+
+  FileState(this._fsState, this.path, this.uri) {
+    _source = new FileSource(_fsState._resourceProvider.getFile(path), uri);
+  }
+
+  /**
+   * The unlinked API signature of the file.
+   */
+  List<int> get apiSignature => _apiSignature;
+
+  /**
+   * The content of the file.
+   */
+  String get content => _content;
+
+  /**
+   * The MD5 hash of the [content].
+   */
+  String get contentHash => _contentHash;
+
+  /**
+   * Return information about line in the file.
+   */
+  LineInfo get lineInfo => _lineInfo;
+
+  /**
+   * Return the list of all direct dependencies.
+   */
+  List<FileState> get dependencies => _dependencies;
+
+  /**
+   * The list of files this file exports.
+   */
+  List<FileState> get exportedFiles => _exportedFiles;
+
+  /**
+   * The list of files this file imports.
+   */
+  List<FileState> get importedFiles => _importedFiles;
+
+  /**
+   * The list of files this library file references as parts.
+   */
+  List<FileState> get partedFiles => _partedFiles;
+
+  /**
+   * The [Source] of the file in the [SourceFactory].
+   */
+  Source get source => _source;
+
+  /**
+   * The [UnlinkedUnit] of the file.
+   */
+  UnlinkedUnit get unlinked => _unlinked;
+
+  /**
+   * Read the file content and ensure that all of the file properties are
+   * consistent with the read content, including API signature.
+   *
+   * Return `true` if the API signature changed since the last refresh.
+   */
+  bool refresh() {
+    // Read the content.
+    try {
+      _content = _fsState._contentOverlay[path];
+      _content ??= _fsState._resourceProvider.getFile(path).readAsStringSync();
+    } catch (_) {
+      _content = '';
+      // TODO(scheglov) We fail to report URI_DOES_NOT_EXIST.
+      // On one hand we need to provide an unlinked bundle to prevent
+      // analysis context from reading the file (we want it to work
+      // hermetically and handle one one file at a time). OTOH,
+      // ResynthesizerResultProvider happily reports that any source in the
+      // SummaryDataStore has MODIFICATION_TIME `0`. We need to return `-1`
+      // for missing files. Maybe add this feature to SummaryDataStore?
+    }
+
+    // Compute the content hash.
+    List<int> contentBytes = UTF8.encode(_content);
+    {
+      List<int> hashBytes = md5.convert(contentBytes).bytes;
+      _contentHash = hex.encode(hashBytes);
+    }
+
+    // Prepare the unlinked bundle key.
+    String unlinkedKey;
+    {
+      ApiSignature signature = new ApiSignature();
+      signature.addUint32List(_fsState._salt);
+      signature.addBytes(contentBytes);
+      unlinkedKey = '${signature.toHex()}.unlinked';
+    }
+
+    // Prepare bytes of the unlinked bundle - existing or new.
+    List<int> bytes;
+    {
+      bytes = _fsState._byteStore.get(unlinkedKey);
+      if (bytes == null) {
+        CompilationUnit unit =
+            _parse(_source, _content, _fsState._analysisOptions);
+        _fsState._logger.run('Create unlinked for $path', () {
+          UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
+          bytes = unlinkedUnit.toBuffer();
+          _fsState._byteStore.put(unlinkedKey, bytes);
+        });
+      }
+    }
+
+    // Read the unlinked bundle.
+    _unlinked = new UnlinkedUnit.fromBuffer(bytes);
+    _lineInfo = new LineInfo(_unlinked.lineStarts);
+    List<int> newApiSignature = _unlinked.apiSignature;
+    bool apiSignatureChanged = _apiSignature != null &&
+        !_equalByteLists(_apiSignature, newApiSignature);
+    _apiSignature = newApiSignature;
+
+    // Build the graph.
+    _importedFiles = <FileState>[];
+    _exportedFiles = <FileState>[];
+    _partedFiles = <FileState>[];
+    for (UnlinkedImport import in _unlinked.imports) {
+      if (!import.isImplicit) {
+        String uri = import.uri;
+        if (!_isDartUri(uri)) {
+          FileState file = _fileForRelativeUri(uri);
+          _importedFiles.add(file);
+        }
+      }
+    }
+    for (UnlinkedExportPublic export in _unlinked.publicNamespace.exports) {
+      String uri = export.uri;
+      if (!_isDartUri(uri)) {
+        FileState file = _fileForRelativeUri(uri);
+        _exportedFiles.add(file);
+      }
+    }
+    for (String uri in _unlinked.publicNamespace.parts) {
+      if (!_isDartUri(uri)) {
+        FileState file = _fileForRelativeUri(uri);
+        _partedFiles.add(file);
+      }
+    }
+
+    // Compute direct dependencies.
+    _dependencies = (new Set<FileState>()
+          ..addAll(_importedFiles)
+          ..addAll(_exportedFiles)
+          ..addAll(_partedFiles))
+        .toList();
+
+    // Return whether the API signature changed.
+    return apiSignatureChanged;
+  }
+
+  @override
+  String toString() => path;
+
+  /**
+   * Return the [FileState] for the given [relativeUri].
+   */
+  FileState _fileForRelativeUri(String relativeUri) {
+    Uri absoluteUri = resolveRelativeUri(uri, FastUri.parse(relativeUri));
+    String absolutePath = _fsState._sourceFactory
+        .resolveUri(null, absoluteUri.toString())
+        .fullName;
+    return _fsState.getFile(absolutePath, absoluteUri);
+  }
+
+  /**
+   * Return `true` if the given byte lists are equal.
+   */
+  static bool _equalByteLists(List<int> a, List<int> b) {
+    if (a == null) {
+      return b == null;
+    } else if (b == null) {
+      return false;
+    }
+    if (a.length != b.length) {
+      return false;
+    }
+    for (int i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static bool _isDartUri(String uri) {
+    return uri.startsWith('dart:');
+  }
+
+  /**
+   * Return the parsed unresolved [CompilationUnit] for the given [content].
+   */
+  static CompilationUnit _parse(
+      Source source, String content, AnalysisOptions analysisOptions) {
+    AnalysisErrorListener errorListener = AnalysisErrorListener.NULL_LISTENER;
+
+    CharSequenceReader reader = new CharSequenceReader(content);
+    Scanner scanner = new Scanner(source, reader, errorListener);
+    scanner.scanGenericMethodComments = analysisOptions.strongMode;
+    Token token = scanner.tokenize();
+    LineInfo lineInfo = new LineInfo(scanner.lineStarts);
+
+    Parser parser = new Parser(source, errorListener);
+    parser.parseGenericMethodComments = analysisOptions.strongMode;
+    CompilationUnit unit = parser.parseCompilationUnit(token);
+    unit.lineInfo = lineInfo;
+    return unit;
+  }
+}
+
+/**
+ * Information about known file system state.
+ */
+class FileSystemState {
+  final PerformanceLog _logger;
+  final ResourceProvider _resourceProvider;
+  final ByteStore _byteStore;
+  final FileContentOverlay _contentOverlay;
+  final SourceFactory _sourceFactory;
+  final AnalysisOptions _analysisOptions;
+  final Uint32List _salt;
+
+  final Map<String, FileState> _pathToFile = <String, FileState>{};
+
+  FileSystemState(
+      this._logger,
+      this._byteStore,
+      this._contentOverlay,
+      this._resourceProvider,
+      this._sourceFactory,
+      this._analysisOptions,
+      this._salt);
+
+  /**
+   * Return the [FileState] for the give [path]. The returned file has the
+   * last known state since if was last refreshed.
+   */
+  FileState getFile(String path, [Uri uri]) {
+    FileState file = _pathToFile[path];
+    if (file == null) {
+      uri ??= _uriForPath(path);
+      file = new FileState(this, path, uri);
+      _pathToFile[path] = file;
+      file.refresh();
+    }
+    return file;
+  }
+
+  /**
+   * Return the default [Uri] for the given path in [_sourceFactory].
+   */
+  Uri _uriForPath(String path) {
+    Source fileSource = _resourceProvider.getFile(path).createSource();
+    return _sourceFactory.restoreUri(fileSource);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index d7d39a8..3f7545e 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -191,45 +191,61 @@
   @override
   MethodElement lookUpConcreteMethod(
           String methodName, LibraryElement library) =>
-      _internalLookUpConcreteMethod(
-          methodName, library, true, new HashSet<ClassElement>());
+      _first(_implementationsOfMethod(methodName).where(
+          (MethodElement method) =>
+              !method.isAbstract && method.isAccessibleIn(library)));
 
   @override
   PropertyAccessorElement lookUpGetter(
           String getterName, LibraryElement library) =>
-      _internalLookUpGetter(getterName, library, true);
+      _first(_implementationsOfGetter(getterName).where(
+          (PropertyAccessorElement getter) => getter.isAccessibleIn(library)));
 
   @override
   PropertyAccessorElement lookUpInheritedConcreteGetter(
           String getterName, LibraryElement library) =>
-      _internalLookUpConcreteGetter(getterName, library, false);
+      _first(_implementationsOfGetter(getterName).where(
+          (PropertyAccessorElement getter) =>
+              !getter.isAbstract &&
+              getter.isAccessibleIn(library) &&
+              getter.enclosingElement != this));
 
   @override
   MethodElement lookUpInheritedConcreteMethod(
           String methodName, LibraryElement library) =>
-      _internalLookUpConcreteMethod(
-          methodName, library, false, new HashSet<ClassElement>());
+      _first(_implementationsOfMethod(methodName).where(
+          (MethodElement method) =>
+              !method.isAbstract &&
+              method.isAccessibleIn(library) &&
+              method.enclosingElement != this));
 
   @override
   PropertyAccessorElement lookUpInheritedConcreteSetter(
           String setterName, LibraryElement library) =>
-      _internalLookUpConcreteSetter(setterName, library, false);
+      _first(_implementationsOfSetter(setterName).where(
+          (PropertyAccessorElement setter) =>
+              !setter.isAbstract &&
+              setter.isAccessibleIn(library) &&
+              setter.enclosingElement != this));
 
   @override
   MethodElement lookUpInheritedMethod(
           String methodName, LibraryElement library) =>
-      _internalLookUpMethod(
-          methodName, library, false, new HashSet<ClassElement>());
+      _first(_implementationsOfMethod(methodName).where(
+          (MethodElement method) =>
+              method.isAccessibleIn(library) &&
+              method.enclosingElement != this));
 
   @override
   MethodElement lookUpMethod(String methodName, LibraryElement library) =>
-      _internalLookUpMethod(
-          methodName, library, true, new HashSet<ClassElement>());
+      _first(_implementationsOfMethod(methodName)
+          .where((MethodElement method) => method.isAccessibleIn(library)));
 
   @override
   PropertyAccessorElement lookUpSetter(
           String setterName, LibraryElement library) =>
-      _internalLookUpSetter(setterName, library, true);
+      _first(_implementationsOfSetter(setterName).where(
+          (PropertyAccessorElement setter) => setter.isAccessibleIn(library)));
 
   @override
   void visitChildren(ElementVisitor visitor) {
@@ -238,151 +254,110 @@
     safelyVisitChildren(fields, visitor);
   }
 
-  PropertyAccessorElement _internalLookUpConcreteGetter(
-      String getterName, LibraryElement library, bool includeThisClass) {
-    PropertyAccessorElement getter =
-        _internalLookUpGetter(getterName, library, includeThisClass);
-    while (getter != null && getter.isAbstract) {
-      Element definingClass = getter.enclosingElement;
-      if (definingClass is! ClassElement) {
-        return null;
-      }
-      getter = getImpl(definingClass)
-          ._internalLookUpGetter(getterName, library, false);
+  /**
+   * Return the first element from the given [iterable], or `null` if the
+   * iterable is empty.
+   */
+  Object/*=E*/ _first/*<E>*/(Iterable/*<E>*/ iterable) {
+    if (iterable.isEmpty) {
+      return null;
     }
-    return getter;
+    return iterable.first;
   }
 
-  MethodElement _internalLookUpConcreteMethod(
-      String methodName,
-      LibraryElement library,
-      bool includeThisClass,
-      HashSet<ClassElement> visitedClasses) {
-    MethodElement method = _internalLookUpMethod(
-        methodName, library, includeThisClass, visitedClasses);
-    while (method != null && method.isAbstract) {
-      ClassElement definingClass = method.enclosingElement;
-      if (definingClass == null) {
-        return null;
-      }
-      method = getImpl(definingClass)
-          ._internalLookUpMethod(methodName, library, false, visitedClasses);
-    }
-    return method;
-  }
-
-  PropertyAccessorElement _internalLookUpConcreteSetter(
-      String setterName, LibraryElement library, bool includeThisClass) {
-    PropertyAccessorElement setter =
-        _internalLookUpSetter(setterName, library, includeThisClass);
-    while (setter != null && setter.isAbstract) {
-      Element definingClass = setter.enclosingElement;
-      if (definingClass is ClassElementImpl) {
-        setter =
-            definingClass._internalLookUpSetter(setterName, library, false);
-      } else {
-        return null;
-      }
-    }
-    return setter;
-  }
-
-  PropertyAccessorElement _internalLookUpGetter(
-      String getterName, LibraryElement library, bool includeThisClass) {
+  /**
+   * Return an iterable containing all of the implementations of a getter with
+   * the given [getterName] that are defined in this class any any superclass of
+   * this class (but not in interfaces).
+   *
+   * The getters that are returned are not filtered in any way. In particular,
+   * they can include getters that are not visible in some context. Clients must
+   * perform any necessary filtering.
+   *
+   * The getters are returned based on the depth of their defining class; if
+   * this class contains a definition of the getter it will occur first, if
+   * Object contains a definition of the getter it will occur last.
+   */
+  Iterable<PropertyAccessorElement> _implementationsOfGetter(
+      String getterName) sync* {
+    ClassElement classElement = this;
     HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
-    ClassElement currentElement = this;
-    if (includeThisClass) {
-      PropertyAccessorElement element = currentElement.getGetter(getterName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
+    while (classElement != null && visitedClasses.add(classElement)) {
+      PropertyAccessorElement getter = classElement.getGetter(getterName);
+      if (getter != null) {
+        yield getter;
       }
-    }
-    while (currentElement != null && visitedClasses.add(currentElement)) {
-      for (InterfaceType mixin in currentElement.mixins.reversed) {
-        ClassElement mixinElement = mixin.element;
-        if (mixinElement != null) {
-          PropertyAccessorElement element = mixinElement.getGetter(getterName);
-          if (element != null && element.isAccessibleIn(library)) {
-            return element;
-          }
+      for (InterfaceType mixin in classElement.mixins.reversed) {
+        getter = mixin.element?.getGetter(getterName);
+        if (getter != null) {
+          yield getter;
         }
       }
-      InterfaceType supertype = currentElement.supertype;
-      if (supertype == null) {
-        return null;
-      }
-      currentElement = supertype.element;
-      PropertyAccessorElement element = currentElement.getGetter(getterName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
-      }
+      classElement = classElement.supertype?.element;
     }
-    return null;
   }
 
-  MethodElement _internalLookUpMethod(String methodName, LibraryElement library,
-      bool includeThisClass, HashSet<ClassElement> visitedClasses) {
-    ClassElement currentElement = this;
-    if (includeThisClass) {
-      MethodElement element = currentElement.getMethod(methodName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
-      }
-    }
-    while (currentElement != null && visitedClasses.add(currentElement)) {
-      for (InterfaceType mixin in currentElement.mixins.reversed) {
-        ClassElement mixinElement = mixin.element;
-        if (mixinElement != null) {
-          MethodElement element = mixinElement.getMethod(methodName);
-          if (element != null && element.isAccessibleIn(library)) {
-            return element;
-          }
-        }
-      }
-      InterfaceType supertype = currentElement.supertype;
-      if (supertype == null) {
-        return null;
-      }
-      currentElement = supertype.element;
-      MethodElement element = currentElement.getMethod(methodName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
-      }
-    }
-    return null;
-  }
-
-  PropertyAccessorElement _internalLookUpSetter(
-      String setterName, LibraryElement library, bool includeThisClass) {
+  /**
+   * Return an iterable containing all of the implementations of a method with
+   * the given [methodName] that are defined in this class any any superclass of
+   * this class (but not in interfaces).
+   *
+   * The methods that are returned are not filtered in any way. In particular,
+   * they can include methods that are not visible in some context. Clients must
+   * perform any necessary filtering.
+   *
+   * The methods are returned based on the depth of their defining class; if
+   * this class contains a definition of the method it will occur first, if
+   * Object contains a definition of the method it will occur last.
+   */
+  Iterable<MethodElement> _implementationsOfMethod(String methodName) sync* {
+    ClassElement classElement = this;
     HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
-    ClassElement currentElement = this;
-    if (includeThisClass) {
-      PropertyAccessorElement element = currentElement.getSetter(setterName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
+    while (classElement != null && visitedClasses.add(classElement)) {
+      MethodElement method = classElement.getMethod(methodName);
+      if (method != null) {
+        yield method;
       }
-    }
-    while (currentElement != null && visitedClasses.add(currentElement)) {
-      for (InterfaceType mixin in currentElement.mixins.reversed) {
-        ClassElement mixinElement = mixin.element;
-        if (mixinElement != null) {
-          PropertyAccessorElement element = mixinElement.getSetter(setterName);
-          if (element != null && element.isAccessibleIn(library)) {
-            return element;
-          }
+      for (InterfaceType mixin in classElement.mixins.reversed) {
+        method = mixin.element?.getMethod(methodName);
+        if (method != null) {
+          yield method;
         }
       }
-      InterfaceType supertype = currentElement.supertype;
-      if (supertype == null) {
-        return null;
-      }
-      currentElement = supertype.element;
-      PropertyAccessorElement element = currentElement.getSetter(setterName);
-      if (element != null && element.isAccessibleIn(library)) {
-        return element;
-      }
+      classElement = classElement.supertype?.element;
     }
-    return null;
+  }
+
+  /**
+   * Return an iterable containing all of the implementations of a setter with
+   * the given [setterName] that are defined in this class any any superclass of
+   * this class (but not in interfaces).
+   *
+   * The setters that are returned are not filtered in any way. In particular,
+   * they can include setters that are not visible in some context. Clients must
+   * perform any necessary filtering.
+   *
+   * The setters are returned based on the depth of their defining class; if
+   * this class contains a definition of the setter it will occur first, if
+   * Object contains a definition of the setter it will occur last.
+   */
+  Iterable<PropertyAccessorElement> _implementationsOfSetter(
+      String setterName) sync* {
+    ClassElement classElement = this;
+    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+    while (classElement != null && visitedClasses.add(classElement)) {
+      PropertyAccessorElement setter = classElement.getSetter(setterName);
+      if (setter != null) {
+        yield setter;
+      }
+      for (InterfaceType mixin in classElement.mixins.reversed) {
+        setter = mixin.element?.getSetter(setterName);
+        if (setter != null) {
+          yield setter;
+        }
+      }
+      classElement = classElement.supertype?.element;
+    }
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index d498728..6210e77 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -923,12 +923,6 @@
   TypeParameterType get type => _type;
 
   @override
-  bool operator ==(obj) =>
-      // TODO(jmesserly): this equality should consider the bound, see:
-      // https://github.com/dart-lang/sdk/issues/27210
-      obj is TypeParameterMember && obj.baseElement == baseElement;
-
-  @override
   accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
 
   /**
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 4bc84b6..bf898e0 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -2555,6 +2555,12 @@
       : super(element, element.name);
 
   @override
+  ElementLocation get definition => element.location;
+
+  @override
+  DartType get bound => element.bound ?? DynamicTypeImpl.instance;
+
+  @override
   TypeParameterElement get element => super.element as TypeParameterElement;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index ed8851b..011b842 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -379,7 +379,7 @@
   static const HintCode UNDEFINED_METHOD = const HintCode(
       'UNDEFINED_METHOD',
       "The method '{0}' isn't defined for the class '{1}'.",
-      "Try correcting the name to the name of an existing method, or"
+      "Try correcting the name to the name of an existing method, or "
       "defining a method named '{0}'.");
 
   /**
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index feea8ee..140c658 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -529,7 +529,7 @@
           "Constant values from a deferred library can't be used to "
           "initialized a const variable.",
           "Try initializing the variable without referencing members of the "
-          "deferred library, or"
+          "deferred library, or "
           "changing the import to not be deferred.");
 
   /**
@@ -2779,7 +2779,7 @@
       const StaticTypeWarningCode(
           'NON_TYPE_AS_TYPE_ARGUMENT',
           "The name '{0}' isn't a type so it can't be used as a type argument.",
-          "Try correcting the name to an existing type, or"
+          "Try correcting the name to an existing type, or "
           "defining a type named '{0}'.");
 
   /**
@@ -2859,7 +2859,7 @@
       const StaticTypeWarningCode(
           'UNDEFINED_ENUM_CONSTANT',
           "There is no constant named '{0}' in '{1}'.",
-          "Try correcting the name to the name of an existing constant, or"
+          "Try correcting the name to the name of an existing constant, or "
           "defining a constant named '{0}'.");
 
   /**
@@ -2879,7 +2879,7 @@
           'UNDEFINED_FUNCTION',
           "The function '{0}' isn't defined.",
           "Try importing the library that defines '{0}', "
-          "correcting the name to the name of an existing function, or"
+          "correcting the name to the name of an existing function, or "
           "defining a funtion named '{0}'.");
 
   /**
@@ -2895,7 +2895,7 @@
           'UNDEFINED_GETTER',
           "The getter '{0}' isn't defined for the class '{1}'.",
           "Try importing the library that defines '{0}', "
-          "correcting the name to the name of an existing getter, or"
+          "correcting the name to the name of an existing getter, or "
           "defining a getter or field named '{0}'.");
 
   /**
@@ -2911,7 +2911,7 @@
       const StaticTypeWarningCode(
           'UNDEFINED_METHOD',
           "The method '{0}' isn't defined for the class '{1}'.",
-          "Try correcting the name to the name of an existing method, or"
+          "Try correcting the name to the name of an existing method, or "
           "defining a method named '{0}'.");
 
   /**
@@ -2970,7 +2970,7 @@
           'UNDEFINED_SETTER',
           "The setter '{0}' isn't defined for the class '{1}'.",
           "Try importing the library that defines '{0}', "
-          "correcting the name to the name of an existing setter, or"
+          "correcting the name to the name of an existing setter, or "
           "defining a setter or field named '{0}'.");
 
   /**
@@ -2985,7 +2985,7 @@
       const StaticTypeWarningCode(
           'UNDEFINED_SUPER_GETTER',
           "The getter '{0}' isn't defined in a superclass of '{1}'.",
-          "Try correcting the name to the name of an existing getter, or"
+          "Try correcting the name to the name of an existing getter, or "
           "defining a getter or field named '{0}' in a superclass.");
 
   /**
@@ -3003,7 +3003,7 @@
       const StaticTypeWarningCode(
           'UNDEFINED_SUPER_METHOD',
           "The method '{0}' isn't defined in a superclass of '{1}'.",
-          "Try correcting the name to the name of an existing method, or"
+          "Try correcting the name to the name of an existing method, or "
           "defining a method named '{0}' in a superclass.");
 
   /**
@@ -3045,7 +3045,7 @@
       const StaticTypeWarningCode(
           'UNDEFINED_SUPER_SETTER',
           "The setter '{0}' isn't defined in a superclass of '{1}'.",
-          "Try correcting the name to the name of an existing setter, or"
+          "Try correcting the name to the name of an existing setter, or "
           "defining a setter or field named '{0}' in a superclass.");
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index d9e8d6e..4430e76 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -4269,6 +4269,9 @@
         _inInitializer = wasInInitializer;
       }
     } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
+      if (isFunctionExpression(currentToken)) {
+        return parseFunctionExpression();
+      }
       return parseListOrMapLiteral(null);
     } else if (type == TokenType.OPEN_CURLY_BRACKET) {
       return parseMapLiteral(null, null);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index e831fc0..b885240 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6887,9 +6887,10 @@
       potentialType ??= DynamicTypeImpl.instance;
 
       // Check if we can promote to potentialType from type.
-      if (typeSystem.canPromoteToType(potentialType, type)) {
+      DartType promoteType = typeSystem.tryPromoteToType(potentialType, type);
+      if (promoteType != null) {
         // Do promote type of variable.
-        _promoteManager.setType(element, potentialType);
+        _promoteManager.setType(element, promoteType);
       }
     }
   }
@@ -9943,8 +9944,18 @@
   @override
   Object visitVariableDeclaration(VariableDeclaration node) {
     super.visitVariableDeclaration(node);
+    var variableList = node.parent as VariableDeclarationList;
+    // When the library is resynthesized, the types of field elements are
+    // already set - statically or inferred. We don't want to overwrite them.
+    // See also dartbug.com/27482 for separating static and inferred types.
+    if (variableList.parent is FieldDeclaration &&
+        LibraryElementImpl.hasResolutionCapability(
+            definingLibrary, LibraryResolutionCapability.resolvedTypeNames)) {
+      return null;
+    }
+    // Resolve the type.
     DartType declaredType;
-    TypeName typeName = (node.parent as VariableDeclarationList).type;
+    TypeName typeName = variableList.type;
     if (typeName == null) {
       declaredType = _dynamicType;
     } else {
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index c8c1fe6..5d08b0a 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart' show ErrorReporter;
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember;
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/error/codes.dart' show StrongModeCode;
 import 'package:analyzer/src/generated/engine.dart'
@@ -170,7 +171,7 @@
   }
 
   @override
-  bool canPromoteToType(DartType to, DartType from) {
+  DartType tryPromoteToType(DartType to, DartType from) {
     // Allow promoting to a subtype, for example:
     //
     //     f(Base b) {
@@ -182,25 +183,17 @@
     // This allows the variable to be used wherever the supertype (here `Base`)
     // is expected, while gaining a more precise type.
     if (isSubtypeOf(to, from)) {
-      return true;
+      return to;
     }
-    // For a type parameter `T extends U`, allow promoting from the upper bound
-    // `U` to `S` where `S <: U`.
-    //
-    // This does restrict the variable, because `S </: T`, it can no longer be
-    // used as a `T` without another cast.
-    //
-    // However the members you could access from a variable of type `T`, were
-    // already those on the upper bound `U`. So all members on `U` will be
-    // accessible, as well as those on `S`. Pragmatically this feels like a
-    // useful enough trade-off to allow promotion.
-    //
-    // (In general we would need union types to support this feature precisely.)
+    // For a type parameter `T extends U`, allow promoting the upper bound
+    // `U` to `S` where `S <: U`, yielding a type parameter `T extends S`.
     if (from is TypeParameterType) {
-      return isSubtypeOf(to, from.resolveToBound(DynamicTypeImpl.instance));
+      if (isSubtypeOf(to, from.resolveToBound(DynamicTypeImpl.instance))) {
+        return new TypeParameterMember(from.element, null, to).type;
+      }
     }
 
-    return false;
+    return null;
   }
 
   @override
@@ -922,7 +915,9 @@
     //  True if T == S
     //  Or true if bound of S is S' and S' <: T
     if (t1 is TypeParameterType) {
-      if (t1 == t2) {
+      if (t2 is TypeParameterType &&
+          t1.definition == t2.definition &&
+          guardedSubtype(t1.bound, t2.bound, visited)) {
         return true;
       }
       if (guardedInferTypeParameter(t1, t2, visited)) {
@@ -1051,15 +1046,18 @@
  */
 abstract class TypeSystem {
   /**
-   * Returns `true` if we can promote to the first type from the second type.
+   * Tries to promote from the first type from the second type, and returns the
+   * promoted type if it succeeds, otherwise null.
    *
-   * In the standard Dart type system, it is not possible to promote from or to
+   * In the Dart 1 type system, it is not possible to promote from or to
    * `dynamic`, and we must be promoting to a more specific type, see
-   * [isMoreSpecificThan].
+   * [isMoreSpecificThan]. Also it will always return the promote [to] type or
+   * null.
    *
-   * In strong mode, this is equivalent to [isSubtypeOf].
+   * In strong mode, this can potentially return a different type, see
+   * the override in [StrongTypeSystemImpl].
    */
-  bool canPromoteToType(DartType to, DartType from);
+  DartType tryPromoteToType(DartType to, DartType from);
 
   /**
    * Make a function type concrete.
@@ -1425,11 +1423,15 @@
   TypeSystemImpl();
 
   @override
-  bool canPromoteToType(DartType to, DartType from) {
+  DartType tryPromoteToType(DartType to, DartType from) {
     // Declared type should not be "dynamic".
     // Promoted type should not be "dynamic".
     // Promoted type should be more specific than declared.
-    return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from);
+    if (!from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from)) {
+      return to;
+    } else {
+      return null;
+    }
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary/api_signature.dart b/pkg/analyzer/lib/src/summary/api_signature.dart
index f2fd506..230b6d0 100644
--- a/pkg/analyzer/lib/src/summary/api_signature.dart
+++ b/pkg/analyzer/lib/src/summary/api_signature.dart
@@ -106,6 +106,13 @@
   }
 
   /**
+   * Collect the given [Uint32List].
+   */
+  void addUint32List(Uint32List data) {
+    addBytes(data.buffer.asUint8List());
+  }
+
+  /**
    * For testing only: retrieve the internal representation of the data that
    * has been collected.
    */
@@ -114,11 +121,17 @@
   }
 
   /**
+   * Return the bytes of the MD5 hash of the data collected so far.
+   */
+  List<int> toByteList() {
+    return md5.convert(new Uint8List.view(_data.buffer, 0, _offset)).bytes;
+  }
+
+  /**
    * Return a hex-encoded MD5 signature of the data collected so far.
    */
   String toHex() {
-    return hex.encode(
-        md5.convert(new Uint8List.view(_data.buffer, 0, _offset)).bytes);
+    return hex.encode(toByteList());
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 85ac30a..3cbfe97 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -8661,6 +8661,7 @@
 }
 
 class UnlinkedUnitBuilder extends Object with _UnlinkedUnitMixin implements idl.UnlinkedUnit {
+  List<int> _apiSignature;
   List<UnlinkedClassBuilder> _classes;
   CodeRangeBuilder _codeRange;
   List<UnlinkedEnumBuilder> _enums;
@@ -8668,6 +8669,7 @@
   List<UnlinkedExportNonPublicBuilder> _exports;
   String _fallbackModePath;
   List<UnlinkedImportBuilder> _imports;
+  bool _isPartOf;
   List<UnlinkedConstBuilder> _libraryAnnotations;
   UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
   String _libraryName;
@@ -8681,6 +8683,19 @@
   List<UnlinkedVariableBuilder> _variables;
 
   @override
+  List<int> get apiSignature => _apiSignature ??= <int>[];
+
+  /**
+   * MD5 hash of the non-informative fields of the [UnlinkedUnit] (not
+   * including this one) as 16 unsigned 8-bit integer values.  This can be used
+   * to identify when the API of a unit may have changed.
+   */
+  void set apiSignature(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._apiSignature = value;
+  }
+
+  @override
   List<UnlinkedClassBuilder> get classes => _classes ??= <UnlinkedClassBuilder>[];
 
   /**
@@ -8756,6 +8771,16 @@
   }
 
   @override
+  bool get isPartOf => _isPartOf ??= false;
+
+  /**
+   * Indicates whether the unit contains a "part of" declaration.
+   */
+  void set isPartOf(bool value) {
+    this._isPartOf = value;
+  }
+
+  @override
   List<UnlinkedConstBuilder> get libraryAnnotations => _libraryAnnotations ??= <UnlinkedConstBuilder>[];
 
   /**
@@ -8876,14 +8901,16 @@
     this._variables = value;
   }
 
-  UnlinkedUnitBuilder({List<UnlinkedClassBuilder> classes, CodeRangeBuilder codeRange, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, String fallbackModePath, List<UnlinkedImportBuilder> imports, List<UnlinkedConstBuilder> libraryAnnotations, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, String libraryName, int libraryNameLength, int libraryNameOffset, List<int> lineStarts, List<UnlinkedPartBuilder> parts, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
-    : _classes = classes,
+  UnlinkedUnitBuilder({List<int> apiSignature, List<UnlinkedClassBuilder> classes, CodeRangeBuilder codeRange, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, String fallbackModePath, List<UnlinkedImportBuilder> imports, bool isPartOf, List<UnlinkedConstBuilder> libraryAnnotations, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, String libraryName, int libraryNameLength, int libraryNameOffset, List<int> lineStarts, List<UnlinkedPartBuilder> parts, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
+    : _apiSignature = apiSignature,
+      _classes = classes,
       _codeRange = codeRange,
       _enums = enums,
       _executables = executables,
       _exports = exports,
       _fallbackModePath = fallbackModePath,
       _imports = imports,
+      _isPartOf = isPartOf,
       _libraryAnnotations = libraryAnnotations,
       _libraryDocumentationComment = libraryDocumentationComment,
       _libraryName = libraryName,
@@ -9006,6 +9033,15 @@
       }
     }
     signature.addString(this._fallbackModePath ?? '');
+    signature.addBool(this._isPartOf == true);
+    if (this._apiSignature == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._apiSignature.length);
+      for (var x in this._apiSignature) {
+        signature.addInt(x);
+      }
+    }
   }
 
   List<int> toBuffer() {
@@ -9014,6 +9050,7 @@
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_apiSignature;
     fb.Offset offset_classes;
     fb.Offset offset_codeRange;
     fb.Offset offset_enums;
@@ -9030,6 +9067,9 @@
     fb.Offset offset_references;
     fb.Offset offset_typedefs;
     fb.Offset offset_variables;
+    if (!(_apiSignature == null || _apiSignature.isEmpty)) {
+      offset_apiSignature = fbBuilder.writeListUint32(_apiSignature);
+    }
     if (!(_classes == null || _classes.isEmpty)) {
       offset_classes = fbBuilder.writeList(_classes.map((b) => b.finish(fbBuilder)).toList());
     }
@@ -9079,6 +9119,9 @@
       offset_variables = fbBuilder.writeList(_variables.map((b) => b.finish(fbBuilder)).toList());
     }
     fbBuilder.startTable();
+    if (offset_apiSignature != null) {
+      fbBuilder.addOffset(19, offset_apiSignature);
+    }
     if (offset_classes != null) {
       fbBuilder.addOffset(2, offset_classes);
     }
@@ -9100,6 +9143,9 @@
     if (offset_imports != null) {
       fbBuilder.addOffset(5, offset_imports);
     }
+    if (_isPartOf == true) {
+      fbBuilder.addBool(18, true);
+    }
     if (offset_libraryAnnotations != null) {
       fbBuilder.addOffset(14, offset_libraryAnnotations);
     }
@@ -9155,6 +9201,7 @@
 
   _UnlinkedUnitImpl(this._bc, this._bcOffset);
 
+  List<int> _apiSignature;
   List<idl.UnlinkedClass> _classes;
   idl.CodeRange _codeRange;
   List<idl.UnlinkedEnum> _enums;
@@ -9162,6 +9209,7 @@
   List<idl.UnlinkedExportNonPublic> _exports;
   String _fallbackModePath;
   List<idl.UnlinkedImport> _imports;
+  bool _isPartOf;
   List<idl.UnlinkedConst> _libraryAnnotations;
   idl.UnlinkedDocumentationComment _libraryDocumentationComment;
   String _libraryName;
@@ -9175,6 +9223,12 @@
   List<idl.UnlinkedVariable> _variables;
 
   @override
+  List<int> get apiSignature {
+    _apiSignature ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 19, const <int>[]);
+    return _apiSignature;
+  }
+
+  @override
   List<idl.UnlinkedClass> get classes {
     _classes ??= const fb.ListReader<idl.UnlinkedClass>(const _UnlinkedClassReader()).vTableGet(_bc, _bcOffset, 2, const <idl.UnlinkedClass>[]);
     return _classes;
@@ -9217,6 +9271,12 @@
   }
 
   @override
+  bool get isPartOf {
+    _isPartOf ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 18, false);
+    return _isPartOf;
+  }
+
+  @override
   List<idl.UnlinkedConst> get libraryAnnotations {
     _libraryAnnotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bc, _bcOffset, 14, const <idl.UnlinkedConst>[]);
     return _libraryAnnotations;
@@ -9287,6 +9347,7 @@
   @override
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
+    if (apiSignature.isNotEmpty) _result["apiSignature"] = apiSignature;
     if (classes.isNotEmpty) _result["classes"] = classes.map((_value) => _value.toJson()).toList();
     if (codeRange != null) _result["codeRange"] = codeRange.toJson();
     if (enums.isNotEmpty) _result["enums"] = enums.map((_value) => _value.toJson()).toList();
@@ -9294,6 +9355,7 @@
     if (exports.isNotEmpty) _result["exports"] = exports.map((_value) => _value.toJson()).toList();
     if (fallbackModePath != '') _result["fallbackModePath"] = fallbackModePath;
     if (imports.isNotEmpty) _result["imports"] = imports.map((_value) => _value.toJson()).toList();
+    if (isPartOf != false) _result["isPartOf"] = isPartOf;
     if (libraryAnnotations.isNotEmpty) _result["libraryAnnotations"] = libraryAnnotations.map((_value) => _value.toJson()).toList();
     if (libraryDocumentationComment != null) _result["libraryDocumentationComment"] = libraryDocumentationComment.toJson();
     if (libraryName != '') _result["libraryName"] = libraryName;
@@ -9310,6 +9372,7 @@
 
   @override
   Map<String, Object> toMap() => {
+    "apiSignature": apiSignature,
     "classes": classes,
     "codeRange": codeRange,
     "enums": enums,
@@ -9317,6 +9380,7 @@
     "exports": exports,
     "fallbackModePath": fallbackModePath,
     "imports": imports,
+    "isPartOf": isPartOf,
     "libraryAnnotations": libraryAnnotations,
     "libraryDocumentationComment": libraryDocumentationComment,
     "libraryName": libraryName,
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index c3eb5e2..023c370 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -2315,6 +2315,13 @@
  */
 table UnlinkedUnit {
   /**
+   * MD5 hash of the non-informative fields of the [UnlinkedUnit] (not
+   * including this one) as 16 unsigned 8-bit integer values.  This can be used
+   * to identify when the API of a unit may have changed.
+   */
+  apiSignature:[uint] (id: 19);
+
+  /**
    * Classes declared in the compilation unit.
    */
   classes:[UnlinkedClass] (id: 2);
@@ -2355,6 +2362,11 @@
   imports:[UnlinkedImport] (id: 5);
 
   /**
+   * Indicates whether the unit contains a "part of" declaration.
+   */
+  isPartOf:bool (id: 18);
+
+  /**
    * Annotations for the library declaration, or the empty list if there is no
    * library declaration.
    */
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index c67dee6..07ce297d8 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -2647,6 +2647,14 @@
       generated.readUnlinkedUnit(buffer);
 
   /**
+   * MD5 hash of the non-informative fields of the [UnlinkedUnit] (not
+   * including this one) as 16 unsigned 8-bit integer values.  This can be used
+   * to identify when the API of a unit may have changed.
+   */
+  @Id(19)
+  List<int> get apiSignature;
+
+  /**
    * Classes declared in the compilation unit.
    */
   @Id(2)
@@ -2695,6 +2703,12 @@
   List<UnlinkedImport> get imports;
 
   /**
+   * Indicates whether the unit contains a "part of" declaration.
+   */
+  @Id(18)
+  bool get isPartOf;
+
+  /**
    * Annotations for the library declaration, or the empty list if there is no
    * library declaration.
    */
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 82d596e..646eed8 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/type.dart' show DartType;
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/public_namespace_computer.dart';
@@ -298,6 +299,11 @@
   bool isCoreLibrary = false;
 
   /**
+   * True is a [PartOfDirective] was found, so the unit is a part.
+   */
+  bool isPartOf = false;
+
+  /**
    * If the library has a library directive, the library name derived from it.
    * Otherwise `null`.
    */
@@ -518,6 +524,7 @@
     compilationUnit.declarations.accept(this);
     UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
     b.lineStarts = compilationUnit.lineInfo?.lineStarts;
+    b.isPartOf = isPartOf;
     b.libraryName = libraryName;
     b.libraryNameOffset = libraryNameOffset;
     b.libraryNameLength = libraryNameLength;
@@ -534,6 +541,7 @@
     b.typedefs = typedefs;
     b.variables = variables;
     b.publicNamespace = computePublicNamespace(compilationUnit);
+    _computeApiSignature(b);
     return b;
   }
 
@@ -1345,6 +1353,7 @@
   @override
   void visitPartOfDirective(PartOfDirective node) {
     isCoreLibrary = node.libraryName.name == 'dart.core';
+    isPartOf = true;
   }
 
   @override
@@ -1386,6 +1395,15 @@
     Identifier name = typeName.name;
     return name is SimpleIdentifier && name.name == 'dynamic';
   }
+
+  /**
+   * Compute the API signature of the unit and record it.
+   */
+  static void _computeApiSignature(UnlinkedUnitBuilder b) {
+    ApiSignature apiSignature = new ApiSignature();
+    b.collectApiSignature(apiSignature);
+    b.apiSignature = apiSignature.toByteList();
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 59ffdd8..56595c4 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -2211,8 +2211,10 @@
     // re-run if anything reachable from this target has been invalidated,
     // and the invalidation code (invalidateLibraryCycles) will ensure that
     // element model results will be re-used here only if they are still valid.
-    if (context.analysisOptions.strongMode) {
-      LibraryElement library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
+    LibraryElement library = getRequiredInput(LIBRARY_ELEMENT_INPUT);
+    if (context.analysisOptions.strongMode &&
+        !LibraryElementImpl.hasResolutionCapability(
+            library, LibraryResolutionCapability.resolvedTypeNames)) {
       List<LibraryElement> component = library.libraryCycle;
       Set<LibraryElement> filter = component.toSet();
       Set<CompilationUnitElement> deps = new Set<CompilationUnitElement>();
diff --git a/pkg/analyzer/lib/src/task/html_work_manager.dart b/pkg/analyzer/lib/src/task/html_work_manager.dart
index 911ef16..d8bc76f 100644
--- a/pkg/analyzer/lib/src/task/html_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/html_work_manager.dart
@@ -40,7 +40,7 @@
    * Initialize a newly created manager.
    */
   HtmlWorkManager(this.context) {
-    analysisCache.onResultInvalidated.listen(onResultInvalidated);
+    context.onResultInvalidated.listen(onResultInvalidated);
   }
 
   /**
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index f172ec6..067627d 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -36,6 +36,28 @@
     verify([source]);
   }
 
+  void
+      test_abstractSuperMemberReference_superHasConcrete_mixinHasAbstract_method() {
+    Source source = addSource('''
+class A {
+  void method() {}
+}
+
+abstract class B {
+  void method();
+}
+
+class C extends A with B {
+  void method() {
+    super.method();
+  }
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_abstractSuperMemberReference_superHasNoSuchMethod() {
     Source source = addSource('''
 abstract class A {
@@ -3718,15 +3740,6 @@
     verify([source]);
   }
 
-  void test_nativeFunctionBodyInNonSDKCode_function() {
-    Source source = addSource(r'''
-import 'dart-ext:x';
-int m(a) native 'string';''');
-    computeLibrarySourceErrors(source);
-    assertNoErrors(source);
-    // Cannot verify the AST because the import's URI cannot be resolved.
-  }
-
   void test_nativeConstConstructor() {
     Source source = addSource(r'''
 import 'dart-ext:x';
@@ -3739,6 +3752,15 @@
     // Cannot verify the AST because the import's URI cannot be resolved.
   }
 
+  void test_nativeFunctionBodyInNonSDKCode_function() {
+    Source source = addSource(r'''
+import 'dart-ext:x';
+int m(a) native 'string';''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    // Cannot verify the AST because the import's URI cannot be resolved.
+  }
+
   void test_newWithAbstractClass_factory() {
     Source source = addSource(r'''
 abstract class A {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 2465b13..e4b714c 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -11364,6 +11364,17 @@
     expect(functionExpression.body, isNotNull);
   }
 
+  void test_parsePrimaryExpression_genericFunctionExpression() {
+    enableGenericMethods = true;
+    createParser('<X, Y>(Map<X, Y> m, X x) => m[x]');
+    Expression expression = parser.parsePrimaryExpression();
+    expectNotNullIfNoErrors(expression);
+    listener.assertNoErrors();
+    expect(expression, new isInstanceOf<FunctionExpression>());
+    FunctionExpression function = expression;
+    expect(function.typeParameters, isNotNull);
+  }
+
   void test_parsePrimaryExpression_hex() {
     String hexLiteral = "3F";
     createParser('0x$hexLiteral');
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 34e20ef..dff172e 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/source.dart';
@@ -50,7 +51,7 @@
 
   final MemoryResourceProvider provider = new MemoryResourceProvider();
   final ByteStore byteStore = new _TestByteStore();
-  final ContentCache contentCache = new ContentCache();
+  final FileContentOverlay contentOverlay = new FileContentOverlay();
   final StringBuffer logBuffer = new StringBuffer();
 
   AnalysisDriver driver;
@@ -69,7 +70,7 @@
         new PerformanceLog(logBuffer),
         provider,
         byteStore,
-        contentCache,
+        contentOverlay,
         new SourceFactory([
           new DartUriResolver(sdk),
           new PackageMapUriResolver(provider, <String, List<Folder>>{
@@ -272,6 +273,20 @@
     }
   }
 
+  test_getResult_inferTypes_finalField() async {
+    _addTestFile(
+        r'''
+class C {
+  final f = 42;
+}
+''',
+        priority: true);
+    await _waitForIdle();
+
+    AnalysisResult result = await driver.getResult(testFile);
+    expect(_getClassFieldType(result.unit, 'C', 'f'), 'int');
+  }
+
   test_getResult_selfConsistent() async {
     var a = _p('/test/lib/a.dart');
     var b = _p('/test/lib/b.dart');
@@ -350,6 +365,19 @@
     expect(result1.unit, isNotNull);
   }
 
+  test_isAddedFile() async {
+    var a = _p('/test/lib/a.dart');
+    var b = _p('/test/lib/b.dart');
+
+    driver.addFile(a);
+    expect(driver.isAddedFile(a), isTrue);
+    expect(driver.isAddedFile(b), isFalse);
+
+    driver.removeFile(a);
+    expect(driver.isAddedFile(a), isFalse);
+    expect(driver.isAddedFile(b), isFalse);
+  }
+
   test_removeFile_changeFile_implicitlyAnalyzed() async {
     var a = _p('/test/lib/a.dart');
     var b = _p('/test/lib/b.dart');
@@ -488,6 +516,39 @@
     }
   }
 
+  ClassDeclaration _getClass(CompilationUnit unit, String name) {
+    for (CompilationUnitMember declaration in unit.declarations) {
+      if (declaration is ClassDeclaration) {
+        if (declaration.name.name == name) {
+          return declaration;
+        }
+      }
+    }
+    fail('Cannot find the class $name in\n$unit');
+    return null;
+  }
+
+  VariableDeclaration _getClassField(
+      CompilationUnit unit, String className, String fieldName) {
+    ClassDeclaration classDeclaration = _getClass(unit, className);
+    for (ClassMember declaration in classDeclaration.members) {
+      if (declaration is FieldDeclaration) {
+        for (var field in declaration.fields.variables) {
+          if (field.name.name == fieldName) {
+            return field;
+          }
+        }
+      }
+    }
+    fail('Cannot find the field $fieldName in the class $className in\n$unit');
+    return null;
+  }
+
+  String _getClassFieldType(
+      CompilationUnit unit, String className, String fieldName) {
+    return _getClassField(unit, className, fieldName).element.type.toString();
+  }
+
   VariableDeclaration _getTopLevelVar(CompilationUnit unit, String name) {
     for (CompilationUnitMember declaration in unit.declarations) {
       if (declaration is TopLevelVariableDeclaration) {
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index a5834ac..c86f547 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -829,6 +829,26 @@
     return findVariable(variableName, failIfAbsent: true);
   }
 
+  test_apiSignature() {
+    List<int> signature1;
+    List<int> signature2;
+    List<int> signature3;
+    {
+      serializeLibraryText('class A {}');
+      signature1 = unlinkedUnits[0].apiSignature;
+    }
+    {
+      serializeLibraryText('class A { }');
+      signature2 = unlinkedUnits[0].apiSignature;
+    }
+    {
+      serializeLibraryText('class B {}');
+      signature3 = unlinkedUnits[0].apiSignature;
+    }
+    expect(signature2, signature1);
+    expect(signature3, isNot(signature1));
+  }
+
   test_bottom_reference_shared() {
     if (skipFullyLinkedData) {
       return;
@@ -9274,6 +9294,13 @@
     expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
   }
 
+  test_part_isPartOf() {
+    addNamedSource('/a.dart', 'part of foo; class C {}');
+    serializeLibraryText('library foo; part "a.dart";');
+    expect(unlinkedUnits[0].isPartOf, isFalse);
+    expect(unlinkedUnits[1].isPartOf, isTrue);
+  }
+
   test_reference_zero() {
     // Element zero of the references table should be populated in a standard
     // way.
diff --git a/pkg/analyzer/test/src/task/html_work_manager_test.dart b/pkg/analyzer/test/src/task/html_work_manager_test.dart
index ee102d4..f4e9e70 100644
--- a/pkg/analyzer/test/src/task/html_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/html_work_manager_test.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/error/error.dart' show AnalysisError;
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/error/codes.dart' show HtmlErrorCode;
 import 'package:analyzer/src/generated/engine.dart'
     show
@@ -32,6 +33,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(HtmlWorkManagerTest);
+    defineReflectiveTests(HtmlWorkManagerIntegrationTest);
   });
 }
 
@@ -303,6 +305,53 @@
   }
 }
 
+@reflectiveTest
+class HtmlWorkManagerIntegrationTest {
+  InternalAnalysisContext context = new AnalysisContextImpl();
+  HtmlWorkManager manager;
+
+  Source source1 = new TestSource('1.html');
+  Source source2 = new TestSource('2.html');
+  CacheEntry entry1;
+  CacheEntry entry2;
+
+  void expect_sourceQueue(List<Source> sources) {
+    expect(manager.sourceQueue, unorderedEquals(sources));
+  }
+
+  void setUp() {
+    manager = new HtmlWorkManager(context);
+    entry1 = context.getCacheEntry(source1);
+    entry2 = context.getCacheEntry(source2);
+  }
+
+  void test_onResultInvalidated_scheduleInvalidatedLibrariesAfterSetSourceFactory() {
+    // Change the source factory, changing the analysis cache from when
+    // the work manager was constructed. This used to create a failure
+    // case for test_onResultInvalidated_scheduleInvalidLibraries so its
+    // tested here.
+    context.sourceFactory = new _SourceFactoryMock();
+
+    // now just do the same checks as
+    // test_onResultInvalidated_scheduleInvalidLibraries
+
+    // set HTML_ERRORS for source1 and source2
+    entry1.setValue(HTML_ERRORS, [], []);
+    entry2.setValue(HTML_ERRORS, [], []);
+    // invalidate HTML_ERRORS for source1, schedule it
+    entry1.setState(HTML_ERRORS, CacheState.INVALID);
+    expect_sourceQueue([source1]);
+    // invalidate HTML_ERRORS for source2, schedule it
+    entry2.setState(HTML_ERRORS, CacheState.INVALID);
+    expect_sourceQueue([source1, source2]);
+  }
+
+}
+
+class _SourceFactoryMock extends TypedMock
+    implements SourceFactory {
+}
+
 class _InternalAnalysisContextMock extends TypedMock
     implements InternalAnalysisContext {
   @override
@@ -311,6 +360,12 @@
   @override
   AnalysisCache analysisCache;
 
+  // The production version is a stream that carries messages from the cache
+  // since the cache changes. Here, we can just pass the inner stream because
+  // it doesn't change.
+  @override
+  get onResultInvalidated => analysisCache.onResultInvalidated;
+
   Map<Source, ChangeNoticeImpl> _pendingNotices = <Source, ChangeNoticeImpl>{};
 
   _InternalAnalysisContextMock() {
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 40fd228..48e6539 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2751,7 +2751,7 @@
 typedef T Returns<T>();
 
 // regression test for https://github.com/dart-lang/sdk/issues/26094
-class A <S extends  Returns<S>, T extends Returns<T>> {
+class A <S extends Returns<S>, T extends Returns<T>> {
   int test(bool b) {
     S s;
     T t;
@@ -3721,7 +3721,9 @@
   }
 
   void test_typePromotionFromTypeParameter() {
-    // Regression test for https://github.com/dart-lang/sdk/issues/26965
+    // Regression test for:
+    // https://github.com/dart-lang/sdk/issues/26965
+    // https://github.com/dart-lang/sdk/issues/27040
     checkFile(r'''
 void f/*<T>*/(/*=T*/ object) {
   if (object is String) print(object.substring(1));
@@ -3734,15 +3736,48 @@
 class SubClonable<T> extends Clonable<T> {
   T m(T t) => t;
 }
+void takesSubClonable/*<A>*/(SubClonable/*<A>*/ t) {}
+
 void h/*<T extends Clonable<T>>*/(/*=T*/ object) {
   if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubClonable/*<T>*/) {
-    // Note we need to cast back to T, because promotion lost that type info.
-    print(object.m(object as dynamic/*=T*/));
+    print(object.m(object));
+
+    SubClonable/*<T>*/ s = object;
+    takesSubClonable/*<T>*/(object);
+    h(object);
   }
 }
 ''');
   }
 
+  void test_typePromotionFromTypeParameterAndInference() {
+    // Regression test for:
+    // https://github.com/dart-lang/sdk/issues/27040
+    checkFile(r'''
+void f/*<T extends num>*/(T x, T y) {
+  var z = x;
+  var f = () => x;
+  f = () => y;
+  if (x is int) {
+    /*info:DYNAMIC_INVOKE*/z./*error:UNDEFINED_GETTER*/isEven;
+    var q = x;
+    q = /*warning:DOWN_CAST_COMPOSITE*/z;
+    /*info:DYNAMIC_INVOKE*/f()./*error:UNDEFINED_GETTER*/isEven;
+
+    // This does not capture the type `T extends int`. Instead the return type
+    // is `T extends num`. What happens is we substitute {T/T} on the function
+    // type, and the way it is implemented, this leads back to `T extends num`.
+    // See https://github.com/dart-lang/sdk/issues/27725
+    var g = () => x;
+    g = f;
+    /*info:DYNAMIC_INVOKE*/g()./*error:UNDEFINED_GETTER*/isEven;
+    q = /*warning:DOWN_CAST_COMPOSITE*/g();
+    int r = x;
+  }
+}
+    ''');
+  }
+
   void test_typeSubtyping_assigningClass() {
     checkFile('''
 class A {}
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 2fa535b..56d826c 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -152,6 +152,10 @@
   /// The URI for 'dart:async'.
   static final Uri dart_async = new Uri(scheme: 'dart', path: 'async');
 
+  /// The URI for 'dart:collection'.
+  static final Uri dart_collection =
+      new Uri(scheme: 'dart', path: 'collection');
+
   /// The URI for 'dart:core'.
   static final Uri dart_core = new Uri(scheme: 'dart', path: 'core');
 
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 9ee75e9..352fc9f 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -395,6 +395,7 @@
     }),
     new OptionHandler(Flags.allowNativeExtensions, setAllowNativeExtensions),
     new OptionHandler(Flags.generateCodeWithCompileTimeErrors, passThrough),
+    new OptionHandler(Flags.useNewSourceInfo, passThrough),
     new OptionHandler(Flags.testMode, passThrough),
 
     // The following three options must come last.
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 05ef3e7..a5e4003 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -463,6 +463,9 @@
   VOID_EXPRESSION,
   VOID_NOT_ALLOWED,
   VOID_VARIABLE,
+  WRONG_ARGUMENT_FOR_JS,
+  WRONG_ARGUMENT_FOR_JS_FIRST,
+  WRONG_ARGUMENT_FOR_JS_SECOND,
   WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
   WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
   YIELDING_MODIFIER_ON_ARROW_BODY,
@@ -2695,6 +2698,18 @@
               "Use an immediately called JavaScript function to capture the"
               " the placeholder values as JavaScript function parameters."),
 
+      MessageKind.WRONG_ARGUMENT_FOR_JS: const MessageTemplate(
+          MessageKind.WRONG_ARGUMENT_FOR_JS,
+          "JS expression must take two or more arguments."),
+
+      MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST: const MessageTemplate(
+          MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST,
+          "JS expression must take two or more arguments."),
+
+      MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND: const MessageTemplate(
+          MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND,
+          "JS second argument must be a string literal."),
+
       MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
           const MessageTemplate(
               MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index e854e4d..06b58d9 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -20,6 +20,7 @@
 import '../tree/tree.dart';
 import '../util/characters.dart' show $_;
 import '../util/util.dart';
+import 'entities.dart';
 import 'visitor.dart' show ElementVisitor;
 
 part 'names.dart';
@@ -1047,7 +1048,8 @@
 ///
 /// A [MemberElement] is the outermost executable element for any executable
 /// context.
-abstract class MemberElement extends Element implements ExecutableElement {
+abstract class MemberElement extends Element
+    implements ExecutableElement, MemberEntity {
   /// The local functions defined within this member.
   List<FunctionElement> get nestedClosures;
 
@@ -1087,6 +1089,8 @@
 /// factories and constructors it is not itself a [Local] but instead
 /// a non-element [Local] is created through a specialized class.
 // TODO(johnniwinther): Should [Local] have `isAssignable` or `type`?
+// TODO(johnniwinther): Move this to 'entities.dart' when it does not refer
+// to [ExecutableElement].
 abstract class Local extends Entity {
   /// The context in which this local is defined.
   ExecutableElement get executableContext;
@@ -1100,7 +1104,8 @@
     implements LocalElement {}
 
 /// A top-level, static or instance field.
-abstract class FieldElement extends VariableElement implements MemberElement {}
+abstract class FieldElement extends VariableElement
+    implements MemberElement, FieldEntity {}
 
 /// A parameter-like element of a function signature.
 ///
@@ -1291,15 +1296,15 @@
 }
 
 /// A top level, static or instance function.
-abstract class MethodElement extends FunctionElement implements MemberElement {}
+abstract class MethodElement extends FunctionElement
+    implements MemberElement, FunctionEntity {}
 
 /// A local function or closure (anonymous local function).
 abstract class LocalFunctionElement extends FunctionElement
     implements LocalElement {}
 
 /// A constructor.
-abstract class ConstructorElement extends FunctionElement
-    implements MemberElement {
+abstract class ConstructorElement extends MethodElement {
   /// Returns `true` if [effectiveTarget] has been computed for this
   /// constructor.
   bool get hasEffectiveTarget;
@@ -1470,7 +1475,7 @@
 }
 
 abstract class ClassElement extends TypeDeclarationElement
-    implements ScopeContainerElement {
+    implements ScopeContainerElement, ClassEntity {
   /// The length of the longest inheritance path from [:Object:].
   int get hierarchyDepth;
 
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
new file mode 100644
index 0000000..7c03e03
--- /dev/null
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library entities;
+
+import 'elements.dart' show Entity;
+
+/// Stripped down super interface for class like entities.
+///
+/// Currently only [ClassElement] but later also kernel based Dart classes
+/// and/or Dart-in-JS classes.
+abstract class ClassEntity extends Entity {
+  bool get isClosure;
+  void forEachInstanceField(f(ClassEntity cls, FieldEntity field),
+      {bool includeSuperAndInjectedMembers: false});
+}
+
+/// Stripped down super interface for member like entities, that is,
+/// constructors, methods, fields etc.
+///
+/// Currently only [MemberElement] but later also kernel based Dart members
+/// and/or Dart-in-JS properties.
+abstract class MemberEntity extends Entity {
+  bool get isField;
+  bool get isFunction;
+  bool get isGetter;
+  bool get isAssignable;
+  ClassEntity get enclosingClass;
+}
+
+/// Stripped down super interface for field like entities.
+///
+/// Currently only [FieldElement] but later also kernel based Dart fields
+/// and/or Dart-in-JS field-like properties.
+abstract class FieldEntity extends MemberEntity {}
+
+/// Stripped down super interface for function like entities.
+///
+/// Currently only [FieldElement] but later also kernel based Dart constructors
+/// and methods and/or Dart-in-JS function-like properties.
+abstract class FunctionEntity extends MemberEntity {}
diff --git a/pkg/compiler/lib/src/inferrer/closure_tracer.dart b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
index bb406ca..a757a7b 100644
--- a/pkg/compiler/lib/src/inferrer/closure_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
@@ -6,6 +6,7 @@
 
 import '../common/names.dart' show Names;
 import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart';
 import '../types/types.dart' show TypeMask;
 import '../universe/selector.dart' show Selector;
 import 'debug.dart' as debug;
@@ -71,7 +72,7 @@
     Element called = info.calledElement;
     if (compiler.backend.isForeign(called)) {
       String name = called.name;
-      if (name == 'JS' || name == 'DART_CLOSURE_TO_JS') {
+      if (name == BackendHelpers.JS || name == 'DART_CLOSURE_TO_JS') {
         bailout('Used in JS ${info.call}');
       }
     }
diff --git a/pkg/compiler/lib/src/inferrer/list_tracer.dart b/pkg/compiler/lib/src/inferrer/list_tracer.dart
index d0985e0..575a8c9 100644
--- a/pkg/compiler/lib/src/inferrer/list_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/list_tracer.dart
@@ -5,6 +5,7 @@
 library compiler.src.inferrer.list_tracer;
 
 import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart';
 import '../universe/selector.dart' show Selector;
 import '../util/util.dart' show Setlet;
 import 'node_tracer.dart';
@@ -164,7 +165,8 @@
   visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
     super.visitStaticCallSiteTypeInformation(info);
     Element called = info.calledElement;
-    if (compiler.backend.isForeign(called) && called.name == 'JS') {
+    if (compiler.backend.isForeign(called) &&
+        called.name == BackendHelpers.JS) {
       bailout('Used in JS ${info.call}');
     }
   }
diff --git a/pkg/compiler/lib/src/inferrer/map_tracer.dart b/pkg/compiler/lib/src/inferrer/map_tracer.dart
index 22a9f0f..0abb2ca 100644
--- a/pkg/compiler/lib/src/inferrer/map_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/map_tracer.dart
@@ -5,6 +5,7 @@
 library compiler.src.inferrer.map_tracer;
 
 import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart';
 import '../universe/selector.dart' show Selector;
 import 'node_tracer.dart';
 import 'type_graph_nodes.dart';
@@ -66,7 +67,8 @@
   visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
     super.visitStaticCallSiteTypeInformation(info);
     Element called = info.calledElement;
-    if (compiler.backend.isForeign(called) && called.name == 'JS') {
+    if (compiler.backend.isForeign(called) &&
+        called.name == BackendHelpers.JS) {
       bailout('Used in JS ${info.call}');
     }
   }
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index 0e95ce5..f2f8e0b 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -12,6 +12,7 @@
 import '../core_types.dart' show CoreClasses, CoreTypes;
 import '../dart_types.dart' show DartType;
 import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart';
 import '../js_backend/js_backend.dart' as js;
 import '../native/native.dart' as native;
 import '../resolution/operators.dart' as op;
@@ -1839,7 +1840,9 @@
     TypeMask mask = elements.getTypeMask(node);
     String name = element.name;
     handleStaticSend(node, selector, mask, element, arguments);
-    if (name == 'JS' || name == 'JS_EMBEDDED_GLOBAL' || name == 'JS_BUILTIN') {
+    if (name == BackendHelpers.JS ||
+        name == BackendHelpers.JS_EMBEDDED_GLOBAL ||
+        name == BackendHelpers.JS_BUILTIN) {
       native.NativeBehavior nativeBehavior = elements.getNativeData(node);
       sideEffects.add(nativeBehavior.sideEffects);
       return inferrer.typeOfNativeBehavior(nativeBehavior);
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index b4a764f..cfb6657 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -522,7 +522,7 @@
   void onStep(js.Node node, Offset offset, StepKind kind) {
     SourceInformation sourceInformation = computeSourceInformation(node);
     if (sourceInformation == null) return;
-    int codeLocation = offset.subexpressionOffset;
+    int codeLocation = offset.value;
     if (codeLocation == null) return;
 
     void registerPosition(SourcePositionKind sourcePositionKind) {
@@ -676,6 +676,8 @@
   Offset(
       this.statementOffset, this.leftToRightOffset, this.subexpressionOffset);
 
+  int get value => subexpressionOffset;
+
   String toString() {
     return 'Offset[statementOffset=$statementOffset,'
         'leftToRightOffset=$leftToRightOffset,'
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 5b843fe..48f7139 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -334,7 +334,7 @@
   static const String TRACE_METHOD = const String.fromEnvironment('traceCalls');
   static const bool TRACE_CALLS =
       TRACE_METHOD == 'post' || TRACE_METHOD == 'console';
-  Element traceHelper;
+  MethodElement traceHelper;
 
   TypeMask get stringType => compiler.commonMasks.stringType;
   TypeMask get doubleType => compiler.commonMasks.doubleType;
@@ -854,7 +854,7 @@
           .handleMethodAnnotations(element);
       if (isNative(element)) {
         native.NativeBehavior behavior =
-            native.NativeBehavior.ofMethod(element, compiler);
+            native.NativeBehavior.ofMethodElement(element, compiler);
         nativeData.setNativeMethodBehavior(element, behavior);
         registry.registerNativeData(behavior);
       }
@@ -863,9 +863,9 @@
           .handleFieldAnnotations(element);
       if (isNative(element)) {
         native.NativeBehavior fieldLoadBehavior =
-            native.NativeBehavior.ofFieldLoad(element, compiler);
-        native.NativeBehavior fieldStoreBehavior =
-            native.NativeBehavior.ofFieldStore(element, compiler);
+            native.NativeBehavior.ofFieldElementLoad(element, compiler);
+        native.NativeBehavior fieldStoreBehavior = native.NativeBehavior
+            .ofFieldElementStore(element, compiler.resolution);
         nativeData.setNativeFieldLoadBehavior(element, fieldLoadBehavior);
         nativeData.setNativeFieldStoreBehavior(element, fieldStoreBehavior);
 
@@ -1434,13 +1434,13 @@
       CallStructure callStructure, ForeignResolver resolver) {
     native.NativeResolutionEnqueuer nativeEnqueuer =
         compiler.enqueuer.resolution.nativeEnqueuer;
-    if (element.name == 'JS') {
+    if (element.name == BackendHelpers.JS) {
       return nativeEnqueuer.resolveJsCall(node, resolver);
-    } else if (element.name == 'JS_EMBEDDED_GLOBAL') {
+    } else if (element.name == BackendHelpers.JS_EMBEDDED_GLOBAL) {
       return nativeEnqueuer.resolveJsEmbeddedGlobalCall(node, resolver);
-    } else if (element.name == 'JS_BUILTIN') {
+    } else if (element.name == BackendHelpers.JS_BUILTIN) {
       return nativeEnqueuer.resolveJsBuiltinCall(node, resolver);
-    } else if (element.name == 'JS_INTERCEPTOR_CONSTANT') {
+    } else if (element.name == BackendHelpers.JS_INTERCEPTOR_CONSTANT) {
       // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
       // a class that will be instantiated outside the program by attaching a
       // native class dispatch record referencing the interceptor.
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index f85e9d0..eb347c3 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -16,8 +16,10 @@
         ConstructorElement,
         Element,
         EnumClassElement,
+        FieldElement,
         FunctionElement,
         LibraryElement,
+        MemberElement,
         MethodElement,
         PublicName;
 import '../library_loader.dart' show LoadedLibraries;
@@ -44,6 +46,11 @@
   static const String INVOKE_ON = '_getCachedInvocation';
   static const String START_ROOT_ISOLATE = 'startRootIsolate';
 
+  static const String JS = 'JS';
+  static const String JS_BUILTIN = 'JS_BUILTIN';
+  static const String JS_EMBEDDED_GLOBAL = 'JS_EMBEDDED_GLOBAL';
+  static const String JS_INTERCEPTOR_CONSTANT = 'JS_INTERCEPTOR_CONSTANT';
+
   final Compiler compiler;
 
   Element cachedCheckConcurrentModificationError;
@@ -100,11 +107,11 @@
   ClassElement jsUInt32Class;
   ClassElement jsUInt31Class;
 
-  Element jsIndexableLength;
+  MemberElement jsIndexableLength;
   Element jsArrayTypedConstructor;
-  Element jsArrayRemoveLast;
-  Element jsArrayAdd;
-  Element jsStringSplit;
+  MethodElement jsArrayRemoveLast;
+  MethodElement jsArrayAdd;
+  MethodElement jsStringSplit;
   Element jsStringToString;
   Element jsStringOperatorAdd;
   Element objectEquals;
@@ -366,10 +373,14 @@
     }
 
     jsIndexableClass.ensureResolved(resolution);
-    jsIndexableLength = compiler.lookupElementIn(jsIndexableClass, 'length');
-    if (jsIndexableLength != null && jsIndexableLength.isAbstractField) {
-      AbstractFieldElement element = jsIndexableLength;
+    Element jsIndexableLengthElement =
+        compiler.lookupElementIn(jsIndexableClass, 'length');
+    if (jsIndexableLengthElement != null &&
+        jsIndexableLengthElement.isAbstractField) {
+      AbstractFieldElement element = jsIndexableLengthElement;
       jsIndexableLength = element.getter;
+    } else {
+      jsIndexableLength = jsIndexableLengthElement;
     }
 
     jsArrayClass.ensureResolved(resolution);
@@ -397,7 +408,7 @@
     return findHelper('mainHasTooManyParameters');
   }
 
-  Element get loadLibraryWrapper {
+  MethodElement get loadLibraryWrapper {
     return findHelper("_loadLibraryWrapper");
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 8043861..e0511a3 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -17,6 +17,7 @@
 import '../dart_types.dart';
 import '../diagnostics/invariant.dart' show DEBUG_MODE;
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
 import '../tree/tree.dart';
@@ -667,7 +668,7 @@
   }
 
   /// Annotated name for [method] encoding arity and named parameters.
-  jsAst.Name instanceMethodName(FunctionElement method) {
+  jsAst.Name instanceMethodName(MethodElement method) {
     if (method.isGenerativeConstructorBody) {
       return constructorBodyName(method);
     }
@@ -1250,7 +1251,7 @@
     return disambiguated;
   }
 
-  String suffixForGetInterceptor(Iterable<ClassElement> classes) {
+  String suffixForGetInterceptor(Iterable<ClassEntity> classes) {
     String abbreviate(ClassElement cls) {
       if (cls == coreClasses.objectClass) return "o";
       if (cls == helpers.jsStringClass) return "s";
@@ -1279,7 +1280,7 @@
   }
 
   /// Property name used for `getInterceptor` or one of its specializations.
-  jsAst.Name nameForGetInterceptor(Iterable<ClassElement> classes) {
+  jsAst.Name nameForGetInterceptor(Iterable<ClassEntity> classes) {
     FunctionElement getInterceptor = helpers.getInterceptorMethod;
     if (classes.contains(helpers.jsInterceptorClass)) {
       // If the base Interceptor class is in the set of intercepted classes, we
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 da0aff8..eabb905 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -60,7 +60,7 @@
   String get patchVersion => emitter.patchVersion;
 
   /// Returns the closure expression of a static function.
-  jsAst.Expression isolateStaticClosureAccess(FunctionElement element) {
+  jsAst.Expression isolateStaticClosureAccess(MethodElement element) {
     return emitter.isolateStaticClosureAccess(element);
   }
 
@@ -87,7 +87,7 @@
   /// Returns the JS function representing the given function.
   ///
   /// The function must be invoked and can not be used as closure.
-  jsAst.Expression staticFunctionAccess(FunctionElement e) {
+  jsAst.Expression staticFunctionAccess(MethodElement e) {
     return emitter.staticFunctionAccess(e);
   }
 
diff --git a/pkg/compiler/lib/src/kernel/constant_visitor.dart b/pkg/compiler/lib/src/kernel/constant_visitor.dart
new file mode 100644
index 0000000..0d1e1a6
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/constant_visitor.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' as ir;
+
+import '../constants/expressions.dart';
+import 'kernel.dart';
+
+/// Visitor that converts a [ConstantExpression] into a kernel constant
+/// expression.
+class ConstantVisitor extends ConstantExpressionVisitor<ir.Node, Kernel> {
+  const ConstantVisitor();
+
+  @override
+  ir.Node visitNamed(NamedArgumentReference exp, Kernel kernel) {
+    throw new UnsupportedError(
+        '${exp.toStructuredText()} is not a valid constant.');
+  }
+
+  @override
+  ir.Node visitPositional(PositionalArgumentReference exp, Kernel kernel) {
+    throw new UnsupportedError(
+        '${exp.toStructuredText()} is not a valid constant.');
+  }
+
+  @override
+  ir.Node visitDeferred(DeferredConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitStringFromEnvironment(
+      StringFromEnvironmentConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitIntFromEnvironment(
+      IntFromEnvironmentConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitBoolFromEnvironment(
+      BoolFromEnvironmentConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitConditional(ConditionalConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitStringLength(StringLengthConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitUnary(UnaryConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitIdentical(IdenticalConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitBinary(BinaryConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitFunction(FunctionConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitVariable(VariableConstantExpression exp, Kernel kernel) {
+    return new ir.StaticGet(kernel.fieldToIr(exp.element));
+  }
+
+  @override
+  ir.Node visitType(TypeConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitSymbol(SymbolConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitConcatenate(ConcatenateConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitConstructed(ConstructedConstantExpression exp, Kernel kernel) {
+    List<ir.Expression> positional = <ir.Expression>[];
+    List<ir.NamedExpression> named = <ir.NamedExpression>[];
+    int positionalCount = exp.callStructure.positionalArgumentCount;
+    for (int index = 0; index < positionalCount; index++) {
+      ir.Expression argument = visit(exp.arguments[index], kernel);
+      if (index < exp.callStructure.positionalArgumentCount) {
+        positional.add(argument);
+      } else {
+        named.add(new ir.NamedExpression(
+            exp.callStructure.namedArguments[index - positionalCount],
+            argument));
+      }
+    }
+    ir.Arguments arguments = new ir.Arguments(positional, named: named);
+    return new ir.ConstructorInvocation(
+        kernel.functionToIr(exp.target), arguments,
+        isConst: true);
+  }
+
+  @override
+  ir.Node visitMap(MapConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitList(ListConstantExpression exp, Kernel kernel) {
+    throw new UnimplementedError('${exp.toStructuredText()} is not supported.');
+  }
+
+  @override
+  ir.Node visitNull(NullConstantExpression exp, Kernel kernel) {
+    return new ir.NullLiteral();
+  }
+
+  @override
+  ir.Node visitString(StringConstantExpression exp, Kernel kernel) {
+    return new ir.StringLiteral(exp.primitiveValue);
+  }
+
+  @override
+  ir.Node visitDouble(DoubleConstantExpression exp, Kernel kernel) {
+    return new ir.DoubleLiteral(exp.primitiveValue);
+  }
+
+  @override
+  ir.Node visitInt(IntConstantExpression exp, Kernel kernel) {
+    return new ir.IntLiteral(exp.primitiveValue);
+  }
+
+  @override
+  ir.Node visitBool(BoolConstantExpression exp, Kernel kernel) {
+    return new ir.BoolLiteral(exp.primitiveValue);
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/kernel.dart b/pkg/compiler/lib/src/kernel/kernel.dart
index 35ff9ea..b4ff25a 100644
--- a/pkg/compiler/lib/src/kernel/kernel.dart
+++ b/pkg/compiler/lib/src/kernel/kernel.dart
@@ -27,10 +27,12 @@
         ImportElement,
         LibraryElement,
         LocalFunctionElement,
+        MetadataAnnotation,
         MixinApplicationElement,
         TypeVariableElement;
 import '../elements/modelx.dart' show ErroneousFieldElementX;
 import '../tree/tree.dart' show FunctionExpression, Node;
+import 'constant_visitor.dart';
 import 'kernel_visitor.dart' show IrFunction, KernelVisitor;
 
 typedef void WorkAction();
@@ -217,6 +219,12 @@
           classNode.implementedTypes.add(interface);
         }
       });
+      addWork(cls.declaration, () {
+        for (MetadataAnnotation metadata in cls.declaration.metadata) {
+          classNode.addAnnotation(
+              const ConstantVisitor().visit(metadata.constant, this));
+        }
+      });
       return classNode;
     });
   }
@@ -391,6 +399,12 @@
           return true;
         });
       });
+      addWork(function.declaration, () {
+        for (MetadataAnnotation metadata in function.declaration.metadata) {
+          member.addAnnotation(
+              const ConstantVisitor().visit(metadata.constant, this));
+        }
+      });
       return member;
     });
   }
@@ -452,6 +466,12 @@
             ..parent = fieldNode;
         }
       });
+      addWork(field.declaration, () {
+        for (MetadataAnnotation metadata in field.declaration.metadata) {
+          fieldNode.addAnnotation(
+              const ConstantVisitor().visit(metadata.constant, this));
+        }
+      });
       return fieldNode;
     });
   }
diff --git a/pkg/compiler/lib/src/kernel/kernel_debug.dart b/pkg/compiler/lib/src/kernel/kernel_debug.dart
index 725e2d1..f86a6a2 100644
--- a/pkg/compiler/lib/src/kernel/kernel_debug.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_debug.dart
@@ -45,7 +45,7 @@
   @override
   void visitVariableDeclaration(VariableDeclaration node) {
     openNode(node, '${node.runtimeType}', {
-      'name': '${node.name}',
+      'name': '${node.name ?? '--unnamed--'}',
       'isFinal': '${node.isFinal}',
       'isConst': '${node.isConst}'
     });
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 57ef61a..8609630 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -6,6 +6,7 @@
 import '../common/backend_api.dart' show ForeignResolver;
 import '../common/resolution.dart' show ParsingContext, Resolution;
 import '../compiler.dart' show Compiler;
+import '../constants/expressions.dart';
 import '../constants/values.dart';
 import '../core_types.dart' show CoreTypes;
 import '../dart_types.dart';
@@ -18,6 +19,8 @@
 import 'enqueue.dart';
 import 'js.dart';
 
+typedef dynamic /*DartType|SpecialType*/ TypeLookup(String typeString);
+
 /// This class is a temporary work-around until we get a more powerful DartType.
 class SpecialType {
   final String name;
@@ -263,7 +266,7 @@
       void setThrows(NativeThrowBehavior throwKind),
       void setIsAllocation(bool isAllocation),
       void setUseGvn(bool useGvn),
-      dynamic resolveType(String typeString),
+      TypeLookup lookupType,
       List typesReturned,
       List typesInstantiated,
       objectType,
@@ -306,7 +309,7 @@
         return;
       }
       for (final typeString in typesString.split('|')) {
-        onType(resolveType(typeString.trim()));
+        onType(_parseType(typeString.trim(), spannable, reporter, lookupType));
       }
     }
 
@@ -486,8 +489,51 @@
     return sideEffects;
   }
 
-  static NativeBehavior ofJsCall(Send jsCall, DiagnosticReporter reporter,
+  /// Returns a [TypeLookup] that uses [resolver] to perform lookup and [node]
+  /// as position for errors.
+  static TypeLookup _typeLookup(Node node, ForeignResolver resolver) {
+    return (String name) => resolver.resolveTypeFromString(node, name);
+  }
+
+  /// Compute the [NativeBehavior] for a [Send] node calling the 'JS' function.
+  static NativeBehavior ofJsCallSend(Send jsCall, DiagnosticReporter reporter,
       ParsingContext parsing, CoreTypes coreTypes, ForeignResolver resolver) {
+    var argNodes = jsCall.arguments;
+    if (argNodes.isEmpty || argNodes.tail.isEmpty) {
+      reporter.reportErrorMessage(jsCall, MessageKind.WRONG_ARGUMENT_FOR_JS);
+      return new NativeBehavior();
+    }
+
+    var specArgument = argNodes.head;
+    if (specArgument is! StringNode || specArgument.isInterpolation) {
+      reporter.reportErrorMessage(
+          specArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
+      return new NativeBehavior();
+    }
+
+    var codeArgument = argNodes.tail.head;
+    if (codeArgument is! StringNode || codeArgument.isInterpolation) {
+      reporter.reportErrorMessage(
+          codeArgument, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
+      return new NativeBehavior();
+    }
+
+    String specString = specArgument.dartString.slowToString();
+    String codeString = codeArgument.dartString.slowToString();
+
+    return ofJsCall(specString, codeString, _typeLookup(specArgument, resolver),
+        specArgument, reporter, coreTypes);
+  }
+
+  /// Compute the [NativeBehavior] for a call to the 'JS' function with the
+  /// given [specString] and [codeString] (first and second arguments).
+  static NativeBehavior ofJsCall(
+      String specString,
+      String codeString,
+      TypeLookup lookupType,
+      Spannable spannable,
+      DiagnosticReporter reporter,
+      CoreTypes coreTypes) {
     // The first argument of a JS-call is a string encoding various attributes
     // of the code.
     //
@@ -496,40 +542,9 @@
 
     NativeBehavior behavior = new NativeBehavior();
 
-    var argNodes = jsCall.arguments;
-    if (argNodes.isEmpty || argNodes.tail.isEmpty) {
-      reporter.reportErrorMessage(jsCall, MessageKind.GENERIC,
-          {'text': "JS expression takes two or more arguments."});
-      return behavior;
-    }
-
-    var specArgument = argNodes.head;
-    if (specArgument is! StringNode || specArgument.isInterpolation) {
-      reporter.reportErrorMessage(specArgument, MessageKind.GENERIC,
-          {'text': "JS first argument must be a string literal."});
-      return behavior;
-    }
-
-    var codeArgument = argNodes.tail.head;
-    if (codeArgument is! StringNode || codeArgument.isInterpolation) {
-      reporter.reportErrorMessage(codeArgument, MessageKind.GENERIC,
-          {'text': "JS second argument must be a string literal."});
-      return behavior;
-    }
-
-    behavior.codeTemplateText = codeArgument.dartString.slowToString();
+    behavior.codeTemplateText = codeString;
     behavior.codeTemplate = js.js.parseForeignJS(behavior.codeTemplateText);
 
-    String specString = specArgument.dartString.slowToString();
-
-    dynamic resolveType(String typeString) {
-      return _parseType(
-          typeString,
-          parsing,
-          (name) => resolver.resolveTypeFromString(specArgument, name),
-          specArgument);
-    }
-
     bool sideEffectsAreEncodedInSpecString = false;
 
     void setSideEffects(SideEffects newEffects) {
@@ -551,12 +566,12 @@
       behavior.useGvn = useGvn;
     }
 
-    processSpecString(reporter, specArgument, specString,
+    processSpecString(reporter, spannable, specString,
         setSideEffects: setSideEffects,
         setThrows: setThrows,
         setIsAllocation: setIsAllocation,
         setUseGvn: setUseGvn,
-        resolveType: resolveType,
+        lookupType: lookupType,
         typesReturned: behavior.typesReturned,
         typesInstantiated: behavior.typesInstantiated,
         objectType: coreTypes.objectType,
@@ -576,40 +591,51 @@
 
   static void _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
       NativeBehavior behavior,
-      Send jsBuiltinOrEmbeddedGlobalCall,
+      Spannable spannable,
+      String specString,
+      TypeLookup lookupType,
       DiagnosticReporter reporter,
-      ParsingContext parsing,
       CoreTypes coreTypes,
-      ForeignResolver resolver,
-      {bool isBuiltin,
-      List<String> validTags}) {
+      {List<String> validTags}) {
+    void setSideEffects(SideEffects newEffects) {
+      behavior.sideEffects.setTo(newEffects);
+    }
+
+    processSpecString(reporter, spannable, specString,
+        validTags: validTags,
+        lookupType: lookupType,
+        setSideEffects: setSideEffects,
+        typesReturned: behavior.typesReturned,
+        typesInstantiated: behavior.typesInstantiated,
+        objectType: coreTypes.objectType,
+        nullType: coreTypes.nullType);
+  }
+
+  static NativeBehavior ofJsBuiltinCallSend(
+      Send jsBuiltinCall,
+      DiagnosticReporter reporter,
+      CoreTypes coreTypes,
+      ForeignResolver resolver) {
+    NativeBehavior behavior = new NativeBehavior();
+    behavior.sideEffects.setTo(new SideEffects());
+
     // The first argument of a JS-embedded global call is a string encoding
     // the type of the code.
     //
     //  'Type1|Type2'.  A union type.
     //  '=Object'.      A JavaScript Object, no subtype.
 
-    String builtinOrGlobal = isBuiltin ? "builtin" : "embedded global";
-
-    Link<Node> argNodes = jsBuiltinOrEmbeddedGlobalCall.arguments;
+    Link<Node> argNodes = jsBuiltinCall.arguments;
     if (argNodes.isEmpty) {
-      reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
-          "JS $builtinOrGlobal expression has no type.");
+      reporter.internalError(
+          jsBuiltinCall, "JS builtin expression has no type.");
     }
 
     // We don't check the given name. That needs to be done at a later point.
     // This is, because we want to allow non-literals (like references to
     // enums) as names.
     if (argNodes.tail.isEmpty) {
-      reporter.internalError(jsBuiltinOrEmbeddedGlobalCall,
-          'JS $builtinOrGlobal is missing name.');
-    }
-
-    if (!isBuiltin) {
-      if (!argNodes.tail.tail.isEmpty) {
-        reporter.internalError(argNodes.tail.tail.head,
-            'JS embedded global has more than 2 arguments');
-      }
+      reporter.internalError(jsBuiltinCall, "JS builtin is missing name.");
     }
 
     LiteralString specLiteral = argNodes.head.asLiteralString();
@@ -621,48 +647,26 @@
 
     String specString = specLiteral.dartString.slowToString();
 
-    dynamic resolveType(String typeString) {
-      return _parseType(
-          typeString,
-          parsing,
-          (name) => resolver.resolveTypeFromString(specLiteral, name),
-          jsBuiltinOrEmbeddedGlobalCall);
-    }
-
-    void setSideEffects(SideEffects newEffects) {
-      behavior.sideEffects.setTo(newEffects);
-    }
-
-    processSpecString(reporter, jsBuiltinOrEmbeddedGlobalCall, specString,
-        validTags: validTags,
-        resolveType: resolveType,
-        setSideEffects: setSideEffects,
-        typesReturned: behavior.typesReturned,
-        typesInstantiated: behavior.typesInstantiated,
-        objectType: coreTypes.objectType,
-        nullType: coreTypes.nullType);
+    return ofJsBuiltinCall(specString, _typeLookup(jsBuiltinCall, resolver),
+        jsBuiltinCall, reporter, coreTypes);
   }
 
   static NativeBehavior ofJsBuiltinCall(
-      Send jsBuiltinCall,
+      String specString,
+      TypeLookup lookupType,
+      Spannable spannable,
       DiagnosticReporter reporter,
-      ParsingContext parsing,
-      CoreTypes coreTypes,
-      ForeignResolver resolver) {
+      CoreTypes coreTypes) {
     NativeBehavior behavior = new NativeBehavior();
     behavior.sideEffects.setTo(new SideEffects());
-
     _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
-        behavior, jsBuiltinCall, reporter, parsing, coreTypes, resolver,
-        isBuiltin: true);
-
+        behavior, spannable, specString, lookupType, reporter, coreTypes);
     return behavior;
   }
 
-  static NativeBehavior ofJsEmbeddedGlobalCall(
+  static NativeBehavior ofJsEmbeddedGlobalCallSend(
       Send jsEmbeddedGlobalCall,
       DiagnosticReporter reporter,
-      ParsingContext parsing,
       CoreTypes coreTypes,
       ForeignResolver resolver) {
     NativeBehavior behavior = new NativeBehavior();
@@ -672,79 +676,74 @@
     behavior.sideEffects.setTo(new SideEffects.empty());
     behavior.throwBehavior = NativeThrowBehavior.NEVER;
 
+    // The first argument of a JS-embedded global call is a string encoding
+    // the type of the code.
+    //
+    //  'Type1|Type2'.  A union type.
+    //  '=Object'.      A JavaScript Object, no subtype.
+
+    Link<Node> argNodes = jsEmbeddedGlobalCall.arguments;
+    if (argNodes.isEmpty) {
+      reporter.internalError(
+          jsEmbeddedGlobalCall, "JS embedded global expression has no type.");
+    }
+
+    // We don't check the given name. That needs to be done at a later point.
+    // This is, because we want to allow non-literals (like references to
+    // enums) as names.
+    if (argNodes.tail.isEmpty) {
+      reporter.internalError(
+          jsEmbeddedGlobalCall, "JS embedded global is missing name.");
+    }
+
+    if (!argNodes.tail.tail.isEmpty) {
+      reporter.internalError(argNodes.tail.tail.head,
+          'JS embedded global has more than 2 arguments');
+    }
+
+    LiteralString specLiteral = argNodes.head.asLiteralString();
+    if (specLiteral == null) {
+      // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2').  It
+      // is not very satisfactory because it does not work for void, dynamic.
+      reporter.internalError(argNodes.head, "Unexpected first argument.");
+    }
+
+    String specString = specLiteral.dartString.slowToString();
+
+    return ofJsEmbeddedGlobalCall(
+        specString,
+        _typeLookup(jsEmbeddedGlobalCall, resolver),
+        jsEmbeddedGlobalCall,
+        reporter,
+        coreTypes);
+  }
+
+  static NativeBehavior ofJsEmbeddedGlobalCall(
+      String specString,
+      TypeLookup lookupType,
+      Spannable spannable,
+      DiagnosticReporter reporter,
+      CoreTypes coreTypes) {
+    NativeBehavior behavior = new NativeBehavior();
+    // TODO(sra): Allow the use site to override these defaults.
+    // Embedded globals are usually pre-computed data structures or JavaScript
+    // functions that never change.
+    behavior.sideEffects.setTo(new SideEffects.empty());
+    behavior.throwBehavior = NativeThrowBehavior.NEVER;
     _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal(
-        behavior, jsEmbeddedGlobalCall, reporter, parsing, coreTypes, resolver,
-        isBuiltin: false, validTags: const ['returns', 'creates']);
-
+        behavior, spannable, specString, lookupType, reporter, coreTypes,
+        validTags: ['returns', 'creates']);
     return behavior;
   }
 
-  static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
-    FunctionType type = method.computeType(compiler.resolution);
-    var behavior = new NativeBehavior();
-    var returnType = type.returnType;
-    bool isInterop = compiler.backend.isJsInterop(method);
-    // Note: For dart:html and other internal libraries we maintain, we can
-    // trust the return type and use it to limit what we enqueue. We have to
-    // be more conservative about JS interop types and assume they can return
-    // anything (unless the user provides the experimental flag to trust the
-    // type of js-interop APIs). We do restrict the allocation effects and say
-    // that interop calls create only interop types (which may be unsound if
-    // an interop call returns a DOM type and declares a dynamic return type,
-    // but otherwise we would include a lot of code by default).
-    // TODO(sigmund,sra): consider doing something better for numeric types.
-    behavior.typesReturned.add(
-        !isInterop || compiler.options.trustJSInteropTypeAnnotations
-            ? returnType
-            : const DynamicType());
-    if (!type.returnType.isVoid) {
-      // Declared types are nullable.
-      behavior.typesReturned.add(compiler.coreTypes.nullType);
+  static NativeBehavior ofMethodElement(
+      FunctionElement element, Compiler compiler) {
+    FunctionType type = element.computeType(compiler.resolution);
+    List<ConstantExpression> metadata = <ConstantExpression>[];
+    for (MetadataAnnotation annotation in element.implementation.metadata) {
+      annotation.ensureResolved(compiler.resolution);
+      metadata.add(annotation.constant);
     }
-    behavior._capture(type, compiler.resolution,
-        isInterop: isInterop, compiler: compiler);
-
-    for (DartType type in type.optionalParameterTypes) {
-      behavior._escape(type, compiler.resolution);
-    }
-    for (DartType type in type.namedParameterTypes) {
-      behavior._escape(type, compiler.resolution);
-    }
-
-    behavior._overrideWithAnnotations(method, compiler);
-    return behavior;
-  }
-
-  static NativeBehavior ofFieldLoad(MemberElement field, Compiler compiler) {
-    Resolution resolution = compiler.resolution;
-    DartType type = field.computeType(resolution);
-    var behavior = new NativeBehavior();
-    bool isInterop = compiler.backend.isJsInterop(field);
-    // TODO(sigmund,sra): consider doing something better for numeric types.
-    behavior.typesReturned.add(
-        !isInterop || compiler.options.trustJSInteropTypeAnnotations
-            ? type
-            : const DynamicType());
-    // Declared types are nullable.
-    behavior.typesReturned.add(resolution.coreTypes.nullType);
-    behavior._capture(type, resolution,
-        isInterop: isInterop, compiler: compiler);
-    behavior._overrideWithAnnotations(field, compiler);
-    return behavior;
-  }
-
-  static NativeBehavior ofFieldStore(MemberElement field, Compiler compiler) {
-    Resolution resolution = compiler.resolution;
-    DartType type = field.computeType(resolution);
-    var behavior = new NativeBehavior();
-    behavior._escape(type, resolution);
-    // We don't override the default behaviour - the annotations apply to
-    // loading the field.
-    return behavior;
-  }
-
-  void _overrideWithAnnotations(Element element, Compiler compiler) {
-    if (element.implementation.metadata.isEmpty) return;
 
     DartType lookup(String name) {
       Element e = element.buildScope().lookup(name);
@@ -755,11 +754,123 @@
       return cls.thisType;
     }
 
+    return ofMethod(element, type, metadata, lookup, compiler,
+        isJsInterop: compiler.backend.isJsInterop(element));
+  }
+
+  static NativeBehavior ofMethod(
+      Spannable spannable,
+      FunctionType type,
+      List<ConstantExpression> metadata,
+      TypeLookup lookupType,
+      Compiler compiler,
+      {bool isJsInterop}) {
+    var behavior = new NativeBehavior();
+    var returnType = type.returnType;
+    // Note: For dart:html and other internal libraries we maintain, we can
+    // trust the return type and use it to limit what we enqueue. We have to
+    // be more conservative about JS interop types and assume they can return
+    // anything (unless the user provides the experimental flag to trust the
+    // type of js-interop APIs). We do restrict the allocation effects and say
+    // that interop calls create only interop types (which may be unsound if
+    // an interop call returns a DOM type and declares a dynamic return type,
+    // but otherwise we would include a lot of code by default).
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    behavior.typesReturned.add(
+        !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
+            ? returnType
+            : const DynamicType());
+    if (!type.returnType.isVoid) {
+      // Declared types are nullable.
+      behavior.typesReturned.add(compiler.coreTypes.nullType);
+    }
+    behavior._capture(type, compiler.resolution,
+        isInterop: isJsInterop, compiler: compiler);
+
+    for (DartType type in type.optionalParameterTypes) {
+      behavior._escape(type, compiler.resolution);
+    }
+    for (DartType type in type.namedParameterTypes) {
+      behavior._escape(type, compiler.resolution);
+    }
+
+    behavior._overrideWithAnnotations(
+        spannable, metadata, lookupType, compiler);
+    return behavior;
+  }
+
+  static NativeBehavior ofFieldElementLoad(
+      MemberElement element, Compiler compiler) {
+    Resolution resolution = compiler.resolution;
+    DartType type = element.computeType(resolution);
+    List<ConstantExpression> metadata = <ConstantExpression>[];
+    for (MetadataAnnotation annotation in element.implementation.metadata) {
+      annotation.ensureResolved(compiler.resolution);
+      metadata.add(annotation.constant);
+    }
+
+    DartType lookup(String name) {
+      Element e = element.buildScope().lookup(name);
+      if (e == null) return null;
+      if (e is! ClassElement) return null;
+      ClassElement cls = e;
+      cls.ensureResolved(compiler.resolution);
+      return cls.thisType;
+    }
+
+    return ofFieldLoad(element, type, metadata, lookup, compiler,
+        isJsInterop: compiler.backend.isJsInterop(element));
+  }
+
+  static NativeBehavior ofFieldLoad(
+      Spannable spannable,
+      DartType type,
+      List<ConstantExpression> metadata,
+      TypeLookup lookupType,
+      Compiler compiler,
+      {bool isJsInterop}) {
+    Resolution resolution = compiler.resolution;
+    var behavior = new NativeBehavior();
+    // TODO(sigmund,sra): consider doing something better for numeric types.
+    behavior.typesReturned.add(
+        !isJsInterop || compiler.options.trustJSInteropTypeAnnotations
+            ? type
+            : const DynamicType());
+    // Declared types are nullable.
+    behavior.typesReturned.add(resolution.coreTypes.nullType);
+    behavior._capture(type, resolution,
+        isInterop: isJsInterop, compiler: compiler);
+    behavior._overrideWithAnnotations(
+        spannable, metadata, lookupType, compiler);
+    return behavior;
+  }
+
+  static NativeBehavior ofFieldElementStore(
+      MemberElement field, Resolution resolution) {
+    DartType type = field.computeType(resolution);
+    return ofFieldStore(type, resolution);
+  }
+
+  static NativeBehavior ofFieldStore(DartType type, Resolution resolution) {
+    var behavior = new NativeBehavior();
+    behavior._escape(type, resolution);
+    // We don't override the default behaviour - the annotations apply to
+    // loading the field.
+    return behavior;
+  }
+
+  void _overrideWithAnnotations(
+      Spannable spannable,
+      Iterable<ConstantExpression> metadata,
+      TypeLookup lookupType,
+      Compiler compiler) {
+    if (metadata.isEmpty) return;
+
     NativeEnqueuer enqueuer = compiler.enqueuer.resolution.nativeEnqueuer;
-    var creates =
-        _collect(element, compiler, enqueuer.annotationCreatesClass, lookup);
-    var returns =
-        _collect(element, compiler, enqueuer.annotationReturnsClass, lookup);
+    var creates = _collect(spannable, metadata, compiler,
+        enqueuer.annotationCreatesClass, lookupType);
+    var returns = _collect(spannable, metadata, compiler,
+        enqueuer.annotationReturnsClass, lookupType);
 
     if (creates != null) {
       typesInstantiated
@@ -778,14 +889,12 @@
    * [annotationClass].
    * Returns `null` if no constraints.
    */
-  static _collect(Element element, Compiler compiler, Element annotationClass,
-      lookup(str)) {
+  static _collect(Spannable spannable, Iterable<ConstantExpression> metadata,
+      Compiler compiler, Element annotationClass, TypeLookup lookupType) {
     DiagnosticReporter reporter = compiler.reporter;
     var types = null;
-    for (MetadataAnnotation annotation in element.implementation.metadata) {
-      annotation.ensureResolved(compiler.resolution);
-      ConstantValue value =
-          compiler.constants.getConstantValue(annotation.constant);
+    for (ConstantExpression constant in metadata) {
+      ConstantValue value = compiler.constants.getConstantValue(constant);
       if (!value.isConstructedObject) continue;
       ConstructedConstantValue constructedObject = value;
       if (constructedObject.type.element != annotationClass) continue;
@@ -793,14 +902,13 @@
       Iterable<ConstantValue> fields = constructedObject.fields.values;
       // TODO(sra): Better validation of the constant.
       if (fields.length != 1 || !fields.single.isString) {
-        reporter.internalError(
-            annotation, 'Annotations needs one string: ${annotation.node}');
+        reporter.internalError(spannable,
+            'Annotations needs one string: ${constant.toStructuredText()}');
       }
       StringConstantValue specStringConstant = fields.single;
       String specString = specStringConstant.toDartString().slowToString();
       for (final typeString in specString.split('|')) {
-        var type =
-            _parseType(typeString, compiler.parsingContext, lookup, annotation);
+        var type = _parseType(typeString, spannable, reporter, lookupType);
         if (types == null) types = [];
         types.add(type);
       }
@@ -874,34 +982,28 @@
     }
   }
 
-  static dynamic _parseType(String typeString, ParsingContext parsing,
-      lookup(name), locationNodeOrElement) {
-    DiagnosticReporter reporter = parsing.reporter;
+  static dynamic /*DartType|SpecialType*/ _parseType(String typeString,
+      Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) {
     if (typeString == '=Object') return SpecialType.JsObject;
     if (typeString == 'dynamic') {
       return const DynamicType();
     }
-    var type = lookup(typeString);
+    var type = lookupType(typeString);
     if (type != null) return type;
 
     int index = typeString.indexOf('<');
     if (index < 1) {
-      reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing),
-          MessageKind.GENERIC, {'text': "Type '$typeString' not found."});
+      reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
+          {'text': "Type '$typeString' not found."});
       return const DynamicType();
     }
-    type = lookup(typeString.substring(0, index));
+    type = lookupType(typeString.substring(0, index));
     if (type != null) {
       // TODO(sra): Parse type parameters.
       return type;
     }
-    reporter.reportErrorMessage(_errorNode(locationNodeOrElement, parsing),
-        MessageKind.GENERIC, {'text': "Type '$typeString' not found."});
+    reporter.reportErrorMessage(spannable, MessageKind.GENERIC,
+        {'text': "Type '$typeString' not found."});
     return const DynamicType();
   }
-
-  static _errorNode(locationNodeOrElement, ParsingContext parsing) {
-    if (locationNodeOrElement is Node) return locationNodeOrElement;
-    return locationNodeOrElement.parseNode(parsing);
-  }
 }
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 8e2d48b..7c3f125 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -584,7 +584,7 @@
    *
    */
   NativeBehavior resolveJsCall(Send node, ForeignResolver resolver) {
-    return NativeBehavior.ofJsCall(
+    return NativeBehavior.ofJsCallSend(
         node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
   }
 
@@ -599,8 +599,8 @@
    */
   NativeBehavior resolveJsEmbeddedGlobalCall(
       Send node, ForeignResolver resolver) {
-    return NativeBehavior.ofJsEmbeddedGlobalCall(
-        node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
+    return NativeBehavior.ofJsEmbeddedGlobalCallSend(
+        node, reporter, compiler.coreTypes, resolver);
   }
 
   /**
@@ -613,8 +613,8 @@
    *
    */
   NativeBehavior resolveJsBuiltinCall(Send node, ForeignResolver resolver) {
-    return NativeBehavior.ofJsBuiltinCall(
-        node, reporter, compiler.parsingContext, compiler.coreTypes, resolver);
+    return NativeBehavior.ofJsBuiltinCallSend(
+        node, reporter, compiler.coreTypes, resolver);
   }
 }
 
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index d15f041..9707724 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -345,6 +345,9 @@
         Node parameterNode = variableDefinitions.definitions.nodes.head;
         InitializingFormalElementX initializingFormal = element;
         FieldElement field = initializingFormal.fieldElement;
+        if (!field.isMalformed) {
+          registry.registerStaticUse(new StaticUse.fieldInit(field));
+        }
         checkForDuplicateInitializers(field, element.initializer);
         if (enableInitializingFormalAccess) {
           visitor.defineLocalVariable(parameterNode, initializingFormal);
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index 0dd861a..2d07373 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -244,7 +244,7 @@
         requiredParameters: [indexFormal],
         requiredParameterCount: 1,
         type: new FunctionType(
-            constructor, const VoidType(), <DartType>[intType]));
+            constructor, const DynamicType(), <DartType>[intType]));
     constructor.functionSignature = constructorSignature;
     enumClass.addMember(constructor, reporter);
 
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 86465be7..00b3725 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -456,14 +456,9 @@
             resolver.constantCompiler.compileConstant(parameter);
       });
     });
-    if (!functionSignature.returnType.isDynamic) {
-      registry.registerTypeUse(
-          new TypeUse.checkedModeCheck(functionSignature.returnType));
-    }
+    registry.registerCheckedModeCheck(functionSignature.returnType);
     functionSignature.forEachParameter((ParameterElement element) {
-      if (!element.type.isDynamic) {
-        registry.registerTypeUse(new TypeUse.checkedModeCheck(element.type));
-      }
+      registry.registerCheckedModeCheck(element.type);
     });
   }
 
@@ -1147,10 +1142,10 @@
     DartType type =
         resolveTypeAnnotation(typeNode, registerCheckedModeCheck: false);
 
-    // GENERIC_METHODS: Method type variables are not reified so we must warn
-    // about the error which will occur at runtime.
+    // GENERIC_METHODS: Method type variables are not reified, so we must inform
+    // the developer about the potentially bug-inducing semantics.
     if (type is MethodTypeVariableType) {
-      reporter.reportWarningMessage(
+      reporter.reportHintMessage(
           node, MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC);
     }
 
@@ -2355,6 +2350,8 @@
     if (result.kind == ResultKind.PREFIX) {
       return handlePrefixSend(node, name, result);
     } else if (node.isConditional) {
+      registry.registerConstantLiteral(new NullConstantExpression());
+      registry.registerDynamicUse(new DynamicUse(Selectors.equals, null));
       return handleDynamicAccessSemantics(
           node, name, new DynamicAccess.ifNotNullProperty(name));
     } else {
@@ -2388,6 +2385,8 @@
     if (result.kind == ResultKind.PREFIX) {
       return handlePrefixSendSet(node, name, result);
     } else if (node.isConditional) {
+      registry.registerConstantLiteral(new NullConstantExpression());
+      registry.registerDynamicUse(new DynamicUse(Selectors.equals, null));
       return handleDynamicUpdateSemantics(
           node, name, null, new DynamicAccess.ifNotNullProperty(name));
     } else {
@@ -4080,8 +4079,8 @@
     DartType type = typeResolver.resolveTypeAnnotation(this, node,
         malformedIsError: malformedIsError,
         deferredIsMalformed: deferredIsMalformed);
-    if (registerCheckedModeCheck && !type.isDynamic) {
-      registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
+    if (registerCheckedModeCheck) {
+      registry.registerCheckedModeCheck(type);
     }
     return type;
   }
@@ -4607,10 +4606,11 @@
       }
       if (cases.isNotEmpty && switchCase.statements.isNotEmpty) {
         Node last = switchCase.statements.last;
-        if (last.asBreakStatement() == null &&
+        if (last.asReturn() == null &&
+            last.asBreakStatement() == null &&
             last.asContinueStatement() == null &&
-            last.asThrow() == null &&
-            last.asReturn() == null) {
+            (last.asExpressionStatement() == null ||
+                last.asExpressionStatement().expression.asThrow() == null)) {
           registry.registerFeature(Feature.FALL_THROUGH_ERROR);
         }
       }
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index da2c129..51d7e81 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -331,6 +331,13 @@
     impactBuilder.registerTypeUse(typeUse);
   }
 
+  /// Register checked mode check of [type] if it isn't `dynamic`.
+  void registerCheckedModeCheck(DartType type) {
+    if (!type.isDynamic) {
+      impactBuilder.registerTypeUse(new TypeUse.checkedModeCheck(type));
+    }
+  }
+
   void registerSuperUse(SourceSpan span) {
     mapping.addSuperUse(span);
   }
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index bdfffd8..09ef8f9 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -315,11 +315,22 @@
           // Ensure the signature of the synthesized element is
           // resolved. This is the only place where the resolver is
           // seeing this element.
-          element.computeType(resolution);
+          FunctionType type = element.computeType(resolution);
           if (!target.isMalformed) {
             registry.registerStaticUse(new StaticUse.superConstructorInvoke(
-                target, CallStructure.NO_ARGS));
+                // TODO(johnniwinther): Provide the right call structure for
+                // forwarding constructors.
+                target,
+                CallStructure.NO_ARGS));
           }
+          // TODO(johnniwinther): Remove this substitution when synthesized
+          // constructors handle type variables correctly.
+          type = type.substByContext(
+              constructor.enclosingClass.asInstanceOf(target.enclosingClass));
+          type.parameterTypes.forEach(registry.registerCheckedModeCheck);
+          type.optionalParameterTypes
+              .forEach(registry.registerCheckedModeCheck);
+          type.namedParameterTypes.forEach(registry.registerCheckedModeCheck);
           return registry.impactBuilder;
         } else {
           assert(element.isDeferredLoaderGetter || element.isMalformed);
@@ -382,6 +393,8 @@
         // happens for enum fields where the type is known but is not in the
         // synthesized AST.
         element.variables.type = const DynamicType();
+      } else {
+        registry.registerCheckedModeCheck(element.variables.type);
       }
 
       Expression initializer = element.initializer;
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index eff4988..31673c2 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -370,7 +370,7 @@
       returnType = element.enclosingClass.thisType;
       // Because there is no type annotation for the return type of
       // this element, we explicitly add one.
-      registry.registerTypeUse(new TypeUse.checkedModeCheck(returnType));
+      registry.registerCheckedModeCheck(returnType);
     } else {
       AsyncMarker asyncMarker = AsyncMarker.SYNC;
       if (isFunctionExpression) {
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index 9db38fd..c9f03f2 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -990,7 +990,9 @@
       strategy.testSets(impact1, impact2, 'staticUses', impact1.staticUses,
           impact2.staticUses, areStaticUsesEquivalent) &&
       strategy.testSets(impact1, impact2, 'typeUses', impact1.typeUses,
-          impact2.typeUses, areTypeUsesEquivalent);
+          impact2.typeUses, areTypeUsesEquivalent) &&
+      strategy.testSets(impact1, impact2, 'nativeData', impact1.nativeData,
+          impact2.nativeData, testNativeBehavior);
 }
 
 /// Tests the equivalence of [resolvedAst1] and [resolvedAst2] using [strategy].
diff --git a/pkg/compiler/lib/src/serialization/system.dart b/pkg/compiler/lib/src/serialization/system.dart
index 8d241ce..9e6da49 100644
--- a/pkg/compiler/lib/src/serialization/system.dart
+++ b/pkg/compiler/lib/src/serialization/system.dart
@@ -9,6 +9,7 @@
 import '../common.dart';
 import '../common/resolution.dart';
 import '../compiler.dart';
+import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../scanner/scanner.dart';
 import '../script.dart';
@@ -156,20 +157,36 @@
   ResolutionImpact getResolutionImpact(Element element) {
     if (element.isConstructor &&
         element.enclosingClass.isUnnamedMixinApplication) {
-      ClassElement superclass = element.enclosingClass.superclass;
+      ConstructorElement constructor = element;
+      ClassElement superclass = constructor.enclosingClass.superclass;
       ConstructorElement superclassConstructor =
-          superclass.lookupConstructor(element.name);
+          superclass.lookupConstructor(constructor.name);
       assert(invariant(element, superclassConstructor != null,
-          message: "Superclass constructor '${element.name}' called from "
+          message: "Superclass constructor '${constructor.name}' called from "
               "${element} not found in ${superclass}."));
       // TODO(johnniwinther): Compute callStructure. Currently not used.
       CallStructure callStructure;
-      return _resolutionImpactDeserializer.registerResolutionImpact(element,
+      return _resolutionImpactDeserializer.registerResolutionImpact(constructor,
           () {
+        List<TypeUse> typeUses = <TypeUse>[];
+        void addCheckedModeCheck(DartType type) {
+          if (!type.isDynamic) {
+            typeUses.add(new TypeUse.checkedModeCheck(type));
+          }
+        }
+
+        FunctionType type = constructor.type;
+        // TODO(johnniwinther): Remove this substitution when synthesized
+        // constructors handle type variables correctly.
+        type = type.substByContext(constructor.enclosingClass
+            .asInstanceOf(constructor.enclosingClass));
+        type.parameterTypes.forEach(addCheckedModeCheck);
+        type.optionalParameterTypes.forEach(addCheckedModeCheck);
+        type.namedParameterTypes.forEach(addCheckedModeCheck);
         return new DeserializedResolutionImpact(staticUses: <StaticUse>[
           new StaticUse.superConstructorInvoke(
               superclassConstructor, callStructure)
-        ]);
+        ], typeUses: typeUses);
       });
     }
     return _resolutionImpactDeserializer.getResolutionImpact(element);
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 9e17d7a..f2def5c 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -20,6 +20,7 @@
 import '../diagnostics/messages.dart' show Message, MessageTemplate;
 import '../dump_info.dart' show InfoReporter;
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../elements/modelx.dart' show ConstructorBodyElementX;
 import '../io/source_information.dart';
 import '../js/js.dart' as js;
@@ -612,7 +613,7 @@
     return graph.addConstant(constantValue, compiler);
   }
 
-  Element get currentNonClosureClass {
+  ClassElement get currentNonClosureClass {
     ClassElement cls = sourceElement.enclosingClass;
     if (cls != null && cls.isClosure) {
       var closureClass = cls;
@@ -719,7 +720,7 @@
         isStatement: true));
   }
 
-  HGraph buildCheckedSetter(VariableElement field) {
+  HGraph buildCheckedSetter(FieldElement field) {
     ResolvedAst resolvedAst = field.resolvedAst;
     openFunction(field, resolvedAst.node);
     HInstruction thisInstruction = localsHandler.readThis();
@@ -747,9 +748,20 @@
     visit(initializer);
     HInstruction value = pop();
     value = potentiallyCheckOrTrustType(value, variable.type);
-    ast.SendSet sendSet = node.definitions.nodes.head;
-    closeAndGotoExit(new HReturn(value,
-        sourceInformationBuilder.buildReturn(sendSet.assignmentOperator)));
+    // In the case of multiple declarations (and some definitions) on the same
+    // line, the source pointer needs to point to the right initialized
+    // variable. So find the specific initialized variable we are referring to.
+    ast.Node sourceInfoNode = initializer;
+    for (var definition in node.definitions) {
+      if (definition is ast.SendSet &&
+          definition.selector.asIdentifier().source == variable.name) {
+        sourceInfoNode = definition.assignmentOperator;
+        break;
+      }
+    }
+
+    closeAndGotoExit(new HReturn(
+        value, sourceInformationBuilder.buildReturn(sourceInfoNode)));
     return closeFunction();
   }
 
@@ -1230,10 +1242,10 @@
 
     // Call the JavaScript constructor with the fields as argument.
     List<HInstruction> constructorArguments = <HInstruction>[];
-    List<Element> fields = <Element>[];
+    List<FieldEntity> fields = <FieldEntity>[];
 
     classElement.forEachInstanceField(
-        (ClassElement enclosingClass, VariableElement member) {
+        (ClassElement enclosingClass, FieldElement member) {
       HInstruction value = fieldValues[member];
       if (value == null) {
         // Uninitialized native fields are pre-initialized by the native
@@ -1588,7 +1600,7 @@
         analyzeTypeArgument(localsHandler.substInContext(supertype));
     HInstruction messageInstruction =
         graph.addConstantString(new ast.DartString.literal(message), compiler);
-    Element element = helpers.assertIsSubtype;
+    MethodElement element = helpers.assertIsSubtype;
     var inputs = <HInstruction>[
       subtypeInstruction,
       supertypeInstruction,
@@ -2223,8 +2235,8 @@
       } else {
         // TODO(5346): Try to avoid the need for calling [declaration] before
         // creating an [HStatic].
-        HInstruction instruction = new HStatic(field.declaration,
-            TypeMaskFactory.inferredTypeForElement(field, compiler))
+        HInstruction instruction = new HStatic(
+            field, TypeMaskFactory.inferredTypeForElement(field, compiler))
           ..sourceInformation = sourceInformation;
         push(instruction);
       }
@@ -2255,13 +2267,14 @@
         inferenceResults.typeOfSend(node, elements), receiver);
   }
 
-  /// Generate a closurization of the static or top level [function].
-  void generateStaticFunctionGet(ast.Send node, MethodElement function) {
+  /// Generate a closurization of the static or top level [method].
+  void generateStaticFunctionGet(ast.Send node, MethodElement method) {
+    assert(method.isDeclaration);
     // TODO(5346): Try to avoid the need for calling [declaration] before
     // creating an [HStatic].
     SourceInformation sourceInformation =
         sourceInformationBuilder.buildGet(node);
-    push(new HStatic(function.declaration, backend.nonNullType)
+    push(new HStatic(method, backend.nonNullType)
       ..sourceInformation = sourceInformation);
   }
 
@@ -2404,9 +2417,9 @@
         pushInvokeStatic(location, element, <HInstruction>[value]);
         pop();
       } else {
-        VariableElement field = element;
+        FieldElement field = element;
         value = potentiallyCheckOrTrustType(value, field.type);
-        addWithPosition(new HStaticStore(element, value), location);
+        addWithPosition(new HStaticStore(field, value), location);
       }
       stack.add(value);
     } else if (Elements.isError(element)) {
@@ -3064,7 +3077,7 @@
 
   void handleForeignSend(ast.Send node, FunctionElement element) {
     String name = element.name;
-    if (name == 'JS') {
+    if (name == BackendHelpers.JS) {
       handleForeignJs(node);
     } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
       handleForeignJsCurrentIsolateContext(node);
@@ -3080,15 +3093,15 @@
       handleForeignJsGetStaticState(node);
     } else if (name == 'JS_GET_NAME') {
       handleForeignJsGetName(node);
-    } else if (name == 'JS_EMBEDDED_GLOBAL') {
+    } else if (name == BackendHelpers.JS_EMBEDDED_GLOBAL) {
       handleForeignJsEmbeddedGlobal(node);
-    } else if (name == 'JS_BUILTIN') {
+    } else if (name == BackendHelpers.JS_BUILTIN) {
       handleForeignJsBuiltin(node);
     } else if (name == 'JS_GET_FLAG') {
       handleForeignJsGetFlag(node);
     } else if (name == 'JS_EFFECT') {
       stack.add(graph.addConstantNull(compiler));
-    } else if (name == 'JS_INTERCEPTOR_CONSTANT') {
+    } else if (name == BackendHelpers.JS_INTERCEPTOR_CONSTANT) {
       handleJsInterceptorConstant(node);
     } else if (name == 'JS_STRING_CONCAT') {
       handleJsStringConcat(node);
@@ -3101,7 +3114,7 @@
       SourceInformation sourceInformation) {
     // Until now we only handle these as getters.
     invariant(node, deferredLoader.isDeferredLoaderGetter);
-    Element loadFunction = helpers.loadLibraryWrapper;
+    FunctionEntity loadFunction = helpers.loadLibraryWrapper;
     PrefixElement prefixElement = deferredLoader.enclosingElement;
     String loadId =
         compiler.deferredLoadTask.getImportDeferName(node, prefixElement);
@@ -3170,16 +3183,16 @@
   }
 
   /// Generate a call to a super method or constructor.
-  void generateSuperInvoke(ast.Send node, FunctionElement function,
+  void generateSuperInvoke(ast.Send node, MethodElement method,
       SourceInformation sourceInformation) {
     // TODO(5347): Try to avoid the need for calling [implementation] before
     // calling [makeStaticArgumentList].
     Selector selector = elements.getSelector(node);
-    assert(invariant(node, selector.applies(function.implementation),
-        message: "$selector does not apply to ${function.implementation}"));
+    assert(invariant(node, selector.applies(method.implementation),
+        message: "$selector does not apply to ${method.implementation}"));
     List<HInstruction> inputs = makeStaticArgumentList(
-        selector.callStructure, node.arguments, function.implementation);
-    push(buildInvokeSuper(selector, function, inputs, sourceInformation));
+        selector.callStructure, node.arguments, method.implementation);
+    push(buildInvokeSuper(selector, method, inputs, sourceInformation));
   }
 
   /// Access the value from the super [element].
@@ -3684,7 +3697,7 @@
           sourceInformationBuilder.buildNew(send);
       potentiallyAddTypeArguments(inputs, cls, expectedType);
       addInlinedInstantiation(expectedType);
-      pushInvokeStatic(node, constructor, inputs,
+      pushInvokeStatic(node, constructor.declaration, inputs,
           typeMask: elementType,
           instanceType: expectedType,
           sourceInformation: sourceInformation);
@@ -4334,10 +4347,11 @@
   }
 
   void pushInvokeStatic(
-      ast.Node location, Element element, List<HInstruction> arguments,
+      ast.Node location, MethodElement element, List<HInstruction> arguments,
       {TypeMask typeMask,
       InterfaceType instanceType,
       SourceInformation sourceInformation}) {
+    assert(element.isDeclaration);
     // TODO(johnniwinther): Use [sourceInformation] instead of [location].
     if (tryInlineMethod(element, null, null, arguments, location,
         instanceType: instanceType)) {
@@ -4356,7 +4370,7 @@
           invokeJsInteropFunction(element, arguments, sourceInformation);
     } else {
       // creating an [HInvokeStatic].
-      instruction = new HInvokeStatic(element.declaration, arguments, typeMask,
+      instruction = new HInvokeStatic(element, arguments, typeMask,
           targetCanThrow: targetCanThrow)
         ..sourceInformation = sourceInformation;
       if (currentInlinedInstantiations.isNotEmpty) {
@@ -4374,7 +4388,7 @@
   }
 
   HInstruction buildInvokeSuper(
-      Selector selector, Element element, List<HInstruction> arguments,
+      Selector selector, MemberElement element, List<HInstruction> arguments,
       [SourceInformation sourceInformation]) {
     HInstruction receiver = localsHandler.readThis();
     // TODO(5346): Try to avoid the need for calling [declaration] before
@@ -5330,7 +5344,7 @@
         inputs.add(analyzeTypeArgument(argument));
       });
     }
-    pushInvokeStatic(node, targetConstructor, inputs);
+    pushInvokeStatic(node, targetConstructor.declaration, inputs);
     HInstruction value = pop();
     emitReturn(value, node);
   }
@@ -5719,7 +5733,7 @@
     HInstruction originalLength = null; // Set for growable lists.
 
     HInstruction buildGetLength() {
-      Element lengthElement = helpers.jsIndexableLength;
+      MemberElement lengthElement = helpers.jsIndexableLength;
       HFieldGet result = new HFieldGet(
           lengthElement, array, backend.positiveIntType,
           isAssignable: !isFixed);
@@ -6197,7 +6211,6 @@
 
     List<HStatementInformation> statements = <HStatementInformation>[];
     bool hasDefault = false;
-    Element getFallThroughErrorElement = helpers.fallThroughError;
     HasNextIterator<ast.Node> caseIterator =
         new HasNextIterator<ast.Node>(switchCases.iterator);
     while (caseIterator.hasNext) {
@@ -6220,8 +6233,8 @@
       localsHandler = new LocalsHandler.from(savedLocals);
       buildSwitchCase(switchCase);
       if (!isAborted()) {
-        if (caseIterator.hasNext) {
-          pushInvokeStatic(switchCase, getFallThroughErrorElement, []);
+        if (caseIterator.hasNext && isReachable) {
+          pushInvokeStatic(switchCase, helpers.fallThroughError, []);
           HInstruction error = pop();
           closeAndGotoExit(new HThrow(error, error.sourceInformation));
         } else if (!isDefaultCase(switchCase)) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 4665ee8..6183f3f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -574,8 +574,8 @@
       _pushStaticInvocation(staticTarget, const <HInstruction>[],
           astAdapter.returnTypeOf(staticTarget));
     } else {
-      Element element = astAdapter.getElement(staticTarget).declaration;
-      push(new HStatic(element, astAdapter.inferredTypeOf(staticTarget)));
+      push(new HStatic(astAdapter.getMember(staticTarget),
+          astAdapter.inferredTypeOf(staticTarget)));
     }
   }
 
@@ -592,7 +592,7 @@
       pop();
     } else {
       // TODO(het): check or trust type
-      add(new HStaticStore(astAdapter.getElement(staticTarget), value));
+      add(new HStaticStore(astAdapter.getMember(staticTarget), value));
     }
     stack.add(value);
   }
@@ -681,7 +681,7 @@
   void _pushStaticInvocation(
       ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
     HInstruction instruction = new HInvokeStatic(
-        astAdapter.getElement(target).declaration, arguments, typeMask,
+        astAdapter.getMember(target), arguments, typeMask,
         targetCanThrow: astAdapter.getCanThrow(target));
     instruction.sideEffects = astAdapter.getSideEffects(target);
 
@@ -757,8 +757,8 @@
     inputs.addAll(arguments);
 
     HInstruction instruction = new HInvokeSuper(
-        astAdapter.getElement(invocation.interfaceTarget),
-        astAdapter.getElement(surroundingClass),
+        astAdapter.getMethod(invocation.interfaceTarget),
+        astAdapter.getClass(surroundingClass),
         selector,
         inputs,
         astAdapter.returnTypeOf(invocation.interfaceTarget),
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index a50cffe..968f9e0 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -11,6 +11,7 @@
 import '../core_types.dart' show CoreClasses;
 import '../dart_types.dart';
 import '../elements/elements.dart';
+import '../elements/entities.dart';
 import '../io/source_information.dart';
 import '../js/js.dart' as js;
 import '../js_backend/backend_helpers.dart' show BackendHelpers;
@@ -1582,7 +1583,7 @@
     js.Expression object = pop();
     String methodName;
     List<js.Expression> arguments = visitArguments(node.inputs);
-    Element target = node.element;
+    MemberElement target = node.element;
 
     // TODO(herhut): The namer should return the appropriate backendname here.
     if (target != null && !node.isInterceptedCall) {
@@ -1680,7 +1681,7 @@
     // If we don't know what we're calling or if we are calling a getter,
     // we need to register that fact that we may be calling a closure
     // with the same arguments.
-    Element target = node.element;
+    MemberElement target = node.element;
     if (target == null || target.isGetter) {
       // TODO(kasperl): If we have a typed selector for the call, we
       // may know something about the types of closures that need
@@ -1762,7 +1763,7 @@
   }
 
   visitInvokeStatic(HInvokeStatic node) {
-    Element element = node.element;
+    MemberElement element = node.element;
     List<DartType> instantiatedTypes = node.instantiatedTypes;
 
     if (instantiatedTypes != null && !instantiatedTypes.isEmpty) {
@@ -1809,7 +1810,7 @@
   }
 
   visitInvokeSuper(HInvokeSuper node) {
-    Element superElement = node.element;
+    MemberElement superElement = node.element;
     ClassElement superClass = superElement.enclosingClass;
     if (superElement.isField) {
       js.Name fieldName = backend.namer.instanceFieldPropertyName(superElement);
@@ -1867,7 +1868,7 @@
 
   visitFieldGet(HFieldGet node) {
     use(node.receiver);
-    Element element = node.element;
+    MemberElement element = node.element;
     if (node.isNullCheck) {
       // We access a JavaScript member we know all objects besides
       // null and undefined have: V8 does not like accessing a member
@@ -1889,7 +1890,7 @@
   }
 
   visitFieldSet(HFieldSet node) {
-    Element element = node.element;
+    MemberElement element = node.element;
     registry.registerStaticUse(new StaticUse.fieldSet(element));
     js.Name name = backend.namer.instanceFieldPropertyName(element);
     use(node.receiver);
@@ -1900,7 +1901,7 @@
   }
 
   visitReadModifyWrite(HReadModifyWrite node) {
-    Element element = node.element;
+    FieldElement element = node.element;
     registry.registerStaticUse(new StaticUse.fieldGet(element));
     registry.registerStaticUse(new StaticUse.fieldSet(element));
     js.Name name = backend.namer.instanceFieldPropertyName(element);
@@ -2279,7 +2280,7 @@
   }
 
   void visitStatic(HStatic node) {
-    Element element = node.element;
+    MemberEntity element = node.element;
     assert(element.isFunction || element.isField);
     if (element.isFunction) {
       push(backend.emitter
@@ -2295,7 +2296,7 @@
   }
 
   void visitLazyStatic(HLazyStatic node) {
-    Element element = node.element;
+    FieldEntity element = node.element;
     registry.registerStaticUse(new StaticUse.staticInit(element));
     js.Expression lazyGetter =
         backend.emitter.isolateLazyInitializerAccess(element);
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 43515f8..c3e2bb6 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -419,7 +419,7 @@
   }
 
   void visitInvokeSuper(HInvokeSuper instruction) {
-    Element superMethod = instruction.element;
+    MemberElement superMethod = instruction.element;
     Selector selector = instruction.selector;
     // If aliased super members cannot be used, we will generate code like
     //
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index 0b54193..be4a558 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -4,14 +4,18 @@
 
 import 'package:kernel/ast.dart' as ir;
 
+import '../constants/expressions.dart';
 import '../common.dart';
 import '../common/names.dart';
 import '../compiler.dart';
 import '../constants/values.dart';
 import '../dart_types.dart';
 import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart';
 import '../js_backend/js_backend.dart';
 import '../kernel/kernel.dart';
+import '../kernel/kernel_debug.dart';
+import '../native/native.dart' show NativeBehavior;
 import '../resolution/tree_elements.dart';
 import '../tree/tree.dart' as ast;
 import '../types/masks.dart';
@@ -61,6 +65,7 @@
   TreeElements get elements => _resolvedAst.elements;
   GlobalTypeInferenceResults get _inferenceResults =>
       _compiler.globalInference.results;
+  DiagnosticReporter get reporter => _compiler.reporter;
 
   ConstantValue getConstantForSymbol(ir.SymbolLiteral node) {
     ast.Node astNode = getNode(node);
@@ -71,12 +76,20 @@
     return constantValue;
   }
 
+  // TODO(johnniwinther): Use the more precise functions below.
   Element getElement(ir.Node node) {
     Element result = _nodeToElement[node];
-    assert(result != null);
+    assert(invariant(CURRENT_ELEMENT_SPANNABLE, result != null,
+        message: "No element found for $node."));
     return result;
   }
 
+  MemberElement getMember(ir.Node node) => getElement(node).declaration;
+
+  MethodElement getMethod(ir.Node node) => getElement(node).declaration;
+
+  ClassElement getClass(ir.Node node) => getElement(node).declaration;
+
   ast.Node getNode(ir.Node node) {
     ast.Node result = _nodeToAst[node];
     assert(result != null);
@@ -246,7 +259,7 @@
   ir.Procedure get mapLiteralConstructorEmpty =>
       kernel.functions[_backend.helpers.mapLiteralConstructorEmpty];
 
-  Element get jsIndexableLength => _backend.helpers.jsIndexableLength;
+  MemberElement get jsIndexableLength => _backend.helpers.jsIndexableLength;
 
   ir.Procedure get checkConcurrentModificationError =>
       kernel.functions[_backend.helpers.checkConcurrentModificationError];
@@ -279,8 +292,232 @@
   List<DartType> getDartTypes(List<ir.DartType> types) {
     return types.map(getDartType).toList();
   }
+
+  /// Computes the function type corresponding the signature of [node].
+  FunctionType getFunctionType(ir.FunctionNode node) {
+    DartType returnType = getDartType(node.returnType);
+    List<DartType> parameterTypes = <DartType>[];
+    List<DartType> optionalParameterTypes = <DartType>[];
+    for (ir.VariableDeclaration variable in node.positionalParameters) {
+      if (parameterTypes.length == node.requiredParameterCount) {
+        optionalParameterTypes.add(getDartType(variable.type));
+      } else {
+        parameterTypes.add(getDartType(variable.type));
+      }
+    }
+    List<String> namedParameters = <String>[];
+    List<DartType> namedParameterTypes = <DartType>[];
+    List<ir.VariableDeclaration> sortedNamedParameters =
+        node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name));
+    for (ir.VariableDeclaration variable in sortedNamedParameters) {
+      namedParameters.add(variable.name);
+      namedParameterTypes.add(getDartType(variable.type));
+    }
+    return new FunctionType.synthesized(returnType, parameterTypes,
+        optionalParameterTypes, namedParameters, namedParameterTypes);
+  }
+
+  /// Converts [annotations] into a list of [ConstantExpression]s.
+  List<ConstantExpression> getMetadata(List<ir.Expression> annotations) {
+    List<ConstantExpression> metadata = <ConstantExpression>[];
+    annotations.forEach((ir.Expression node) {
+      ConstantExpression constant = node.accept(new Constantifier(this));
+      if (constant == null) {
+        throw new UnsupportedError(
+            'No constant for ${DebugPrinter.prettyPrint(node)}');
+      }
+      metadata.add(constant);
+    });
+    return metadata;
+  }
+
+  /// Compute the kind of foreign helper function called by [node], if any.
+  @override
+  ForeignKind getForeignKind(ir.StaticInvocation node) {
+    if (isForeignLibrary(node.target.enclosingLibrary)) {
+      switch (node.target.name.name) {
+        case BackendHelpers.JS:
+          return ForeignKind.JS;
+        case BackendHelpers.JS_BUILTIN:
+          return ForeignKind.JS_BUILTIN;
+        case BackendHelpers.JS_EMBEDDED_GLOBAL:
+          return ForeignKind.JS_EMBEDDED_GLOBAL;
+        case BackendHelpers.JS_INTERCEPTOR_CONSTANT:
+          return ForeignKind.JS_INTERCEPTOR_CONSTANT;
+      }
+    }
+    return ForeignKind.NONE;
+  }
+
+  /// Return `true` if [node] is the `dart:_foreign_helper` library.
+  bool isForeignLibrary(ir.Library node) {
+    return node.importUri == BackendHelpers.DART_FOREIGN_HELPER;
+  }
+
+  /// Looks up [typeName] for use in the spec-string of a `JS` called.
+  // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling the
+  // `ForeignResolver`.
+  // TODO(johnniwinther): Cache the result to avoid redundant lookups?
+  DartType _typeLookup(String typeName) {
+    DartType findIn(Uri uri) {
+      LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri);
+      if (library != null) {
+        Element element = library.find(typeName);
+        if (element != null && element.isClass) {
+          ClassElement cls = element;
+          return cls.rawType;
+        }
+      }
+      return null;
+    }
+
+    DartType type = findIn(Uris.dart_core);
+    type ??= findIn(BackendHelpers.DART_JS_HELPER);
+    type ??= findIn(BackendHelpers.DART_INTERCEPTORS);
+    type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER);
+    type ??= findIn(Uris.dart_collection);
+    type ??= findIn(Uris.dart_html);
+    return type;
+  }
+
+  String _getStringArgument(ir.StaticInvocation node, int index) {
+    return node.arguments.positional[index].accept(new Stringifier());
+  }
+
+  /// Computes the [NativeBehavior] for a call to the [JS] function.
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 2 ||
+        node.arguments.named.isNotEmpty) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
+      return new NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
+      return new NativeBehavior();
+    }
+
+    String codeString = _getStringArgument(node, 1);
+    if (codeString == null) {
+      reporter.reportErrorMessage(
+          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
+      return new NativeBehavior();
+    }
+
+    return NativeBehavior.ofJsCall(specString, codeString, _typeLookup,
+        CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes);
+  }
+
+  /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN] function.
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 1) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
+      return new NativeBehavior();
+    }
+    if (node.arguments.positional.length < 2) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
+      return new NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+      return new NativeBehavior();
+    }
+    return NativeBehavior.ofJsBuiltinCall(specString, _typeLookup,
+        CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes);
+  }
+
+  /// Computes the [NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL]
+  /// function.
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+      ir.StaticInvocation node) {
+    if (node.arguments.positional.length < 1) {
+      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+          "JS embedded global expression has no type.");
+      return new NativeBehavior();
+    }
+    if (node.arguments.positional.length < 2) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
+      return new NativeBehavior();
+    }
+    if (node.arguments.positional.length > 2 ||
+        node.arguments.named.isNotEmpty) {
+      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
+          "JS embedded global has more than 2 arguments.");
+      return new NativeBehavior();
+    }
+    String specString = _getStringArgument(node, 0);
+    if (specString == null) {
+      reporter.internalError(
+          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
+      return new NativeBehavior();
+    }
+    return NativeBehavior.ofJsEmbeddedGlobalCall(specString, _typeLookup,
+        CURRENT_ELEMENT_SPANNABLE, reporter, _compiler.coreTypes);
+  }
+
+  /// Returns `true` is [node] has a `@Native(...)` annotation.
+  // TODO(johnniwinther): Cache this for later use.
+  bool isNative(ir.Class node) {
+    for (ir.Expression annotation in node.annotations) {
+      if (annotation is ir.ConstructorInvocation) {
+        ConstructorElement target = getElement(annotation.target).declaration;
+        if (target.enclosingClass ==
+            _compiler.commonElements.nativeAnnotationClass) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /// Computes the native behavior for reading the native [field].
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
+    DartType type = getDartType(field.type);
+    List<ConstantExpression> metadata = getMetadata(field.annotations);
+    return NativeBehavior.ofFieldLoad(
+        CURRENT_ELEMENT_SPANNABLE, type, metadata, _typeLookup, _compiler,
+        isJsInterop: false);
+  }
+
+  /// Computes the native behavior for writing to the native [field].
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
+    DartType type = getDartType(field.type);
+    return NativeBehavior.ofFieldStore(type, _compiler.resolution);
+  }
+
+  /// Computes the native behavior for calling [procedure].
+  // TODO(johnniwinther): Cache this for later use.
+  NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
+    DartType type = getFunctionType(procedure.function);
+    List<ConstantExpression> metadata = getMetadata(procedure.annotations);
+    return NativeBehavior.ofMethod(
+        CURRENT_ELEMENT_SPANNABLE, type, metadata, _typeLookup, _compiler,
+        isJsInterop: false);
+  }
 }
 
+/// Kinds of foreign functions.
+enum ForeignKind {
+  JS,
+  JS_BUILTIN,
+  JS_EMBEDDED_GLOBAL,
+  JS_INTERCEPTOR_CONSTANT,
+  NONE,
+}
+
+/// Visitor that converts kernel dart types into [DartType].
 class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
   final KernelAstAdapter astAdapter;
 
@@ -295,7 +532,19 @@
 
   @override
   DartType visitTypeParameterType(ir.TypeParameterType node) {
-    return new TypeVariableType(astAdapter.getElement(node.parameter));
+    if (node.parameter.parent is ir.Class) {
+      ir.Class cls = node.parameter.parent;
+      int index = cls.typeParameters.indexOf(node.parameter);
+      ClassElement classElement = astAdapter.getElement(cls);
+      return classElement.typeVariables[index];
+    } else if (node.parameter.parent is ir.FunctionNode) {
+      ir.FunctionNode func = node.parameter.parent;
+      int index = func.typeParameters.indexOf(node.parameter);
+      ConstructorElement constructorElement = astAdapter.getElement(func);
+      ClassElement classElement = constructorElement.enclosingClass;
+      return classElement.typeVariables[index];
+    }
+    throw new UnsupportedError('Unsupported type parameter type node $node.');
   }
 
   @override
@@ -333,3 +582,64 @@
     throw new UnimplementedError("Invalid types not currently supported");
   }
 }
+
+/// Visitor that converts string literals and concatenations of string literals
+/// into the string value.
+class Stringifier extends ir.ExpressionVisitor<String> {
+  @override
+  String visitStringLiteral(ir.StringLiteral node) => node.value;
+
+  @override
+  String visitStringConcatenation(ir.StringConcatenation node) {
+    StringBuffer sb = new StringBuffer();
+    for (ir.Expression expression in node.expressions) {
+      String value = expression.accept(this);
+      if (value == null) return null;
+      sb.write(value);
+    }
+    return sb.toString();
+  }
+}
+
+/// Visitor that converts a kernel constant expression into a
+/// [ConstantExpression].
+class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
+  final KernelAstAdapter astAdapter;
+
+  Constantifier(this.astAdapter);
+
+  @override
+  ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
+    ConstructorElement constructor =
+        astAdapter.getElement(node.target).declaration;
+    List<DartType> typeArguments = <DartType>[];
+    for (ir.DartType type in node.arguments.types) {
+      typeArguments.add(astAdapter.getDartType(type));
+    }
+    List<ConstantExpression> arguments = <ConstantExpression>[];
+    List<String> argumentNames = <String>[];
+    for (ir.Expression argument in node.arguments.positional) {
+      ConstantExpression constant = argument.accept(this);
+      if (constant == null) return null;
+      arguments.add(constant);
+    }
+    for (ir.NamedExpression argument in node.arguments.named) {
+      argumentNames.add(argument.name);
+      ConstantExpression constant = argument.value.accept(this);
+      if (constant == null) return null;
+      arguments.add(constant);
+    }
+    return new ConstructedConstantExpression(
+        constructor.enclosingClass.thisType.createInstantiation(typeArguments),
+        constructor,
+        new CallStructure(
+            node.arguments.positional.length + argumentNames.length,
+            argumentNames),
+        arguments);
+  }
+
+  @override
+  ConstantExpression visitStringLiteral(ir.StringLiteral node) {
+    return new StringConstantExpression(node.value);
+  }
+}
diff --git a/pkg/compiler/lib/src/ssa/kernel_impact.dart b/pkg/compiler/lib/src/ssa/kernel_impact.dart
index 0c31e97..c035c2d 100644
--- a/pkg/compiler/lib/src/ssa/kernel_impact.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_impact.dart
@@ -26,37 +26,39 @@
 /// Computes the [ResolutionImpact] for [resolvedAst] through kernel.
 ResolutionImpact build(Compiler compiler, ResolvedAst resolvedAst) {
   AstElement element = resolvedAst.element;
-  JavaScriptBackend backend = compiler.backend;
-  Kernel kernel = backend.kernelTask.kernel;
-  KernelImpactBuilder builder =
-      new KernelImpactBuilder(resolvedAst, compiler, kernel);
-  if (element.isFunction ||
-      element.isGetter ||
-      element.isSetter ||
-      element.isFactoryConstructor) {
-    ir.Procedure function = kernel.functions[element];
-    if (function == null) {
-      throw "FOUND NULL FUNCTION: $element";
+  return compiler.reporter.withCurrentElement(element.implementation, () {
+    JavaScriptBackend backend = compiler.backend;
+    Kernel kernel = backend.kernelTask.kernel;
+    KernelImpactBuilder builder =
+        new KernelImpactBuilder(resolvedAst, compiler, kernel);
+    if (element.isFunction ||
+        element.isGetter ||
+        element.isSetter ||
+        element.isFactoryConstructor) {
+      ir.Procedure function = kernel.functions[element];
+      if (function == null) {
+        throw "FOUND NULL FUNCTION: $element";
+      } else {
+        return builder.buildProcedure(function);
+      }
+    } else if (element.isGenerativeConstructor) {
+      ir.Constructor constructor = kernel.functions[element];
+      if (constructor == null) {
+        throw "FOUND NULL CONSTRUCTOR: $element";
+      } else {
+        return builder.buildConstructor(constructor);
+      }
+    } else if (element.isField) {
+      ir.Field field = kernel.fields[element];
+      if (field == null) {
+        throw "FOUND NULL FIELD: $element";
+      } else {
+        return builder.buildField(field);
+      }
     } else {
-      return builder.buildProcedure(function);
+      throw new UnsupportedError("Unsupported element: $element");
     }
-  } else if (element.isGenerativeConstructor) {
-    ir.Constructor constructor = kernel.functions[element];
-    if (constructor == null) {
-      throw "FOUND NULL CONSTRUCTOR: $element";
-    } else {
-      return builder.buildConstructor(constructor);
-    }
-  } else if (element.isField) {
-    ir.Field field = kernel.fields[element];
-    if (field == null) {
-      throw "FOUND NULL FIELD: $element";
-    } else {
-      return builder.buildField(field);
-    }
-  } else {
-    throw new UnsupportedError("Unsupported element: $element");
-  }
+  });
 }
 
 class KernelImpactBuilder extends ir.Visitor {
@@ -105,12 +107,18 @@
     checkType(field.type);
     if (field.initializer != null) {
       visitNode(field.initializer);
-      if (!field.isConst) {
+      if (!field.isInstanceMember && !field.isConst) {
         impactBuilder.registerFeature(Feature.LAZY_FIELD);
       }
     } else {
       impactBuilder.registerFeature(Feature.FIELD_WITHOUT_INITIALIZER);
     }
+    if (field.isInstanceMember && astAdapter.isNative(field.enclosingClass)) {
+      impactBuilder
+          .registerNativeData(astAdapter.getNativeBehaviorForFieldLoad(field));
+      impactBuilder
+          .registerNativeData(astAdapter.getNativeBehaviorForFieldStore(field));
+    }
     return impactBuilder;
   }
 
@@ -140,6 +148,11 @@
         compiler.reporter.internalError(resolvedAst.element,
             "Unexpected async marker: ${procedure.function.asyncMarker}");
     }
+    if (procedure.isExternal &&
+        !astAdapter.isForeignLibrary(procedure.enclosingLibrary)) {
+      impactBuilder
+          .registerNativeData(astAdapter.getNativeBehaviorForMethod(procedure));
+    }
     return impactBuilder;
   }
 
@@ -291,12 +304,40 @@
       // to B. Currently, we only do this soundly if we register A<int> and
       // A<String> as instantiated. We should instead register that A.T is
       // instantiated as int and String.
-      handleNew(node, node.target);
+      handleNew(node, node.target, isConst: node.isConst);
     } else {
       _visitArguments(node.arguments);
       impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
           target, astAdapter.getCallStructure(node.arguments)));
     }
+    switch (astAdapter.getForeignKind(node)) {
+      case ForeignKind.JS:
+        impactBuilder
+            .registerNativeData(astAdapter.getNativeBehaviorForJsCall(node));
+        break;
+      case ForeignKind.JS_BUILTIN:
+        impactBuilder.registerNativeData(
+            astAdapter.getNativeBehaviorForJsBuiltinCall(node));
+        break;
+      case ForeignKind.JS_EMBEDDED_GLOBAL:
+        impactBuilder.registerNativeData(
+            astAdapter.getNativeBehaviorForJsEmbeddedGlobalCall(node));
+        break;
+      case ForeignKind.JS_INTERCEPTOR_CONSTANT:
+        if (node.arguments.positional.length != 1 ||
+            node.arguments.named.isNotEmpty) {
+          astAdapter.reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
+              MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
+        }
+        ir.Node argument = node.arguments.positional.first;
+        if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
+          impactBuilder.registerTypeUse(
+              new TypeUse.instantiation(astAdapter.getDartType(argument.type)));
+        }
+        break;
+      case ForeignKind.NONE:
+        break;
+    }
   }
 
   @override
@@ -317,6 +358,64 @@
     impactBuilder.registerStaticUse(new StaticUse.staticSet(element));
   }
 
+  void handleSuperInvocation(ir.Node target, ir.Node arguments) {
+    Element element = astAdapter.getElement(target).declaration;
+    _visitArguments(arguments);
+    impactBuilder.registerStaticUse(new StaticUse.superInvoke(
+        element, astAdapter.getCallStructure(arguments)));
+  }
+
+  @override
+  void visitDirectMethodInvocation(ir.DirectMethodInvocation node) {
+    handleSuperInvocation(node.target, node.arguments);
+  }
+
+  @override
+  void visitSuperMethodInvocation(ir.SuperMethodInvocation node) {
+    // TODO(johnniwinther): Should we support this or always use the
+    // [MixinFullResolution] transformer?
+    handleSuperInvocation(node.interfaceTarget, node.arguments);
+  }
+
+  void handleSuperGet(ir.Member target) {
+    Element element = astAdapter.getElement(target).declaration;
+    if (target is ir.Procedure && target.kind == ir.ProcedureKind.Method) {
+      impactBuilder.registerStaticUse(new StaticUse.superTearOff(element));
+    } else {
+      impactBuilder.registerStaticUse(new StaticUse.superGet(element));
+    }
+  }
+
+  @override
+  void visitDirectGet(ir.StaticGet node) {
+    handleSuperGet(node.target);
+  }
+
+  @override
+  void visitSuperPropertyGet(ir.SuperPropertyGet node) {
+    handleSuperGet(node.interfaceTarget);
+  }
+
+  void handleSuperSet(ir.Node target, ir.Node value) {
+    visitNode(value);
+    Element element = astAdapter.getElement(target).declaration;
+    if (target is ir.Field) {
+      impactBuilder.registerStaticUse(new StaticUse.superFieldSet(element));
+    } else {
+      impactBuilder.registerStaticUse(new StaticUse.superSetterSet(element));
+    }
+  }
+
+  @override
+  void visitDirectPropertySet(ir.DirectPropertySet node) {
+    handleSuperSet(node.target, node.value);
+  }
+
+  @override
+  void visitSuperPropertySet(ir.SuperPropertySet node) {
+    handleSuperSet(node.interfaceTarget, node.value);
+  }
+
   @override
   void visitMethodInvocation(ir.MethodInvocation invocation) {
     var receiver = invocation.receiver;
@@ -392,12 +491,14 @@
   void visitIsExpression(ir.IsExpression node) {
     impactBuilder.registerTypeUse(
         new TypeUse.isCheck(astAdapter.getDartType(node.type)));
+    visitNode(node.operand);
   }
 
   @override
   void visitAsExpression(ir.AsExpression node) {
     impactBuilder
         .registerTypeUse(new TypeUse.asCast(astAdapter.getDartType(node.type)));
+    visitNode(node.operand);
   }
 
   @override
@@ -448,6 +549,27 @@
     visitNode(node.finalizer);
   }
 
+  @override
+  void visitTypeLiteral(ir.TypeLiteral node) {
+    impactBuilder.registerTypeUse(
+        new TypeUse.typeLiteral(astAdapter.getDartType(node.type)));
+  }
+
+  @override
+  void visitFieldInitializer(ir.FieldInitializer node) {
+    impactBuilder.registerStaticUse(
+        new StaticUse.fieldInit(astAdapter.getElement(node.field)));
+    visitNode(node.value);
+  }
+
+  @override
+  void visitRedirectingInitializer(ir.RedirectingInitializer node) {
+    _visitArguments(node.arguments);
+    Element target = astAdapter.getElement(node.target).declaration;
+    impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke(
+        target, astAdapter.getCallStructure(node.arguments)));
+  }
+
   // TODO(johnniwinther): Make this throw and visit child nodes explicitly
   // instead to ensure that we don't visit unwanted parts of the ir.
   @override
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index adc2076..f2d1af7 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -8,7 +8,9 @@
 import '../constants/constant_system.dart';
 import '../constants/values.dart';
 import '../dart_types.dart';
-import '../elements/elements.dart';
+import '../elements/elements.dart'
+    show Entity, JumpTarget, LabelDefinition, Local;
+import '../elements/entities.dart';
 import '../io/source_information.dart';
 import '../js/js.dart' as js;
 import '../js_backend/backend_helpers.dart' show BackendHelpers;
@@ -154,7 +156,8 @@
 }
 
 class HGraph {
-  Element element; // Used for debug printing.
+  // TODO(johnniwinther): Maybe this should be [MemberLike].
+  Entity element; // Used for debug printing.
   HBasicBlock entry;
   HBasicBlock exit;
   HThis thisInstruction;
@@ -224,9 +227,9 @@
     return result;
   }
 
-  HConstant addDeferredConstant(ConstantValue constant, PrefixElement prefix,
+  HConstant addDeferredConstant(ConstantValue constant, Entity prefix,
       SourceInformation sourceInformation, Compiler compiler) {
-    // TODO(sigurdm,johnniwinter): These deferred constants should be created
+    // TODO(sigurdm,johnniwinther): These deferred constants should be created
     // by the constant evaluator.
     ConstantValue wrapper = new DeferredConstantValue(constant, prefix);
     compiler.deferredLoadTask.registerConstantDeferredUse(wrapper, prefix);
@@ -928,20 +931,20 @@
 
   /// Returns `true` if [typeMask] contains [cls].
   static bool containsType(
-      TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) {
+      TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) {
     return closedWorld.isInstantiated(cls) &&
         typeMask.contains(cls, closedWorld);
   }
 
   /// Returns `true` if [typeMask] contains only [cls].
   static bool containsOnlyType(
-      TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) {
+      TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) {
     return closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls);
   }
 
   /// Returns `true` if [typeMask] is an instance of [cls].
   static bool isInstanceOf(
-      TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) {
+      TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) {
     return closedWorld.isImplemented(cls) &&
         typeMask.satisfies(cls, closedWorld);
   }
@@ -1367,23 +1370,23 @@
     // Only the builder knows how to create [HTypeConversion]
     // instructions with generics. It has the generic type context
     // available.
-    assert(type.kind != TypeKind.TYPE_VARIABLE);
+    assert(!type.isTypeVariable);
     assert(type.treatAsRaw || type.isFunctionType);
     if (type.isDynamic) return this;
     if (type.isObject) return this;
-    // The type element is either a class or the void element.
-    Element element = type.element;
     JavaScriptBackend backend = compiler.backend;
-    if (type.kind != TypeKind.INTERFACE) {
+    if (type.isVoid || type.isFunctionType || type.isMalformed) {
       return new HTypeConversion(type, kind, backend.dynamicType, this);
-    } else if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) {
+    }
+    assert(type.isInterfaceType);
+    if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) {
       // Boolean conversion checks work on non-nullable booleans.
       return new HTypeConversion(type, kind, backend.boolType, this);
     } else if (kind == HTypeConversion.CHECKED_MODE_CHECK && !type.treatAsRaw) {
       throw 'creating compound check to $type (this = ${this})';
     } else {
-      TypeMask subtype =
-          new TypeMask.subtype(element.declaration, compiler.closedWorld);
+      Entity cls = type.element;
+      TypeMask subtype = new TypeMask.subtype(cls, compiler.closedWorld);
       return new HTypeConversion(type, kind, subtype, this);
     }
   }
@@ -1507,7 +1510,7 @@
 
 // Allocates and initializes an instance.
 class HCreate extends HInstruction {
-  final ClassElement element;
+  final ClassEntity element;
 
   /// Does this instruction have reified type information as the last input?
   final bool hasRtiInput;
@@ -1562,7 +1565,7 @@
   final InvokeDynamicSpecializer specializer;
   Selector selector;
   TypeMask mask;
-  Element element;
+  MemberEntity element;
 
   HInvokeDynamic(Selector selector, this.mask, this.element,
       List<HInstruction> inputs, TypeMask type,
@@ -1615,14 +1618,14 @@
 }
 
 abstract class HInvokeDynamicField extends HInvokeDynamic {
-  HInvokeDynamicField(Selector selector, TypeMask mask, Element element,
+  HInvokeDynamicField(Selector selector, TypeMask mask, MemberEntity element,
       List<HInstruction> inputs, TypeMask type)
       : super(selector, mask, element, inputs, type);
   toString() => 'invoke dynamic field: selector=$selector, mask=$mask';
 }
 
 class HInvokeDynamicGetter extends HInvokeDynamicField {
-  HInvokeDynamicGetter(Selector selector, TypeMask mask, Element element,
+  HInvokeDynamicGetter(Selector selector, TypeMask mask, MemberEntity element,
       List<HInstruction> inputs, TypeMask type)
       : super(selector, mask, element, inputs, type);
   toString() => 'invoke dynamic getter: selector=$selector, mask=$mask';
@@ -1635,7 +1638,7 @@
 }
 
 class HInvokeDynamicSetter extends HInvokeDynamicField {
-  HInvokeDynamicSetter(Selector selector, TypeMask mask, Element element,
+  HInvokeDynamicSetter(Selector selector, TypeMask mask, MemberEntity element,
       List<HInstruction> inputs, TypeMask type)
       : super(selector, mask, element, inputs, type);
   toString() => 'invoke dynamic setter: selector=$selector, mask=$mask';
@@ -1643,7 +1646,7 @@
 }
 
 class HInvokeStatic extends HInvoke {
-  final Element element;
+  final MemberEntity element;
 
   final bool targetCanThrow;
 
@@ -1667,11 +1670,11 @@
 
 class HInvokeSuper extends HInvokeStatic {
   /** The class where the call to super is being done. */
-  final ClassElement caller;
+  final ClassEntity caller;
   final bool isSetter;
   final Selector selector;
 
-  HInvokeSuper(Element element, this.caller, this.selector, inputs, type,
+  HInvokeSuper(MemberEntity element, this.caller, this.selector, inputs, type,
       SourceInformation sourceInformation,
       {this.isSetter})
       : super(element, inputs, type) {
@@ -1711,11 +1714,12 @@
 }
 
 abstract class HFieldAccess extends HInstruction {
-  final Element element;
+  // TODO(johnniwinther): This should be a [FieldLike] but JSIndexable.length is
+  // encoded using a [HFieldGet].
+  final MemberEntity element;
 
-  HFieldAccess(Element element, List<HInstruction> inputs, TypeMask type)
-      : this.element = element,
-        super(inputs, type);
+  HFieldAccess(this.element, List<HInstruction> inputs, TypeMask type)
+      : super(inputs, type);
 
   HInstruction get receiver => inputs[0];
 }
@@ -1723,7 +1727,7 @@
 class HFieldGet extends HFieldAccess {
   final bool isAssignable;
 
-  HFieldGet(Element element, HInstruction receiver, TypeMask type,
+  HFieldGet(MemberEntity element, HInstruction receiver, TypeMask type,
       {bool isAssignable})
       : this.isAssignable =
             (isAssignable != null) ? isAssignable : element.isAssignable,
@@ -1764,7 +1768,7 @@
 }
 
 class HFieldSet extends HFieldAccess {
-  HFieldSet(Element element, HInstruction receiver, HInstruction value)
+  HFieldSet(MemberEntity element, HInstruction receiver, HInstruction value)
       : super(element, <HInstruction>[receiver, value],
             const TypeMask.nonNullEmpty()) {
     sideEffects.clearAllSideEffects();
@@ -1792,11 +1796,11 @@
   static const ASSIGN_OP = 0;
   static const PRE_OP = 1;
   static const POST_OP = 2;
-  final Element element;
+  final FieldEntity element;
   final String jsOp;
   final int opKind;
 
-  HReadModifyWrite._(Element this.element, this.jsOp, this.opKind,
+  HReadModifyWrite._(this.element, this.jsOp, this.opKind,
       List<HInstruction> inputs, TypeMask type)
       : super(inputs, type) {
     sideEffects.clearAllSideEffects();
@@ -1805,17 +1809,17 @@
     sideEffects.setDependsOnInstancePropertyStore();
   }
 
-  HReadModifyWrite.assignOp(Element element, String jsOp, HInstruction receiver,
-      HInstruction operand, TypeMask type)
+  HReadModifyWrite.assignOp(FieldEntity element, String jsOp,
+      HInstruction receiver, HInstruction operand, TypeMask type)
       : this._(
             element, jsOp, ASSIGN_OP, <HInstruction>[receiver, operand], type);
 
   HReadModifyWrite.preOp(
-      Element element, String jsOp, HInstruction receiver, TypeMask type)
+      FieldEntity element, String jsOp, HInstruction receiver, TypeMask type)
       : this._(element, jsOp, PRE_OP, <HInstruction>[receiver], type);
 
   HReadModifyWrite.postOp(
-      Element element, String jsOp, HInstruction receiver, TypeMask type)
+      FieldEntity element, String jsOp, HInstruction receiver, TypeMask type)
       : this._(element, jsOp, POST_OP, <HInstruction>[receiver], type);
 
   HInstruction get receiver => inputs[0];
@@ -2504,10 +2508,9 @@
 }
 
 class HStatic extends HInstruction {
-  final Element element;
+  final MemberEntity element;
   HStatic(this.element, type) : super(<HInstruction>[], type) {
     assert(element != null);
-    assert(invariant(this, element.isDeclaration));
     sideEffects.clearAllSideEffects();
     sideEffects.clearAllDependencies();
     if (element.isAssignable) {
@@ -2528,7 +2531,7 @@
 class HInterceptor extends HInstruction {
   // This field should originally be null to allow GVN'ing all
   // [HInterceptor] on the same input.
-  Set<ClassElement> interceptedClasses;
+  Set<ClassEntity> interceptedClasses;
 
   // inputs[0] is initially the only input, the receiver.
 
@@ -2579,7 +2582,7 @@
  * constant as the first input.
  */
 class HOneShotInterceptor extends HInvokeDynamic {
-  Set<ClassElement> interceptedClasses;
+  Set<ClassEntity> interceptedClasses;
   HOneShotInterceptor(Selector selector, TypeMask mask,
       List<HInstruction> inputs, TypeMask type, this.interceptedClasses)
       : super(selector, mask, null, inputs, type, true) {
@@ -2594,7 +2597,7 @@
 
 /** An [HLazyStatic] is a static that is initialized lazily at first read. */
 class HLazyStatic extends HInstruction {
-  final Element element;
+  final FieldEntity element;
   HLazyStatic(this.element, type) : super(<HInstruction>[], type) {
     // TODO(4931): The first access has side-effects, but we afterwards we
     // should be able to GVN.
@@ -2612,7 +2615,7 @@
 }
 
 class HStaticStore extends HInstruction {
-  Element element;
+  MemberEntity element;
   HStaticStore(this.element, HInstruction value)
       : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
     sideEffects.clearAllSideEffects();
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index e9bfd4a..507c459 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -332,7 +332,7 @@
         ListConstantValue constant = constantInput.constant;
         return graph.addConstantInt(constant.length, compiler);
       }
-      Element element = helpers.jsIndexableLength;
+      MemberElement element = helpers.jsIndexableLength;
       bool isFixed = isFixedLength(actualReceiver.instructionType, compiler);
       TypeMask actualType = node.instructionType;
       ClosedWorld closedWorld = compiler.closedWorld;
@@ -383,7 +383,7 @@
     }
 
     if (selector.isCall || selector.isOperator) {
-      Element target;
+      MethodElement target;
       if (input.isExtendableArray(compiler)) {
         if (applies(helpers.jsArrayRemoveLast)) {
           target = helpers.jsArrayRemoveLast;
@@ -453,7 +453,7 @@
         // [:noSuchMethod:] we just ignore it.
         &&
         node.selector.applies(element)) {
-      FunctionElement method = element;
+      MethodElement method = element;
 
       if (backend.isNative(method)) {
         HInstruction folded = tryInlineNativeMethod(node, method);
@@ -464,7 +464,7 @@
         FunctionSignature parameters = method.functionSignature;
         if (parameters.optionalParameterCount == 0 ||
             parameters.parameterCount == node.selector.argumentCount) {
-          node.element = element;
+          node.element = method;
         }
       }
       return node;
@@ -477,11 +477,11 @@
     if (element != null &&
         element.isField &&
         element.name == node.selector.name) {
-      if (!backend.isNative(element) && !node.isCallOnInterceptor(compiler)) {
+      FieldElement field = element;
+      if (!backend.isNative(field) && !node.isCallOnInterceptor(compiler)) {
         HInstruction receiver = node.getDartReceiver(compiler);
-        TypeMask type =
-            TypeMaskFactory.inferredTypeForElement(element, compiler);
-        HInstruction load = new HFieldGet(element, receiver, type);
+        TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler);
+        HInstruction load = new HFieldGet(field, receiver, type);
         node.block.addBefore(node, load);
         Selector callSelector = new Selector.callClosureFrom(node.selector);
         List<HInstruction> inputs = <HInstruction>[load]
@@ -498,7 +498,7 @@
   }
 
   HInstruction tryInlineNativeMethod(
-      HInvokeDynamicMethod node, FunctionElement method) {
+      HInvokeDynamicMethod node, MethodElement method) {
     // Enable direct calls to a native method only if we don't run in checked
     // mode, where the Dart version may have type annotations on parameters and
     // return type that it should check.
@@ -825,7 +825,7 @@
 
   HInstruction removeCheck(HCheck node) => node.checkedInput;
 
-  VariableElement findConcreteFieldForDynamicAccess(
+  FieldElement findConcreteFieldForDynamicAccess(
       HInstruction receiver, Selector selector) {
     TypeMask receiverType = receiver.instructionType;
     return compiler.closedWorld.locateSingleField(selector, receiverType);
@@ -900,11 +900,12 @@
       if (folded != node) return folded;
     }
     HInstruction receiver = node.getDartReceiver(compiler);
-    Element field = findConcreteFieldForDynamicAccess(receiver, node.selector);
+    FieldElement field =
+        findConcreteFieldForDynamicAccess(receiver, node.selector);
     if (field != null) return directFieldGet(receiver, field);
 
     if (node.element == null) {
-      Element element = compiler.closedWorld
+      MemberElement element = compiler.closedWorld
           .locateSingleElement(node.selector, receiver.instructionType);
       if (element != null && element.name == node.selector.name) {
         node.element = element;
@@ -919,7 +920,7 @@
     return node;
   }
 
-  HInstruction directFieldGet(HInstruction receiver, Element field) {
+  HInstruction directFieldGet(HInstruction receiver, FieldElement field) {
     bool isAssignable = !compiler.closedWorld.fieldNeverChanges(field);
 
     TypeMask type;
@@ -940,7 +941,7 @@
     }
 
     HInstruction receiver = node.getDartReceiver(compiler);
-    VariableElement field =
+    FieldElement field =
         findConcreteFieldForDynamicAccess(receiver, node.selector);
     if (field == null || !field.isAssignable) return node;
     // Use [:node.inputs.last:] in case the call follows the
@@ -966,7 +967,7 @@
 
   HInstruction visitInvokeStatic(HInvokeStatic node) {
     propagateConstantValueToUses(node);
-    Element element = node.element;
+    MemberElement element = node.element;
 
     if (element == backend.helpers.checkConcurrentModificationError) {
       if (node.inputs.length == 2) {
@@ -1338,7 +1339,7 @@
   }
 
   void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
-    Element element = node.element;
+    MemberElement element = node.element;
     if (node.isInterceptedCall) return;
     if (element != helpers.jsArrayRemoveLast) return;
     if (boundsChecked.contains(node)) return;
@@ -2162,7 +2163,7 @@
   }
 
   collectTargets(HInstruction instruction, List<HBasicBlock> trueTargets,
-                 List<HBasicBlock> falseTargets) {
+      List<HBasicBlock> falseTargets) {
     for (HInstruction user in instruction.usedBy) {
       if (user is HIf) {
         trueTargets?.add(user.thenBlock);
@@ -2259,7 +2260,7 @@
 
   void visitFieldGet(HFieldGet instruction) {
     if (instruction.isNullCheck) return;
-    Element element = instruction.element;
+    MemberElement element = instruction.element;
     HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck();
     HInstruction existing = memorySet.lookupFieldValue(element, receiver);
     if (existing != null) {
@@ -2280,7 +2281,7 @@
     memorySet.registerAllocation(instruction);
     if (shouldTrackInitialValues(instruction)) {
       int argumentIndex = 0;
-      instruction.element.forEachInstanceField((_, Element member) {
+      instruction.element.forEachInstanceField((_, FieldElement member) {
         if (compiler.elementHasCompileTimeError(member)) return;
         memorySet.registerFieldValue(
             member, instruction, instruction.inputs[argumentIndex++]);
@@ -2337,10 +2338,11 @@
   }
 
   void visitLazyStatic(HLazyStatic instruction) {
-    handleStaticLoad(instruction.element, instruction);
+    FieldElement field = instruction.element;
+    handleStaticLoad(field, instruction);
   }
 
-  void handleStaticLoad(Element element, HInstruction instruction) {
+  void handleStaticLoad(MemberElement element, HInstruction instruction) {
     HInstruction existing = memorySet.lookupFieldValue(element, null);
     if (existing != null) {
       instruction.block.rewriteWithBetterUser(instruction, existing);
@@ -2487,7 +2489,7 @@
    * may be affected by this update.
    */
   void registerFieldValueUpdate(
-      Element element, HInstruction receiver, HInstruction value) {
+      MemberElement element, HInstruction receiver, HInstruction value) {
     assert(receiver == null || receiver == receiver.nonCheck());
     if (backend.isNative(element)) {
       return; // TODO(14955): Remove this restriction?
@@ -2507,7 +2509,7 @@
    * Registers that `receiver.element` is now [value].
    */
   void registerFieldValue(
-      Element element, HInstruction receiver, HInstruction value) {
+      MemberElement element, HInstruction receiver, HInstruction value) {
     assert(receiver == null || receiver == receiver.nonCheck());
     if (backend.isNative(element)) {
       return; // TODO(14955): Remove this restriction?
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index 46beb9e..5a94e8d 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -271,7 +271,7 @@
       Iterable<Element> targets = compiler.closedWorld.allFunctions
           .filter(instruction.selector, instruction.mask);
       if (targets.length == 1) {
-        Element target = targets.first;
+        MemberElement target = targets.first;
         ClassElement cls = target.enclosingClass;
         TypeMask type =
             new TypeMask.nonNullSubclass(cls.declaration, closedWorld);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index dbeee8a..014b16e 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -17,7 +17,7 @@
         FunctionElement,
         MixinApplicationElement,
         TypedefElement,
-        VariableElement;
+        FieldElement;
 import 'js_backend/backend.dart' show JavaScriptBackend;
 import 'ordered_typeset.dart';
 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask;
@@ -264,7 +264,7 @@
   /// Returns the single field that matches a call to [selector] on a
   /// receiver of type [mask]. If multiple targets exist or the single target
   /// is not a field, `null` is returned.
-  VariableElement locateSingleField(Selector selector, TypeMask mask);
+  FieldElement locateSingleField(Selector selector, TypeMask mask);
 
   /// Returns the side effects of executing [element].
   SideEffects getSideEffectsOfElement(Element element);
@@ -1066,7 +1066,7 @@
     }
   }
 
-  VariableElement locateSingleField(Selector selector, TypeMask mask) {
+  FieldElement locateSingleField(Selector selector, TypeMask mask) {
     Element result = locateSingleElement(selector, mask);
     return (result != null && result.isField) ? result : null;
   }
diff --git a/pkg/compiler/lib/src/dart2js_profile_many.dart b/pkg/compiler/tool/dart2js_profile_many.dart
similarity index 94%
rename from pkg/compiler/lib/src/dart2js_profile_many.dart
rename to pkg/compiler/tool/dart2js_profile_many.dart
index 8288a9a..ba344e0 100644
--- a/pkg/compiler/lib/src/dart2js_profile_many.dart
+++ b/pkg/compiler/tool/dart2js_profile_many.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'dart2js.dart' as cmdline;
+import 'package:compiler/src/dart2js.dart' as cmdline
 
 const String USAGE = """
 Usage: dart2js_profile_many.dart [OPTIONS] [FILES]
diff --git a/pkg/compiler/lib/src/dart2js_stress.dart b/pkg/compiler/tool/dart2js_stress.dart
similarity index 80%
rename from pkg/compiler/lib/src/dart2js_stress.dart
rename to pkg/compiler/tool/dart2js_stress.dart
index 804c577..d699e2b 100644
--- a/pkg/compiler/lib/src/dart2js_stress.dart
+++ b/pkg/compiler/tool/dart2js_stress.dart
@@ -4,7 +4,8 @@
 
 library dart2js.stress;
 
-import "dart2js.dart" as dart2js;
+import 'package:compiler/src/dart2js.dart' as dart2js;
+import 'dart:io' show Platform;
 
 const ITERATIONS_FLAG_PREFIX = "--iterations=";
 void main(List<String> args) {
@@ -20,7 +21,9 @@
         "Use '$ITERATIONS_FLAG_PREFIX<count>' to set a repetition count"
         " (as first flag).");
   }
-  args = ["--suppress-warnings", "--suppress-hints"]..addAll(args);
+  args = ["--suppress-warnings", "--suppress-hints", "--library-root="
+      "${Platform.script.resolve('../../../sdk').toFilePath()}"]
+           ..addAll(args);
   void iterate() {
     count++;
     sw.reset();
diff --git a/pkg/dev_compiler/karma.conf.js b/pkg/dev_compiler/karma.conf.js
index dab62fc..e904106 100644
--- a/pkg/dev_compiler/karma.conf.js
+++ b/pkg/dev_compiler/karma.conf.js
@@ -19,6 +19,7 @@
       {pattern: 'gen/codegen_output/corelib/**/*.js', included: false},
       {pattern: 'gen/codegen_output/lib/**/*.js', included: false},
       {pattern: 'test/browser/*.js', included: false},
+      {pattern: 'node_modules/is_js/*.js', included: false},      
       'test-main.js',
     ],
 
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index e50f74c..b809f1f 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -1913,7 +1913,8 @@
     if (result != null) return dart.wrapType(result);
     let extension = dart.getExtensionType(obj);
     if (extension != null) {
-      return obj[dartx.runtimeType];
+      result = obj[dartx.runtimeType];
+      return result != null ? result : dart.wrapType(extension);
     }
     if (typeof obj == "function") {
       return dart.wrapType(dart.getReifiedType(obj));
@@ -13199,6 +13200,10 @@
     return _js_mirrors._dart.wrapType(obj);
   };
   dart.fn(_js_mirrors._wrap, dynamicTodynamic$());
+  _js_mirrors._runtimeType = function(obj) {
+    return _js_mirrors._wrap(_js_mirrors._dart.getReifiedType(obj));
+  };
+  dart.fn(_js_mirrors._runtimeType, dynamicTodynamic$());
   _js_mirrors._unimplemented = function(t, i) {
     dart.throw(new core.UnimplementedError(dart.str`${t}.${_js_mirrors.getName(i.memberName)} unimplemented`));
   };
@@ -13311,7 +13316,7 @@
     }
     get type() {
       if (this.reflectee == null) return mirrors.reflectClass(dart.wrapType(core.Null));
-      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(dart.runtimeType(this.reflectee))));
+      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(_js_mirrors._runtimeType(this.reflectee))));
     }
     _(reflectee) {
       this.reflectee = reflectee;
@@ -28393,14 +28398,12 @@
       }),
       getters: () => ({
         iterator: dart.definiteFunctionType(core.Iterator$(E), []),
-        length: dart.definiteFunctionType(core.int, []),
         first: dart.definiteFunctionType(E, []),
         last: dart.definiteFunctionType(E, []),
         single: dart.definiteFunctionType(E, [])
       }),
       methods: () => ({
         [_compare]: dart.definiteFunctionType(core.int, [E, E]),
-        contains: dart.definiteFunctionType(core.bool, [core.Object]),
         add: dart.definiteFunctionType(core.bool, [E]),
         remove: dart.definiteFunctionType(core.bool, [core.Object]),
         addAll: dart.definiteFunctionType(dart.void, [IterableOfE()]),
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index 259b2e1..6615391 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -1913,7 +1913,8 @@
     if (result != null) return dart.wrapType(result);
     let extension = dart.getExtensionType(obj);
     if (extension != null) {
-      return obj[dartx.runtimeType];
+      result = obj[dartx.runtimeType];
+      return result != null ? result : dart.wrapType(extension);
     }
     if (typeof obj == "function") {
       return dart.wrapType(dart.getReifiedType(obj));
@@ -13199,6 +13200,10 @@
     return _js_mirrors._dart.wrapType(obj);
   };
   dart.fn(_js_mirrors._wrap, dynamicTodynamic$());
+  _js_mirrors._runtimeType = function(obj) {
+    return _js_mirrors._wrap(_js_mirrors._dart.getReifiedType(obj));
+  };
+  dart.fn(_js_mirrors._runtimeType, dynamicTodynamic$());
   _js_mirrors._unimplemented = function(t, i) {
     dart.throw(new core.UnimplementedError(dart.str`${t}.${_js_mirrors.getName(i.memberName)} unimplemented`));
   };
@@ -13311,7 +13316,7 @@
     }
     get type() {
       if (this.reflectee == null) return mirrors.reflectClass(dart.wrapType(core.Null));
-      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(dart.runtimeType(this.reflectee))));
+      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(_js_mirrors._runtimeType(this.reflectee))));
     }
     _(reflectee) {
       this.reflectee = reflectee;
@@ -28393,14 +28398,12 @@
       }),
       getters: () => ({
         iterator: dart.definiteFunctionType(core.Iterator$(E), []),
-        length: dart.definiteFunctionType(core.int, []),
         first: dart.definiteFunctionType(E, []),
         last: dart.definiteFunctionType(E, []),
         single: dart.definiteFunctionType(E, [])
       }),
       methods: () => ({
         [_compare]: dart.definiteFunctionType(core.int, [E, E]),
-        contains: dart.definiteFunctionType(core.bool, [core.Object]),
         add: dart.definiteFunctionType(core.bool, [E]),
         remove: dart.definiteFunctionType(core.bool, [core.Object]),
         addAll: dart.definiteFunctionType(dart.void, [IterableOfE()]),
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index 04625a8..ba30bab 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -1911,7 +1911,8 @@
   if (result != null) return dart.wrapType(result);
   let extension = dart.getExtensionType(obj);
   if (extension != null) {
-    return obj[dartx.runtimeType];
+    result = obj[dartx.runtimeType];
+    return result != null ? result : dart.wrapType(extension);
   }
   if (typeof obj == "function") {
     return dart.wrapType(dart.getReifiedType(obj));
@@ -13197,6 +13198,10 @@
   return _js_mirrors._dart.wrapType(obj);
 };
 dart.fn(_js_mirrors._wrap, dynamicTodynamic());
+_js_mirrors._runtimeType = function(obj) {
+  return _js_mirrors._wrap(_js_mirrors._dart.getReifiedType(obj));
+};
+dart.fn(_js_mirrors._runtimeType, dynamicTodynamic());
 _js_mirrors._unimplemented = function(t, i) {
   dart.throw(new core.UnimplementedError(dart.str`${t}.${_js_mirrors.getName(i.memberName)} unimplemented`));
 };
@@ -13309,7 +13314,7 @@
   }
   get type() {
     if (this.reflectee == null) return mirrors.reflectClass(dart.wrapType(core.Null));
-    return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(dart.runtimeType(this.reflectee))));
+    return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(_js_mirrors._runtimeType(this.reflectee))));
   }
   _(reflectee) {
     this.reflectee = reflectee;
@@ -28391,14 +28396,12 @@
     }),
     getters: () => ({
       iterator: dart.definiteFunctionType(core.Iterator$(E), []),
-      length: dart.definiteFunctionType(core.int, []),
       first: dart.definiteFunctionType(E, []),
       last: dart.definiteFunctionType(E, []),
       single: dart.definiteFunctionType(E, [])
     }),
     methods: () => ({
       [_compare]: dart.definiteFunctionType(core.int, [E, E]),
-      contains: dart.definiteFunctionType(core.bool, [core.Object]),
       add: dart.definiteFunctionType(core.bool, [E]),
       remove: dart.definiteFunctionType(core.bool, [core.Object]),
       addAll: dart.definiteFunctionType(dart.void, [IterableOfE()]),
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index ab2cabd..c230e85 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -1914,7 +1914,8 @@
     if (result != null) return dart.wrapType(result);
     let extension = dart.getExtensionType(obj);
     if (extension != null) {
-      return obj[dartx.runtimeType];
+      result = obj[dartx.runtimeType];
+      return result != null ? result : dart.wrapType(extension);
     }
     if (typeof obj == "function") {
       return dart.wrapType(dart.getReifiedType(obj));
@@ -13200,6 +13201,10 @@
     return _js_mirrors._dart.wrapType(obj);
   };
   dart.fn(_js_mirrors._wrap, dynamicTodynamic$());
+  _js_mirrors._runtimeType = function(obj) {
+    return _js_mirrors._wrap(_js_mirrors._dart.getReifiedType(obj));
+  };
+  dart.fn(_js_mirrors._runtimeType, dynamicTodynamic$());
   _js_mirrors._unimplemented = function(t, i) {
     dart.throw(new core.UnimplementedError(dart.str`${t}.${_js_mirrors.getName(i.memberName)} unimplemented`));
   };
@@ -13312,7 +13317,7 @@
     }
     get type() {
       if (this.reflectee == null) return mirrors.reflectClass(dart.wrapType(core.Null));
-      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(dart.runtimeType(this.reflectee))));
+      return mirrors.ClassMirror._check(_js_mirrors.reflectType(core.Type._check(_js_mirrors._runtimeType(this.reflectee))));
     }
     _(reflectee) {
       this.reflectee = reflectee;
@@ -28394,14 +28399,12 @@
       }),
       getters: () => ({
         iterator: dart.definiteFunctionType(core.Iterator$(E), []),
-        length: dart.definiteFunctionType(core.int, []),
         first: dart.definiteFunctionType(E, []),
         last: dart.definiteFunctionType(E, []),
         single: dart.definiteFunctionType(E, [])
       }),
       methods: () => ({
         [_compare]: dart.definiteFunctionType(core.int, [E, E]),
-        contains: dart.definiteFunctionType(core.bool, [core.Object]),
         add: dart.definiteFunctionType(core.bool, [E]),
         remove: dart.definiteFunctionType(core.bool, [core.Object]),
         addAll: dart.definiteFunctionType(dart.void, [IterableOfE()]),
diff --git a/pkg/dev_compiler/lib/runtime/dart_sdk.sum b/pkg/dev_compiler/lib/runtime/dart_sdk.sum
deleted file mode 100644
index 394bad4..0000000
--- a/pkg/dev_compiler/lib/runtime/dart_sdk.sum
+++ /dev/null
Binary files differ
diff --git a/pkg/dev_compiler/lib/sdk/ddc_sdk.sum b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
new file mode 100644
index 0000000..5b9947b
--- /dev/null
+++ b/pkg/dev_compiler/lib/sdk/ddc_sdk.sum
Binary files differ
diff --git a/pkg/dev_compiler/lib/src/analyzer/context.dart b/pkg/dev_compiler/lib/src/analyzer/context.dart
index 05bacf9..209c2fe 100644
--- a/pkg/dev_compiler/lib/src/analyzer/context.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/context.dart
@@ -55,13 +55,25 @@
       this.packagePaths: const []})
       : dartSdkPath = dartSdkPath ?? getSdkDir().path;
 
-  AnalyzerOptions.fromArguments(ArgResults args)
-      : summaryPaths = args['summary'] as List<String>,
-        dartSdkPath = args['dart-sdk'] ?? getSdkDir().path,
-        dartSdkSummaryPath = args['dart-sdk-summary'],
-        customUrlMappings = _parseUrlMappings(args['url-mapping']),
-        packageRoot = args['package-root'],
-        packagePaths = (args['package-paths'] as String)?.split(',') ?? [];
+  factory AnalyzerOptions.fromArguments(ArgResults args) {
+    var sdkPath = args['dart-sdk'] ?? getSdkDir().path;
+    var sdkSummaryPath = args['dart-sdk-summary'];
+
+    if (sdkSummaryPath == null) {
+      sdkSummaryPath = path.join(sdkPath, 'lib', '_internal', 'ddc_sdk.sum');
+    } else if (sdkSummaryPath == 'build') {
+      // For building the SDK, we explicitly set the path to none.
+      sdkSummaryPath = null;
+    }
+
+    return new AnalyzerOptions(
+        summaryPaths: args['summary'] as List<String>,
+        dartSdkPath: sdkPath,
+        dartSdkSummaryPath: sdkSummaryPath,
+        customUrlMappings: _parseUrlMappings(args['url-mapping']),
+        packageRoot: args['package-root'],
+        packagePaths: (args['package-paths'] as String)?.split(',') ?? []);
+  }
 
   /// Whether to resolve 'package:' uris using the multi-package resolver.
   bool get useMultiPackage => packagePaths.isNotEmpty;
@@ -70,9 +82,10 @@
     parser
       ..addOption('summary',
           abbr: 's', help: 'summary file(s) to include', allowMultiple: true)
-      ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null)
+      ..addOption('dart-sdk',
+          help: 'Dart SDK Path', defaultsTo: null, hide: true)
       ..addOption('dart-sdk-summary',
-          help: 'Dart SDK Summary Path', defaultsTo: null)
+          help: 'Dart SDK Summary Path', defaultsTo: null, hide: true)
       ..addOption('package-root',
           abbr: 'p', help: 'Package root to resolve "package:" imports')
       ..addOption('url-mapping',
diff --git a/pkg/dev_compiler/lib/src/compiler/command.dart b/pkg/dev_compiler/lib/src/compiler/command.dart
index 352fb08..d97ae11 100644
--- a/pkg/dev_compiler/lib/src/compiler/command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/command.dart
@@ -15,7 +15,7 @@
 import 'module_builder.dart';
 
 final ArgParser _argParser = () {
-  var argParser = new ArgParser()
+  var argParser = new ArgParser(allowTrailingOptions: true)
     ..addFlag('help', abbr: 'h', help: 'Display this message.')
     ..addOption('out',
         abbr: 'o', allowMultiple: true, help: 'Output file (required).')
@@ -154,11 +154,17 @@
 
   // Write JS file, as well as source map and summary (if requested).
   for (var i = 0; i < outPaths.length; i++) {
-    var outPath = outPaths[i];
-    module.writeCodeSync(moduleFormats[i], singleOutFile, outPath);
-    if (module.summaryBytes != null) {
-      var summaryPath =
-          path.withoutExtension(outPath) + '.${compilerOpts.summaryExtension}';
+    module.writeCodeSync(moduleFormats[i], outPaths[i],
+        singleOutFile: singleOutFile);
+  }
+  if (module.summaryBytes != null) {
+    var summaryPaths = compilerOpts.summaryOutPath != null
+        ? [compilerOpts.summaryOutPath]
+        : outPaths.map((p) =>
+            '${path.withoutExtension(p)}.${compilerOpts.summaryExtension}');
+
+    // place next to every compiled module
+    for (var summaryPath in summaryPaths) {
       // Only overwrite if summary changed.  This plays better with timestamp
       // based build systems.
       var file = new File(summaryPath);
diff --git a/pkg/dev_compiler/lib/src/compiler/compiler.dart b/pkg/dev_compiler/lib/src/compiler/compiler.dart
index c5d9387..d2eeca4 100644
--- a/pkg/dev_compiler/lib/src/compiler/compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/compiler.dart
@@ -261,6 +261,10 @@
   /// source maps.
   final Map<String, String> bazelMapping;
 
+  /// If specified, the path to write the summary file.
+  /// Used when building the SDK.
+  final String summaryOutPath;
+
   const CompilerOptions(
       {this.sourceMap: true,
       this.sourceMapComment: true,
@@ -277,7 +281,8 @@
       this.nameTypeTests: true,
       this.hoistTypeTests: true,
       this.useAngular2Whitelist: false,
-      this.bazelMapping: const {}});
+      this.bazelMapping: const {},
+      this.summaryOutPath});
 
   CompilerOptions.fromArguments(ArgResults args)
       : sourceMap = args['source-map'],
@@ -295,7 +300,8 @@
         nameTypeTests = args['name-type-tests'],
         hoistTypeTests = args['hoist-type-tests'],
         useAngular2Whitelist = args['unsafe-angular2-whitelist'],
-        bazelMapping = _parseBazelMappings(args['bazel-mapping']);
+        bazelMapping = _parseBazelMappings(args['bazel-mapping']),
+        summaryOutPath = args['summary-out'];
 
   static void addArguments(ArgParser parser) {
     parser
@@ -349,7 +355,9 @@
               'to/library.dart as the path for library.dart in source maps.',
           allowMultiple: true,
           splitCommas: false,
-          hide: true);
+          hide: true)
+      ..addOption('summary-out',
+          help: 'location to write the summary file', hide: true);
   }
 
   static Map<String, String> _parseBazelMappings(Iterable argument) {
@@ -427,8 +435,8 @@
   //
   // TODO(jmesserly): this should match our old logic, but I'm not sure we are
   // correctly handling the pointer from the .js file to the .map file.
-  JSModuleCode getCode(
-      ModuleFormat format, bool singleOutFile, String jsUrl, String mapUrl) {
+  JSModuleCode getCode(ModuleFormat format, String jsUrl, String mapUrl,
+      {bool singleOutFile: false}) {
     var opts = new JS.JavaScriptPrintingOptions(
         emitTypes: options.closure,
         allowKeywordsInProperties: true,
@@ -443,7 +451,8 @@
       printer = new JS.SimpleJavaScriptPrintingContext();
     }
 
-    var tree = transformModuleFormat(format, singleOutFile, moduleTree);
+    var tree =
+        transformModuleFormat(format, moduleTree, singleOutFile: singleOutFile);
     tree.accept(
         new JS.Printer(opts, printer, localNamer: new JS.TemporaryNamer(tree)));
 
@@ -477,15 +486,20 @@
   ///
   /// If [mapPath] is not supplied but [options.sourceMap] is set, mapPath
   /// will default to [jsPath].map.
-  void writeCodeSync(ModuleFormat format, bool singleOutFile, String jsPath) {
+  void writeCodeSync(ModuleFormat format, String jsPath,
+      {bool singleOutFile: false}) {
     String mapPath = jsPath + '.map';
-    var code = getCode(format, singleOutFile, jsPath, mapPath);
+    var code = getCode(format, jsPath, mapPath, singleOutFile: singleOutFile);
     var c = code.code;
     if (singleOutFile) {
       // In singleOutFile mode we wrap each module in an eval statement to
       // leverage sourceURL to improve the debugging experience when source maps
       // are not enabled.
-      c += '\n//# sourceURL=${name}.js\n';
+      //
+      // Note: We replace all `/` with `.` so that we don't break relative urls
+      // to sources in the original sourcemap. The name of this file is bogus
+      // anyways, so it has very little effect on things.
+      c += '\n//# sourceURL=${name.replaceAll("/", ".")}.js\n';
       c = 'eval(${JSON.encode(c)});\n';
     }
     new File(jsPath).writeAsStringSync(c);
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
index 828a0fa..0fd990c 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -65,9 +65,10 @@
         allowMultiple: allowMultiple,
         defaultsTo: 'amd')
     ..addFlag('single-out-file',
-        help: 'emit output so that libraries can be concatenated together into '
-            'a single file. Only compatible with legacy and amd module formats.',
-        defaultsTo: false);
+        help: 'emit modules that can be concatenated into one file.\n'
+            'Only compatible with legacy and amd module formats.',
+        defaultsTo: false,
+        hide: true);
 }
 
 /// Transforms an ES6 [module] into a given module [format].
@@ -78,17 +79,21 @@
 /// structure as possible with the original. The transformation is a shallow one
 /// that affects the top-level module items, especially [ImportDeclaration]s and
 /// [ExportDeclaration]s.
-Program transformModuleFormat(
-    ModuleFormat format, bool singleOutFile, Program module) {
+Program transformModuleFormat(ModuleFormat format, Program module,
+    {bool singleOutFile: false}) {
   switch (format) {
     case ModuleFormat.legacy:
-      return new LegacyModuleBuilder(singleOutFile).build(module);
+      // Legacy format always generates output compatible with single file mode.
+      return new LegacyModuleBuilder().build(module);
     case ModuleFormat.common:
-      return new CommonJSModuleBuilder(singleOutFile).build(module);
+      assert(!singleOutFile);
+      return new CommonJSModuleBuilder().build(module);
     case ModuleFormat.amd:
-      return new AmdModuleBuilder(singleOutFile).build(module);
+      // TODO(jmesserly): encode singleOutFile as a module format?
+      // Since it's irrelevant except for AMD.
+      return new AmdModuleBuilder(singleOutFile: singleOutFile).build(module);
     case ModuleFormat.es6:
-      assert(singleOutFile == false);
+      assert(!singleOutFile);
       return module;
   }
   return null; // unreachable. suppresses a bogus analyzer message
@@ -137,10 +142,6 @@
 /// Generates modules for with our legacy `dart_library.js` loading mechanism.
 // TODO(jmesserly): remove this and replace with something that interoperates.
 class LegacyModuleBuilder extends _ModuleBuilder {
-  /// The legacy module format always generates output compatible with a single
-  /// file mode.
-  LegacyModuleBuilder(bool singleOutFile);
-
   Program build(Program module) {
     // Collect imports/exports/statements.
     visitProgram(module);
@@ -198,14 +199,6 @@
 
 /// Generates CommonJS modules (used by Node.js).
 class CommonJSModuleBuilder extends _ModuleBuilder {
-  final bool singleOutFile;
-
-  CommonJSModuleBuilder(this.singleOutFile) {
-    // singleOutFile mode is not currently supported by the CommonJS module
-    // builder.
-    assert(singleOutFile == false);
-  }
-
   Program build(Program module) {
     var importStatements = <Statement>[];
 
@@ -257,7 +250,7 @@
 class AmdModuleBuilder extends _ModuleBuilder {
   final bool singleOutFile;
 
-  AmdModuleBuilder(this.singleOutFile);
+  AmdModuleBuilder({this.singleOutFile: false});
 
   Program build(Program module) {
     var importStatements = <Statement>[];
diff --git a/pkg/dev_compiler/lib/src/js_ast/js_ast.dart b/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
index 68c706a..21eadd3 100644
--- a/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/js_ast.dart
@@ -11,7 +11,6 @@
 part 'nodes.dart';
 part 'builder.dart';
 part 'js_types.dart';
-part 'module_transform.dart';
 part 'printer.dart';
 part 'template.dart';
 part 'type_printer.dart';
diff --git a/pkg/dev_compiler/lib/src/js_ast/module_transform.dart b/pkg/dev_compiler/lib/src/js_ast/module_transform.dart
deleted file mode 100644
index d8749db..0000000
--- a/pkg/dev_compiler/lib/src/js_ast/module_transform.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of js_ast;
-
-/**
- * Transforms ECMAScript 6 modules to an ES 5 file using a module pattern.
- *
- * There are various module patterns in JavaScript, see
- * <http://babeljs.io/docs/usage/modules/> for some examples.
- *
- * At the moment, we only support our "custom Dart" conversion, roughly similar
- * to Asynchronous Module Definition (AMD), see also
- * <http://requirejs.org/docs/whyamd.html>. Like AMD, module files can
- * be loaded directly in the browser with no further transformation (e.g.
- * browserify, webpack).
- */
-// TODO(jmesserly): deprecate the "custom dart" form in favor of AMD.
-class CustomDartModuleTransform extends BaseVisitor {
-  // TODO(jmesserly): implement these. Module should transform to Program.
-  visitImportDeclaration(ImportDeclaration node) {}
-  visitExportDeclaration(ExportDeclaration node) {}
-  visitModule(Module node) {}
-}
diff --git a/pkg/dev_compiler/package.json b/pkg/dev_compiler/package.json
index 0c3ef0b..2616c06 100644
--- a/pkg/dev_compiler/package.json
+++ b/pkg/dev_compiler/package.json
@@ -18,6 +18,7 @@
   "devDependencies": {
     "chai": "^2.2.0",
     "electron-prebuilt": "^0.36.0",
+    "is_js": "^0.9.0",
     "karma": "^0.12.31",
     "karma-chai": "^0.1.0",
     "karma-chrome-launcher": "^0.1.8",
diff --git a/pkg/dev_compiler/test-main.js b/pkg/dev_compiler/test-main.js
index fc04a7b..bcb70fe 100644
--- a/pkg/dev_compiler/test-main.js
+++ b/pkg/dev_compiler/test-main.js
@@ -56,6 +56,7 @@
     path: 'gen/codegen_output/pkg/path',
     stack_trace: 'gen/codegen_output/pkg/stack_trace',
     unittest: 'gen/codegen_output/pkg/unittest',
+    is: 'node_modules/is_js/is',
   },
 
   // Require all test files before starting tests.
diff --git a/pkg/dev_compiler/test/browser/language_tests.js b/pkg/dev_compiler/test/browser/language_tests.js
index b360aef..378ac92 100644
--- a/pkg/dev_compiler/test/browser/language_tests.js
+++ b/pkg/dev_compiler/test/browser/language_tests.js
@@ -2,8 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-define(['dart_sdk', 'async_helper', 'expect', 'unittest', 'require'],
-      function(dart_sdk, async_helper, expect, unittest, require) {
+define(['dart_sdk', 'async_helper', 'expect', 'unittest', 'is', 'require'],
+      function(dart_sdk, async_helper, expect, unittest, is, require) {
   'use strict';
 
   async_helper = async_helper.async_helper;
@@ -14,6 +14,7 @@
   // Test attributes are a list of strings, or a string for a single
   // attribute. Valid attributes are:
   //
+  //   'pass' - test passes (default)
   //   'skip' - don't run the test
   //   'fail' - test fails
   //   'timeout' - test times out
@@ -22,10 +23,15 @@
   //   'unittest' - run separately as a unittest test.
   //
   // Common combinations:
+  const pass = 'pass';
   const fail = 'fail';
   const skip_fail = ['skip', 'fail'];
   const skip_timeout = ['skip', 'timeout'];
 
+  // Browsers
+  const firefox_fail = is.firefox() ? fail : pass;
+  const chrome_fail = is.chrome() ? fail : pass;
+
   // Tests marked with this are still using the deprecated unittest package
   // because they rely on its support for futures and asynchronous tests, which
   // expect and minitest do not handle.
@@ -257,6 +263,7 @@
       'mixin_type_parameter3_test': skip_fail,
       'modulo_test': fail,
       'named_parameter_clash_test': skip_fail,
+      'named_parameters_passing_falsy_test': firefox_fail,
       'nan_identical_test': skip_fail,
       'nested_switch_label_test': skip_fail,
       'number_identifier_test_05_multi': skip_fail,
@@ -290,6 +297,7 @@
       'throwing_lazy_variable_test': skip_fail,
       'top_level_non_prefixed_library_test': skip_fail,
       'truncdiv_test': fail,  // did not throw
+      'type_literal_test': firefox_fail,
       'type_variable_nested_test': skip_fail,  // unsound is-check
       'type_variable_typedef_test': skip_fail,  // unsound is-check
 
@@ -343,8 +351,10 @@
       'const_list_remove_range_test': fail,
       'const_list_set_range_test': fail,
       'double_parse_test_01_multi': fail,
+      'double_parse_test_02_multi': firefox_fail,
       'error_stack_trace1_test': fail,
       'error_stack_trace2_test': fail,
+      'for_in_test': firefox_fail,
       'hash_map2_test': skip_timeout,
       'hash_set_test_01_multi': fail,
       'hidden_library2_test_01_multi': fail,
@@ -367,22 +377,28 @@
       'main_test': fail,
       'map_keys2_test': fail,
       'map_to_string_test': fail,
+      'map_from_iterable_test': firefox_fail,
       'nan_infinity_test_01_multi': fail,
       'null_nosuchmethod_test': fail,
       'null_test': fail,
       'num_sign_test': fail,
       'regress_r21715_test': fail,
       'throw_half_surrogate_pair_test_02_multi': fail,
-      'stacktrace_current_test': fail,
+      'splay_tree_from_iterable_test': firefox_fail,
+      'stacktrace_current_test': chrome_fail,
+      'string_case_test_01_multi': firefox_fail,
       'string_fromcharcodes_test': skip_timeout,
       'string_operations_with_null_test': fail,
       'symbol_reserved_word_test_06_multi': fail,
       'symbol_reserved_word_test_09_multi': fail,
       'symbol_reserved_word_test_12_multi': fail,
       'throw_half_surrogate_pair_test_01_multi': fail,
+      'unicode_test': firefox_fail,
+      'uri_parameters_all_test': firefox_fail,
       // TODO(rnystrom): Times out because it tests a huge number of
       // combinations of URLs (4 * 5 * 5 * 8 * 6 * 6 * 4 = 115200).
       'uri_parse_test': skip_timeout,
+      'uri_test': firefox_fail,
 
       'list_insert_test': fail,
       'list_removeat_test': fail,
@@ -390,7 +406,9 @@
     },
 
     'corelib/regexp': {
-      'default_arguments_test': fail
+      'default_arguments_test': fail,
+      'UC16_test': firefox_fail,
+      'unicodeCaseInsensitive_test': firefox_fail
     },
 
     'lib/convert': {
@@ -414,7 +432,7 @@
     'lib/html': {
       'async_spawnuri_test': async_unittest,
       'async_test': async_unittest,
-      'audiocontext_test': 'fail', // was sdk#27578, needs triage
+      'audiocontext_test': is.chrome('<=55') ? fail : pass, // was sdk#27578, needs triage
       'blob_constructor_test': 'fail', // was sdk#27578, needs triage
       'canvas_test': ['unittest'],
       'canvasrenderingcontext2d_test': ['unittest'],
@@ -437,6 +455,7 @@
       // Failure: 'Expected 56 to be in the inclusive range [111, 160].'.
       'element_offset_test': 'fail',
       'element_test': async_unittest,
+      'element_types_test': firefox_fail,
       'event_customevent_test': async_unittest,
       'events_test': async_unittest,
 
@@ -484,12 +503,14 @@
       'postmessage_structured_test': async_unittest,
       'request_animation_frame_test': async_unittest,
       'resource_http_test': async_unittest,
-      'rtc_test': 'fail', // was sdk#27578, needs triage
+      'rtc_test': is.chrome('<=55') ? fail : pass, // was sdk#27578, needs triage
 
       // Expected 1, got null.
       'serialized_script_value_test': 'fail',
+      'shadow_dom_test': firefox_fail,
       'speechrecognition_test': 'fail', // was sdk#27578, needs triage
-      'svgelement_test': 'fail', // was sdk#27578, needs triage
+      'svgelement_test': chrome_fail, // was sdk#27578, needs triage
+      'text_event_test': firefox_fail,
       'touchevent_test': 'fail', // was sdk#27578, needs triage
       'transferables_test': async_unittest,
       'transition_event_test': async_unittest,
@@ -636,7 +657,6 @@
       'private_class_field_test': fail,
       'private_symbol_mangling_test': fail,
       'private_types_test': fail,
-      'proxy_type_test': fail,
       'raw_type_test_01_multi': fail,
       'raw_type_test_none_multi': fail,
       'reflect_class_test_none_multi': fail,
@@ -653,9 +673,7 @@
       'regress_26187_test': fail,
       'relation_assignable_test': fail,
       'relation_subtype_test': fail,
-      'runtime_type_test': fail,
       'set_field_with_final_test': fail,
-      'superclass2_test': fail,
       'symbol_validation_test_01_multi': fail,
       'symbol_validation_test_none_multi': fail,
       'to_string_test': fail,
@@ -668,6 +686,7 @@
       'typedef_metadata_test': fail,
       'typedef_test': fail,
       'typevariable_mirror_metadata_test': fail,
+      'unmangled_type_test': firefox_fail,
       'unnamed_library_test': fail,
       'variable_is_const_test_none_multi': fail,
     },
diff --git a/pkg/dev_compiler/test/codegen_test.dart b/pkg/dev_compiler/test/codegen_test.dart
index 1f171f0..5c215e0 100644
--- a/pkg/dev_compiler/test/codegen_test.dart
+++ b/pkg/dev_compiler/test/codegen_test.dart
@@ -68,7 +68,7 @@
 
   var sdkDir = path.join(repoDirectory, 'gen', 'patched_sdk');
   var sdkSummaryFile =
-      path.join(testDirectory, '..', 'lib', 'js', 'amd', 'dart_sdk.sum');
+      path.join(testDirectory, '..', 'lib', 'sdk', 'ddc_sdk.sum');
 
   var summaryPaths = new Directory(path.join(codegenOutputDir, 'pkg'))
       .listSync()
@@ -174,7 +174,7 @@
   if (errors.isNotEmpty && !errors.endsWith('\n')) errors += '\n';
   new File(outPath + '.txt').writeAsStringSync(errors);
 
-  result.writeCodeSync(format, false, outPath + '.js');
+  result.writeCodeSync(format, outPath + '.js');
 
   if (result.summaryBytes != null) {
     new File(outPath + '.sum').writeAsBytesSync(result.summaryBytes);
@@ -188,7 +188,7 @@
 
     var expectFile = new File(expectPath + '.js');
     if (result.isValid) {
-      result.writeCodeSync(format, false, expectFile.path);
+      result.writeCodeSync(format, expectFile.path);
     } else {
       expectFile.writeAsStringSync("//FAILED TO COMPILE");
     }
diff --git a/pkg/dev_compiler/test/worker/worker_test.dart b/pkg/dev_compiler/test/worker/worker_test.dart
index 8cb8f65..6ad4c05 100644
--- a/pkg/dev_compiler/test/worker/worker_test.dart
+++ b/pkg/dev_compiler/test/worker/worker_test.dart
@@ -17,10 +17,13 @@
     final argsFile = new File('test/worker/hello_world.args').absolute;
     final inputDartFile = new File('test/worker/hello_world.dart').absolute;
     final outputJsFile = new File('test/worker/hello_world.js').absolute;
+    final dartSdkSummary = new File('lib/sdk/ddc_sdk.sum').absolute;
     final executableArgs = ['bin/dartdevc.dart'];
     final compilerArgs = [
       '--no-source-map',
       '--no-summarize',
+      '--dart-sdk-summary',
+      dartSdkSummary.path,
       '-o',
       outputJsFile.path,
       inputDartFile.path,
@@ -116,10 +119,13 @@
     });
 
     test('can compile in basic mode', () {
+      final dartSdkSummary = new File('lib/sdk/ddc_sdk.sum').absolute;
       var result = Process.runSync('dart', [
         'bin/dartdevc.dart',
         '--summary-extension=api.ds',
         '--no-source-map',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '-o',
         greetingJS.path,
         greetingDart.path,
@@ -134,6 +140,8 @@
         'bin/dartdevc.dart',
         '--no-source-map',
         '--no-summarize',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '--summary-extension=api.ds',
         '-s',
         greetingSummary.path,
@@ -149,6 +157,7 @@
   });
 
   group('Error handling', () {
+    final dartSdkSummary = new File('lib/sdk/ddc_sdk.sum').absolute;
     final badFileDart = new File('test/worker/bad.dart').absolute;
     final badFileJs = new File('test/worker/bad.js').absolute;
 
@@ -158,7 +167,7 @@
     });
 
     test('incorrect usage', () {
-      var result = Process.runSync('dart', ['bin/dartdevc.dart', 'oops',]);
+      var result = Process.runSync('dart', ['bin/dartdevc.dart', '--dart-sdk-summary', dartSdkSummary.path, 'oops',]);
       expect(result.exitCode, 64);
       expect(
           result.stdout, contains('Please include the output file location.'));
@@ -170,6 +179,8 @@
       var result = Process.runSync('dart', [
         'bin/dartdevc.dart',
         '--no-source-map',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '-o',
         badFileJs.path,
         badFileDart.path,
@@ -180,6 +191,7 @@
   });
 
   group('Parts', () {
+    final dartSdkSummary = new File('lib/sdk/ddc_sdk.sum').absolute;
     final partFile = new File('test/worker/greeting.dart').absolute;
     final libraryFile = new File('test/worker/hello.dart').absolute;
 
@@ -204,6 +216,8 @@
         'bin/dartdevc.dart',
         '--no-summarize',
         '--no-source-map',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '-o',
         outJS.path,
         partFile.path,
@@ -220,6 +234,8 @@
         'bin/dartdevc.dart',
         '--no-summarize',
         '--no-source-map',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '-o',
         outJS.path,
         libraryFile.path,
@@ -235,6 +251,8 @@
         'bin/dartdevc.dart',
         '--no-summarize',
         '--no-source-map',
+        '--dart-sdk-summary',
+        dartSdkSummary.path,
         '-o',
         outJS.path,
         partFile.path,
diff --git a/pkg/dev_compiler/tool/build_pkgs.sh b/pkg/dev_compiler/tool/build_pkgs.sh
new file mode 100755
index 0000000..a26c7ea
--- /dev/null
+++ b/pkg/dev_compiler/tool/build_pkgs.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+set -e # bail on error
+
+cd $( dirname "${BASH_SOURCE[0]}" )/..
+
+mkdir -p gen/codegen_output/pkg/
+
+SDK=--dart-sdk-summary=lib/sdk/ddc_sdk.sum
+
+# Build leaf packages.  These have no other package dependencies.
+
+# Under pkg
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/async_helper.js \
+    package:async_helper/async_helper.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/expect.js \
+    package:expect/expect.dart \
+    package:expect/minitest.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/js.js \
+    package:js/js.dart \
+    package:js/js_util.dart \
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/lookup_map.js \
+    package:lookup_map/lookup_map.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/meta.js \
+    package:meta/meta.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/microlytics.js \
+    package:microlytics/microlytics.dart \
+    package:microlytics/html_channels.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/typed_mock.js \
+    package:typed_mock/typed_mock.dart
+
+# Under third_party/pkg
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/args.js \
+    package:args/args.dart \
+    package:args/command_runner.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/charcode.js \
+    package:charcode/charcode.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/collection.js \
+    package:collection/collection.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/fixnum.js \
+    package:fixnum/fixnum.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/logging.js \
+    package:logging/logging.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/markdown.js \
+    package:markdown/markdown.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/matcher.js \
+    package:matcher/matcher.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/mime.js \
+    package:mime/mime.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/path.js \
+    package:path/path.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/plugin.js \
+    package:plugin/plugin.dart \
+    package:plugin/manager.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/typed_data.js \
+    package:typed_data/typed_data.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/usage.js \
+    package:usage/usage.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/utf.js \
+    package:utf/utf.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/when.js \
+    package:when/when.dart
+
+# Composite packages with dependencies
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/async.js \
+   -s gen/codegen_output/pkg/collection.sum \
+   package:async/async.dart
+
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/stack_trace.js \
+    -s gen/codegen_output/pkg/path.sum \
+    package:stack_trace/stack_trace.dart
diff --git a/pkg/dev_compiler/tool/build_sdk.sh b/pkg/dev_compiler/tool/build_sdk.sh
index 71f6db4..561f5c4 100755
--- a/pkg/dev_compiler/tool/build_sdk.sh
+++ b/pkg/dev_compiler/tool/build_sdk.sh
@@ -11,6 +11,8 @@
 # TODO(jmesserly): break out dart:html & friends.
 dart -c tool/build_sdk.dart \
     --dart-sdk gen/patched_sdk \
+    --dart-sdk-summary=build \
+    --summary-out lib/sdk/ddc_sdk.sum \
     --modules=amd \
     -o lib/js/amd/dart_sdk.js \
     --modules=es6 \
diff --git a/pkg/dev_compiler/tool/build_test_pkgs.sh b/pkg/dev_compiler/tool/build_test_pkgs.sh
index 42ab6c9..bb63177 100755
--- a/pkg/dev_compiler/tool/build_test_pkgs.sh
+++ b/pkg/dev_compiler/tool/build_test_pkgs.sh
@@ -5,7 +5,7 @@
 
 mkdir -p gen/codegen_output/pkg/
 
-SDK=--dart-sdk-summary=lib/js/amd/dart_sdk.sum
+SDK=--dart-sdk-summary=lib/sdk/ddc_sdk.sum
 
 ./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/expect.js \
     package:expect/expect.dart \
@@ -15,6 +15,9 @@
     --url-mapping=package:async_helper/async_helper.dart,test/codegen/async_helper.dart \
     package:async_helper/async_helper.dart
 
+./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/collection.js \
+    package:collection/collection.dart
+
 ./bin/dartdevc.dart $SDK -o gen/codegen_output/pkg/js.js \
     package:js/js.dart
 
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index 946507c..5553144 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -795,7 +795,9 @@
   // Delegate to the (possibly user-defined) method on the object.
   var extension = getExtensionType(obj);
   if (extension != null) {
-    return JS('', '#[dartx.runtimeType]', obj);
+    result = JS('', '#[dartx.runtimeType]', obj);
+    // If extension doesn't override runtimeType, return the extension type.
+    return result ?? wrapType(extension);
   }
   if (JS('bool', 'typeof # == "function"', obj)) {
     return wrapType(getReifiedType(obj));
diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart b/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart
index 151affb..6c985d7 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart
@@ -147,6 +147,9 @@
 
 dynamic _wrap(obj) => JS('', '#.wrapType(#)', _dart, obj);
 
+dynamic _runtimeType(obj) =>
+  _wrap(JS('', '#.getReifiedType(#)', _dart, obj));
+
 _unimplemented(Type t, Invocation i) {
   throw new UnimplementedError('$t.${getName(i.memberName)} unimplemented');
 }
@@ -190,7 +193,7 @@
     // The spec guarantees that `null` is the singleton instance of the `Null`
     // class.
     if (reflectee == null) return reflectClass(Null);
-    return reflectType(reflectee.runtimeType);
+    return reflectType(_runtimeType(reflectee));
   }
 
   JsInstanceMirror._(this.reflectee);
diff --git a/pkg/dev_compiler/tool/sdk_expected_errors.txt b/pkg/dev_compiler/tool/sdk_expected_errors.txt
index 7c083b0..81c8204 100644
--- a/pkg/dev_compiler/tool/sdk_expected_errors.txt
+++ b/pkg/dev_compiler/tool/sdk_expected_errors.txt
@@ -24,7 +24,7 @@
 [warning] Unsound implicit cast from 'dynamic' to 'E'. (dart:_interceptors/js_array.dart, line 564, col 12)
 [warning] Unsound implicit cast from 'dynamic' to 'JSArray<String>'. (dart:_js_helper, line 79, col 37)
 [warning] Unsound implicit cast from 'dynamic' to 'E'. (dart:_js_helper, line 882, col 16)
-[warning] Unsound implicit cast from 'dynamic' to '() → List<Type>'. (dart:_js_mirrors, line 422, col 40)
+[warning] Unsound implicit cast from 'dynamic' to '() → List<Type>'. (dart:_js_mirrors, line 425, col 40)
 [warning] Unsound implicit cast from 'dynamic' to 'List<String>'. (dart:_interceptors/js_string.dart, line 92, col 14)
 [warning] Unsound implicit cast from 'dynamic' to 'List<String>'. (dart:_interceptors/js_string.dart, line 95, col 14)
 [warning] Unsound implicit cast from 'dynamic' to 'LinkedHashMapCell<K, V>'. (dart:_js_helper/linked_hash_map.dart, line 119, col 40)
diff --git a/pkg/dev_compiler/web/web_command.dart b/pkg/dev_compiler/web/web_command.dart
index 68b216a..bc4c1ad 100644
--- a/pkg/dev_compiler/web/web_command.dart
+++ b/pkg/dev_compiler/web/web_command.dart
@@ -197,11 +197,13 @@
 
       JSModuleFile module = compiler.compile(unit, compilerOptions);
 
-      var moduleCode = module.isValid
-          ? module
-              .getCode(ModuleFormat.legacy, true, unit.name, unit.name + '.map')
-              .code
-          : '';
+      var moduleCode = '';
+      if (module.isValid) {
+        moduleCode = module
+            .getCode(ModuleFormat.legacy, unit.name, unit.name + '.map',
+                singleOutFile: true)
+            .code;
+      }
 
       return new CompileResult(
           code: moduleCode, isValid: module.isValid, errors: module.errors);
diff --git a/pkg/front_end/lib/file_system.dart b/pkg/front_end/lib/file_system.dart
index 404f7f6..cadf82f 100644
--- a/pkg/front_end/lib/file_system.dart
+++ b/pkg/front_end/lib/file_system.dart
@@ -31,10 +31,9 @@
 
   /// Returns a [FileSystemEntity] corresponding to the given [uri].
   ///
-  /// Uses of `..` and `.` in the URI are normalized before returning.  Relative
-  /// paths are also converted to absolute paths.
+  /// Uses of `..` and `.` in the URI are normalized before returning.
   ///
-  /// If [uri] is not a `file:` URI, an [Error] will be thrown.
+  /// If [uri] is not an absolute `file:` URI, an [Error] will be thrown.
   ///
   /// Does not check whether a file or folder exists at the given location.
   FileSystemEntity entityForUri(Uri uri);
@@ -42,6 +41,9 @@
 
 /// Abstract representation of a file system entity that may or may not exist.
 ///
+/// Instances of this class have suitable implementations of equality tests and
+/// hashCode.
+///
 /// Not intended to be implemented or extended by clients.
 abstract class FileSystemEntity {
   /// Returns the absolute normalized path represented by this file system
@@ -67,7 +69,7 @@
   /// The file is assumed to be UTF-8 encoded.
   ///
   /// If an error occurs while attempting to read the file (e.g. because no such
-  /// file exists, or the entity is a directory), the future is completed with
-  /// an [Exception].
+  /// file exists, the entity is a directory, or the file is not valid UTF-8),
+  /// the future is completed with an [Exception].
   Future<String> readAsString();
 }
diff --git a/pkg/front_end/lib/memory_file_system.dart b/pkg/front_end/lib/memory_file_system.dart
new file mode 100644
index 0000000..267cbe3
--- /dev/null
+++ b/pkg/front_end/lib/memory_file_system.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library front_end.memory_file_system;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:typed_data';
+
+import 'package:path/path.dart' as p;
+
+import 'file_system.dart';
+
+/// Concrete implementation of [FileSystem] which performs its operations on an
+/// in-memory virtual file system.
+///
+/// Not intended to be implemented or extended by clients.
+class MemoryFileSystem implements FileSystem {
+  @override
+  final p.Context context;
+
+  final Map<String, Uint8List> _files = {};
+
+  /// The "current directory" in the in-memory virtual file system.
+  ///
+  /// This is used to convert relative paths to absolute paths.
+  String currentDirectory;
+
+  MemoryFileSystem(this.context, this.currentDirectory);
+
+  @override
+  MemoryFileSystemEntity entityForPath(String path) =>
+      new MemoryFileSystemEntity._(
+          this, context.normalize(context.join(currentDirectory, path)));
+
+  @override
+  MemoryFileSystemEntity entityForUri(Uri uri) {
+    if (uri.scheme != 'file') throw new ArgumentError('File URI expected');
+    // Note: we don't have to verify that the URI's path is absolute, because
+    // URIs with non-empty schemes always have absolute paths.
+    return entityForPath(context.fromUri(uri));
+  }
+}
+
+/// Concrete implementation of [FileSystemEntity] for use by
+/// [MemoryFileSystem].
+class MemoryFileSystemEntity implements FileSystemEntity {
+  final MemoryFileSystem _fileSystem;
+
+  @override
+  final String path;
+
+  MemoryFileSystemEntity._(this._fileSystem, this.path);
+
+  @override
+  int get hashCode => path.hashCode;
+
+  @override
+  bool operator ==(Object other) =>
+      other is MemoryFileSystemEntity &&
+      other.path == path &&
+      identical(other._fileSystem, _fileSystem);
+
+  @override
+  Future<List<int>> readAsBytes() async {
+    List<int> contents = _fileSystem._files[path];
+    if (contents != null) {
+      return contents.toList();
+    }
+    throw new Exception('File does not exist');
+  }
+
+  @override
+  Future<String> readAsString() async {
+    List<int> contents = await readAsBytes();
+    return UTF8.decode(contents);
+  }
+
+  /// Writes the given raw bytes to this file system entity.
+  ///
+  /// If no file exists, one is created.  If a file exists already, it is
+  /// overwritten.
+  void writeAsBytesSync(List<int> bytes) {
+    _fileSystem._files[path] = new Uint8List.fromList(bytes);
+  }
+
+  /// Writes the given string to this file system entity.
+  ///
+  /// The string is encoded as UTF-8.
+  ///
+  /// If no file exists, one is created.  If a file exists already, it is
+  /// overwritten.
+  void writeAsStringSync(String s) {
+    // Note: the return type of UTF8.encode is List<int>, but in practice it
+    // always returns Uint8List.  We rely on that for efficiency, so that we
+    // don't have to make an extra copy.
+    _fileSystem._files[path] = UTF8.encode(s) as Uint8List;
+  }
+}
diff --git a/pkg/front_end/lib/physical_file_system.dart b/pkg/front_end/lib/physical_file_system.dart
new file mode 100644
index 0000000..0ed5d8b
--- /dev/null
+++ b/pkg/front_end/lib/physical_file_system.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library front_end.physical_file_system;
+
+import 'dart:async';
+import 'dart:io' as io;
+
+import 'package:path/path.dart' as p;
+
+import 'file_system.dart';
+
+/// Concrete implementation of [FileSystem] which performs its operations using
+/// I/O.
+///
+/// Not intended to be implemented or extended by clients.
+class PhysicalFileSystem implements FileSystem {
+  static final PhysicalFileSystem instance = new PhysicalFileSystem._();
+
+  PhysicalFileSystem._();
+
+  @override
+  p.Context get context => p.context;
+
+  @override
+  FileSystemEntity entityForPath(String path) =>
+      new _PhysicalFileSystemEntity(context.normalize(context.absolute(path)));
+
+  @override
+  FileSystemEntity entityForUri(Uri uri) {
+    if (uri.scheme != 'file') throw new ArgumentError('File URI expected');
+    // Note: we don't have to verify that the URI's path is absolute, because
+    // URIs with non-empty schemes always have absolute paths.
+    return entityForPath(context.fromUri(uri));
+  }
+}
+
+/// Concrete implementation of [FileSystemEntity] for use by
+/// [PhysicalFileSystem].
+class _PhysicalFileSystemEntity implements FileSystemEntity {
+  @override
+  final String path;
+
+  _PhysicalFileSystemEntity(this.path);
+
+  @override
+  int get hashCode => path.hashCode;
+
+  @override
+  bool operator ==(Object other) =>
+      other is _PhysicalFileSystemEntity && other.path == path;
+
+  @override
+  Future<List<int>> readAsBytes() => new io.File(path).readAsBytes();
+
+  @override
+  Future<String> readAsString() => new io.File(path).readAsString();
+}
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 9c09fa2..58c4bb1 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -10,10 +10,12 @@
   path: '^1.3.9'
   source_span: '^1.2.3'
 dev_dependencies:
-  package_config: '^1.0.0'
   # TODO(sigmund): update to a version constraint once we roll the latest kernel
   # to the repo.
   kernel: {path: ../../third_party/pkg/kernel}
+  package_config: '^1.0.0'
+  test: ^0.12.0
+  test_reflective_loader: ^0.1.0
 # TODO(sigmund): remove once kernel is moved into the sdk repo.
 dependency_overrides:
   analyzer: '^0.29.0'
diff --git a/pkg/front_end/test/memory_file_system_test.dart b/pkg/front_end/test/memory_file_system_test.dart
new file mode 100644
index 0000000..b9757f3
--- /dev/null
+++ b/pkg/front_end/test/memory_file_system_test.dart
@@ -0,0 +1,259 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
+
+library front_end.test.memory_file_system_test;
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:front_end/memory_file_system.dart';
+import 'package:path/path.dart' as pathos;
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MemoryFileSystemTestNative);
+    defineReflectiveTests(MemoryFileSystemTestPosix);
+    defineReflectiveTests(MemoryFileSystemTestWindows);
+    defineReflectiveTests(FileTest);
+  });
+}
+
+@reflectiveTest
+class FileTest extends _BaseTestNative {
+  String path;
+  MemoryFileSystemEntity file;
+
+  setUp() {
+    super.setUp();
+    path = join(tempPath, 'file.txt');
+    file = fileSystem.entityForPath(path);
+  }
+
+  test_equals_differentPaths() {
+    expect(
+        file == fileSystem.entityForPath(join(tempPath, 'file2.txt')), isFalse);
+  }
+
+  test_equals_samePath() {
+    expect(
+        file == fileSystem.entityForPath(join(tempPath, 'file.txt')), isTrue);
+  }
+
+  test_hashCode_samePath() {
+    expect(file.hashCode,
+        fileSystem.entityForPath(join(tempPath, 'file.txt')).hashCode);
+  }
+
+  test_path() {
+    expect(file.path, path);
+  }
+
+  test_readAsBytes_badUtf8() async {
+    // A file containing invalid UTF-8 can still be read as raw bytes.
+    List<int> bytes = [0xc0, 0x40]; // Invalid UTF-8
+    file.writeAsBytesSync(bytes);
+    expect(await file.readAsBytes(), bytes);
+  }
+
+  test_readAsBytes_doesNotExist() {
+    expect(file.readAsBytes(), throwsException);
+  }
+
+  test_readAsBytes_exists() async {
+    var s = 'contents';
+    file.writeAsStringSync(s);
+    expect(await file.readAsBytes(), UTF8.encode(s));
+  }
+
+  test_readAsString_badUtf8() {
+    file.writeAsBytesSync([0xc0, 0x40]); // Invalid UTF-8
+    expect(file.readAsString(), throwsException);
+  }
+
+  test_readAsString_doesNotExist() {
+    expect(file.readAsString(), throwsException);
+  }
+
+  test_readAsString_exists() async {
+    var s = 'contents';
+    file.writeAsStringSync(s);
+    expect(await file.readAsString(), s);
+  }
+
+  test_readAsString_utf8() async {
+    file.writeAsBytesSync([0xe2, 0x82, 0xac]); // Unicode € symbol, in UTF-8
+    expect(await file.readAsString(), '\u20ac');
+  }
+
+  test_writeAsBytesSync_modifyAfterRead() async {
+    file.writeAsBytesSync([1]);
+    (await file.readAsBytes())[0] = 2;
+    expect(await file.readAsBytes(), [1]);
+  }
+
+  test_writeAsBytesSync_modifyAfterWrite() async {
+    var bytes = [1];
+    file.writeAsBytesSync(bytes);
+    bytes[0] = 2;
+    expect(await file.readAsBytes(), [1]);
+  }
+
+  test_writeAsBytesSync_overwrite() async {
+    file.writeAsBytesSync([1]);
+    file.writeAsBytesSync([2]);
+    expect(await file.readAsBytes(), [2]);
+  }
+
+  test_writeAsStringSync_overwrite() async {
+    file.writeAsStringSync('first');
+    file.writeAsStringSync('second');
+    expect(await file.readAsString(), 'second');
+  }
+
+  test_writeAsStringSync_utf8() async {
+    file.writeAsStringSync('\u20ac'); // Unicode € symbol
+    expect(await file.readAsBytes(), [0xe2, 0x82, 0xac]);
+  }
+}
+
+abstract class MemoryFileSystemTestMixin extends _BaseTest {
+  Uri tempUri;
+
+  setUp() {
+    super.setUp();
+    tempUri = fileSystem.context.toUri(tempPath);
+  }
+
+  test_entityForPath() {
+    var path = join(tempPath, 'file.txt');
+    expect(fileSystem.entityForPath(path).path, path);
+  }
+
+  test_entityForPath_absolutize() {
+    expect(fileSystem.entityForPath('file.txt').path,
+        join(fileSystem.currentDirectory, 'file.txt'));
+  }
+
+  test_entityForPath_normalize_dot() {
+    expect(fileSystem.entityForPath(join(tempPath, '.', 'file.txt')).path,
+        join(tempPath, 'file.txt'));
+  }
+
+  test_entityForPath_normalize_dotDot() {
+    expect(
+        fileSystem.entityForPath(join(tempPath, 'foo', '..', 'file.txt')).path,
+        join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri() {
+    expect(fileSystem.entityForUri(Uri.parse('$tempUri/file.txt')).path,
+        join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri_bareUri_absolute() {
+    expect(() => fileSystem.entityForUri(Uri.parse('/file.txt')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_bareUri_relative() {
+    expect(() => fileSystem.entityForUri(Uri.parse('file.txt')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_fileUri_relative() {
+    // A weird quirk of the Uri class is that it doesn't seem possible to create
+    // a `file:` uri with a relative path, no matter how many slashes you use or
+    // if you populate the fields directly.  But just to be certain, try to do
+    // so, and make that `file:` uris with relative paths are rejected.
+    for (var uri in <Uri>[
+      new Uri(scheme: 'file', path: 'file.txt'),
+      Uri.parse('file:file.txt'),
+      Uri.parse('file:/file.txt'),
+      Uri.parse('file://file.txt'),
+      Uri.parse('file:///file.txt')
+    ]) {
+      if (!uri.path.startsWith('/')) {
+        expect(() => fileSystem.entityForUri(uri),
+            throwsA(new isInstanceOf<Error>()));
+      }
+    }
+  }
+
+  test_entityForUri_nonFileUri() {
+    expect(() => fileSystem.entityForUri(Uri.parse('package:foo/bar.dart')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_normalize_dot() {
+    expect(fileSystem.entityForUri(Uri.parse('$tempUri/./file.txt')).path,
+        join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri_normalize_dotDot() {
+    expect(fileSystem.entityForUri(Uri.parse('$tempUri/foo/../file.txt')).path,
+        join(tempPath, 'file.txt'));
+  }
+}
+
+@reflectiveTest
+class MemoryFileSystemTestNative extends _BaseTestNative
+    with MemoryFileSystemTestMixin {}
+
+@reflectiveTest
+class MemoryFileSystemTestPosix extends _BaseTestPosix
+    with MemoryFileSystemTestMixin {}
+
+@reflectiveTest
+class MemoryFileSystemTestWindows extends _BaseTestWindows
+    with MemoryFileSystemTestMixin {}
+
+abstract class _BaseTest {
+  MemoryFileSystem get fileSystem;
+  String get tempPath;
+  String join(String path1, String path2, [String path3, String path4]);
+  void setUp();
+}
+
+class _BaseTestNative extends _BaseTest {
+  MemoryFileSystem fileSystem;
+  String tempPath;
+
+  String join(String path1, String path2, [String path3, String path4]) =>
+      pathos.join(path1, path2, path3, path4);
+
+  setUp() {
+    tempPath = pathos.join(io.Directory.systemTemp.path, 'test_file_system');
+    fileSystem =
+        new MemoryFileSystem(pathos.context, io.Directory.current.path);
+  }
+}
+
+class _BaseTestPosix extends _BaseTest {
+  MemoryFileSystem fileSystem;
+  String tempPath;
+
+  String join(String path1, String path2, [String path3, String path4]) =>
+      pathos.posix.join(path1, path2, path3, path4);
+
+  void setUp() {
+    tempPath = '/test_file_system';
+    fileSystem = new MemoryFileSystem(pathos.posix, '/cwd');
+  }
+}
+
+class _BaseTestWindows extends _BaseTest {
+  MemoryFileSystem fileSystem;
+  String tempPath;
+
+  String join(String path1, String path2, [String path3, String path4]) =>
+      pathos.windows.join(path1, path2, path3, path4);
+
+  void setUp() {
+    tempPath = r'c:\test_file_system';
+    fileSystem = new MemoryFileSystem(pathos.windows, r'c:\cwd');
+  }
+}
diff --git a/pkg/front_end/test/physical_file_system_test.dart b/pkg/front_end/test/physical_file_system_test.dart
new file mode 100644
index 0000000..5c07a8c
--- /dev/null
+++ b/pkg/front_end/test/physical_file_system_test.dart
@@ -0,0 +1,212 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
+
+library front_end.test.physical_file_system_test;
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:front_end/file_system.dart';
+import 'package:front_end/physical_file_system.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(PhysicalFileSystemTest);
+    defineReflectiveTests(FileTest);
+  });
+}
+
+@reflectiveTest
+class FileTest extends _BaseTest {
+  String path;
+  FileSystemEntity file;
+
+  setUp() {
+    super.setUp();
+    path = p.join(tempPath, 'file.txt');
+    file = PhysicalFileSystem.instance.entityForPath(path);
+  }
+
+  test_equals_differentPaths() {
+    expect(
+        file ==
+            PhysicalFileSystem.instance
+                .entityForPath(p.join(tempPath, 'file2.txt')),
+        isFalse);
+  }
+
+  test_equals_samePath() {
+    expect(
+        file ==
+            PhysicalFileSystem.instance
+                .entityForPath(p.join(tempPath, 'file.txt')),
+        isTrue);
+  }
+
+  test_hashCode_samePath() {
+    expect(
+        file.hashCode,
+        PhysicalFileSystem.instance
+            .entityForPath(p.join(tempPath, 'file.txt'))
+            .hashCode);
+  }
+
+  test_path() {
+    expect(file.path, path);
+  }
+
+  test_readAsBytes_badUtf8() async {
+    // A file containing invalid UTF-8 can still be read as raw bytes.
+    List<int> bytes = [0xc0, 0x40]; // Invalid UTF-8
+    new io.File(path).writeAsBytesSync(bytes);
+    expect(await file.readAsBytes(), bytes);
+  }
+
+  test_readAsBytes_doesNotExist() {
+    expect(file.readAsBytes(), throwsException);
+  }
+
+  test_readAsBytes_exists() async {
+    var s = 'contents';
+    new io.File(path).writeAsStringSync(s);
+    expect(await file.readAsBytes(), UTF8.encode(s));
+  }
+
+  test_readAsString_badUtf8() {
+    new io.File(path).writeAsBytesSync([0xc0, 0x40]); // Invalid UTF-8
+    expect(file.readAsString(), throwsException);
+  }
+
+  test_readAsString_doesNotExist() {
+    expect(file.readAsString(), throwsException);
+  }
+
+  test_readAsString_exists() async {
+    var s = 'contents';
+    new io.File(path).writeAsStringSync(s);
+    expect(await file.readAsString(), s);
+  }
+
+  test_readAsString_utf8() async {
+    var bytes = [0xe2, 0x82, 0xac]; // Unicode € symbol (in UTF-8)
+    new io.File(path).writeAsBytesSync(bytes);
+    expect(await file.readAsString(), '\u20ac');
+  }
+}
+
+@reflectiveTest
+class PhysicalFileSystemTest extends _BaseTest {
+  Uri tempUri;
+
+  setUp() {
+    super.setUp();
+    tempUri = new Uri.directory(tempPath);
+  }
+
+  test_entityForPath() {
+    var path = p.join(tempPath, 'file.txt');
+    expect(PhysicalFileSystem.instance.entityForPath(path).path, path);
+  }
+
+  test_entityForPath_absolutize() {
+    expect(PhysicalFileSystem.instance.entityForPath('file.txt').path,
+        new io.File('file.txt').absolute.path);
+  }
+
+  test_entityForPath_normalize_dot() {
+    expect(
+        PhysicalFileSystem.instance
+            .entityForPath(p.join(tempPath, '.', 'file.txt'))
+            .path,
+        p.join(tempPath, 'file.txt'));
+  }
+
+  test_entityForPath_normalize_dotDot() {
+    expect(
+        PhysicalFileSystem.instance
+            .entityForPath(p.join(tempPath, 'foo', '..', 'file.txt'))
+            .path,
+        p.join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri() {
+    expect(
+        PhysicalFileSystem.instance
+            .entityForUri(Uri.parse('$tempUri/file.txt'))
+            .path,
+        p.join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri_bareUri_absolute() {
+    expect(
+        () => PhysicalFileSystem.instance.entityForUri(Uri.parse('/file.txt')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_bareUri_relative() {
+    expect(
+        () => PhysicalFileSystem.instance.entityForUri(Uri.parse('file.txt')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_fileUri_relative() {
+    // A weird quirk of the Uri class is that it doesn't seem possible to create
+    // a `file:` uri with a relative path, no matter how many slashes you use or
+    // if you populate the fields directly.  But just to be certain, try to do
+    // so, and make that `file:` uris with relative paths are rejected.
+    for (var uri in <Uri>[
+      new Uri(scheme: 'file', path: 'file.txt'),
+      Uri.parse('file:file.txt'),
+      Uri.parse('file:/file.txt'),
+      Uri.parse('file://file.txt'),
+      Uri.parse('file:///file.txt')
+    ]) {
+      if (!uri.path.startsWith('/')) {
+        expect(() => PhysicalFileSystem.instance.entityForUri(uri),
+            throwsA(new isInstanceOf<Error>()));
+      }
+    }
+  }
+
+  test_entityForUri_nonFileUri() {
+    expect(
+        () => PhysicalFileSystem.instance
+            .entityForUri(Uri.parse('package:foo/bar.dart')),
+        throwsA(new isInstanceOf<Error>()));
+  }
+
+  test_entityForUri_normalize_dot() {
+    expect(
+        PhysicalFileSystem.instance
+            .entityForUri(Uri.parse('$tempUri/./file.txt'))
+            .path,
+        p.join(tempPath, 'file.txt'));
+  }
+
+  test_entityForUri_normalize_dotDot() {
+    expect(
+        PhysicalFileSystem.instance
+            .entityForUri(Uri.parse('$tempUri/foo/../file.txt'))
+            .path,
+        p.join(tempPath, 'file.txt'));
+  }
+}
+
+class _BaseTest {
+  io.Directory tempDirectory;
+  String tempPath;
+
+  setUp() {
+    tempDirectory = io.Directory.systemTemp.createTempSync('test_file_system');
+    tempPath = tempDirectory.absolute.path;
+  }
+
+  tearDown() {
+    tempDirectory.deleteSync(recursive: true);
+  }
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d0913e6..ee9fe4a 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -26,6 +26,7 @@
 mutation_observer: Skip # Issue 21149
 unittest/*: Skip # Issue 21949
 lookup_map/*: SkipByDesign
+front_end/*: SkipByDesign
 
 [ $runtime == vm && $mode == debug ]
 analysis_server/test/completion_test: Pass, Slow
@@ -53,6 +54,8 @@
 front_end/tool/*: SkipByDesign # Only meant to run on vm
 lookup_map/test/version_check_test: SkipByDesign # Only meant to run in vm.
 typed_data/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
+front_end/test/memory_file_system_test: CompileTimeError # Issue 23773
+front_end/test/physical_file_system_test: SkipByDesign # Uses dart:io
 
 [ $compiler == dart2js && $builder_tag != dart2js_analyzer ]
 analyzer/test/*: Skip # Issue 26813
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index dc6ee17..874e442 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -27,9 +27,6 @@
 // using functions listed in io_natives.cc.
 #define BUILTIN_NATIVE_LIST(V)                                                 \
   V(Builtin_PrintString, 1)                                                    \
-  V(Builtin_LoadSource, 4)                                                     \
-  V(Builtin_AsyncLoadError, 3)                                                 \
-  V(Builtin_DoneLoading, 0)                                                    \
   V(Builtin_GetCurrentDirectory, 0)                                            \
 
 
diff --git a/runtime/bin/crypto_fuchsia.cc b/runtime/bin/crypto_fuchsia.cc
index 04c5f22..b4c84d0 100644
--- a/runtime/bin/crypto_fuchsia.cc
+++ b/runtime/bin/crypto_fuchsia.cc
@@ -19,8 +19,9 @@
     const intptr_t len =
         (MX_CPRNG_DRAW_MAX_LEN < remaining) ? MX_CPRNG_DRAW_MAX_LEN
                                             : remaining;
-    const mx_ssize_t res = mx_cprng_draw(buffer + read, len);
-    if (res == ERR_INVALID_ARGS) {
+    mx_size_t res = 0;
+    const mx_status_t status = mx_cprng_draw(buffer + read, len, &res);
+    if (status != NO_ERROR) {
       return false;
     }
     read += res;
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index dd13e6d..ff8b53d 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -545,122 +545,6 @@
 }
 
 
-// Callback function, gets called from asynchronous script and library
-// reading code when there is an i/o error.
-void FUNCTION_NAME(Builtin_AsyncLoadError)(Dart_NativeArguments args) {
-  //  Dart_Handle source_uri = Dart_GetNativeArgument(args, 0);
-  Dart_Handle library_uri = Dart_GetNativeArgument(args, 1);
-  Dart_Handle error = Dart_GetNativeArgument(args, 2);
-
-  Dart_Handle library = Dart_LookupLibrary(library_uri);
-  // If a library with the given uri exists, give it a chance to handle
-  // the error. If the load requests stems from a deferred library load,
-  // an IO error is not fatal.
-  if (!Dart_IsError(library)) {
-    ASSERT(Dart_IsLibrary(library));
-    Dart_Handle res = Dart_LibraryHandleError(library, error);
-    if (Dart_IsNull(res)) {
-      return;
-    }
-  }
-  // The error was not handled above. Propagate an unhandled exception.
-  error = Dart_NewUnhandledExceptionError(error);
-  Dart_PropagateError(error);
-}
-
-
-// Callback function that gets called from dartutils when the library
-// source has been read. Loads the library or part into the VM.
-void FUNCTION_NAME(Builtin_LoadSource)(Dart_NativeArguments args) {
-  Dart_Handle tag_in = Dart_GetNativeArgument(args, 0);
-  Dart_Handle resolved_script_uri = Dart_GetNativeArgument(args, 1);
-  Dart_Handle library_uri = Dart_GetNativeArgument(args, 2);
-  Dart_Handle source_data = Dart_GetNativeArgument(args, 3);
-
-  Dart_TypedData_Type type = Dart_GetTypeOfExternalTypedData(source_data);
-  bool external = type == Dart_TypedData_kUint8;
-  uint8_t* data = NULL;
-  intptr_t num_bytes;
-  Dart_Handle result = Dart_TypedDataAcquireData(
-      source_data, &type, reinterpret_cast<void**>(&data), &num_bytes);
-  if (Dart_IsError(result)) Dart_PropagateError(result);
-
-  uint8_t* buffer_copy = NULL;
-  if (!external) {
-    // If the buffer is not external, take a copy.
-    buffer_copy = reinterpret_cast<uint8_t*>(malloc(num_bytes));
-    memmove(buffer_copy, data, num_bytes);
-    data = buffer_copy;
-  }
-
-  Dart_TypedDataReleaseData(source_data);
-
-  if (Dart_IsNull(tag_in) && Dart_IsNull(library_uri)) {
-    // Entry file. Check for payload and load accordingly.
-    const uint8_t* payload = data;
-    const DartUtils::MagicNumber payload_type =
-        DartUtils::SniffForMagicNumber(&payload, &num_bytes);
-
-    if (payload_type == DartUtils::kSnapshotMagicNumber) {
-      result = Dart_LoadScriptFromSnapshot(payload, num_bytes);
-    } else if (payload_type == DartUtils::kKernelMagicNumber) {
-      UNREACHABLE();
-    } else {
-      Dart_Handle source = Dart_NewStringFromUTF8(data, num_bytes);
-      if (Dart_IsError(source)) {
-        result = DartUtils::NewError("%s is not a valid UTF-8 script",
-                                     resolved_script_uri);
-      } else {
-        result = Dart_LoadScript(resolved_script_uri, Dart_Null(),
-                                 source, 0, 0);
-      }
-    }
-  } else {
-    int64_t tag = DartUtils::GetIntegerValue(tag_in);
-
-    Dart_Handle source = Dart_NewStringFromUTF8(data, num_bytes);
-    if (Dart_IsError(source)) {
-      result = DartUtils::NewError("%s is not a valid UTF-8 script",
-                                   resolved_script_uri);
-    } else {
-      if (tag == Dart_kImportTag) {
-        result = Dart_LoadLibrary(resolved_script_uri, Dart_Null(),
-                                  source, 0, 0);
-      } else {
-        ASSERT(tag == Dart_kSourceTag);
-        Dart_Handle library = Dart_LookupLibrary(library_uri);
-        if (Dart_IsError(library)) {
-          Dart_PropagateError(library);
-        }
-        result = Dart_LoadSource(library, resolved_script_uri, Dart_Null(),
-                                 source, 0, 0);
-      }
-    }
-  }
-
-  if (buffer_copy != NULL) {
-    free(buffer_copy);
-  }
-
-  if (Dart_IsError(result)) {
-    Dart_PropagateError(result);
-  }
-}
-
-
-// Callback function that gets called from dartutils when there are
-// no more outstanding load requests.
-void FUNCTION_NAME(Builtin_DoneLoading)(Dart_NativeArguments args) {
-  Dart_Handle res = Dart_FinalizeLoading(true);
-  if (Dart_IsError(res)) {
-    // TODO(hausner): If compilation/loading errors are supposed to
-    // be observable by the program, we need to mark the bad library
-    // with the error instead of propagating it.
-    Dart_PropagateError(res);
-  }
-}
-
-
 void FUNCTION_NAME(Builtin_GetCurrentDirectory)(Dart_NativeArguments args) {
   const char* current = Directory::Current();
   if (current != NULL) {
diff --git a/runtime/bin/eventhandler_fuchsia.cc b/runtime/bin/eventhandler_fuchsia.cc
index 0d52f55..3e7096b 100644
--- a/runtime/bin/eventhandler_fuchsia.cc
+++ b/runtime/bin/eventhandler_fuchsia.cc
@@ -36,29 +36,17 @@
   if (descriptor_infos_ == NULL) {
     FATAL("Failed to allocate descriptor_infos array");
   }
-  handles_ = static_cast<mx_handle_t*>(
-      malloc(kInitialCapacity * sizeof(*handles_)));
-  if (handles_ == NULL) {
-    FATAL("Failed to allocate handles array");
-  }
-  signals_ = static_cast<mx_signals_t*>(
-      malloc(kInitialCapacity * sizeof(*signals_)));
-  if (signals_ == NULL) {
-    FATAL("Failed to allocate signals array");
-  }
-  signals_states_ = static_cast<mx_signals_state_t*>(
-      malloc(kInitialCapacity * sizeof(*signals_states_)));
-  if (signals_states_ == NULL) {
-    FATAL("Failed to allocate signals_states array");
+  items_ = static_cast<mx_wait_item_t*>(
+      malloc(kInitialCapacity * sizeof(*items_)));
+  if (items_ == NULL) {
+    FATAL("Failed to allocate items array");
   }
 }
 
 
 MagentaWaitManyInfo::~MagentaWaitManyInfo() {
   free(descriptor_infos_);
-  free(handles_);
-  free(signals_);
-  free(signals_states_);
+  free(items_);
 }
 
 
@@ -68,7 +56,7 @@
 #if defined(DEBUG)
   // Check that the handle is not already in the list.
   for (intptr_t i = 0; i < size_; i++) {
-    if (handles_[i] == handle) {
+    if (items_[i].handle == handle) {
       FATAL("The handle is already in the list!");
     }
   }
@@ -76,10 +64,9 @@
   intptr_t new_size = size_ + 1;
   GrowArraysIfNeeded(new_size);
   descriptor_infos_[size_] = di;
-  handles_[size_] = handle;
-  signals_[size_] = signals;
-  signals_states_[size_].satisfied = MX_SIGNAL_NONE;
-  signals_states_[size_].satisfiable = MX_SIGNAL_NONE;
+  items_[size_].handle = handle;
+  items_[size_].waitfor = signals;
+  items_[size_].pending = 0;
   size_ = new_size;
   LOG_INFO("AddHandle(%ld, %ld, %p), size = %ld\n", handle, signals, di, size_);
 }
@@ -88,7 +75,7 @@
 void MagentaWaitManyInfo::RemoveHandle(mx_handle_t handle) {
   intptr_t idx;
   for (idx = 1; idx < size_; idx++) {
-    if (handle == handles_[idx]) {
+    if (handle == items_[idx].handle) {
       break;
     }
   }
@@ -98,15 +85,10 @@
 
   if (idx != (size_ - 1)) {
     descriptor_infos_[idx] = descriptor_infos_[size_ - 1];
-    handles_[idx] = handles_[size_ - 1];
-    signals_[idx] = signals_[size_ - 1];
-    signals_states_[idx] = signals_states_[size_ - 1];
+    items_[idx] = items_[size_ - 1];
   }
   descriptor_infos_[size_ - 1] = NULL;
-  handles_[size_ - 1] = MX_HANDLE_INVALID;
-  signals_[size_ - 1] = MX_SIGNAL_NONE;
-  signals_states_[size_ - 1].satisfied = MX_SIGNAL_NONE;
-  signals_states_[size_ - 1].satisfiable = MX_SIGNAL_NONE;
+  items_[size_ - 1] = {MX_HANDLE_INVALID, 0, 0};
   size_ = size_ - 1;
   LOG_INFO("RemoveHandle(%ld), size = %ld\n", handle, size_);
 }
@@ -122,20 +104,10 @@
   if (descriptor_infos_ == NULL) {
     FATAL("Failed to grow descriptor_infos array");
   }
-  handles_ = static_cast<mx_handle_t*>(
-      realloc(handles_, new_capacity * sizeof(*handles_)));
-  if (handles_ == NULL) {
-    FATAL("Failed to grow handles array");
-  }
-  signals_ = static_cast<mx_signals_t*>(
-      realloc(signals_, new_capacity * sizeof(*signals_)));
-  if (signals_ == NULL) {
-    FATAL("Failed to grow signals array");
-  }
-  signals_states_ = static_cast<mx_signals_state_t*>(
-      realloc(signals_states_, new_capacity * sizeof(*signals_states_)));
-  if (signals_states_ == NULL) {
-    FATAL("Failed to grow signals_states array");
+  items_ = static_cast<mx_wait_item_t*>(
+      realloc(items_, new_capacity * sizeof(*items_)));
+  if (items_ == NULL) {
+    FATAL("Failed to grow items array");
   }
   capacity_ = new_capacity;
   LOG_INFO("GrowArraysIfNeeded(%ld), capacity = %ld\n",
@@ -144,9 +116,10 @@
 
 
 EventHandlerImplementation::EventHandlerImplementation() {
-  mx_status_t status = mx_msgpipe_create(interrupt_handles_, 0);
+  mx_status_t status = mx_channel_create(0, &interrupt_handles_[0],
+                                         &interrupt_handles_[1]);
   if (status != NO_ERROR) {
-    FATAL1("mx_msgpipe_create failed: %s\n", mx_status_get_string(status));
+    FATAL1("mx_channel_create failed: %s\n", mx_status_get_string(status));
   }
   shutdown_ = false;
   info_.AddHandle(interrupt_handles_[0],
@@ -178,9 +151,9 @@
   msg.data = data;
 
   mx_status_t status =
-    mx_msgpipe_write(interrupt_handles_[1], &msg, sizeof(msg), NULL, 0, 0);
+    mx_channel_write(interrupt_handles_[1], 0, &msg, sizeof(msg), NULL, 0);
   if (status != NO_ERROR) {
-    FATAL1("mx_msgpipe_write failed: %s\n", mx_status_get_string(status));
+    FATAL1("mx_channel_write failed: %s\n", mx_status_get_string(status));
   }
   LOG_INFO("WakeupHandler(%ld, %ld, %lld)\n", id, dart_port, data);
 }
@@ -192,8 +165,8 @@
   uint32_t bytes = kInterruptMessageSize;
   mx_status_t status;
   while (true) {
-    status = mx_msgpipe_read(
-        interrupt_handles_[0], &msg, &bytes, NULL, NULL, 0);
+    status = mx_channel_read(
+        interrupt_handles_[0], 0, &msg, bytes, &bytes, NULL, 0, NULL);
     if (status != NO_ERROR) {
       break;
     }
@@ -213,7 +186,7 @@
   // status == ERR_SHOULD_WAIT when we try to read and there are no messages
   // available, so it is an error if we get here and status != ERR_SHOULD_WAIT.
   if (status != ERR_SHOULD_WAIT) {
-    FATAL1("mx_msgpipe_read failed: %s\n", mx_status_get_string(status));
+    FATAL1("mx_channel_read failed: %s\n", mx_status_get_string(status));
   }
   LOG_INFO("HandleInterruptFd exit\n");
 }
@@ -222,20 +195,21 @@
 void EventHandlerImplementation::HandleEvents() {
   LOG_INFO("HandleEvents entry\n");
   for (intptr_t i = 1; i < info_.size(); i++) {
-    if (info_.signals_states()[i].satisfied != MX_SIGNAL_NONE) {
+    const mx_wait_item_t& wait_item = info_.items()[i];
+    if (wait_item.pending & wait_item.waitfor) {
       // Only the control handle has no descriptor info.
       ASSERT(info_.descriptor_infos()[i] != NULL);
-      ASSERT(info_.handles()[i] != interrupt_handles_[0]);
+      ASSERT(wait_item.handle != interrupt_handles_[0]);
       // TODO(zra): Handle events on other handles. At the moment we are
       // only interrupted when there is a message on interrupt_handles_[0].
       UNIMPLEMENTED();
     }
   }
 
-  if ((info_.signals_states()[0].satisfied & MX_SIGNAL_PEER_CLOSED) != 0) {
+  if ((info_.items()[0].pending & MX_SIGNAL_PEER_CLOSED) != 0) {
     FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n");
   }
-  if ((info_.signals_states()[0].satisfied & MX_SIGNAL_READABLE) != 0) {
+  if ((info_.items()[0].pending & MX_SIGNAL_READABLE) != 0) {
     LOG_INFO("HandleEvents interrupt_handles_[0] readable\n");
     HandleInterruptFd();
   } else {
@@ -277,17 +251,12 @@
     mx_time_t timeout =
         millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond;
     const MagentaWaitManyInfo& info = handler_impl->info();
-    uint32_t result_index;
-    LOG_INFO("mx_handle_wait_many(%ld, %p, %p, %lld, %p, %p)\n",
-        info.size(), info.handles(), info.signals(), timeout, &result_index,
-        info.signals_states());
+    LOG_INFO("mx_handle_wait_many(%p, %ld, %lld)\n",
+        info.items(), info.size(), timeout);
     mx_status_t status = mx_handle_wait_many(
+        info.items(),
         info.size(),
-        info.handles(),
-        info.signals(),
-        timeout,
-        &result_index,
-        info.signals_states());
+        timeout);
     if ((status != NO_ERROR) && (status != ERR_TIMED_OUT)) {
       FATAL1("mx_handle_wait_many failed: %s\n", mx_status_get_string(status));
     } else {
diff --git a/runtime/bin/eventhandler_fuchsia.h b/runtime/bin/eventhandler_fuchsia.h
index 27e4903..a15b4e1 100644
--- a/runtime/bin/eventhandler_fuchsia.h
+++ b/runtime/bin/eventhandler_fuchsia.h
@@ -63,9 +63,7 @@
   intptr_t capacity() const { return capacity_; }
   intptr_t size() const { return size_; }
   DescriptorInfo** descriptor_infos() const { return descriptor_infos_; }
-  mx_handle_t* handles() const { return handles_; }
-  mx_signals_t* signals() const { return signals_; }
-  mx_signals_state_t* signals_states() const { return signals_states_; }
+  mx_wait_item_t* items() const { return items_; }
 
   void AddHandle(mx_handle_t handle, mx_signals_t signals, DescriptorInfo* di);
   void RemoveHandle(mx_handle_t handle);
@@ -78,9 +76,7 @@
   intptr_t capacity_;
   intptr_t size_;
   DescriptorInfo** descriptor_infos_;
-  mx_handle_t* handles_;
-  mx_signals_t* signals_;
-  mx_signals_state_t* signals_states_;
+  mx_wait_item_t* items_;
 
   DISALLOW_COPY_AND_ASSIGN(MagentaWaitManyInfo);
 };
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index fe76e51..5ed1ed8 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -16,8 +16,6 @@
 class EventHandler;
 class Loader;
 
-typedef void (*ExitHook)(int64_t exit_code);
-
 // Data associated with every isolate in the standalone VM
 // embedding. This is used to free external resources for each isolate
 // when the isolate shuts down.
@@ -31,8 +29,7 @@
         packages_file(NULL),
         udp_receive_buffer(NULL),
         builtin_lib_(NULL),
-        loader_(NULL),
-        exit_hook_(NULL) {
+        loader_(NULL) {
     if (package_root != NULL) {
       ASSERT(packages_file == NULL);
       this->package_root = strdup(package_root);
@@ -67,9 +64,6 @@
     builtin_lib_ = Dart_NewPersistentHandle(lib);
   }
 
-  ExitHook exit_hook() const { return exit_hook_; }
-  void set_exit_hook(ExitHook hook) { exit_hook_ = hook; }
-
   char* script_url;
   char* package_root;
   char* packages_file;
@@ -89,7 +83,6 @@
  private:
   Dart_Handle builtin_lib_;
   Loader* loader_;
-  ExitHook exit_hook_;
 
   DISALLOW_COPY_AND_ASSIGN(IsolateData);
 };
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index c953b62..773fdda 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -105,6 +105,9 @@
 static bool trace_loading = false;
 
 
+static Dart_Isolate main_isolate = NULL;
+
+
 static const char* DEFAULT_VM_SERVICE_SERVER_IP = "127.0.0.1";
 static const int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
 // VM Service options.
@@ -798,9 +801,6 @@
   IsolateData* isolate_data = new IsolateData(script_uri,
                                               package_root,
                                               packages_config);
-  if (gen_snapshot_kind == kAppJIT) {
-    isolate_data->set_exit_hook(SnapshotOnExitHook);
-  }
   Dart_Isolate isolate = Dart_CreateIsolate(script_uri,
                                             main,
                                             isolate_snapshot_buffer,
@@ -1539,6 +1539,11 @@
 
 
 static void SnapshotOnExitHook(int64_t exit_code) {
+  if (Dart_CurrentIsolate() != main_isolate) {
+    Log::PrintErr("A snapshot was requested, but a secondary isolate "
+                  "performed a hard exit (%" Pd64 ").\n", exit_code);
+    Platform::Exit(kErrorExitCode);
+  }
   if (exit_code == 0) {
     GenerateAppSnapshot();
   }
@@ -1577,6 +1582,7 @@
     EventHandler::Stop();
     Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
   }
+  main_isolate = isolate;
   delete [] isolate_name;
 
   Dart_EnterIsolate(isolate);
@@ -1891,6 +1897,9 @@
 #if defined(DART_PRECOMPILED_RUNTIME)
   vm_options.AddArgument("--precompilation");
 #endif
+  if (gen_snapshot_kind == kAppJIT) {
+    Process::SetExitHook(SnapshotOnExitHook);
+  }
 
   Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
 
diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc
index d09a8be..1d3814d 100644
--- a/runtime/bin/platform.cc
+++ b/runtime/bin/platform.cc
@@ -40,7 +40,7 @@
 
 
 void FUNCTION_NAME(Platform_ExecutableName)(Dart_NativeArguments args) {
-  if (Dart_IsRunningPrecompiledCode()) {
+  if (Dart_IsPrecompiledRuntime()) {
     // This is a work-around to be able to use most of the existing test suite
     // for precompilation. Many tests do something like Process.run(
     // Platform.executable, some_other_script.dart). But with precompilation
@@ -60,7 +60,7 @@
 
 
 void FUNCTION_NAME(Platform_ResolvedExecutableName)(Dart_NativeArguments args) {
-  if (Dart_IsRunningPrecompiledCode()) {
+  if (Dart_IsPrecompiledRuntime()) {
     Dart_ThrowException(Dart_NewStringFromCString(
         "Platform.resolvedExecutable not supported under precompilation"));
     UNREACHABLE();
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index ee1ac49..c6b119d 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -28,7 +28,7 @@
 char** Platform::argv_ = NULL;
 
 bool Platform::Initialize() {
-  // Nothing to do on Windows.
+  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
   return true;
 }
 
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index ff88201..e22e07c 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -246,11 +246,7 @@
   int64_t status = 0;
   // Ignore result if passing invalid argument and just exit 0.
   DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status);
-  IsolateData* isolate_data =
-      reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
-  if (isolate_data->exit_hook() != NULL) {
-    isolate_data->exit_hook()(status);
-  }
+  Process::RunExitHook(status);
   Dart_ExitIsolate();
   Platform::Exit(static_cast<int>(status));
 }
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index 2886e71..4ef8929 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -126,6 +126,16 @@
     global_exit_code_ = exit_code;
   }
 
+  typedef void (*ExitHook)(int64_t exit_code);
+  static void SetExitHook(ExitHook hook) {
+    exit_hook_ = hook;
+  }
+  static void RunExitHook(int64_t exit_code) {
+    if (exit_hook_ != NULL) {
+      exit_hook_(exit_code);
+    }
+  }
+
   static intptr_t CurrentProcessId();
 
   static intptr_t SetSignalHandler(intptr_t signal);
@@ -139,6 +149,7 @@
  private:
   static int global_exit_code_;
   static Mutex* global_exit_code_mutex_;
+  static ExitHook exit_hook_;
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Process);
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 00d6ca2..89c5bf7 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -34,6 +34,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 // ProcessInfo is used to map a process id to the file descriptor for
 // the pipe used to communicate the exit code of the process to Dart.
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index 5858800..cd2f8bf 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -18,6 +18,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 void Process::TerminateExitCodeHandler() {
 }
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index e533cc5..fff03f9 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -34,6 +34,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 // ProcessInfo is used to map a process id to the file descriptor for
 // the pipe used to communicate the exit code of the process to Dart.
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index b3b5662..9f671a8 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -35,6 +35,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 // ProcessInfo is used to map a process id to the file descriptor for
 // the pipe used to communicate the exit code of the process to Dart.
diff --git a/runtime/bin/process_unsupported.cc b/runtime/bin/process_unsupported.cc
index 64bed26..d91b83c 100644
--- a/runtime/bin/process_unsupported.cc
+++ b/runtime/bin/process_unsupported.cc
@@ -15,6 +15,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 void Process::TerminateExitCodeHandler() {
 }
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index b96e67b..c373787 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -29,6 +29,7 @@
 
 int Process::global_exit_code_ = 0;
 Mutex* Process::global_exit_code_mutex_ = new Mutex();
+Process::ExitHook Process::exit_hook_ = NULL;
 
 // ProcessInfo is used to map a process id to the process handle,
 // wait handle for registered exit code event and the pipe used to
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index db8baf2..3c72422 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -264,15 +264,16 @@
   drain_fd(stdout_pipe, test_stdout);
   drain_fd(stderr_pipe, test_stderr);
 
-  mx_signals_state_t state;
   mx_status_t r = mx_handle_wait_one(
-      p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state);
+      p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL);
   RETURN_IF_ERROR(r);
 
   mx_info_process_t proc_info;
-  mx_ssize_t info_size = mx_object_get_info(
-      p, MX_INFO_PROCESS, sizeof(proc_info.rec), &proc_info, sizeof(proc_info));
-  RETURN_IF_ERROR(info_size);
+  mx_size_t info_size;
+  mx_status_t status =
+      mx_object_get_info(p, MX_INFO_PROCESS, sizeof(proc_info.rec),
+                         &proc_info, sizeof(proc_info), &info_size);
+  RETURN_IF_ERROR(status);
 
   r = mx_handle_close(p);
   RETURN_IF_ERROR(r);
@@ -325,7 +326,8 @@
     const char* test = args->test_list[index];
     char* test_stdout = NULL;
     char* test_stderr = NULL;
-    mx_handle_t vmo_dup = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
+    mx_handle_t vmo_dup = MX_HANDLE_INVALID;
+    mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS, &vmo_dup);
     int test_status = run_test(vmo_dup, test, &test_stdout, &test_stderr);
     handle_result(test_status, test_stdout, test_stderr, test);
     free(test_stdout);
@@ -393,8 +395,10 @@
   // Run with --list to grab the list of tests.
   char* list_stdout = NULL;
   char* list_stderr = NULL;
-  mx_handle_t list_vmo = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
-  RETURN_IF_ERROR(list_vmo);
+  mx_handle_t list_vmo = MX_HANDLE_INVALID;
+  mx_status_t status =
+      mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS, &list_vmo);
+  RETURN_IF_ERROR(status);
   int list_result = run_test(list_vmo, "--list", &list_stdout, &list_stderr);
   if (list_result != 0) {
     fprintf(stderr, "Failed to list tests: %s\n%s\n", list_stdout, list_stderr);
@@ -431,7 +435,7 @@
   }
   free(test_list);
   pthread_mutex_destroy(&args_mutex);
-  mx_status_t status = mx_handle_close(binary_vmo);
+  status = mx_handle_close(binary_vmo);
   RETURN_IF_ERROR(status);
 
   // Complain if we didn't try to run all of the tests.
diff --git a/runtime/bin/secure_socket_boringssl.cc b/runtime/bin/secure_socket_boringssl.cc
index 132588d..83f96d2 100644
--- a/runtime/bin/secure_socket_boringssl.cc
+++ b/runtime/bin/secure_socket_boringssl.cc
@@ -439,7 +439,6 @@
   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, CertificateCallback);
   SSL_CTX_set_min_version(ctx, TLS1_VERSION);
   SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM");
-  SSL_CTX_set_cipher_list_tls11(ctx, "HIGH:MEDIUM");
   SSLContext* context = new SSLContext(ctx);
   Dart_Handle err = SetSecurityContext(args, context);
   if (Dart_IsError(err)) {
diff --git a/runtime/bin/utils_fuchsia.cc b/runtime/bin/utils_fuchsia.cc
index 0809723..79a1fba 100644
--- a/runtime/bin/utils_fuchsia.cc
+++ b/runtime/bin/utils_fuchsia.cc
@@ -88,7 +88,7 @@
 
 
 int64_t TimerUtils::GetCurrentMonotonicMicros() {
-  int64_t ticks = mx_current_time();
+  int64_t ticks = mx_time_get(MX_CLOCK_MONOTONIC);
   return ticks / kNanosecondsPerMicrosecond;
 }
 
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 32ee7d6..69f0728 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -126,12 +126,23 @@
   final bool _originCheckDisabled;
   HttpServer _server;
   bool get running => _server != null;
-  bool _displayMessages = false;
 
-  Server(this._service, this._ip, this._port, this._originCheckDisabled) {
-    _displayMessages = (_ip != '127.0.0.1' || _port != 8181);
+  /// Returns the server address including the auth token.
+  Uri get serverAddress {
+    if (!running) {
+      return null;
+    }
+    var ip = _server.address.address;
+    var port = _server.port;
+    if (useAuthToken) {
+      return Uri.parse('http://$ip:$port/$serviceAuthToken/');
+    } else {
+      return Uri.parse('http://$ip:$port/');
+    }
   }
 
+  Server(this._service, this._ip, this._port, this._originCheckDisabled);
+
   bool _isAllowedOrigin(String origin) {
     Uri uri;
     try {
@@ -179,6 +190,28 @@
     return false;
   }
 
+  /// Checks the [requestUri] for the service auth token and returns the path.
+  /// If the service auth token check fails, returns null.
+  String _checkAuthTokenAndGetPath(Uri requestUri) {
+    if (!useAuthToken) {
+      return requestUri.path == '/' ? ROOT_REDIRECT_PATH : requestUri.path;
+    }
+    final List<String> requestPathSegments = requestUri.pathSegments;
+    if (requestPathSegments.length < 2) {
+      // Malformed.
+      return null;
+    }
+    // Check that we were given the auth token.
+    final String authToken = requestPathSegments[0];
+    if (authToken != serviceAuthToken) {
+      // Malformed.
+      return null;
+    }
+    // Construct the actual request path by chopping off the auth token.
+    return (requestPathSegments[1] == '') ?
+        ROOT_REDIRECT_PATH : '/${requestPathSegments.sublist(1).join('/')}';
+  }
+
   Future _requestHandler(HttpRequest request) async {
     if (!_originCheck(request)) {
       // This is a cross origin attempt to connect
@@ -231,8 +264,12 @@
       return;
     }
 
-    final String path =
-          request.uri.path == '/' ? ROOT_REDIRECT_PATH : request.uri.path;
+    final String path = _checkAuthTokenAndGetPath(request.uri);
+    if (path == null) {
+      // Malformed.
+      request.response.close();
+      return;
+    }
 
     if (path == WEBSOCKET_PATH) {
       WebSocketTransformer.upgrade(request).then(
@@ -274,18 +311,14 @@
     return HttpServer.bind(address, _port).then((s) {
       _server = s;
       _server.listen(_requestHandler, cancelOnError: true);
-      var ip = _server.address.address;
-      var port = _server.port;
-      if (_displayMessages) {
-        print('Observatory listening on http://$ip:$port');
-      }
+      print('Observatory listening on $serverAddress');
       // Server is up and running.
-      _notifyServerState(ip, _server.port);
-      onServerAddressChange('http://$ip:$port');
+      _notifyServerState(serverAddress.toString());
+      onServerAddressChange('$serverAddress');
       return this;
     }).catchError((e, st) {
       print('Could not start Observatory HTTP server:\n$e\n$st\n');
-      _notifyServerState("", 0);
+      _notifyServerState("");
       onServerAddressChange(null);
       return this;
     });
@@ -304,24 +337,18 @@
       return new Future.value(this);
     }
 
-    // Force displaying of status messages if we are forcibly shutdown.
-    _displayMessages = _displayMessages || forced;
-
     // Shutdown HTTP server and subscription.
-    var ip = _server.address.address.toString();
-    var port = _server.port.toString();
+    String oldServerAddress = serverAddress;
     return cleanup(forced).then((_) {
-      if (_displayMessages) {
-        print('Observatory no longer listening on http://$ip:$port');
-      }
+      print('Observatory no longer listening on $oldServerAddress');
       _server = null;
-      _notifyServerState("", 0);
+      _notifyServerState("");
       onServerAddressChange(null);
       return this;
     }).catchError((e, st) {
       _server = null;
       print('Could not shutdown Observatory HTTP server:\n$e\n$st\n');
-      _notifyServerState("", 0);
+      _notifyServerState("");
       onServerAddressChange(null);
       return this;
     });
@@ -329,5 +356,5 @@
 
 }
 
-void _notifyServerState(String ip, int port)
+void _notifyServerState(String uri)
     native "VMServiceIO_NotifyServerState";
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 7ae65d4..a883a73 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -162,6 +162,27 @@
   return result;
 }
 
+Future<Uri> serverInformationCallback() async {
+  _lazyServerBoot();
+  return server.serverAddress;
+}
+
+Future<Uri> webServerControlCallback(bool enable) async {
+  _lazyServerBoot();
+  if (server.running == enable) {
+    // No change.
+    return server.serverAddress;
+  }
+
+  if (enable) {
+    await server.startup();
+    return server.serverAddress;
+  } else {
+    await server.shutdown(true);
+    return server.serverAddress;
+  }
+}
+
 _clearFuture(_) {
   serverFuture = null;
 }
@@ -204,6 +225,8 @@
   VMServiceEmbedderHooks.writeStreamFile = writeStreamFileCallback;
   VMServiceEmbedderHooks.readFile = readFileCallback;
   VMServiceEmbedderHooks.listFiles = listFilesCallback;
+  VMServiceEmbedderHooks.serverInformation = serverInformationCallback;
+  VMServiceEmbedderHooks.webServerControl = webServerControlCallback;
   // Always instantiate the vmservice object so that the exit message
   // can be delivered and waiting loaders can be cancelled.
   var service = new VMService();
diff --git a/runtime/bin/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index cd40dd7..e523dad 100644
--- a/runtime/bin/vmservice_dartium.cc
+++ b/runtime/bin/vmservice_dartium.cc
@@ -77,13 +77,8 @@
 }
 
 
-const char* VmServiceServer::GetServerIP() {
-  return VmService::GetServerIP();
-}
-
-
-intptr_t VmServiceServer::GetServerPort() {
-  return VmService::GetServerPort();
+const char* VmServiceServer::GetServerAddress() {
+  return VmService::GetServerAddress();
 }
 
 
diff --git a/runtime/bin/vmservice_dartium.h b/runtime/bin/vmservice_dartium.h
index b1287f8..dfbf768 100644
--- a/runtime/bin/vmservice_dartium.h
+++ b/runtime/bin/vmservice_dartium.h
@@ -18,8 +18,7 @@
   static void Bootstrap();
   static Dart_Isolate CreateIsolate(const uint8_t* snapshot_buffer);
 
-  static const char* GetServerIP();
-  static intptr_t GetServerPort();
+  static const char* GetServerAddress();
 
   static void DecompressAssets(const uint8_t* input, unsigned int input_len,
                                uint8_t** output, unsigned int* output_length);
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 871a91c..004cf66 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -91,27 +91,20 @@
 
 void NotifyServerState(Dart_NativeArguments args) {
   Dart_EnterScope();
-  const char* ip_chars;
-  Dart_Handle ip_arg = Dart_GetNativeArgument(args, 0);
-  if (Dart_IsError(ip_arg)) {
-    VmService::SetServerIPAndPort("", 0);
+  const char* uri_chars;
+  Dart_Handle uri_arg = Dart_GetNativeArgument(args, 0);
+  if (Dart_IsError(uri_arg)) {
+    VmService::SetServerAddress("");
     Dart_ExitScope();
     return;
   }
-  Dart_Handle result = Dart_StringToCString(ip_arg, &ip_chars);
+  Dart_Handle result = Dart_StringToCString(uri_arg, &uri_chars);
   if (Dart_IsError(result)) {
-    VmService::SetServerIPAndPort("", 0);
+    VmService::SetServerAddress("");
     Dart_ExitScope();
     return;
   }
-  Dart_Handle port_arg = Dart_GetNativeArgument(args, 1);
-  if (Dart_IsError(port_arg)) {
-    VmService::SetServerIPAndPort("", 0);
-    Dart_ExitScope();
-    return;
-  }
-  int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
-  VmService::SetServerIPAndPort(ip_chars, port);
+  VmService::SetServerAddress(uri_chars);
   Dart_ExitScope();
 }
 
@@ -129,7 +122,7 @@
 
 
 static VmServiceIONativeEntry _VmServiceIONativeEntries[] = {
-  {"VMServiceIO_NotifyServerState", 2, NotifyServerState},
+  {"VMServiceIO_NotifyServerState", 1, NotifyServerState},
   {"VMServiceIO_Shutdown", 0, Shutdown },
 };
 
@@ -156,8 +149,7 @@
 
 
 const char* VmService::error_msg_ = NULL;
-char VmService::server_ip_[kServerIpStringBufferSize];
-intptr_t VmService::server_port_ = 0;
+char VmService::server_uri_[kServerUriStringBufferSize];
 
 
 bool VmService::LoadForGenPrecompiled() {
@@ -180,7 +172,7 @@
                       bool dev_mode_server) {
   Dart_Isolate isolate = Dart_CurrentIsolate();
   ASSERT(isolate != NULL);
-  SetServerIPAndPort("", 0);
+  SetServerAddress("");
 
   Dart_Handle result;
 
@@ -290,13 +282,16 @@
 }
 
 
-void VmService::SetServerIPAndPort(const char* ip, intptr_t port) {
-  if (ip == NULL) {
-    ip = "";
+void VmService::SetServerAddress(const char* server_uri) {
+  if (server_uri == NULL) {
+    server_uri = "";
   }
-  strncpy(server_ip_, ip, kServerIpStringBufferSize);
-  server_ip_[kServerIpStringBufferSize - 1] = '\0';
-  server_port_ = port;
+  const intptr_t server_uri_len = strlen(server_uri);
+  if (server_uri_len >= (kServerUriStringBufferSize - 1)) {
+    FATAL1("vm-service: Server URI exceeded length: %s\n", server_uri);
+  }
+  strncpy(server_uri_, server_uri, kServerUriStringBufferSize);
+  server_uri_[kServerUriStringBufferSize - 1] = '\0';
 }
 
 
diff --git a/runtime/bin/vmservice_impl.h b/runtime/bin/vmservice_impl.h
index 5c03c33..f923dca 100644
--- a/runtime/bin/vmservice_impl.h
+++ b/runtime/bin/vmservice_impl.h
@@ -24,21 +24,16 @@
   // Error message if startup failed.
   static const char* GetErrorMessage();
 
-  // HTTP server's IP.
-  static const char* GetServerIP() {
-    return &server_ip_[0];
-  }
-
-  // HTTP server's port.
-  static intptr_t GetServerPort() {
-    return server_port_;
+  // HTTP Server's address.
+  static const char* GetServerAddress() {
+    return &server_uri_[0];
   }
 
  private:
-  static const intptr_t kServerIpStringBufferSize = 256;
+  static const intptr_t kServerUriStringBufferSize = 1024;
   friend void NotifyServerState(Dart_NativeArguments args);
 
-  static void SetServerIPAndPort(const char* ip, intptr_t port);
+  static void SetServerAddress(const char* server_uri_);
   static Dart_Handle GetSource(const char* name);
   static Dart_Handle LoadScript(const char* name);
   static Dart_Handle LoadLibrary(const char* name);
@@ -49,8 +44,7 @@
                                        Dart_Handle url);
 
   static const char* error_msg_;
-  static char server_ip_[kServerIpStringBufferSize];
-  static intptr_t server_port_;
+  static char server_uri_[kServerUriStringBufferSize];
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(VmService);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 105bb66..2608724 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3187,19 +3187,9 @@
 
 /**
  *  Returns whether the VM only supports running from precompiled snapshots and
- *  not from any other kind of snapshot or no snapshot (that is, the VM was
+ *  not from any other kind of snapshot or from source (that is, the VM was
  *  compiled with DART_PRECOMPILED_RUNTIME).
  */
 DART_EXPORT bool Dart_IsPrecompiledRuntime();
 
-
-/**
- *  Returns whether the VM was initialized with a precompiled snapshot. Only
- *  valid after Dart_Initialize.
- *  DEPRECATED. This is currently used to disable Platform.executable and
- *  Platform.resolvedExecutable under precompilation to prevent process
- *  spawning tests from becoming fork-bombs.
- */
-DART_EXPORT bool Dart_IsRunningPrecompiledCode();
-
 #endif  /* INCLUDE_DART_API_H_ */  /* NOLINT */
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index 57a1a4c..a0e315f 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -9,6 +9,7 @@
 #include "vm/debugger.h"
 #include "vm/exceptions.h"
 #include "vm/flags.h"
+#include "vm/message.h"
 #include "vm/native_entry.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
@@ -120,4 +121,61 @@
 #endif  // PRODUCT
 }
 
+DEFINE_NATIVE_ENTRY(Developer_getServiceMajorVersion, 0) {
+#if defined(PRODUCT)
+  return Smi::New(0);
+#else
+  return Smi::New(SERVICE_PROTOCOL_MAJOR_VERSION);
+#endif
+}
+
+
+DEFINE_NATIVE_ENTRY(Developer_getServiceMinorVersion, 0) {
+#if defined(PRODUCT)
+  return Smi::New(0);
+#else
+  return Smi::New(SERVICE_PROTOCOL_MINOR_VERSION);
+#endif
+}
+
+
+static void SendNull(const SendPort& port) {
+  const Dart_Port destination_port_id = port.Id();
+  PortMap::PostMessage(new Message(
+        destination_port_id, Object::null(), Message::kNormalPriority));
+}
+
+
+DEFINE_NATIVE_ENTRY(Developer_getServerInfo, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
+#if defined(PRODUCT)
+  SendNull(port);
+  return Object::null();
+#else
+  if (!ServiceIsolate::IsRunning()) {
+    SendNull(port);
+  } else {
+    ServiceIsolate::RequestServerInfo(port);
+  }
+  return Object::null();
+#endif
+}
+
+
+DEFINE_NATIVE_ENTRY(Developer_webServerControl, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
+#if defined(PRODUCT)
+  SendNull(port);
+  return Object::null();
+#else
+  GET_NON_NULL_NATIVE_ARGUMENT(Bool, enabled, arguments->NativeArgAt(1));
+  if (!ServiceIsolate::IsRunning()) {
+    SendNull(port);
+  } else {
+    ServiceIsolate::ControlWebServer(port, enabled.value());
+  }
+  return Object::null();
+#endif
+}
+
 }  // namespace dart
diff --git a/runtime/lib/developer.dart b/runtime/lib/developer.dart
index 4c6ea7d..e9b90b9 100644
--- a/runtime/lib/developer.dart
+++ b/runtime/lib/developer.dart
@@ -149,3 +149,12 @@
   }
   replyPort.send(sb.toString());
 }
+
+@patch int _getServiceMajorVersion() native "Developer_getServiceMajorVersion";
+
+@patch int _getServiceMinorVersion() native "Developer_getServiceMinorVersion";
+
+@patch void _getServerInfo(SendPort sp) native "Developer_getServerInfo";
+
+@patch void _webServerControl(SendPort sp, bool enable)
+    native "Developer_webServerControl";
\ No newline at end of file
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index 34d7803..2fd2e97 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -6,8 +6,6 @@
   factory _Double.fromInteger(int value)
       native "Double_doubleFromInteger";
 
-  Type get runtimeType => double;
-
   // TODO: Make a stared static method for hashCode and _identityHashCode
   //       when semantics are corrected as described in:
   //       https://github.com/dart-lang/sdk/issues/2884
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index b039efa..75f354d 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -14,6 +14,15 @@
 // Scan the stack until we hit the first function in the _AssertionError
 // class. We then return the next frame's script taking inlining into account.
 static RawScript* FindScript(DartFrameIterator* iterator) {
+  if (FLAG_precompiled_runtime) {
+    // The precompiled runtime faces two issues in recovering the correct
+    // assertion text. First, the precompiled runtime does not include
+    // the inlining meta-data so we cannot walk the inline-aware stack trace.
+    // Second, the script text itself is missing so whatever script is returned
+    // from here will be missing the assertion expression text.
+    iterator->NextFrame();  // Skip _AssertionError._checkAssertion frame
+    return Exceptions::GetCallerScript(iterator);
+  }
   StackFrame* stack_frame = iterator->NextFrame();
   Code& code = Code::Handle();
   Function& func = Function::Handle();
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index 0c5b119..f465e3b 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -6,8 +6,6 @@
   // The Dart class _Bigint extending _IntegerImplementation requires a
   // default constructor.
 
-  Type get runtimeType => int;
-
   num operator +(num other) {
     var result = other._addFromInteger(this);
     if (result != null) return result;
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index e1b7a71..530b210 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -116,12 +116,54 @@
 
 DEFINE_NATIVE_ENTRY(Object_runtimeType, 1) {
   const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
-  // Special handling for following types outside this native.
-  ASSERT(!instance.IsString() && !instance.IsInteger() && !instance.IsDouble());
+  if (instance.IsString()) {
+    return Type::StringType();
+  } else if (instance.IsInteger()) {
+    return Type::IntType();
+  } else if (instance.IsDouble()) {
+    return Type::Double();
+  }
   return instance.GetType();
 }
 
 
+DEFINE_NATIVE_ENTRY(Object_haveSameRuntimeType, 2) {
+  const Instance& left = Instance::CheckedHandle(arguments->NativeArgAt(0));
+  const Instance& right = Instance::CheckedHandle(arguments->NativeArgAt(1));
+
+  const intptr_t left_cid = left.GetClassId();
+  const intptr_t right_cid = right.GetClassId();
+
+  if (left_cid != right_cid) {
+    if (RawObject::IsIntegerClassId(left_cid)) {
+      return Bool::Get(RawObject::IsIntegerClassId(right_cid)).raw();
+    } else if (RawObject::IsStringClassId(right_cid)) {
+      return Bool::Get(RawObject::IsStringClassId(right_cid)).raw();
+    } else {
+      return Bool::False().raw();
+    }
+  }
+
+  const Class& cls = Class::Handle(left.clazz());
+  if (cls.IsClosureClass()) {
+    // TODO(vegorov): provide faster implementation for closure classes.
+    const AbstractType& left_type = AbstractType::Handle(left.GetType());
+    const AbstractType& right_type = AbstractType::Handle(right.GetType());
+    return Bool::Get(left_type.raw() == right_type.raw()).raw();
+  }
+
+  if (!cls.IsGeneric()) {
+    return Bool::True().raw();
+  }
+
+  const TypeArguments& left_type_arguments =
+      TypeArguments::Handle(left.GetTypeArguments());
+  const TypeArguments& right_type_arguments =
+      TypeArguments::Handle(right.GetTypeArguments());
+  return Bool::Get(left_type_arguments.Equals(right_type_arguments)).raw();
+}
+
+
 DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
   const Instance& instance =
       Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index 8959feb..d83ba13 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -53,6 +53,8 @@
 
   @patch Type get runtimeType native "Object_runtimeType";
 
+  static bool _haveSameRuntimeType(a, b) native "Object_haveSameRuntimeType";
+
   // Call this function instead of inlining instanceof, thus collecting
   // type feedback and reducing code size of unoptimized code.
   bool _instanceOf(instantiator_type_arguments, type, bool negate)
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index 17962df..5abad66 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -83,8 +83,6 @@
         "_StringBase can't be instaniated");
   }
 
-  Type get runtimeType => String;
-
   int get hashCode native "String_getHashCode";
 
   bool get _isOneByte {
diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn
index 5058eed..4978c1a 100644
--- a/runtime/observatory/BUILD.gn
+++ b/runtime/observatory/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("../../utils/invoke_dart.gni")
+
 # Currently paths here are hard coded for convenience in building Mojo/Flutter.
 declare_args() {
   # Specify the path to a host compatible version of the Dart SDK.
@@ -10,9 +12,40 @@
 
   # Specify the path to a host compatible version of pub.
   # This is used to compile the Observatory frontend sources.
+  #
+  # The observatory build tool searches for pub first using this GN arg, then
+  # for the checked-in SDK, and if that doesn't work, it uses the dart_bootstrap
+  # built as part of the build to invoke pub. If this arg is set to a non-empty
+  # string, we assume that there is no need for dart_bootstrap. If it is set to
+  # "", then we assume that there may be a need for dart_bootstrap.
   dart_host_pub_exe = rebase_path("$dart_host_sdk/bin/pub")
 }
 
+# Construct arguments to the observatory tool for finding pub.
+pub_build_deps = []
+pub_build_args = []
+if (dart_host_pub_exe != "") {
+  pub_build_args = [
+    "--pub-executable",
+    dart_host_pub_exe,
+  ]
+} else {
+  pub_build_deps += [ "../bin:dart_bootstrap($host_toolchain)" ]
+
+  dart_out_dir =
+      get_label_info("../bin:dart_bootstrap($host_toolchain)", "root_out_dir")
+  dart_bootstrap =
+      rebase_path("$dart_out_dir/dart_bootstrap$dart_executable_suffix")
+
+  pub_build_args = [
+    "--sdk=True",
+    "--dart-executable",
+    dart_bootstrap,
+  ]
+}
+
+current_dir = rebase_path(".", "//")
+
 # Helper build rules for packaging the Dart observatory resources.
 observatory_sources_gypi =
     exec_script("../../tools/gypi_to_gn.py",
@@ -28,30 +61,25 @@
 }
 
 action("write_observatory_pubspec_yaml") {
-  deps = [
-    ":copy_observatory",
-  ]
-
-  script = "../../tools/observatory_tool.py"
+  deps = [ ":copy_observatory" ] + pub_build_deps
 
   inputs = [
     rebase_path("pubspec.yaml"),
   ]
 
-  current_dir = rebase_path(".", "//")
-  args = [
-    "--silent=True",
-    "--pub-executable",
-    dart_host_pub_exe,
-    "--directory",
-    rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
-    "--command",
-    "rewrite",
-    rebase_path("../observatory/pubspec.yaml"),
-    rebase_path("$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml"),
-    "../../third_party/",
-    rebase_path("../../third_party/"),
-  ]
+  script = "../../tools/observatory_tool.py"
+  args =
+      pub_build_args + [
+        "--silent=True",
+        "--directory",
+        rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
+        "--command",
+        "rewrite",
+        rebase_path("../observatory/pubspec.yaml"),
+        rebase_path("$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml"),
+        "../../third_party/",
+        rebase_path("../../third_party/"),
+      ]
 
   outputs = [
     "$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml",
@@ -59,29 +87,23 @@
 }
 
 action("copy_observatory_deps") {
-  deps = [
-    ":write_observatory_pubspec_yaml",
-  ]
+  deps = [ ":write_observatory_pubspec_yaml" ] + pub_build_deps
 
-  script = "../../tools/observatory_tool.py"
-
-  current_dir = rebase_path(".", "//")
   inputs = [
-    script,
     "$root_gen_dir/observatory_copy/$current_dir/pubspec.yaml",
   ]
 
-  args = [
-    "--silent=True",
-    "--pub-executable",
-    dart_host_pub_exe,
-    "--stamp",
-    rebase_path("$root_gen_dir/observatory_copy/$current_dir/packages.stamp"),
-    "--directory",
-    rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
-    "--command",
-    "get",
-  ]
+  script = "../../tools/observatory_tool.py"
+  args = pub_build_args + [
+           "--silent=True",
+           "--stamp",
+           rebase_path(
+               "$root_gen_dir/observatory_copy/$current_dir/packages.stamp"),
+           "--directory",
+           rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
+           "--command",
+           "get",
+         ]
 
   outputs = [
     "$root_gen_dir/observatory_copy/$current_dir/packages.stamp",
@@ -89,34 +111,27 @@
 }
 
 action("pub_build_observatory") {
-  current_dir = rebase_path(".", "//")
+  deps = [
+           ":copy_observatory",
+           ":copy_observatory_deps",
+         ] + pub_build_deps
+
   sources = rebase_path(observatory_sources_gypi.sources,
                         "",
                         "$root_gen_dir/observatory_copy/$current_dir")
 
-  deps = [
-    ":copy_observatory",
-    ":copy_observatory_deps",
-  ]
+  inputs =
+      sources + [ "$root_gen_dir/observatory_copy/$current_dir/packages.stamp" ]
 
   script = "../../tools/observatory_tool.py"
-
-  inputs = [
-    script,
-    "$root_gen_dir/observatory_copy/$current_dir/packages.stamp",
-  ]
-  inputs += sources
-
-  args = [
-    "--silent=True",
-    "--pub-executable",
-    dart_host_pub_exe,
-    "--directory",
-    rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
-    "--command",
-    "build",
-    rebase_path("$root_out_dir/observatory/build"),
-  ]
+  args = pub_build_args + [
+           "--silent=True",
+           "--directory",
+           rebase_path("$root_gen_dir/observatory_copy/$current_dir/"),
+           "--command",
+           "build",
+           rebase_path("$root_out_dir/observatory/build"),
+         ]
 
   outputs = [
     "$root_out_dir/observatory/build/web/main.dart.js",
@@ -124,9 +139,7 @@
 }
 
 action("deploy_observatory") {
-  deps = [
-    ":pub_build_observatory",
-  ]
+  deps = [ ":pub_build_observatory" ] + pub_build_deps
 
   script = "../../tools/observatory_tool.py"
 
@@ -135,15 +148,13 @@
     "$root_out_dir/observatory/build/web/main.dart.js",
   ]
 
-  args = [
-    "--silent=True",
-    "--pub-executable",
-    dart_host_pub_exe,
-    "--directory",
-    rebase_path("$root_out_dir/observatory"),
-    "--command",
-    "deploy",
-  ]
+  args = pub_build_args + [
+           "--silent=True",
+           "--directory",
+           rebase_path("$root_out_dir/observatory"),
+           "--command",
+           "deploy",
+         ]
 
   outputs = [
     "$root_out_dir/observatory/deployed/web/main.dart.js",
@@ -164,16 +175,15 @@
       ":deploy_observatory",
     ]
 
-    script = "../tools/create_archive.py"
-
     inputs = [
-      script,
       "$root_out_dir/observatory/deployed/web/main.dart.js",
     ]
 
     inner_namespace = invoker.inner_namespace
     outer_namespace = invoker.outer_namespace
     output_name = target_name
+
+    script = "../tools/create_archive.py"
     args = [
       "--output",
       rebase_path("$root_gen_dir/observatory/${output_name}.cc"),
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index 977550f..db07c701 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -239,6 +239,7 @@
       final bool currentTargetConnected = (_vm != null) && !_vm.isDisconnected;
       if (!currentTarget || !currentTargetConnected) {
         _switchVM(new WebSocketVM(targets.current));
+        app.locationManager.go(Uris.vm());
       }
     });
 
diff --git a/runtime/observatory/lib/src/elements/vm_connect.dart b/runtime/observatory/lib/src/elements/vm_connect.dart
index 6c0b87f..e57463b 100644
--- a/runtime/observatory/lib/src/elements/vm_connect.dart
+++ b/runtime/observatory/lib/src/elements/vm_connect.dart
@@ -12,6 +12,7 @@
 import 'package:observatory/src/elements/helpers/tag.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/nav_bar.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
 import 'package:observatory/src/elements/nav/notify.dart';
 import 'package:observatory/src/elements/nav/top_menu.dart';
 import 'package:observatory/src/elements/view_footer.dart';
@@ -119,7 +120,7 @@
                         ..text = 'Connect'
                         ..onClick.listen((e) {
                           e.preventDefault();
-                          _create();
+                          _createAndConnect();
                         }),
                     ],
                   new BRElement(),
@@ -150,11 +151,11 @@
   TextInputElement _createAddressBox() {
     var textbox = new TextInputElement()
       ..classes = ['textbox']
-      ..placeholder = '127.0.0.1:8181'
+      ..placeholder = 'http://127.0.0.1:8181/...'
       ..value = _address
       ..onKeyUp.where((e) => e.key == '\n').listen((e) {
         e.preventDefault();
-        _create();
+        _createAndConnect();
       });
     textbox.onInput.listen((e) {
       _address = textbox.value;
@@ -176,9 +177,14 @@
     return e;
   }
 
-  void _create() {
+  void _createAndConnect() {
     if (_address == null || _address.isEmpty) return;
-    _targets.add(_normalizeStandaloneAddress(_address));
+    String normalizedNetworkAddress = _normalizeStandaloneAddress(_address);
+    _targets.add(normalizedNetworkAddress);
+    var target = _targets.find(normalizedNetworkAddress);
+    assert(target != null);
+    _targets.setCurrent(target);
+    ObservatoryApplication.app.locationManager.go(Uris.vm());
   }
 
   void _connect(TargetEvent e) {
@@ -194,8 +200,7 @@
     }
     try {
       Uri uri = Uri.parse(networkAddress);
-      print('returning ${uri.host} ${uri.port}');
-      return 'ws://${uri.host}:${uri.port}/ws';
+      return 'ws://${uri.authority}${uri.path}ws';
     } catch (e) {
       print('caught exception with: $networkAddress -- $e');
       return networkAddress;
diff --git a/runtime/observatory/lib/src/repositories/target.dart b/runtime/observatory/lib/src/repositories/target.dart
index cad6dc5..69290fc 100644
--- a/runtime/observatory/lib/src/repositories/target.dart
+++ b/runtime/observatory/lib/src/repositories/target.dart
@@ -29,15 +29,15 @@
   TargetRepository._(this._onChange, this.onChange) {
     _restore();
     // Add the default address if it doesn't already exist.
-    if (_find(_networkAddressOfDefaultTarget()) == null) {
+    if (find(_networkAddressOfDefaultTarget()) == null) {
       add(_networkAddressOfDefaultTarget());
     }
     // Set the current target to the default target.
-    current = _find(_networkAddressOfDefaultTarget());
+    current = find(_networkAddressOfDefaultTarget());
   }
 
   void add(String address) {
-    if (_find(address) != null) {
+    if (find(address) != null) {
       return;
     }
     _list.insert(0, new SC.WebSocketVMTarget(address));
@@ -91,7 +91,7 @@
   }
 
   /// Find by networkAddress.
-  SC.WebSocketVMTarget _find(String networkAddress) {
+  SC.WebSocketVMTarget find(String networkAddress) {
     for (SC.WebSocketVMTarget item in _list) {
       if (item.networkAddress == networkAddress) {
         return item;
@@ -101,14 +101,7 @@
   }
 
   static String _networkAddressOfDefaultTarget() {
-    if (Utils.runningInJavaScript()) {
-      // We are running as JavaScript, use the same host that Observatory has
-      // been loaded from.
-      return 'ws://${window.location.host}/ws';
-    } else {
-      // Otherwise, assume we are running from Dart Editor and want to connect
-      // to the default host.
-      return 'ws://localhost:8181/ws';
-    }
+    Uri serverAddress = Uri.parse(window.location.toString());
+    return 'ws://${serverAddress.authority}${serverAddress.path}ws';
   }
 }
diff --git a/runtime/observatory/tests/observatory_ui/observatory_ui.status b/runtime/observatory/tests/observatory_ui/observatory_ui.status
index dcb5893..1b96aa6 100644
--- a/runtime/observatory/tests/observatory_ui/observatory_ui.status
+++ b/runtime/observatory/tests/observatory_ui/observatory_ui.status
@@ -8,6 +8,7 @@
 [ $runtime == dartium ]
 isolate/*: Skip
 allocation_profile: Skip
+vm_connect/element_test: Skip # See issue 27714
 
 [ $runtime == ff || $runtime == safari ]
 allocation_profile: Skip
diff --git a/runtime/observatory/tests/service/developer_server_control_test.dart b/runtime/observatory/tests/service/developer_server_control_test.dart
new file mode 100644
index 0000000..fc1e940
--- /dev/null
+++ b/runtime/observatory/tests/service/developer_server_control_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'dart:async';
+import 'dart:developer';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+Future<Null> testeeBefore() async {
+  print('testee before');
+  print(await Service.getInfo());
+  // Start the web server.
+  ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
+  print(info);
+}
+
+var tests = [
+(Isolate isolate) async {
+  await isolate.reload();
+  // Just getting here means that the testee enabled the service protocol
+  // web server.
+  expect(true, true);
+}
+];
+
+main(args) => runIsolateTests(args,
+                              tests,
+                              testeeBefore: testeeBefore,
+                              // the testee is responsible for starting the
+                              // web server.
+                              testeeControlsServer: true);
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 6810137..fa58842 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -59,6 +59,8 @@
 get_allocation_samples_test: RuntimeError # Profiling unimplemented.
 get_cpu_profile_timeline_rpc_test: RuntimeError # Profiling unimplemented.
 implicit_getter_setter_test: RuntimeError # Field guards unimplemented.
+debugger_location_second_test: Skip # Issue #27746
+debugger_location_test: Skip # Issue #27746
 
 [ $hot_reload || $hot_reload_rollback ]
 # Skip all service tests because random reloads interfere.
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 63b8fc2..b1bf590 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -91,25 +91,29 @@
                                 bool pause_on_exit,
                                 bool pause_on_unhandled_exceptions,
                                 bool trace_service,
-                                bool trace_compiler) {
+                                bool trace_compiler,
+                                bool testeeControlsServer) {
     assert(pause_on_start != null);
     assert(pause_on_exit != null);
     assert(pause_on_unhandled_exceptions != null);
     assert(trace_service != null);
     assert(trace_compiler != null);
+    assert(testeeControlsServer != null);
 
     if (_shouldLaunchSkyShell()) {
       return _spawnSkyProcess(pause_on_start,
                               pause_on_exit,
                               pause_on_unhandled_exceptions,
                               trace_service,
-                              trace_compiler);
+                              trace_compiler,
+                              testeeControlsServer);
     } else {
       return _spawnDartProcess(pause_on_start,
                                pause_on_exit,
                                pause_on_unhandled_exceptions,
                                trace_service,
-                               trace_compiler);
+                               trace_compiler,
+                               testeeControlsServer);
     }
   }
 
@@ -117,7 +121,8 @@
                                     bool pause_on_exit,
                                     bool pause_on_unhandled_exceptions,
                                     bool trace_service,
-                                    bool trace_compiler) {
+                                    bool trace_compiler,
+                                    bool testeeControlsServer) {
     assert(!_shouldLaunchSkyShell());
 
     String dartExecutable = Platform.executable;
@@ -141,7 +146,9 @@
     }
 
     fullArgs.addAll(Platform.executableArguments);
-    fullArgs.add('--enable-vm-service:0');
+    if (!testeeControlsServer) {
+      fullArgs.add('--enable-vm-service:0');
+    }
     fullArgs.addAll(args);
 
     return _spawnCommon(dartExecutable, fullArgs);
@@ -151,7 +158,8 @@
                                    bool pause_on_exit,
                                    bool pause_on_unhandled_exceptions,
                                    bool trace_service,
-                                   bool trace_compiler) {
+                                   bool trace_compiler,
+                                   bool testeeControlsServer) {
     assert(_shouldLaunchSkyShell());
 
     String dartExecutable = _skyShellPath();
@@ -179,7 +187,9 @@
     dartFlags.add('--enable_mirrors=true');
 
     fullArgs.addAll(Platform.executableArguments);
-    fullArgs.add('--observatory-port=0');
+    if (!testeeControlsServer) {
+      fullArgs.add('--observatory-port=0');
+    }
     fullArgs.add('--dart-flags=${dartFlags.join(' ')}');
     fullArgs.addAll(args);
 
@@ -194,37 +204,38 @@
     return Process.start(executable, arguments, environment: environment);
   }
 
-  Future<int> launch(bool pause_on_start,
+  Future<Uri> launch(bool pause_on_start,
                      bool pause_on_exit,
                      bool pause_on_unhandled_exceptions,
                      bool trace_service,
-                     bool trace_compiler) {
+                     bool trace_compiler,
+                     bool testeeControlsServer) {
     return _spawnProcess(pause_on_start,
                   pause_on_exit,
                   pause_on_unhandled_exceptions,
                   trace_service,
-                  trace_compiler).then((p) {
-      Completer completer = new Completer();
+                  trace_compiler,
+                  testeeControlsServer).then((p) {
+      Completer<Uri> completer = new Completer<Uri>();
       process = p;
-      var portNumber;
+      Uri uri;
       var blank;
       var first = true;
       process.stdout.transform(UTF8.decoder)
                     .transform(new LineSplitter()).listen((line) {
-        if (line.startsWith('Observatory listening on http://')) {
-          RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)");
-          var port = portExp.firstMatch(line).group(1);
-          portNumber = int.parse(port);
+        const kObservatoryListening = 'Observatory listening on ';
+        if (line.startsWith(kObservatoryListening)) {
+          uri = Uri.parse(line.substring(kObservatoryListening.length));
         }
         if (pause_on_start || line == '') {
           // Received blank line.
           blank = true;
         }
-        if (portNumber != null && blank == true && first == true) {
-          completer.complete(portNumber);
+        if ((uri != null) && (blank == true) && (first == true)) {
+          completer.complete(uri);
           // Stop repeat completions.
           first = false;
-          print('** Signaled to run test queries on $portNumber');
+          print('** Signaled to run test queries on $uri');
         }
         print('>testee>out> $line');
       });
@@ -250,62 +261,11 @@
   }
 }
 
-// A tester runner that doesn't spawn a process but instead connects to
-// an already running flutter application running on a device. Assumes
-// port 8100. This is only useful for debugging.
-class _FlutterDeviceServiceTesterRunner {
-  void run({List<String> mainArgs,
-            List<VMTest> vmTests,
-            List<IsolateTest> isolateTests,
-            bool pause_on_start: false,
-            bool pause_on_exit: false,
-            bool trace_service: false,
-            bool trace_compiler: false,
-            bool verbose_vm: false,
-            bool pause_on_unhandled_exceptions: false}) {
-    var port = 8100;
-    serviceWebsocketAddress = 'ws://localhost:$port/ws';
-    serviceHttpAddress = 'http://localhost:$port';
-    var name = Platform.script.pathSegments.last;
-    Chain.capture(() async {
-      var vm =
-          new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress));
-      print('Loading VM...');
-      await vm.load();
-      print('Done loading VM');
-
-      // Run vm tests.
-      if (vmTests != null) {
-        var testIndex = 1;
-        var totalTests = vmTests.length;
-        for (var test in vmTests) {
-          vm.verbose = verbose_vm;
-          print('Running $name [$testIndex/$totalTests]');
-          testIndex++;
-          await test(vm);
-        }
-      }
-
-      // Run isolate tests.
-      if (isolateTests != null) {
-        var isolate = await vm.isolates.first.load();
-        var testIndex = 1;
-        var totalTests = isolateTests.length;
-        for (var test in isolateTests) {
-          vm.verbose = verbose_vm;
-          print('Running $name [$testIndex/$totalTests]');
-          testIndex++;
-          await test(isolate);
-        }
-      }
-    }, onError: (error, stackTrace) {
-      print('Unexpected exception in service tests: $error\n$stackTrace');
-    });
-  }
-}
-
-void suppressWarning() {
-  new _FlutterDeviceServiceTesterRunner();
+void setupAddresses(Uri serverAddress) {
+  serviceWebsocketAddress =
+          'ws://${serverAddress.authority}${serverAddress.path}ws';
+  serviceHttpAddress =
+      'http://${serverAddress.authority}${serverAddress.path}';
 }
 
 class _ServiceTesterRunner {
@@ -317,19 +277,20 @@
             bool trace_service: false,
             bool trace_compiler: false,
             bool verbose_vm: false,
-            bool pause_on_unhandled_exceptions: false}) {
+            bool pause_on_unhandled_exceptions: false,
+            bool testeeControlsServer: false}) {
     var process = new _ServiceTesteeLauncher();
     process.launch(pause_on_start, pause_on_exit,
                    pause_on_unhandled_exceptions,
-                   trace_service, trace_compiler).then((port) async {
+                   trace_service, trace_compiler,
+                   testeeControlsServer).then((Uri serverAddress) async {
       if (mainArgs.contains("--gdb")) {
         var pid = process.process.pid;
         var wait = new Duration(seconds: 10);
         print("Testee has pid $pid, waiting $wait before continuing");
         sleep(wait);
       }
-      serviceWebsocketAddress = 'ws://localhost:$port/ws';
-      serviceHttpAddress = 'http://localhost:$port';
+      setupAddresses(serverAddress);
       var name = Platform.script.pathSegments.last;
       Chain.capture(() async {
         var vm =
@@ -386,7 +347,8 @@
                         bool trace_service: false,
                         bool trace_compiler: false,
                         bool verbose_vm: false,
-                        bool pause_on_unhandled_exceptions: false}) async {
+                        bool pause_on_unhandled_exceptions: false,
+                        bool testeeControlsServer: false}) async {
   assert(!pause_on_start || testeeBefore == null);
   if (_isTestee()) {
     new _ServiceTesteeRunner().run(testeeBefore: testeeBefore,
@@ -402,7 +364,8 @@
         trace_service: trace_service,
         trace_compiler: trace_compiler,
         verbose_vm: verbose_vm,
-        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions,
+        testeeControlsServer: testeeControlsServer);
   }
 }
 
diff --git a/runtime/platform/address_sanitizer.h b/runtime/platform/address_sanitizer.h
index 584f3a5..ec8baf7 100644
--- a/runtime/platform/address_sanitizer.h
+++ b/runtime/platform/address_sanitizer.h
@@ -11,13 +11,17 @@
 // told about areas where the VM does the equivalent of a long-jump.
 #if defined(__has_feature)
 #if __has_feature(address_sanitizer)
-extern "C" void __asan_unpoison_memory_region(void *, size_t);
+extern "C" void __asan_unpoison_memory_region(void*, size_t);
 #define ASAN_UNPOISON(ptr, len) __asan_unpoison_memory_region(ptr, len)
 #else  // __has_feature(address_sanitizer)
-#define ASAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0)
+#define ASAN_UNPOISON(ptr, len)                                                \
+  do {                                                                         \
+  } while (false && (ptr) == 0 && (len) == 0)
 #endif  // __has_feature(address_sanitizer)
-#else  // defined(__has_feature)
-#define ASAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0)
+#else   // defined(__has_feature)
+#define ASAN_UNPOISON(ptr, len)                                                \
+  do {                                                                         \
+  } while (false && (ptr) == 0 && (len) == 0)
 #endif  // defined(__has_feature)
 
 #endif  // RUNTIME_PLATFORM_ADDRESS_SANITIZER_H_
diff --git a/runtime/platform/assert.cc b/runtime/platform/assert.cc
index 524c7a2..49c6bec 100644
--- a/runtime/platform/assert.cc
+++ b/runtime/platform/assert.cc
@@ -28,9 +28,7 @@
   va_list arguments;
   va_start(arguments, format);
   vsnprintf(buffer + file_and_line_length,
-            sizeof(buffer) - file_and_line_length,
-            format,
-            arguments);
+            sizeof(buffer) - file_and_line_length, format, arguments);
   va_end(arguments);
 
   // Print the buffer on stderr and/or syslog.
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index 1d35327..02e0e8f 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -26,51 +26,48 @@
 
 class DynamicAssertionHelper {
  public:
-  enum Kind {
-    ASSERT,
-    EXPECT
-  };
+  enum Kind { ASSERT, EXPECT };
 
   DynamicAssertionHelper(const char* file, int line, Kind kind)
-      : file_(file), line_(line), kind_(kind) { }
+      : file_(file), line_(line), kind_(kind) {}
 
   void Fail(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
 
   static bool failed() { return failed_; }
 
 #if defined(TESTING)
-  template<typename E, typename A>
+  template <typename E, typename A>
   void Equals(const E& expected, const A& actual);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void NotEquals(const E& not_expected, const A& actual);
 
-  template<typename E, typename A, typename T>
+  template <typename E, typename A, typename T>
   void FloatEquals(const E& expected, const A& actual, const T& tol);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void StringEquals(const E& expected, const A& actual);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void IsSubstring(const E& needle, const A& haystack);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void IsNotSubstring(const E& needle, const A& haystack);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void LessThan(const E& left, const A& right);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void LessEqual(const E& left, const A& right);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void GreaterThan(const E& left, const A& right);
 
-  template<typename E, typename A>
+  template <typename E, typename A>
   void GreaterEqual(const E& left, const A& right);
 #endif
 
-  template<typename T>
+  template <typename T>
   T NotNull(const T p);
 
  private:
@@ -84,24 +81,24 @@
 };
 
 
-class Assert: public DynamicAssertionHelper {
+class Assert : public DynamicAssertionHelper {
  public:
   Assert(const char* file, int line)
-      : DynamicAssertionHelper(file, line, ASSERT) { }
+      : DynamicAssertionHelper(file, line, ASSERT) {}
 };
 
 
-class Expect: public DynamicAssertionHelper {
+class Expect : public DynamicAssertionHelper {
  public:
   Expect(const char* file, int line)
-      : DynamicAssertionHelper(file, line, EXPECT) { }
+      : DynamicAssertionHelper(file, line, EXPECT) {}
 };
 
 
 #if defined(TESTING)
 // Only allow the expensive (with respect to code size) assertions
 // in testing code.
-template<typename E, typename A>
+template <typename E, typename A>
 void DynamicAssertionHelper::Equals(const E& expected, const A& actual) {
   if (actual == expected) return;
   std::ostringstream ess, ass;
@@ -112,9 +109,8 @@
 }
 
 
-template<typename E, typename A>
-void DynamicAssertionHelper::NotEquals(const E& not_expected,
-                                       const A& actual) {
+template <typename E, typename A>
+void DynamicAssertionHelper::NotEquals(const E& not_expected, const A& actual) {
   if (actual != not_expected) return;
   std::ostringstream ness;
   ness << not_expected;
@@ -123,7 +119,7 @@
 }
 
 
-template<typename E, typename A, typename T>
+template <typename E, typename A, typename T>
 void DynamicAssertionHelper::FloatEquals(const E& expected,
                                          const A& actual,
                                          const T& tol) {
@@ -135,16 +131,14 @@
   ass << actual;
   tolss << tol;
   std::string es = ess.str(), as = ass.str(), tols = tolss.str();
-  Fail("expected: <%s> but was: <%s> (tolerance: <%s>)",
-       es.c_str(),
-       as.c_str(),
+  Fail("expected: <%s> but was: <%s> (tolerance: <%s>)", es.c_str(), as.c_str(),
        tols.c_str());
 }
 
 
-template<typename E, typename A>
-NO_SANITIZE_MEMORY
-void DynamicAssertionHelper::StringEquals(const E& expected, const A& actual) {
+template <typename E, typename A>
+NO_SANITIZE_MEMORY void DynamicAssertionHelper::StringEquals(const E& expected,
+                                                             const A& actual) {
   std::ostringstream ess, ass;
   ess << expected;
   ass << actual;
@@ -154,34 +148,34 @@
 }
 
 
-template<typename E, typename A>
-NO_SANITIZE_MEMORY
-void DynamicAssertionHelper::IsSubstring(const E& needle, const A& haystack) {
+template <typename E, typename A>
+NO_SANITIZE_MEMORY void DynamicAssertionHelper::IsSubstring(const E& needle,
+                                                            const A& haystack) {
   std::ostringstream ess, ass;
   ess << needle;
   ass << haystack;
   std::string es = ess.str(), as = ass.str();
   if (as.find(es) != std::string::npos) return;
-  Fail("expected <\"%s\"> to be a substring of <\"%s\">",
-       es.c_str(), as.c_str());
+  Fail("expected <\"%s\"> to be a substring of <\"%s\">", es.c_str(),
+       as.c_str());
 }
 
 
-template<typename E, typename A>
-NO_SANITIZE_MEMORY
-void DynamicAssertionHelper::IsNotSubstring(const E& needle,
-                                            const A& haystack) {
+template <typename E, typename A>
+NO_SANITIZE_MEMORY void DynamicAssertionHelper::IsNotSubstring(
+    const E& needle,
+    const A& haystack) {
   std::ostringstream ess, ass;
   ess << needle;
   ass << haystack;
   std::string es = ess.str(), as = ass.str();
   if (as.find(es) == std::string::npos) return;
-  Fail("expected <\"%s\"> to not be a substring of <\"%s\">",
-       es.c_str(), as.c_str());
+  Fail("expected <\"%s\"> to not be a substring of <\"%s\">", es.c_str(),
+       as.c_str());
 }
 
 
-template<typename E, typename A>
+template <typename E, typename A>
 void DynamicAssertionHelper::LessThan(const E& left, const A& right) {
   if (left < right) return;
   std::ostringstream ess, ass;
@@ -192,7 +186,7 @@
 }
 
 
-template<typename E, typename A>
+template <typename E, typename A>
 void DynamicAssertionHelper::LessEqual(const E& left, const A& right) {
   if (left <= right) return;
   std::ostringstream ess, ass;
@@ -203,7 +197,7 @@
 }
 
 
-template<typename E, typename A>
+template <typename E, typename A>
 void DynamicAssertionHelper::GreaterThan(const E& left, const A& right) {
   if (left > right) return;
   std::ostringstream ess, ass;
@@ -214,7 +208,7 @@
 }
 
 
-template<typename E, typename A>
+template <typename E, typename A>
 void DynamicAssertionHelper::GreaterEqual(const E& left, const A& right) {
   if (left >= right) return;
   std::ostringstream ess, ass;
@@ -226,7 +220,7 @@
 #endif
 
 
-template<typename T>
+template <typename T>
 T DynamicAssertionHelper::NotNull(const T p) {
   if (p != NULL) return p;
   Fail("expected: not NULL, found NULL");
@@ -236,11 +230,9 @@
 }  // namespace dart
 
 
-#define FATAL(error)                                                           \
-  dart::Assert(__FILE__, __LINE__).Fail("%s", error)
+#define FATAL(error) dart::Assert(__FILE__, __LINE__).Fail("%s", error)
 
-#define FATAL1(format, p1)                                                     \
-  dart::Assert(__FILE__, __LINE__).Fail(format, (p1))
+#define FATAL1(format, p1) dart::Assert(__FILE__, __LINE__).Fail(format, (p1))
 
 #define FATAL2(format, p1, p2)                                                 \
   dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2))
@@ -248,14 +240,11 @@
 #define FATAL3(format, p1, p2, p3)                                             \
   dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2), (p3))
 
-#define UNIMPLEMENTED()                                                        \
-  FATAL("unimplemented code")
+#define UNIMPLEMENTED() FATAL("unimplemented code")
 
-#define UNREACHABLE()                                                          \
-  FATAL("unreachable code")
+#define UNREACHABLE() FATAL("unreachable code")
 
-#define OUT_OF_MEMORY()                                                        \
-  FATAL("Out of memory.")
+#define OUT_OF_MEMORY() FATAL("Out of memory.")
 
 
 #if defined(DEBUG)
@@ -275,15 +264,16 @@
 
 // Returns 'ptr'; useful for initializer lists:
 //   class Foo { Foo(int* ptr) : ptr_(ASSERT_NOTNULL(ptr)) ...
-#define ASSERT_NOTNULL(ptr)                                                    \
-  dart::Assert(__FILE__, __LINE__).NotNull((ptr))
+#define ASSERT_NOTNULL(ptr) dart::Assert(__FILE__, __LINE__).NotNull((ptr))
 
 #else  // if defined(DEBUG)
 
 // In order to avoid variable unused warnings for code that only uses
 // a variable in an ASSERT or EXPECT, we make sure to use the macro
 // argument.
-#define ASSERT(condition) do {} while (false && (condition))
+#define ASSERT(condition)                                                      \
+  do {                                                                         \
+  } while (false && (condition))
 
 #define DEBUG_ASSERT(cond)
 
@@ -310,8 +300,7 @@
 //
 
 template <bool>
-struct CompileAssert {
-};
+struct CompileAssert {};
 // Macro to concatenate two tokens. The helper is need to proper expansion
 // in case an argument is a macro itself.
 #if !defined(COMPILE_ASSERT)
@@ -319,8 +308,8 @@
 #define COMPILE_ASSERT_JOIN_HELPER(a, b) a##b
 #define COMPILE_ASSERT(expr)                                                   \
   DART_UNUSED typedef CompileAssert<(static_cast<bool>(expr))>                 \
-  COMPILE_ASSERT_JOIN(CompileAssertTypeDef, __LINE__)[static_cast<bool>(expr)  \
-  ? 1 : -1]
+      COMPILE_ASSERT_JOIN(CompileAssertTypeDef,                                \
+                          __LINE__)[static_cast<bool>(expr) ? 1 : -1]
 #endif  // !defined(COMPILE_ASSERT)
 
 #if defined(TESTING)
@@ -365,14 +354,11 @@
 #define EXPECT_GE(left, right)                                                 \
   dart::Expect(__FILE__, __LINE__).GreaterEqual((left), (right))
 
-#define EXPECT_NOTNULL(ptr)                                                    \
-  dart::Expect(__FILE__, __LINE__).NotNull((ptr))
+#define EXPECT_NOTNULL(ptr) dart::Expect(__FILE__, __LINE__).NotNull((ptr))
 
-#define FAIL(error)                                                            \
-  dart::Expect(__FILE__, __LINE__).Fail("%s", error)
+#define FAIL(error) dart::Expect(__FILE__, __LINE__).Fail("%s", error)
 
-#define FAIL1(format, p1)                                                      \
-  dart::Expect(__FILE__, __LINE__).Fail(format, (p1))
+#define FAIL1(format, p1) dart::Expect(__FILE__, __LINE__).Fail(format, (p1))
 
 #define FAIL2(format, p1, p2)                                                  \
   dart::Expect(__FILE__, __LINE__).Fail(format, (p1), (p2))
diff --git a/runtime/platform/c99_support_win.h b/runtime/platform/c99_support_win.h
index d90f34d..b7b625b 100644
--- a/runtime/platform/c99_support_win.h
+++ b/runtime/platform/c99_support_win.h
@@ -21,11 +21,10 @@
 
 #ifndef va_copy
 #define va_copy(dst, src) (memmove(&(dst), &(src), sizeof(dst)))
-#endif  /* va_copy */
+#endif /* va_copy */
 
 
-#define NAN \
-    *reinterpret_cast<const double*>(&kQuietNaNMask)
+#define NAN *reinterpret_cast<const double*>(&kQuietNaNMask)
 
 namespace std {
 
diff --git a/runtime/platform/floating_point.h b/runtime/platform/floating_point.h
index 24d2f9c..0d29a70 100644
--- a/runtime/platform/floating_point.h
+++ b/runtime/platform/floating_point.h
@@ -5,7 +5,11 @@
 #ifndef RUNTIME_PLATFORM_FLOATING_POINT_H_
 #define RUNTIME_PLATFORM_FLOATING_POINT_H_
 
-inline double fmod_ieee(double x, double y) { return fmod(x, y); }
-inline double atan2_ieee(double y, double x) { return atan2(y, x); }
+inline double fmod_ieee(double x, double y) {
+  return fmod(x, y);
+}
+inline double atan2_ieee(double y, double x) {
+  return atan2(y, x);
+}
 
 #endif  // RUNTIME_PLATFORM_FLOATING_POINT_H_
diff --git a/runtime/platform/floating_point_win.cc b/runtime/platform/floating_point_win.cc
index 76ce626..8863ec5 100644
--- a/runtime/platform/floating_point_win.cc
+++ b/runtime/platform/floating_point_win.cc
@@ -38,9 +38,8 @@
     // Same is with index_y.
     int index_x = (cls_x & _FPCLASS_PINF) != 0 ? 0 : 1;
     int index_y = (cls_y & _FPCLASS_PINF) != 0 ? 0 : 1;
-    static double atans_at_infinities[2][2] =
-      { { atan2(1.,  1.), atan2(1.,  -1.) },
-        { atan2(-1., 1.), atan2(-1., -1.) } };
+    static double atans_at_infinities[2][2] = {
+        {atan2(1., 1.), atan2(1., -1.)}, {atan2(-1., 1.), atan2(-1., -1.)}};
     return atans_at_infinities[index_x][index_y];
   } else {
     return atan2(x, y);
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 8503221..cd74901 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -195,9 +195,7 @@
     v[0] = double_storage[0];
     v[1] = double_storage[1];
   }
-  void writeTo(simd128_value_t* v) {
-    *v = *this;
-  }
+  void writeTo(simd128_value_t* v) { *v = *this; }
 };
 
 // Processor architecture detection.  For more info on what's defined, see:
@@ -228,18 +226,17 @@
 typedef struct {
   union {
     uint32_t u;
-    float    f;
+    float f;
   } data_[4];
 } simd_value_t;
 typedef simd_value_t fpu_register_t;
-#define simd_value_safe_load(addr)                                             \
-  (*reinterpret_cast<simd_value_t *>(addr))
+#define simd_value_safe_load(addr) (*reinterpret_cast<simd_value_t*>(addr))
 #define simd_value_safe_store(addr, value)                                     \
   do {                                                                         \
-    reinterpret_cast<simd_value_t *>(addr)->data_[0] = value.data_[0];         \
-    reinterpret_cast<simd_value_t *>(addr)->data_[1] = value.data_[1];         \
-    reinterpret_cast<simd_value_t *>(addr)->data_[2] = value.data_[2];         \
-    reinterpret_cast<simd_value_t *>(addr)->data_[3] = value.data_[3];         \
+    reinterpret_cast<simd_value_t*>(addr)->data_[0] = value.data_[0];          \
+    reinterpret_cast<simd_value_t*>(addr)->data_[1] = value.data_[1];          \
+    reinterpret_cast<simd_value_t*>(addr)->data_[2] = value.data_[2];          \
+    reinterpret_cast<simd_value_t*>(addr)->data_[3] = value.data_[3];          \
   } while (0)
 
 #elif defined(__MIPSEL__)
@@ -335,14 +332,12 @@
 
 // Verify that host and target architectures match, we cannot
 // have a 64 bit Dart VM generating 32 bit code or vice-versa.
-#if defined(TARGET_ARCH_X64) ||                                                \
-    defined(TARGET_ARCH_ARM64)
+#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
 #if !defined(ARCH_IS_64_BIT)
 #error Mismatched Host/Target architectures.
 #endif
-#elif defined(TARGET_ARCH_IA32) ||                                             \
-      defined(TARGET_ARCH_ARM) ||                                              \
-      defined(TARGET_ARCH_MIPS)
+#elif defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) ||                 \
+    defined(TARGET_ARCH_MIPS)
 #if !defined(ARCH_IS_32_BIT)
 #error Mismatched Host/Target architectures.
 #endif
@@ -350,9 +345,9 @@
 
 // Determine whether we will be using the simulator.
 #if defined(TARGET_ARCH_IA32)
-  // No simulator used.
+// No simulator used.
 #elif defined(TARGET_ARCH_X64)
-  // No simulator used.
+// No simulator used.
 #elif defined(TARGET_ARCH_ARM)
 #if !defined(HOST_ARCH_ARM)
 #define USING_SIMULATOR 1
@@ -429,7 +424,7 @@
 // Usage: instead of writing 0x1234567890123456ULL
 //      write DART_2PART_UINT64_C(0x12345678,90123456);
 #define DART_2PART_UINT64_C(a, b)                                              \
-                 (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
+  (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
 
 // Integer constants.
 const int32_t kMinInt32 = 0x80000000;
@@ -457,11 +452,11 @@
 // Byte sizes.
 const int kWordSize = sizeof(word);
 const int kDoubleSize = sizeof(double);  // NOLINT
-const int kFloatSize = sizeof(float);  // NOLINT
+const int kFloatSize = sizeof(float);    // NOLINT
 const int kQuadSize = 4 * kFloatSize;
 const int kSimd128Size = sizeof(simd128_value_t);  // NOLINT
-const int kInt32Size = sizeof(int32_t);  // NOLINT
-const int kInt16Size = sizeof(int16_t);  // NOLINT
+const int kInt32Size = sizeof(int32_t);            // NOLINT
+const int kInt16Size = sizeof(int16_t);            // NOLINT
 #ifdef ARCH_IS_32_BIT
 const int kWordSizeLog2 = 2;
 const uword kUwordMax = kMaxUint32;
@@ -510,13 +505,13 @@
 // Time constants.
 const int kMillisecondsPerSecond = 1000;
 const int kMicrosecondsPerMillisecond = 1000;
-const int kMicrosecondsPerSecond = (kMicrosecondsPerMillisecond *
-                                    kMillisecondsPerSecond);
+const int kMicrosecondsPerSecond =
+    (kMicrosecondsPerMillisecond * kMillisecondsPerSecond);
 const int kNanosecondsPerMicrosecond = 1000;
-const int kNanosecondsPerMillisecond = (kNanosecondsPerMicrosecond *
-                                        kMicrosecondsPerMillisecond);
-const int kNanosecondsPerSecond = (kNanosecondsPerMicrosecond *
-                                   kMicrosecondsPerSecond);
+const int kNanosecondsPerMillisecond =
+    (kNanosecondsPerMicrosecond * kMicrosecondsPerMillisecond);
+const int kNanosecondsPerSecond =
+    (kNanosecondsPerMicrosecond * kMicrosecondsPerSecond);
 
 // Helpers to scale micro second times to human understandable values.
 inline double MicrosecondsToSeconds(int64_t micros) {
@@ -530,7 +525,7 @@
 // This should be used in the private: declarations for a class.
 #if !defined(DISALLOW_COPY_AND_ASSIGN)
 #define DISALLOW_COPY_AND_ASSIGN(TypeName)                                     \
-private:                                                                       \
+ private:                                                                      \
   TypeName(const TypeName&);                                                   \
   void operator=(const TypeName&)
 #endif  // !defined(DISALLOW_COPY_AND_ASSIGN)
@@ -542,7 +537,7 @@
 // containing only static methods.
 #if !defined(DISALLOW_IMPLICIT_CONSTRUCTORS)
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)                               \
-private:                                                                       \
+ private:                                                                      \
   TypeName();                                                                  \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 #endif  // !defined(DISALLOW_IMPLICIT_CONSTRUCTORS)
@@ -553,19 +548,20 @@
 // platform/assert.h.
 #if !defined(DISALLOW_ALLOCATION)
 #define DISALLOW_ALLOCATION()                                                  \
-public:                                                                        \
+ public:                                                                       \
   void operator delete(void* pointer) {                                        \
     fprintf(stderr, "unreachable code\n");                                     \
     abort();                                                                   \
   }                                                                            \
-private:                                                                       \
+                                                                               \
+ private:                                                                      \
   void* operator new(size_t size);
 #endif  // !defined(DISALLOW_ALLOCATION)
 
 // The USE(x) template is used to silence C++ compiler warnings issued
 // for unused variables.
 template <typename T>
-static inline void USE(T) { }
+static inline void USE(T) {}
 
 
 // Use implicit_cast as a safe version of static_cast or const_cast
@@ -585,15 +581,15 @@
 // implicit_cast would have been part of the C++ standard library,
 // but the proposal was submitted too late.  It will probably make
 // its way into the language in the future.
-template<typename To, typename From>
-inline To implicit_cast(From const &f) {
+template <typename To, typename From>
+inline To implicit_cast(From const& f) {
   return f;
 }
 
 
 // Use like this: down_cast<T*>(foo);
-template<typename To, typename From>  // use like this: down_cast<T*>(foo);
-inline To down_cast(From* f) {  // so we only accept pointers
+template <typename To, typename From>  // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {         // so we only accept pointers
   // Ensures that To is a sub-type of From *.  This test is here only
   // for compile-time type checking, and has no overhead in an
   // optimized build at run-time, as it will be optimized away completely.
@@ -647,12 +643,11 @@
 // optimizations of GCC 4.4. Basically, GCC mindlessly relies on
 // obscure details in the C++ standard that make reinterpret_cast
 // virtually useless.
-template<class D, class S>
+template <class D, class S>
 inline D bit_copy(const S& source) {
   D destination;
   // This use of memcpy is safe: source and destination cannot overlap.
-  memcpy(&destination,
-         reinterpret_cast<const void*>(&source),
+  memcpy(&destination, reinterpret_cast<const void*>(&source),
          sizeof(destination));
   return destination;
 }
@@ -691,7 +686,7 @@
 // N.B.: As the GCC manual states, "[s]ince non-static C++ methods
 // have an implicit 'this' argument, the arguments of such methods
 // should be counted from two, not one."
-#define PRINTF_ATTRIBUTE(string_index, first_to_check) \
+#define PRINTF_ATTRIBUTE(string_index, first_to_check)                         \
   __attribute__((__format__(__printf__, string_index, first_to_check)))
 #else
 #define PRINTF_ATTRIBUTE(string_index, first_to_check)
diff --git a/runtime/platform/hashmap.h b/runtime/platform/hashmap.h
index 1cd8a4a..1fd1235 100644
--- a/runtime/platform/hashmap.h
+++ b/runtime/platform/hashmap.h
@@ -11,9 +11,9 @@
 
 class HashMap {
  public:
-  typedef bool (*MatchFun) (void* key1, void* key2);
+  typedef bool (*MatchFun)(void* key1, void* key2);
 
-  typedef void (*ClearFun) (void* value);
+  typedef void (*ClearFun)(void* value);
 
   // initial_capacity is the size of the initial hash map;
   // it must be a power of 2 (and thus must not be 0).
@@ -21,9 +21,7 @@
 
   ~HashMap();
 
-  static bool SamePointerValue(void* key1, void* key2) {
-    return key1 == key2;
-  }
+  static bool SamePointerValue(void* key1, void* key2) { return key1 == key2; }
 
   static uint32_t StringHash(char* key) {
     uint32_t hash_ = 0;
diff --git a/runtime/platform/memory_sanitizer.h b/runtime/platform/memory_sanitizer.h
index dddfe31..27cb25d 100644
--- a/runtime/platform/memory_sanitizer.h
+++ b/runtime/platform/memory_sanitizer.h
@@ -11,15 +11,19 @@
 // told about areas that are initialized by generated code.
 #if defined(__has_feature)
 #if __has_feature(memory_sanitizer)
-extern "C" void __msan_unpoison(void *, size_t);
+extern "C" void __msan_unpoison(void*, size_t);
 #define MSAN_UNPOISON(ptr, len) __msan_unpoison(ptr, len)
 #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
 #else  // __has_feature(memory_sanitizer)
-#define MSAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0)
+#define MSAN_UNPOISON(ptr, len)                                                \
+  do {                                                                         \
+  } while (false && (ptr) == 0 && (len) == 0)
 #define NO_SANITIZE_MEMORY
 #endif  // __has_feature(memory_sanitizer)
-#else  // defined(__has_feature)
-#define MSAN_UNPOISON(ptr, len) do {} while (false && (ptr) == 0 && (len) == 0)
+#else   // defined(__has_feature)
+#define MSAN_UNPOISON(ptr, len)                                                \
+  do {                                                                         \
+  } while (false && (ptr) == 0 && (len) == 0)
 #define NO_SANITIZE_MEMORY
 #endif  // defined(__has_feature)
 
diff --git a/runtime/platform/signal_blocker.h b/runtime/platform/signal_blocker.h
index 28c22ac..2afe49f 100644
--- a/runtime/platform/signal_blocker.h
+++ b/runtime/platform/signal_blocker.h
@@ -57,51 +57,59 @@
 // errors (type long int changed to intptr_t and do/while split on
 // separate lines with body in {}s) and to also block signals.
 #define TEMP_FAILURE_RETRY(expression)                                         \
-    ({ ThreadSignalBlocker tsb(SIGPROF);                                       \
-       intptr_t __result;                                                      \
-       do {                                                                    \
-         __result = (expression);                                              \
-       } while ((__result == -1L) && (errno == EINTR));                        \
-       __result; })
+  ({                                                                           \
+    ThreadSignalBlocker tsb(SIGPROF);                                          \
+    intptr_t __result;                                                         \
+    do {                                                                       \
+      __result = (expression);                                                 \
+    } while ((__result == -1L) && (errno == EINTR));                           \
+    __result;                                                                  \
+  })
 
 // This is a version of TEMP_FAILURE_RETRY which does not use the value
 // returned from the expression.
 #define VOID_TEMP_FAILURE_RETRY(expression)                                    \
-    (static_cast<void>(TEMP_FAILURE_RETRY(expression)))
+  (static_cast<void>(TEMP_FAILURE_RETRY(expression)))
 
 // This macro can be used to insert checks that a call is made, that
 // was expected to not return EINTR, but did it anyway.
 #define NO_RETRY_EXPECTED(expression)                                          \
-    ({ intptr_t __result = (expression);                                       \
-       if (__result == -1L && errno == EINTR) {                                \
-         FATAL("Unexpected EINTR errno");                                      \
-       }                                                                       \
-       __result; })
+  ({                                                                           \
+    intptr_t __result = (expression);                                          \
+    if (__result == -1L && errno == EINTR) {                                   \
+      FATAL("Unexpected EINTR errno");                                         \
+    }                                                                          \
+    __result;                                                                  \
+  })
 
 #define VOID_NO_RETRY_EXPECTED(expression)                                     \
-    (static_cast<void>(NO_RETRY_EXPECTED(expression)))
+  (static_cast<void>(NO_RETRY_EXPECTED(expression)))
 
 // Define to check in debug mode, if a signal is currently being blocked.
 #define CHECK_IS_BLOCKING(signal)                                              \
-    ({ sigset_t signal_mask;                                                   \
-       int __r = pthread_sigmask(SIG_BLOCK, NULL, &signal_mask);               \
-       USE(__r);                                                               \
-       ASSERT(__r == 0);                                                       \
-       sigismember(&signal_mask, signal); })                                   \
+  ({                                                                           \
+    sigset_t signal_mask;                                                      \
+    int __r = pthread_sigmask(SIG_BLOCK, NULL, &signal_mask);                  \
+    USE(__r);                                                                  \
+    ASSERT(__r == 0);                                                          \
+    sigismember(&signal_mask, signal);                                         \
+  })
 
 
 // Versions of the above, that does not enter a signal blocking scope. Use only
 // when a signal blocking scope is entered manually.
 #define TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(expression)                       \
-    ({ intptr_t __result;                                                      \
-       ASSERT(CHECK_IS_BLOCKING(SIGPROF));                                     \
-       do {                                                                    \
-         __result = (expression);                                              \
-       } while ((__result == -1L) && (errno == EINTR));                        \
-       __result; })
+  ({                                                                           \
+    intptr_t __result;                                                         \
+    ASSERT(CHECK_IS_BLOCKING(SIGPROF));                                        \
+    do {                                                                       \
+      __result = (expression);                                                 \
+    } while ((__result == -1L) && (errno == EINTR));                           \
+    __result;                                                                  \
+  })
 
 #define VOID_TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(expression)                  \
-    (static_cast<void>(TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(expression)))
+  (static_cast<void>(TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(expression)))
 
 }  // namespace dart
 
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
index b06c49f..b44ed69 100644
--- a/runtime/platform/text_buffer.cc
+++ b/runtime/platform/text_buffer.cc
@@ -52,8 +52,7 @@
 }
 
 
-void TextBuffer::AddRaw(const uint8_t* buffer,
-                        intptr_t buffer_length) {
+void TextBuffer::AddRaw(const uint8_t* buffer, intptr_t buffer_length) {
   EnsureCapacity(buffer_length);
   memmove(&buf_[msg_len_], buffer, buffer_length);
   msg_len_ += buffer_length;
diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h
index 5689f0f..a9b5326 100644
--- a/runtime/platform/text_buffer.h
+++ b/runtime/platform/text_buffer.h
@@ -24,8 +24,7 @@
   void EscapeAndAddCodeUnit(uint32_t cu);
   void AddString(const char* s);
   void AddEscapedString(const char* s);
-  void AddRaw(const uint8_t* buffer,
-              intptr_t buffer_length);
+  void AddRaw(const uint8_t* buffer, intptr_t buffer_length);
 
   void Clear();
 
diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc
index 7778390..0dde3c7 100644
--- a/runtime/platform/utils.cc
+++ b/runtime/platform/utils.cc
@@ -39,11 +39,26 @@
   uint64_t x = static_cast<uint64_t>((v > 0) ? v : -v);
   uint64_t t;
   int r = 0;
-  if ((t = x >> 32) != 0) { x = t; r += 32; }
-  if ((t = x >> 16) != 0) { x = t; r += 16; }
-  if ((t = x >> 8) != 0) { x = t; r += 8; }
-  if ((t = x >> 4) != 0) { x = t; r += 4; }
-  if ((t = x >> 2) != 0) { x = t; r += 2; }
+  if ((t = x >> 32) != 0) {
+    x = t;
+    r += 32;
+  }
+  if ((t = x >> 16) != 0) {
+    x = t;
+    r += 16;
+  }
+  if ((t = x >> 8) != 0) {
+    x = t;
+    r += 8;
+  }
+  if ((t = x >> 4) != 0) {
+    x = t;
+    r += 4;
+  }
+  if ((t = x >> 2) != 0) {
+    x = t;
+    r += 2;
+  }
   if (x > 1) r += 1;
   return r;
 }
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index b67c96e..911cf50 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -12,28 +12,28 @@
 
 class Utils {
  public:
-  template<typename T>
+  template <typename T>
   static inline T Minimum(T x, T y) {
     return x < y ? x : y;
   }
 
-  template<typename T>
+  template <typename T>
   static inline T Maximum(T x, T y) {
     return x > y ? x : y;
   }
 
-  template<typename T>
+  template <typename T>
   static inline T Abs(T x) {
     if (x < 0) return -x;
     return x;
   }
 
-  template<typename T>
+  template <typename T>
   static inline bool IsPowerOfTwo(T x) {
     return ((x & (x - 1)) == 0) && (x != 0);
   }
 
-  template<typename T>
+  template <typename T>
   static inline int ShiftForPowerOfTwo(T x) {
     ASSERT(IsPowerOfTwo(x));
     int num_shifts = 0;
@@ -44,34 +44,34 @@
     return num_shifts;
   }
 
-  template<typename T>
+  template <typename T>
   static inline bool IsAligned(T x, intptr_t n) {
     ASSERT(IsPowerOfTwo(n));
     return (x & (n - 1)) == 0;
   }
 
-  template<typename T>
+  template <typename T>
   static inline bool IsAligned(T* x, intptr_t n) {
     return IsAligned(reinterpret_cast<uword>(x), n);
   }
 
-  template<typename T>
+  template <typename T>
   static inline T RoundDown(T x, intptr_t n) {
     ASSERT(IsPowerOfTwo(n));
     return (x & -n);
   }
 
-  template<typename T>
+  template <typename T>
   static inline T* RoundDown(T* x, intptr_t n) {
     return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uword>(x), n));
   }
 
-  template<typename T>
+  template <typename T>
   static inline T RoundUp(T x, intptr_t n) {
     return RoundDown(x + n - 1, n);
   }
 
-  template<typename T>
+  template <typename T>
   static inline T* RoundUp(T* x, intptr_t n) {
     return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uword>(x), n));
   }
@@ -97,7 +97,7 @@
   static uint32_t WordHash(intptr_t key);
 
   // Check whether an N-bit two's-complement representation can hold value.
-  template<typename T>
+  template <typename T>
   static inline bool IsInt(int N, T value) {
     ASSERT((0 < N) &&
            (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
@@ -105,7 +105,7 @@
     return (-limit <= value) && (value < limit);
   }
 
-  template<typename T>
+  template <typename T>
   static inline bool IsUint(int N, T value) {
     ASSERT((0 < N) &&
            (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
@@ -115,7 +115,7 @@
 
   // Check whether the magnitude of value fits in N bits, i.e., whether an
   // (N+1)-bit sign-magnitude representation can hold value.
-  template<typename T>
+  template <typename T>
   static inline bool IsAbsoluteUint(int N, T value) {
     ASSERT((0 < N) &&
            (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
@@ -143,14 +143,11 @@
     return (static_cast<int64_t>(high) << 32) | (low & 0x0ffffffffLL);
   }
 
-  static bool IsDecimalDigit(char c) {
-    return ('0' <= c) && (c <= '9');
-  }
+  static bool IsDecimalDigit(char c) { return ('0' <= c) && (c <= '9'); }
 
   static bool IsHexDigit(char c) {
-    return IsDecimalDigit(c)
-          || (('A' <= c) && (c <= 'F'))
-          || (('a' <= c) && (c <= 'f'));
+    return IsDecimalDigit(c) || (('A' <= c) && (c <= 'F')) ||
+           (('a' <= c) && (c <= 'f'));
   }
 
   static int HexDigitToInt(char c) {
@@ -172,9 +169,7 @@
   static inline bool RangeCheck(intptr_t offset,
                                 intptr_t count,
                                 intptr_t length) {
-    return offset >= 0 &&
-           count >= 0 &&
-           length >= 0 &&
+    return offset >= 0 && count >= 0 && length >= 0 &&
            count <= (length - offset);
   }
 
diff --git a/runtime/platform/utils_linux.h b/runtime/platform/utils_linux.h
index 5be126d..b5214fd 100644
--- a/runtime/platform/utils_linux.h
+++ b/runtime/platform/utils_linux.h
@@ -62,8 +62,8 @@
 
 
 inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
-#if !defined(__GLIBC__) ||                                              \
-((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
+#if !defined(__GLIBC__) ||                                                     \
+    ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
   // Use the XSI version.
   if (strerror_r(err, buffer, bufsize) != 0) {
     snprintf(buffer, bufsize, "%s", "strerror_r failed");
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 61d2bac..d58bdef 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -160,6 +160,9 @@
 # This test is meaningless for DBC as allocation stubs are not used.
 cc/RegenerateAllocStubs: Skip
 
+[ ($arch == simdbc || $arch == simdbc64) && $checked ]
+dart/optimized_stacktrace_test: RuntimeError # Issue 27732
+
 [ $hot_reload || $hot_reload_rollback ]
 dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 71fe87e..7922cf0 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -2,6 +2,8 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
+import("../../utils/invoke_dart.gni")
+
 config("libdart_vm_config") {
   if (defined(is_fuchsia) && is_fuchsia) {
     libs = [ "magenta" ]
@@ -414,127 +416,137 @@
   }
 }
 
-template("generate_patched_sdk") {
-  assert(defined(invoker.libraries), "Need libraries in $target_name")
+if (!defined(is_fuchsia) || !is_fuchsia) {
+  template("generate_patched_sdk") {
+    assert(defined(invoker.libraries), "Need libraries in $target_name")
 
-  concatenation_target_names = []
-  concatenation_files = []
+    concatenation_target_names = []
+    concatenation_files = []
 
-  # Concatenate vm library patches.
-  foreach(library, invoker.libraries) {
-    name = library[1]
+    # Concatenate vm library patches.
+    foreach(library, invoker.libraries) {
+      name = library[1]
 
-    target_output = "$target_gen_dir/patches/${name}_patch.dart"
-    concatenate_patch("concatenate_${name}_patch") {
-      libname = name
-      dir = library[0]
-      output = target_output
+      target_output = "$target_gen_dir/patches/${name}_patch.dart"
+      concatenate_patch("concatenate_${name}_patch") {
+        libname = name
+        dir = library[0]
+        output = target_output
+      }
+      concatenation_target_names += [ ":concatenate_${name}_patch" ]
+      concatenation_files += [ target_output ]
     }
-    concatenation_target_names += [ ":concatenate_${name}_patch" ]
-    concatenation_files += [ target_output ]
+
+    # Build the patched sdk out of the concatenated patches and the special
+    # libraries.
+    action(target_name) {
+      deps = [ "../bin:dart_bootstrap($host_toolchain)" ] +
+             concatenation_target_names
+
+      patches_dir = "$target_gen_dir/patches"
+      patched_sdk_dir = "$root_out_dir/patched_sdk"
+
+      script = "../../tools/patch_sdk.py"
+
+      # We list all files which make up the sdk (modulo patches) and get them back
+      # as a GN list object.
+      shared_sdk_sources = exec_script("../../tools/list_dart_files.py",
+                                       [ "../../sdk/lib" ],
+                                       "list lines")
+
+      # We list the `patch_sdk.dart` tool here because the [script] (which is
+      # implicitly an input) will call it.
+      inputs = [
+        "../../tools/patch_sdk.dart",
+      ]
+
+      # Files below are not patches, they will not be in [concatenation_files] but
+      # the `patch_sdk.dart` script will copy them into the patched sdk.
+      inputs += [
+        "../lib/typed_data.dart",
+        "../bin/builtin.dart",
+        "../bin/vmservice/vmservice_io.dart",
+        "../bin/vmservice/loader.dart",
+        "../bin/vmservice/server.dart",
+      ]
+
+      # Add all the normal sdk sources.
+      inputs += shared_sdk_sources
+
+      # Add all the concatenated patch files.
+      inputs += concatenation_files
+
+      outputs = [
+        # Instead of listing all outputs we list a single well-known one.
+        "${patched_sdk_dir}/lib/core/core.dart",
+      ]
+
+      dart_out_dir = get_label_info("../bin:dart_bootstrap($host_toolchain)",
+                                    "root_out_dir")
+      dart_bootstrap =
+          rebase_path("$dart_out_dir/dart_bootstrap$dart_executable_suffix")
+
+      args = [
+        "--dart-executable",
+        dart_bootstrap,
+        "vm",
+        rebase_path("../../sdk"),
+        rebase_path(patches_dir, root_build_dir),
+        rebase_path(patched_sdk_dir, root_build_dir),
+      ]
+    }
   }
 
-  # Build the patched sdk out of the concatenated patches and the special
-  # libraries.
-  action(target_name) {
-    deps = concatenation_target_names
-
-    patches_dir = "$target_gen_dir/patches"
-    patched_sdk_dir = "$target_gen_dir/patched_sdk"
-
-    script = "../../tools/patch_sdk.py"
-
-    # We list all files which make up the sdk (modulo patches) and get them back
-    # as a GN list object.
-    shared_sdk_sources = exec_script("../../tools/list_dart_files.py",
-                                     [ "../../sdk/lib" ],
-                                     "list lines")
-
-    # We list the `patch_sdk.dart` tool here because the [script] (which is
-    # implicitly an input) will call it.
-    inputs = [
-      "../../tools/patch_sdk.dart",
-    ]
-
-    # Files below are not patches, they will not be in [concatenation_files] but
-    # the `patch_sdk.dart` script will copy them into the patched sdk.
-    inputs += [
-      "../lib/typed_data.dart",
-      "../bin/builtin.dart",
-      "../bin/vmservice/vmservice_io.dart",
-      "../bin/vmservice/loader.dart",
-      "../bin/vmservice/server.dart",
-    ]
-
-    # Add all the normal sdk sources.
-    inputs += shared_sdk_sources
-
-    # Add all the concatenated patch files.
-    inputs += concatenation_files
-
-    outputs = [
-      # Instead of listing all outputs we list a single well-known one.
-      "${patched_sdk_dir}/lib/core/core.dart",
-    ]
-
-    args = [
-      "vm",
-      rebase_path("../../sdk"),
-      rebase_path(patches_dir, root_build_dir),
-      rebase_path(patched_sdk_dir, root_build_dir),
+  generate_patched_sdk("patched_sdk") {
+    libraries = [
+      [
+        "lib",
+        "async",
+      ],
+      [
+        "lib",
+        "collection",
+      ],
+      [
+        "lib",
+        "convert",
+      ],
+      [
+        "lib",
+        "core",
+      ],
+      [
+        "lib",
+        "developer",
+      ],
+      [
+        "lib",
+        "internal",
+      ],
+      [
+        "lib",
+        "isolate",
+      ],
+      [
+        "lib",
+        "math",
+      ],
+      [
+        "lib",
+        "mirrors",
+      ],
+      [
+        "lib",
+        "profiler",
+      ],
+      [
+        "lib",
+        "vmservice",
+      ],
+      [
+        "bin",
+        "io",
+      ],
     ]
   }
 }
-
-generate_patched_sdk("patched_sdk") {
-  libraries = [
-    [
-      "lib",
-      "async",
-    ],
-    [
-      "lib",
-      "collection",
-    ],
-    [
-      "lib",
-      "convert",
-    ],
-    [
-      "lib",
-      "core",
-    ],
-    [
-      "lib",
-      "developer",
-    ],
-    [
-      "lib",
-      "internal",
-    ],
-    [
-      "lib",
-      "isolate",
-    ],
-    [
-      "lib",
-      "math",
-    ],
-    [
-      "lib",
-      "mirrors",
-    ],
-    [
-      "lib",
-      "profiler",
-    ],
-    [
-      "lib",
-      "vmservice",
-    ],
-    [
-      "bin",
-      "io",
-    ],
-  ]
-}
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index c938bc3..c1d1b8f 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -72,10 +72,12 @@
 }
 
 
-AotOptimizer::AotOptimizer(FlowGraph* flow_graph,
+AotOptimizer::AotOptimizer(Precompiler* precompiler,
+                           FlowGraph* flow_graph,
                            bool use_speculative_inlining,
                            GrowableArray<intptr_t>* inlining_black_list)
     : FlowGraphVisitor(flow_graph->reverse_postorder()),
+      precompiler_(precompiler),
       flow_graph_(flow_graph),
       use_speculative_inlining_(use_speculative_inlining),
       inlining_black_list_(inlining_black_list),
@@ -124,6 +126,47 @@
 }
 
 
+bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
+  if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) {
+    return false;
+  }
+
+  if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) {
+    return false;
+  }
+
+  // There is only a single function Object.get:runtimeType that can be invoked
+  // by this call. Convert dynamic invocation to a static one.
+  const Class& cls = Class::Handle(Z, I->object_store()->object_class());
+  const Array& args_desc_array = Array::Handle(Z,
+      ArgumentsDescriptor::New(call->ArgumentCount(),
+                               call->argument_names()));
+  ArgumentsDescriptor args_desc(args_desc_array);
+  const Function& function = Function::Handle(Z,
+      Resolver::ResolveDynamicForReceiverClass(
+          cls,
+          call->function_name(),
+          args_desc));
+  ASSERT(!function.IsNull());
+
+  ZoneGrowableArray<PushArgumentInstr*>* args =
+      new (Z) ZoneGrowableArray<PushArgumentInstr*>(
+          call->ArgumentCount());
+  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+    args->Add(call->PushArgumentAt(i));
+  }
+  StaticCallInstr* static_call = new (Z) StaticCallInstr(
+      call->token_pos(),
+      Function::ZoneHandle(Z, function.raw()),
+      call->argument_names(),
+      args,
+      call->deopt_id());
+  static_call->set_result_cid(kTypeCid);
+  call->ReplaceWith(static_call, current_iterator());
+  return true;
+}
+
+
 // Optimize instance calls using cid.  This is called after optimizer
 // converted instance calls to instructions. Any remaining
 // instance calls are either megamorphic calls, cannot be optimized or
@@ -629,6 +672,58 @@
 
 static bool SmiFitsInDouble() { return kSmiBits < 53; }
 
+
+static bool IsGetRuntimeType(Definition* defn) {
+  StaticCallInstr* call = defn->AsStaticCall();
+  return (call != NULL) &&
+      (call->function().recognized_kind() ==
+          MethodRecognizer::kObjectRuntimeType);
+}
+
+
+// Recognize a.runtimeType == b.runtimeType and fold it into
+// Object._haveSameRuntimeType(a, b).
+// Note: this optimization is not speculative.
+bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) {
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.NumArgsTested() == 2);
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() &&
+      IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) {
+    const Class& cls = Class::Handle(Z, I->object_store()->object_class());
+    const Function& have_same_runtime_type = Function::ZoneHandle(Z,
+        cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType()));
+    ASSERT(!have_same_runtime_type.IsNull());
+
+    ZoneGrowableArray<PushArgumentInstr*>* args =
+        new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+    PushArgumentInstr* arg = new (Z) PushArgumentInstr(
+        new (Z) Value(left->ArgumentAt(0)));
+    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
+    args->Add(arg);
+    arg = new (Z) PushArgumentInstr(
+         new (Z) Value(right->ArgumentAt(0)));
+    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
+    args->Add(arg);
+    StaticCallInstr* static_call = new (Z) StaticCallInstr(
+        call->token_pos(),
+        have_same_runtime_type,
+        Object::null_array(),  // argument_names
+        args,
+        call->deopt_id());
+    static_call->set_result_cid(kBoolCid);
+    ReplaceCall(call, static_call);
+    return true;
+  }
+
+  return false;
+}
+
+
 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
                                             Token::Kind op_kind) {
   const ICData& ic_data = *call->ic_data();
@@ -640,11 +735,7 @@
 
   intptr_t cid = kIllegalCid;
   if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
-    if (TryStringLengthOneEquality(call, op_kind)) {
-      return true;
-    } else {
-      return false;
-    }
+    return TryStringLengthOneEquality(call, op_kind);
   } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
     InsertBefore(call,
                  new(Z) CheckSmiInstr(new(Z) Value(left),
@@ -710,6 +801,8 @@
       cid = kSmiCid;
     } else {
       // Shortcut for equality with null.
+      // TODO(vegorov): this optimization is not speculative and should
+      // be hoisted out of this function.
       ConstantInstr* right_const = right->AsConstant();
       ConstantInstr* left_const = left->AsConstant();
       if ((right_const != NULL && right_const->value().IsNull()) ||
@@ -1757,6 +1850,14 @@
     return;
   }
 
+  if (RecognizeRuntimeTypeGetter(instr)) {
+    return;
+  }
+
+  if ((op_kind == Token::kEQ) && TryReplaceWithHaveSameRuntimeType(instr)) {
+    return;
+  }
+
   const ICData& unary_checks =
       ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
   if (IsAllowedForInlining(instr->deopt_id()) &&
@@ -1819,7 +1920,21 @@
     case Token::kLT:
     case Token::kLTE:
     case Token::kGT:
-    case Token::kGTE:
+    case Token::kGTE: {
+      if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
+          HasLikelySmiOperand(instr)) {
+        Definition* left = instr->ArgumentAt(0);
+        Definition* right = instr->ArgumentAt(1);
+        CheckedSmiComparisonInstr* smi_op =
+            new(Z) CheckedSmiComparisonInstr(instr->token_kind(),
+                                             new(Z) Value(left),
+                                             new(Z) Value(right),
+                                             instr);
+        ReplaceCall(instr, smi_op);
+        return;
+      }
+      break;
+    }
     case Token::kBIT_OR:
     case Token::kBIT_XOR:
     case Token::kBIT_AND:
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index 2a63a16..01a81ca2 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -13,13 +13,16 @@
 class CSEInstructionMap;
 template <typename T> class GrowableArray;
 class ParsedFunction;
+class Precompiler;
 class RawBool;
 
 class AotOptimizer : public FlowGraphVisitor {
  public:
-  AotOptimizer(FlowGraph* flow_graph,
+  AotOptimizer(Precompiler* precompiler,
+               FlowGraph* flow_graph,
                bool use_speculative_inlining,
                GrowableArray<intptr_t>* inlining_black_list);
+
   virtual ~AotOptimizer() {}
 
   FlowGraph* flow_graph() const { return flow_graph_; }
@@ -101,6 +104,9 @@
 
   void ReplaceCall(Definition* call, Definition* replacement);
 
+  bool RecognizeRuntimeTypeGetter(InstanceCallInstr* call);
+  bool TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call);
+
   bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
                                    RawFunction::Kind kind) const;
 
@@ -131,6 +137,7 @@
 
   bool IsAllowedForInlining(intptr_t deopt_id);
 
+  Precompiler* precompiler_;
   FlowGraph* flow_graph_;
 
   const bool use_speculative_inlining_;
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 6599e59..89977e4 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -2842,6 +2842,7 @@
   vldmd(IA, IP, first, count);
 }
 
+
 void Assembler::StoreMultipleDToOffset(DRegister first,
                                        intptr_t count,
                                        Register base,
@@ -3239,16 +3240,10 @@
 }
 
 
-void Assembler::NoMonomorphicCheckedEntry() {
-  buffer_.Reset();
-  bkpt(0);
-  bkpt(0);
-  ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
-}
-
-
 // R0 receiver, R9 guarded cid as Smi
 void Assembler::MonomorphicCheckedEntry() {
+  ASSERT(has_single_entry_point_);
+  has_single_entry_point_ = false;
 #if defined(TESTING) || defined(DEBUG)
   bool saved_use_far_branches = use_far_branches();
   set_use_far_branches(false);
@@ -3481,6 +3476,22 @@
 }
 
 
+void Assembler::LoadElementAddressForIntIndex(Register address,
+                                              bool is_load,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              intptr_t index) {
+  const int64_t offset_base =
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  const int64_t offset = offset_base +
+      static_cast<int64_t>(index) * index_scale;
+  ASSERT(Utils::IsInt(32, offset));
+  AddImmediate(address, array, offset);
+}
+
+
 Address Assembler::ElementAddressForRegIndex(bool is_load,
                                              bool is_external,
                                              intptr_t cid,
@@ -3525,6 +3536,81 @@
 }
 
 
+void Assembler::LoadElementAddressForRegIndex(Register address,
+                                              bool is_load,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  if (shift < 0) {
+    ASSERT(shift == -1);
+    add(address, array, Operand(index, ASR, 1));
+  } else {
+    add(address, array, Operand(index, LSL, shift));
+  }
+  if (offset != 0) {
+    AddImmediate(address, offset);
+  }
+}
+
+
+void Assembler::LoadHalfWordUnaligned(Register dst,
+                                      Register addr,
+                                      Register tmp) {
+  ASSERT(dst != addr);
+  ldrb(dst, Address(addr, 0));
+  ldrsb(tmp, Address(addr, 1));
+  orr(dst, dst, Operand(tmp, LSL, 8));
+}
+
+
+void Assembler::LoadHalfWordUnsignedUnaligned(Register dst,
+                                              Register addr,
+                                              Register tmp) {
+  ASSERT(dst != addr);
+  ldrb(dst, Address(addr, 0));
+  ldrb(tmp, Address(addr, 1));
+  orr(dst, dst, Operand(tmp, LSL, 8));
+}
+
+
+void Assembler::StoreHalfWordUnaligned(Register src,
+                                       Register addr,
+                                       Register tmp) {
+  strb(src, Address(addr, 0));
+  Lsr(tmp, src, Operand(8));
+  strb(tmp, Address(addr, 1));
+}
+
+
+void Assembler::LoadWordUnaligned(Register dst, Register addr, Register tmp) {
+  ASSERT(dst != addr);
+  ldrb(dst, Address(addr, 0));
+  ldrb(tmp, Address(addr, 1));
+  orr(dst, dst, Operand(tmp, LSL, 8));
+  ldrb(tmp, Address(addr, 2));
+  orr(dst, dst, Operand(tmp, LSL, 16));
+  ldrb(tmp, Address(addr, 3));
+  orr(dst, dst, Operand(tmp, LSL, 24));
+}
+
+
+void Assembler::StoreWordUnaligned(Register src, Register addr, Register tmp) {
+  strb(src, Address(addr, 0));
+  Lsr(tmp, src, Operand(8));
+  strb(tmp, Address(addr, 1));
+  Lsr(tmp, src, Operand(16));
+  strb(tmp, Address(addr, 2));
+  Lsr(tmp, src, Operand(24));
+  strb(tmp, Address(addr, 3));
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
   "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 4c17227..735a5f7 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -366,10 +366,10 @@
   explicit Assembler(bool use_far_branches = false)
       : buffer_(),
         prologue_offset_(-1),
+        has_single_entry_point_(true),
         use_far_branches_(use_far_branches),
         comments_(),
         constant_pool_allowed_(false) {
-    MonomorphicCheckedEntry();
   }
 
   ~Assembler() { }
@@ -382,6 +382,7 @@
   // Misc. functionality
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return prologue_offset_; }
+  bool has_single_entry_point() const { return has_single_entry_point_; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.  On ARM there are no pointers in code.
@@ -946,7 +947,6 @@
   void EnterStubFrame();
   void LeaveStubFrame();
 
-  void NoMonomorphicCheckedEntry();
   void MonomorphicCheckedEntry();
 
   // The register into which the allocation stats table is loaded with
@@ -971,6 +971,14 @@
                                     intptr_t index,
                                     Register temp);
 
+  void LoadElementAddressForIntIndex(Register address,
+                                     bool is_load,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     intptr_t index);
+
   Address ElementAddressForRegIndex(bool is_load,
                                     bool is_external,
                                     intptr_t cid,
@@ -978,6 +986,20 @@
                                     Register array,
                                     Register index);
 
+  void LoadElementAddressForRegIndex(Register address,
+                                     bool is_load,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     Register index);
+
+  void LoadHalfWordUnaligned(Register dst, Register addr, Register tmp);
+  void LoadHalfWordUnsignedUnaligned(Register dst, Register addr, Register tmp);
+  void StoreHalfWordUnaligned(Register src, Register addr, Register tmp);
+  void LoadWordUnaligned(Register dst, Register addr, Register tmp);
+  void StoreWordUnaligned(Register src, Register addr, Register tmp);
+
   // If allocation tracing for |cid| is enabled, will jump to |trace| label,
   // which will allocate in the runtime where tracing occurs.
   void MaybeTraceAllocation(intptr_t cid,
@@ -1019,9 +1041,8 @@
  private:
   AssemblerBuffer buffer_;  // Contains position independent code.
   ObjectPoolWrapper object_pool_wrapper_;
-
   int32_t prologue_offset_;
-
+  bool has_single_entry_point_;
   bool use_far_branches_;
 
   // If you are thinking of using one or both of these instructions directly,
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 37e9ca3..e7cab40 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -24,10 +24,10 @@
 Assembler::Assembler(bool use_far_branches)
     : buffer_(),
       prologue_offset_(-1),
+      has_single_entry_point_(true),
       use_far_branches_(use_far_branches),
       comments_(),
       constant_pool_allowed_(false) {
-  MonomorphicCheckedEntry();
 }
 
 
@@ -1238,18 +1238,10 @@
 }
 
 
-void Assembler::NoMonomorphicCheckedEntry() {
-  buffer_.Reset();
-  brk(0);
-  brk(0);
-  brk(0);
-  brk(0);
-  ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
-}
-
-
 // R0 receiver, R5 guarded cid as Smi
 void Assembler::MonomorphicCheckedEntry() {
+  ASSERT(has_single_entry_point_);
+  has_single_entry_point_ = false;
   bool saved_use_far_branches = use_far_branches();
   set_use_far_branches(false);
 
@@ -1444,6 +1436,18 @@
 }
 
 
+void Assembler::LoadElementAddressForIntIndex(Register address,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              intptr_t index) {
+  const int64_t offset = index * index_scale +
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  AddImmediate(address, array, offset);
+}
+
+
 Address Assembler::ElementAddressForRegIndex(bool is_load,
                                              bool is_external,
                                              intptr_t cid,
@@ -1470,6 +1474,102 @@
   return Address(base, offset, Address::Offset, size);
 }
 
+
+void Assembler::LoadElementAddressForRegIndex(Register address,
+                                              bool is_load,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  const int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  if (shift == 0) {
+    add(address, array, Operand(index));
+  } else if (shift < 0) {
+    ASSERT(shift == -1);
+    add(address, array, Operand(index, ASR, 1));
+  } else {
+    add(address, array, Operand(index, LSL, shift));
+  }
+  if (offset != 0) {
+    AddImmediate(address, address, offset);
+  }
+}
+
+
+void Assembler::LoadUnaligned(Register dst, Register addr, Register tmp,
+                              OperandSize sz) {
+  ASSERT(dst != addr);
+  ldr(dst, Address(addr, 0), kUnsignedByte);
+  if (sz == kHalfword) {
+    ldr(tmp, Address(addr, 1), kByte);
+    orr(dst, dst, Operand(tmp, LSL, 8));
+    return;
+  }
+  ldr(tmp, Address(addr, 1), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 8));
+  if (sz == kUnsignedHalfword) {
+    return;
+  }
+  ldr(tmp, Address(addr, 2), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 16));
+  if (sz == kWord) {
+    ldr(tmp, Address(addr, 3), kByte);
+    orr(dst, dst, Operand(tmp, LSL, 24));
+    return;
+  }
+  ldr(tmp, Address(addr, 3), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 24));
+  if (sz == kUnsignedWord) {
+    return;
+  }
+  ldr(tmp, Address(addr, 4), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 32));
+  ldr(tmp, Address(addr, 5), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 40));
+  ldr(tmp, Address(addr, 6), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 48));
+  ldr(tmp, Address(addr, 7), kUnsignedByte);
+  orr(dst, dst, Operand(tmp, LSL, 56));
+  if (sz == kDoubleWord) {
+    return;
+  }
+  UNIMPLEMENTED();
+}
+
+
+void Assembler::StoreUnaligned(Register src, Register addr, Register tmp,
+                               OperandSize sz) {
+  str(src, Address(addr, 0), kUnsignedByte);
+  LsrImmediate(tmp, src, 8);
+  str(tmp, Address(addr, 1), kUnsignedByte);
+  if ((sz == kHalfword) || (sz == kUnsignedHalfword)) {
+    return;
+  }
+  LsrImmediate(tmp, src, 16);
+  str(tmp, Address(addr, 2), kUnsignedByte);
+  LsrImmediate(tmp, src, 24);
+  str(tmp, Address(addr, 3), kUnsignedByte);
+  if ((sz == kWord) || (sz == kUnsignedWord)) {
+    return;
+  }
+  LsrImmediate(tmp, src, 24);
+  str(tmp, Address(addr, 4), kUnsignedByte);
+  LsrImmediate(tmp, src, 32);
+  str(tmp, Address(addr, 5), kUnsignedByte);
+  LsrImmediate(tmp, src, 40);
+  str(tmp, Address(addr, 6), kUnsignedByte);
+  LsrImmediate(tmp, src, 48);
+  str(tmp, Address(addr, 7), kUnsignedByte);
+  if (sz == kDoubleWord) {
+    return;
+  }
+  UNIMPLEMENTED();
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index 77d7fce..4ef4f95 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -467,6 +467,7 @@
   // Misc. functionality
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return prologue_offset_; }
+  bool has_single_entry_point() const { return has_single_entry_point_; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.  On ARM64 there are no pointers in code.
@@ -1363,7 +1364,6 @@
   void EnterStubFrame();
   void LeaveStubFrame();
 
-  void NoMonomorphicCheckedEntry();
   void MonomorphicCheckedEntry();
 
   void UpdateAllocationStats(intptr_t cid,
@@ -1401,20 +1401,36 @@
                                     intptr_t index_scale,
                                     Register array,
                                     intptr_t index) const;
+  void LoadElementAddressForIntIndex(Register address,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     intptr_t index);
   Address ElementAddressForRegIndex(bool is_load,
                                     bool is_external,
                                     intptr_t cid,
                                     intptr_t index_scale,
                                     Register array,
                                     Register index);
+  void LoadElementAddressForRegIndex(Register address,
+                                     bool is_load,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     Register index);
+
+  void LoadUnaligned(Register dst, Register addr, Register tmp,
+                     OperandSize sz);
+  void StoreUnaligned(Register src, Register addr, Register tmp,
+                      OperandSize sz);
 
  private:
   AssemblerBuffer buffer_;  // Contains position independent code.
-
   ObjectPoolWrapper object_pool_wrapper_;
-
   int32_t prologue_offset_;
-
+  bool has_single_entry_point_;
   bool use_far_branches_;
 
   class CodeComment : public ZoneAllocated {
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 3d95b7c..ea2d2df 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -1684,6 +1684,191 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnaligned, assembler) {
+  __ LoadUnaligned(R1, R0, TMP, kHalfword);
+  __ mov(R0, R1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xAB89)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xCDAB)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnsignedUnaligned, assembler) {
+  __ LoadUnaligned(R1, R0, TMP, kUnsignedHalfword);
+  __ mov(R0, R1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnsignedUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnsignedUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(0xAB89,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnsignedUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCDAB,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                 LoadHalfWordUnsignedUnaligned,
+                 test->entry(),
+                 reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreHalfWordUnaligned, assembler) {
+  __ LoadImmediate(R1, 0xABCD);
+  __ StoreUnaligned(R1, R0, TMP, kHalfword);
+  __ mov(R0, R1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(StoreHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0, 0, 0, 0,
+  };
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCD, buffer[0]);
+  EXPECT_EQ(0xAB, buffer[1]);
+  EXPECT_EQ(0, buffer[2]);
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0xCD, buffer[1]);
+  EXPECT_EQ(0xAB, buffer[2]);
+  EXPECT_EQ(0, buffer[3]);
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadWordUnaligned, assembler) {
+  __ LoadUnaligned(R1, R0, TMP, kUnsignedWord);
+  __ mov(R0, R1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(LoadWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef int32_t (*LoadWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xBC, 0xDE, 0xF0
+  };
+
+  EXPECT_EQ(static_cast<int32_t>(0x78563412),
+            EXECUTE_TEST_CODE_INT32_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(static_cast<int32_t>(0x9A785634),
+            EXECUTE_TEST_CODE_INT32_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(static_cast<int32_t>(0xBC9A7856),
+            EXECUTE_TEST_CODE_INT32_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(static_cast<int32_t>(0xDEBC9A78),
+            EXECUTE_TEST_CODE_INT32_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreWordUnaligned, assembler) {
+  __ LoadImmediate(R1, 0x12345678);
+  __ StoreUnaligned(R1, R0, TMP, kUnsignedWord);
+  __ mov(R0, R1);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(StoreWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0, 0, 0, 0,
+    0, 0, 0, 0
+  };
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0x78, buffer[0]);
+  EXPECT_EQ(0x56, buffer[1]);
+  EXPECT_EQ(0x34, buffer[2]);
+  EXPECT_EQ(0x12, buffer[3]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0x78, buffer[1]);
+  EXPECT_EQ(0x56, buffer[2]);
+  EXPECT_EQ(0x34, buffer[3]);
+  EXPECT_EQ(0x12, buffer[4]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(0x78, buffer[2]);
+  EXPECT_EQ(0x56, buffer[3]);
+  EXPECT_EQ(0x34, buffer[4]);
+  EXPECT_EQ(0x12, buffer[5]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+  EXPECT_EQ(0x78, buffer[3]);
+  EXPECT_EQ(0x56, buffer[4]);
+  EXPECT_EQ(0x34, buffer[5]);
+  EXPECT_EQ(0x12, buffer[6]);
+}
+
+
 static void EnterTestFrame(Assembler* assembler) {
   __ EnterFrame(0);
   __ Push(CODE_REG);
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 7eca350..8fe9960 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -97,6 +97,191 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnaligned, assembler) {
+  __ LoadHalfWordUnaligned(R1, R0, TMP);
+  __ mov(R0, Operand(R1));
+  __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xAB89)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xCDAB)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnsignedUnaligned, assembler) {
+  __ LoadHalfWordUnsignedUnaligned(R1, R0, TMP);
+  __ mov(R0, Operand(R1));
+  __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnsignedUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnsignedUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(0xAB89,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnsignedUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCDAB,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnsignedUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreHalfWordUnaligned, assembler) {
+  __ LoadImmediate(R1, 0xABCD);
+  __ StoreWordUnaligned(R1, R0, TMP);
+  __ mov(R0, Operand(R1));
+  __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(StoreHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0, 0, 0, 0,
+  };
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCD, buffer[0]);
+  EXPECT_EQ(0xAB, buffer[1]);
+  EXPECT_EQ(0, buffer[2]);
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0xCD, buffer[1]);
+  EXPECT_EQ(0xAB, buffer[2]);
+  EXPECT_EQ(0, buffer[3]);
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadWordUnaligned, assembler) {
+  __ LoadWordUnaligned(R1, R0, TMP);
+  __ mov(R0, Operand(R1));
+  __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xBC, 0xDE, 0xF0
+  };
+
+  EXPECT_EQ(0x78563412,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0x9A785634,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0xBC9A7856,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(0xDEBC9A78,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreWordUnaligned, assembler) {
+  __ LoadImmediate(R1, 0x12345678);
+  __ StoreWordUnaligned(R1, R0, TMP);
+  __ mov(R0, Operand(R1));
+  __ bx(LR);
+}
+
+
+ASSEMBLER_TEST_RUN(StoreWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0, 0, 0, 0,
+    0, 0, 0, 0
+  };
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0x78, buffer[0]);
+  EXPECT_EQ(0x56, buffer[1]);
+  EXPECT_EQ(0x34, buffer[2]);
+  EXPECT_EQ(0x12, buffer[3]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0x78, buffer[1]);
+  EXPECT_EQ(0x56, buffer[2]);
+  EXPECT_EQ(0x34, buffer[3]);
+  EXPECT_EQ(0x12, buffer[4]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(0x78, buffer[2]);
+  EXPECT_EQ(0x56, buffer[3]);
+  EXPECT_EQ(0x34, buffer[4]);
+  EXPECT_EQ(0x12, buffer[5]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+  EXPECT_EQ(0x78, buffer[3]);
+  EXPECT_EQ(0x56, buffer[4]);
+  EXPECT_EQ(0x34, buffer[5]);
+  EXPECT_EQ(0x12, buffer[6]);
+}
+
+
 ASSEMBLER_TEST_GENERATE(Vmov, assembler) {
   if (TargetCPUFeatures::vfp_supported()) {
     __ mov(R3, Operand(43));
diff --git a/runtime/vm/assembler_dbc.h b/runtime/vm/assembler_dbc.h
index d775e45..d956f70 100644
--- a/runtime/vm/assembler_dbc.h
+++ b/runtime/vm/assembler_dbc.h
@@ -86,6 +86,7 @@
   // Misc. functionality
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return 0; }
+  bool has_single_entry_point() const { return true; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 75eb1dc..d49e844 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -783,6 +783,7 @@
 
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return prologue_offset_; }
+  bool has_single_entry_point() const { return true; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index aa8905e..dcf1473 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -860,17 +860,10 @@
 }
 
 
-void Assembler::NoMonomorphicCheckedEntry() {
-  buffer_.Reset();
-  break_(0);
-  break_(0);
-  break_(0);
-  ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
-}
-
-
 // T0 receiver, S5 guarded cid as Smi
 void Assembler::MonomorphicCheckedEntry() {
+  ASSERT(has_single_entry_point_);
+  has_single_entry_point_ = false;
   bool saved_use_far_branches = use_far_branches();
   set_use_far_branches(false);
 
@@ -1236,6 +1229,18 @@
 }
 
 
+void Assembler::LoadElementAddressForIntIndex(Register address,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              intptr_t index) {
+  const int64_t offset = index * index_scale +
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  AddImmediate(address, array, offset);
+}
+
+
 Address Assembler::ElementAddressForRegIndex(bool is_load,
                                              bool is_external,
                                              intptr_t cid,
@@ -1264,6 +1269,92 @@
 }
 
 
+void Assembler::LoadElementAddressForRegIndex(Register address,
+                                              bool is_load,
+                                              bool is_external,
+                                              intptr_t cid,
+                                              intptr_t index_scale,
+                                              Register array,
+                                              Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  const int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  if (shift < 0) {
+    ASSERT(shift == -1);
+    sra(address, index, 1);
+    addu(address, array, address);
+  } else if (shift == 0) {
+    addu(address, array, index);
+  } else {
+    sll(address, index, shift);
+    addu(address, array, address);
+  }
+  if (offset != 0) {
+    AddImmediate(address, offset);
+  }
+}
+
+
+void Assembler::LoadHalfWordUnaligned(Register dst,
+                                      Register addr,
+                                      Register tmp) {
+  ASSERT(dst != addr);
+  lbu(dst, Address(addr, 0));
+  lb(tmp, Address(addr, 1));
+  sll(tmp, tmp, 8);
+  or_(dst, dst, tmp);
+}
+
+
+void Assembler::LoadHalfWordUnsignedUnaligned(Register dst,
+                                              Register addr,
+                                              Register tmp) {
+  ASSERT(dst != addr);
+  lbu(dst, Address(addr, 0));
+  lbu(tmp, Address(addr, 1));
+  sll(tmp, tmp, 8);
+  or_(dst, dst, tmp);
+}
+
+
+void Assembler::StoreHalfWordUnaligned(Register src,
+                                       Register addr,
+                                       Register tmp) {
+  sb(src, Address(addr, 0));
+  srl(tmp, src, 8);
+  sb(tmp, Address(addr, 1));
+}
+
+
+void Assembler::LoadWordUnaligned(Register dst, Register addr, Register tmp) {
+  // TODO(rmacnak): LWL + LWR
+  ASSERT(dst != addr);
+  lbu(dst, Address(addr, 0));
+  lbu(tmp, Address(addr, 1));
+  sll(tmp, tmp, 8);
+  or_(dst, dst, tmp);
+  lbu(tmp, Address(addr, 2));
+  sll(tmp, tmp, 16);
+  or_(dst, dst, tmp);
+  lbu(tmp, Address(addr, 3));
+  sll(tmp, tmp, 24);
+  or_(dst, dst, tmp);
+}
+
+
+void Assembler::StoreWordUnaligned(Register src, Register addr, Register tmp) {
+  // TODO(rmacnak): SWL + SWR
+  sb(src, Address(addr, 0));
+  srl(tmp, src, 8);
+  sb(tmp, Address(addr, 1));
+  srl(tmp, src, 16);
+  sb(tmp, Address(addr, 2));
+  srl(tmp, src, 24);
+  sb(tmp, Address(addr, 3));
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "zr", "tmp", "v0", "v1", "a0", "a1", "a2", "a3",
   "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index bc06a7a..4abaa23 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -239,12 +239,12 @@
   explicit Assembler(bool use_far_branches = false)
       : buffer_(),
         prologue_offset_(-1),
+        has_single_entry_point_(true),
         use_far_branches_(use_far_branches),
         delay_slot_available_(false),
         in_delay_slot_(false),
         comments_(),
         constant_pool_allowed_(true) {
-    MonomorphicCheckedEntry();
   }
   ~Assembler() { }
 
@@ -256,6 +256,7 @@
   // Misc. functionality
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return prologue_offset_; }
+  bool has_single_entry_point() const { return has_single_entry_point_; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.
@@ -296,7 +297,6 @@
   // the branch delay slot.
   void LeaveStubFrameAndReturn(Register ra = RA);
 
-  void NoMonomorphicCheckedEntry();
   void MonomorphicCheckedEntry();
 
   void UpdateAllocationStats(intptr_t cid,
@@ -1599,12 +1599,31 @@
                                     intptr_t index_scale,
                                     Register array,
                                     intptr_t index) const;
+  void LoadElementAddressForIntIndex(Register address,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     intptr_t index);
   Address ElementAddressForRegIndex(bool is_load,
                                     bool is_external,
                                     intptr_t cid,
                                     intptr_t index_scale,
                                     Register array,
                                     Register index);
+  void LoadElementAddressForRegIndex(Register address,
+                                     bool is_load,
+                                     bool is_external,
+                                     intptr_t cid,
+                                     intptr_t index_scale,
+                                     Register array,
+                                     Register index);
+
+  void LoadHalfWordUnaligned(Register dst, Register addr, Register tmp);
+  void LoadHalfWordUnsignedUnaligned(Register dst, Register addr, Register tmp);
+  void StoreHalfWordUnaligned(Register src, Register addr, Register tmp);
+  void LoadWordUnaligned(Register dst, Register addr, Register tmp);
+  void StoreWordUnaligned(Register src, Register addr, Register tmp);
 
   static Address VMTagAddress() {
     return Address(THR, Thread::vm_tag_offset());
@@ -1627,7 +1646,7 @@
   ObjectPoolWrapper object_pool_wrapper_;
 
   intptr_t prologue_offset_;
-
+  bool has_single_entry_point_;
   bool use_far_branches_;
   bool delay_slot_available_;
   bool in_delay_slot_;
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 2a77101..f34b79cb 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -320,6 +320,188 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnaligned, assembler) {
+  __ LoadHalfWordUnaligned(V0, A0, TMP);
+  __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xAB89)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(static_cast<int16_t>(static_cast<uint16_t>(0xCDAB)),
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadHalfWordUnsignedUnaligned, assembler) {
+  __ LoadHalfWordUnsignedUnaligned(V0, A0, TMP);
+  __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadHalfWordUnsignedUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadHalfWordUnsignedUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0x89, 0xAB, 0xCD, 0xEF,
+  };
+
+  EXPECT_EQ(0xAB89,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnsignedUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCDAB,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadHalfWordUnsignedUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreHalfWordUnaligned, assembler) {
+  __ LoadImmediate(A1, 0xABCD);
+  __ StoreWordUnaligned(A1, A0, TMP);
+  __ mov(V0, A1);
+  __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(StoreHalfWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreHalfWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[4] = {
+    0, 0, 0, 0,
+  };
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0xCD, buffer[0]);
+  EXPECT_EQ(0xAB, buffer[1]);
+  EXPECT_EQ(0, buffer[2]);
+
+  EXPECT_EQ(0xABCD,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreHalfWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0xCD, buffer[1]);
+  EXPECT_EQ(0xAB, buffer[2]);
+  EXPECT_EQ(0, buffer[3]);
+}
+
+
+ASSEMBLER_TEST_GENERATE(LoadWordUnaligned, assembler) {
+  __ LoadWordUnaligned(V0, A0, TMP);
+  __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(LoadWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*LoadWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0x12, 0x34, 0x56, 0x78,
+    0x9A, 0xBC, 0xDE, 0xF0
+  };
+
+  EXPECT_EQ(0x78563412,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0x9A785634,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0xBC9A7856,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(0xDEBC9A78,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                LoadWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+}
+
+
+ASSEMBLER_TEST_GENERATE(StoreWordUnaligned, assembler) {
+  __ LoadImmediate(A1, 0x12345678);
+  __ StoreWordUnaligned(A1, A0, TMP);
+  __ mov(V0, A1);
+  __ jr(RA);
+}
+
+
+ASSEMBLER_TEST_RUN(StoreWordUnaligned, test) {
+  EXPECT(test != NULL);
+  typedef intptr_t (*StoreWordUnaligned)(intptr_t) DART_UNUSED;
+  uint8_t buffer[8] = {
+    0, 0, 0, 0,
+    0, 0, 0, 0
+  };
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[0])));
+  EXPECT_EQ(0x78, buffer[0]);
+  EXPECT_EQ(0x56, buffer[1]);
+  EXPECT_EQ(0x34, buffer[2]);
+  EXPECT_EQ(0x12, buffer[3]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[1])));
+  EXPECT_EQ(0x78, buffer[1]);
+  EXPECT_EQ(0x56, buffer[2]);
+  EXPECT_EQ(0x34, buffer[3]);
+  EXPECT_EQ(0x12, buffer[4]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[2])));
+  EXPECT_EQ(0x78, buffer[2]);
+  EXPECT_EQ(0x56, buffer[3]);
+  EXPECT_EQ(0x34, buffer[4]);
+  EXPECT_EQ(0x12, buffer[5]);
+
+  EXPECT_EQ(0x12345678,
+            EXECUTE_TEST_CODE_INTPTR_INTPTR(
+                StoreWordUnaligned,
+                test->entry(),
+                reinterpret_cast<intptr_t>(&buffer[3])));
+  EXPECT_EQ(0x78, buffer[3]);
+  EXPECT_EQ(0x56, buffer[4]);
+  EXPECT_EQ(0x34, buffer[5]);
+  EXPECT_EQ(0x12, buffer[6]);
+}
+
+
 ASSEMBLER_TEST_GENERATE(Lui, assembler) {
   __ lui(V0, Immediate(42));
   __ jr(RA);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index ea2c95d..a1b6695 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -24,11 +24,11 @@
 Assembler::Assembler(bool use_far_branches)
     : buffer_(),
       prologue_offset_(-1),
+      has_single_entry_point_(true),
       comments_(),
       constant_pool_allowed_(false) {
   // Far branching mode is only needed and implemented for MIPS and ARM.
   ASSERT(!use_far_branches);
-  MonomorphicCheckedEntry();
 }
 
 
@@ -3322,17 +3322,10 @@
 }
 
 
-void Assembler::NoMonomorphicCheckedEntry() {
-  buffer_.Reset();
-  for (intptr_t i = 0; i < Instructions::kCheckedEntryOffset; i++) {
-    int3();
-  }
-  ASSERT(CodeSize() == Instructions::kCheckedEntryOffset);
-}
-
-
 // RDI receiver, RBX guarded cid as Smi
 void Assembler::MonomorphicCheckedEntry() {
+  ASSERT(has_single_entry_point_);
+  has_single_entry_point_ = false;
   Label immediate, have_cid, miss;
   Bind(&miss);
   jmp(Address(THR, Thread::monomorphic_miss_entry_offset()));
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 82094d2..b6db263 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -882,6 +882,7 @@
 
   intptr_t CodeSize() const { return buffer_.Size(); }
   intptr_t prologue_offset() const { return prologue_offset_; }
+  bool has_single_entry_point() const { return has_single_entry_point_; }
 
   // Count the fixups that produce a pointer offset, without processing
   // the fixups.
@@ -949,8 +950,6 @@
   void EnterStubFrame();
   void LeaveStubFrame();
 
-  void RawEntry() { buffer_.Reset(); }
-  void NoMonomorphicCheckedEntry();
   void MonomorphicCheckedEntry();
 
   void UpdateAllocationStats(intptr_t cid,
@@ -1025,6 +1024,7 @@
   ObjectPoolWrapper object_pool_wrapper_;
 
   intptr_t prologue_offset_;
+  bool has_single_entry_point_;
 
   class CodeComment : public ZoneAllocated {
    public:
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 8a3c373..4193276 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -3113,8 +3113,6 @@
 
 
 ASSEMBLER_TEST_GENERATE(TestNop, assembler) {
-  __ RawEntry();
-
   __ nop(1);
   __ nop(2);
   __ nop(3);
@@ -3136,8 +3134,6 @@
 
 
 ASSEMBLER_TEST_GENERATE(TestAlign0, assembler) {
-  __ RawEntry();
-
   __ Align(4, 0);
   __ movq(RAX, Immediate(assembler->CodeSize()));  // Return code size.
   __ ret();
@@ -3152,8 +3148,6 @@
 
 
 ASSEMBLER_TEST_GENERATE(TestAlign1, assembler) {
-  __ RawEntry();
-
   __ nop(1);
   __ Align(4, 0);
   __ movq(RAX, Immediate(assembler->CodeSize()));  // Return code size.
@@ -3169,8 +3163,6 @@
 
 
 ASSEMBLER_TEST_GENERATE(TestAlign1Offset1, assembler) {
-  __ RawEntry();
-
   __ nop(1);
   __ Align(4, 1);
   __ movq(RAX, Immediate(assembler->CodeSize()));  // Return code size.
@@ -3186,8 +3178,6 @@
 
 
 ASSEMBLER_TEST_GENERATE(TestAlignLarge, assembler) {
-  __ RawEntry();
-
   __ nop(1);
   __ Align(16, 0);
   __ movq(RAX, Immediate(assembler->CodeSize()));  // Return code size.
diff --git a/runtime/vm/bigint_test.cc b/runtime/vm/bigint_test.cc
index 967e036..21ba79b 100644
--- a/runtime/vm/bigint_test.cc
+++ b/runtime/vm/bigint_test.cc
@@ -9,12 +9,6 @@
 
 namespace dart {
 
-static uword ZoneAllocator(intptr_t size) {
-  Zone* zone = Thread::Current()->zone();
-  return zone->AllocUnsafe(size);
-}
-
-
 TEST_CASE(BigintSmi) {
   {
     const Smi& smi = Smi::Handle(Smi::New(5));
@@ -235,6 +229,7 @@
 
 
 TEST_CASE(BigintHexStrings) {
+  Zone* zone = Thread::Current()->zone();
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0x0"));
     EXPECT(bigint.FitsIntoSmi());
@@ -255,41 +250,41 @@
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0x123"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0x123", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0xaBcEf"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0xABCEF", str);
   }
 
   {
     const char* in = "0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
   {
     const char* in = "0xFFFFFFF";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
   {
     const char* in = "0x10000000";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
   {
     const char* in = "0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
@@ -301,27 +296,27 @@
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-0x123"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0x123", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-0xaBcEf"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0xABCEF", str);
   }
 
   {
     const char* in = "-0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
   {
     const char* in = "-0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(in, str);
   }
 
@@ -334,14 +329,14 @@
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("0x000000123"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0x123", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("0x0000aBcEf"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0xABCEF", str);
   }
 
@@ -349,7 +344,7 @@
     const char* in = "0x00000000000000000000000000000000000000000000123456789";
     const char* out =                                            "0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
 
@@ -357,7 +352,7 @@
     const char* in = "0x00000123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const char* out =     "0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
 
@@ -371,14 +366,14 @@
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("-0x00000123"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0x123", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("-0x000aBcEf"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0xABCEF", str);
   }
 
@@ -386,7 +381,7 @@
     const char* in = "-0x00000000000000000000000000000000000000000000123456789";
     const char* out =                                            "-0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
 
@@ -394,7 +389,7 @@
     const char* in = "-0x0000123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const char* out =    "-0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
   {
@@ -402,63 +397,64 @@
     const char* out = "0xAB54A98CEB1F0AD2";
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString(test));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
   {
     const char* test = "-12345678901234567890";
     const char* out = "-0xAB54A98CEB1F0AD2";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(test));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ(out, str);
   }
 }
 
 
 TEST_CASE(BigintDecStrings) {
+  Zone* zone = Thread::Current()->zone();
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0x0"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("0", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0x123"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("291", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0xaBcEf"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("703727", str);
   }
 
   {
     const char* in = "0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("4886718345", str);
   }
 
   {
     const char* in = "0xFFFFFFF";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("268435455", str);
   }
 
   {
     const char* in = "0x10000000";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("268435456", str);
   }
 
   {
     const char* in = "0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("7141946863373290020600059860922167424469804758405880798960",
         str);
   }
@@ -471,27 +467,27 @@
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-0x123"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("-291", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-0xaBcEf"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("-703727", str);
   }
 
   {
     const char* in = "-0x123456789";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("-4886718345", str);
   }
 
   {
     const char* in = "-0x123456789ABCDEF01234567890ABCDEF0123456789ABCDEF0";
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString(in));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("-7141946863373290020600059860922167424469804758405880798960",
         str);
   }
@@ -505,14 +501,14 @@
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("0x000000123"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("291", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("100000000000000000000000000000000"));
-    const char* str = bigint.ToDecCString(&ZoneAllocator);
+    const char* str = bigint.ToDecCString(zone);
     EXPECT_STREQ("100000000000000000000000000000000", str);
   }
 }
@@ -590,6 +586,7 @@
 
 
 TEST_CASE(BigintDecimalStrings) {
+  Zone* zone = Thread::Current()->zone();
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("0"));
     EXPECT(bigint.FitsIntoSmi());
@@ -604,20 +601,20 @@
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("703710"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0xABCDE", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("11259375"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0xABCDEF", str);
   }
 
   {
     const Bigint& bigint =
         Bigint::Handle(Bigint::NewFromCString("1311768467463790320"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("0x123456789ABCDEF0", str);
   }
 
@@ -635,20 +632,20 @@
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-703710"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0xABCDE", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(Bigint::NewFromCString("-11259375"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0xABCDEF", str);
   }
 
   {
     const Bigint& bigint = Bigint::Handle(
         Bigint::NewFromCString("-1311768467463790320"));
-    const char* str = bigint.ToHexCString(&ZoneAllocator);
+    const char* str = bigint.ToHexCString(zone);
     EXPECT_STREQ("-0x123456789ABCDEF0", str);
   }
 }
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 4677ca1..cad4e67 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -20,6 +20,7 @@
   V(Object_toString, 1)                                                        \
   V(Object_noSuchMethod, 6)                                                    \
   V(Object_runtimeType, 1)                                                     \
+  V(Object_haveSameRuntimeType, 2)                                             \
   V(Object_instanceOf, 4)                                                      \
   V(Object_simpleInstanceOf, 2)                                                \
   V(Object_instanceOfNum, 2)                                                   \
@@ -70,11 +71,15 @@
   V(Bigint_getDigits, 1)                                                       \
   V(Bigint_allocate, 4)                                                        \
   V(Developer_debugger, 2)                                                     \
+  V(Developer_getServerInfo, 1)                                                \
+  V(Developer_getServiceMajorVersion, 0)                                       \
+  V(Developer_getServiceMinorVersion, 0)                                       \
   V(Developer_inspect, 1)                                                      \
   V(Developer_lookupExtension, 1)                                              \
   V(Developer_registerExtension, 2)                                            \
   V(Developer_log, 8)                                                          \
   V(Developer_postEvent, 2)                                                    \
+  V(Developer_webServerControl, 2)                                             \
   V(Double_getIsNegative, 1)                                                   \
   V(Double_getIsInfinite, 1)                                                   \
   V(Double_getIsNaN, 1)                                                        \
diff --git a/runtime/vm/branch_optimizer.cc b/runtime/vm/branch_optimizer.cc
index b34baf7..567a2bf 100644
--- a/runtime/vm/branch_optimizer.cc
+++ b/runtime/vm/branch_optimizer.cc
@@ -44,6 +44,12 @@
   BranchInstr* branch = block->last_instruction()->AsBranch();
   ASSERT(branch != NULL);
   ComparisonInstr* comparison = branch->comparison();
+  if (comparison->InputCount() != 2) {
+    return false;
+  }
+  if (comparison->CanDeoptimize() || comparison->MayThrow()) {
+    return false;
+  }
   Value* left = comparison->left();
   PhiInstr* phi = left->definition()->AsPhi();
   Value* right = comparison->right();
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index dccb8c1..298fac3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -855,7 +855,8 @@
                                    &inline_id_to_token_pos,
                                    &caller_inline_id,
                                    use_speculative_inlining,
-                                   NULL);
+                                   /*inlining_black_list=*/ NULL,
+                                   /*precompiler=*/ NULL);
           inliner.Inline();
           // Use lists are maintained and validated by the inliner.
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -1459,7 +1460,8 @@
                                     const Function& function) {
 #ifdef DART_PRECOMPILER
   if (FLAG_precompiled_mode) {
-    return Precompiler::CompileFunction(thread, thread->zone(), function);
+    return Precompiler::CompileFunction(
+        /* precompiler = */ NULL, thread, thread->zone(), function);
   }
 #endif
   Isolate* isolate = thread->isolate();
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 06f8dd5..b63f849 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -941,6 +941,12 @@
 }
 
 
+void ConstantPropagator::VisitCheckedSmiComparison(
+    CheckedSmiComparisonInstr* instr) {
+  SetValue(instr, non_constant_);
+}
+
+
 void ConstantPropagator::VisitBinarySmiOp(BinarySmiOpInstr* instr) {
   VisitBinaryIntegerOp(instr);
 }
@@ -1170,16 +1176,21 @@
 
 void ConstantPropagator::VisitDoubleTestOp(DoubleTestOpInstr* instr) {
   const Object& value = instr->value()->definition()->constant_value();
+  const bool is_negated = instr->kind() != Token::kEQ;
   if (value.IsInteger()) {
-    SetValue(instr, Bool::False());
+    SetValue(instr, is_negated ? Bool::True() : Bool::False());
   } else if (IsIntegerOrDouble(value)) {
     switch (instr->op_kind()) {
-      case MethodRecognizer::kDouble_getIsNaN:
-        SetValue(instr, Bool::Get(isnan(ToDouble(value))));
+      case MethodRecognizer::kDouble_getIsNaN: {
+        const bool is_nan = isnan(ToDouble(value));
+        SetValue(instr, Bool::Get(is_negated ? !is_nan : is_nan));
         break;
-      case MethodRecognizer::kDouble_getIsInfinite:
-        SetValue(instr, Bool::Get(isinf(ToDouble(value))));
+      }
+      case MethodRecognizer::kDouble_getIsInfinite: {
+        const bool is_inf = isinf(ToDouble(value));
+        SetValue(instr, Bool::Get(is_negated ? !is_inf : is_inf));
         break;
+      }
       default:
         UNREACHABLE();
     }
diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h
index e93bc0b..1c0d1be 100644
--- a/runtime/vm/constants_dbc.h
+++ b/runtime/vm/constants_dbc.h
@@ -729,8 +729,8 @@
   V(DCeil,                         A_D, reg, reg, ___) \
   V(DoubleToFloat,                 A_D, reg, reg, ___) \
   V(FloatToDouble,                 A_D, reg, reg, ___) \
-  V(DoubleIsNaN,                   A_D, reg, reg, ___) \
-  V(DoubleIsInfinite,              A_D, reg, reg, ___) \
+  V(DoubleIsNaN,                     A, reg, ___, ___) \
+  V(DoubleIsInfinite,                A, reg, ___, ___) \
   V(StoreStaticTOS,                  D, lit, ___, ___) \
   V(PushStatic,                      D, lit, ___, ___) \
   V(InitStaticTOS,                   0, ___, ___, ___) \
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index 1f55a8e..1995ee6 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -323,10 +323,6 @@
   FLAG_verify_handles = true;
 #ifdef DEBUG
   FLAG_verify_on_transition = true;
-  // Cannot verify heap while running compilation in background. Issue #26149.
-  FLAG_background_compilation = false;
-  // Issue #26150.
-  FLAG_use_osr = false;
 #endif
   event_queue = new EventQueue();
 
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 413dad3..579691e 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -95,6 +95,7 @@
   CHECK_OFFSET(Thread::stack_limit_offset(), 4);
   CHECK_OFFSET(Thread::object_null_offset(), 36);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 14);
+  CHECK_OFFSET(Isolate::object_store_offset(), 28);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
 #endif
 #if defined(TARGET_ARCH_MIPS)
@@ -104,6 +105,7 @@
   CHECK_OFFSET(Thread::stack_limit_offset(), 4);
   CHECK_OFFSET(Thread::object_null_offset(), 36);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 14);
+  CHECK_OFFSET(Isolate::object_store_offset(), 28);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
 #endif
 #if defined(TARGET_ARCH_ARM64)
@@ -113,6 +115,7 @@
   CHECK_OFFSET(Thread::stack_limit_offset(), 8);
   CHECK_OFFSET(Thread::object_null_offset(), 72);
   CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 28);
+  CHECK_OFFSET(Isolate::object_store_offset(), 56);
   NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 208));
 #endif
 #undef CHECK_OFFSET
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 6d485a5..343f597 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -2302,11 +2302,6 @@
 }
 
 
-static uword BigintAllocate(intptr_t size) {
-  return Api::TopScope(Thread::Current())->zone()->AllocUnsafe(size);
-}
-
-
 DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
                                                  const char** value) {
   API_TIMELINE_DURATION;
@@ -2315,12 +2310,13 @@
   if (int_obj.IsNull()) {
     RETURN_TYPE_ERROR(Z, integer, Integer);
   }
+  Zone* scope_zone = Api::TopScope(Thread::Current())->zone();
   if (int_obj.IsSmi() || int_obj.IsMint()) {
     const Bigint& bigint = Bigint::Handle(Z,
         Bigint::NewFromInt64(int_obj.AsInt64Value()));
-    *value = bigint.ToHexCString(BigintAllocate);
+    *value = bigint.ToHexCString(scope_zone);
   } else {
-    *value = Bigint::Cast(int_obj).ToHexCString(BigintAllocate);
+    *value = Bigint::Cast(int_obj).ToHexCString(scope_zone);
   }
   return Api::Success();
 }
@@ -6637,11 +6633,6 @@
 }
 
 
-DART_EXPORT bool Dart_IsRunningPrecompiledCode() {
-  return Snapshot::IncludesCode(Dart::snapshot_kind());
-}
-
-
 DART_EXPORT bool Dart_IsPrecompiledRuntime() {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return true;
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index f513b30..fc20379 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -84,6 +84,14 @@
       THR_Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
     }
   }
+  if (current->ArgumentCount() != 0) {
+    // This is a call instruction. Must remove original push arguments.
+    for (intptr_t i = 0; i < current->ArgumentCount(); ++i) {
+      PushArgumentInstr* push = current->PushArgumentAt(i);
+      push->ReplaceUsesWith(push->value()->definition());
+      push->RemoveFromGraph();
+    }
+  }
   iterator->RemoveCurrentFromGraph();
 }
 
@@ -2014,7 +2022,10 @@
     }
     for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
       Instruction* current = it.Current();
-      if (!current->CanDeoptimize()) {
+      if (!current->CanDeoptimize() &&
+          (!current->MayThrow() || !current->GetBlock()->InsideTryBlock())) {
+        // Instructions that can throw need an environment for optimized
+        // try-catch.
         // TODO(srdjan): --source-lines needs deopt environments to get at
         // the code for this instruction, however, leaving the environment
         // changes code.
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index d6871ae..11e4d39 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2394,7 +2394,7 @@
       const intptr_t index_scale = Instance::ElementSizeFor(class_id);
       StoreIndexedInstr* store = new(Z) StoreIndexedInstr(
           array, index, for_value.value(), emit_store_barrier,
-          index_scale, class_id, deopt_id, node->token_pos());
+          index_scale, class_id, kAlignedAccess, deopt_id, node->token_pos());
       Do(store);
     }
     ReturnDefinition(ExitTempLocalScope(array_val));
@@ -4637,7 +4637,7 @@
 void FlowGraphBuilder::PruneUnreachable() {
   ASSERT(osr_id_ != Compiler::kNoOSRDeoptId);
   BitVector* block_marks = new(Z) BitVector(Z, last_used_block_id_ + 1);
-  bool found = graph_entry_->PruneUnreachable(this, graph_entry_, NULL, osr_id_,
+  bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_,
                                               block_marks);
   ASSERT(found);
 }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 488b475..bc1ebce 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1025,6 +1025,13 @@
 //   R4: arguments descriptor array.
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
+  const Function& function = parsed_function().function();
+
+#ifdef DART_PRECOMPILER
+  if (function.IsDynamicFunction()) {
+    __ MonomorphicCheckedEntry();
+  }
+#endif  // DART_PRECOMPILER
 
   if (TryIntrinsify()) {
     // Skip regular code generation.
@@ -1034,8 +1041,6 @@
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
 
-  const Function& function = parsed_function().function();
-
   const int num_fixed_params = function.num_fixed_parameters();
   const int num_copied_params = parsed_function().num_copied_params();
   const int num_locals = parsed_function().num_stack_locals();
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index e76bf3b..326ca58 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1020,6 +1020,13 @@
 //   R4: arguments descriptor array.
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
+  const Function& function = parsed_function().function();
+
+#ifdef DART_PRECOMPILER
+  if (function.IsDynamicFunction()) {
+    __ MonomorphicCheckedEntry();
+  }
+#endif  // DART_PRECOMPILER
 
   if (TryIntrinsify()) {
     // Skip regular code generation.
@@ -1029,8 +1036,6 @@
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
 
-  const Function& function = parsed_function().function();
-
   const int num_fixed_params = function.num_fixed_parameters();
   const int num_copied_params = parsed_function().num_copied_params();
   const int num_locals = parsed_function().num_stack_locals();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 9dd8859..ca0be62 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1042,6 +1042,13 @@
 //   S4: arguments descriptor array.
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
+  const Function& function = parsed_function().function();
+
+#ifdef DART_PRECOMPILER
+  if (function.IsDynamicFunction()) {
+    __ MonomorphicCheckedEntry();
+  }
+#endif  // DART_PRECOMPILER
 
   if (TryIntrinsify()) {
     // Skip regular code generation.
@@ -1049,8 +1056,7 @@
   }
 
   EmitFrameEntry();
-
-  const Function& function = parsed_function().function();
+  ASSERT(assembler()->constant_pool_allowed());
 
   const int num_fixed_params = function.num_fixed_parameters();
   const int num_copied_params = parsed_function().num_copied_params();
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index bc7139c..db309c2 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -984,9 +984,6 @@
 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc
 // needs to be updated to match.
 void FlowGraphCompiler::EmitFrameEntry() {
-  const Function& function = parsed_function().function();
-  // Load pool pointer.
-
   if (flow_graph().IsCompiledForOsr()) {
     intptr_t extra_slots = StackSize()
         - flow_graph().num_stack_locals()
@@ -997,6 +994,7 @@
     const Register new_pp = R13;
     __ LoadPoolPointer(new_pp);
 
+    const Function& function = parsed_function().function();
     if (CanOptimizeFunction() &&
         function.IsOptimizable() &&
         (!is_optimizing() || may_reoptimize())) {
@@ -1027,6 +1025,13 @@
 
 void FlowGraphCompiler::CompileGraph() {
   InitCompiler();
+  const Function& function = parsed_function().function();
+
+#ifdef DART_PRECOMPILER
+  if (function.IsDynamicFunction()) {
+    __ MonomorphicCheckedEntry();
+  }
+#endif  // DART_PRECOMPILER
 
   if (TryIntrinsify()) {
     // Skip regular code generation.
@@ -1036,8 +1041,6 @@
   EmitFrameEntry();
   ASSERT(assembler()->constant_pool_allowed());
 
-  const Function& function = parsed_function().function();
-
   const int num_fixed_params = function.num_fixed_parameters();
   const int num_copied_params = parsed_function().num_copied_params();
   const int num_locals = parsed_function().num_stack_locals();
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 05f6579..3b42c06 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -848,7 +848,8 @@
           // Deopt-ids overlap between caller and callee.
           if (FLAG_precompiled_mode) {
 #ifdef DART_PRECOMPILER
-            AotOptimizer optimizer(callee_graph,
+            AotOptimizer optimizer(inliner_->precompiler_,
+                                   callee_graph,
                                    inliner_->use_speculative_inlining_,
                                    inliner_->inlining_black_list_);
             optimizer.PopulateWithICData();
@@ -1899,14 +1900,16 @@
     GrowableArray<TokenPosition>* inline_id_to_token_pos,
     GrowableArray<intptr_t>* caller_inline_id,
     bool use_speculative_inlining,
-    GrowableArray<intptr_t>* inlining_black_list)
+    GrowableArray<intptr_t>* inlining_black_list,
+    Precompiler* precompiler)
     : flow_graph_(flow_graph),
       inline_id_to_function_(inline_id_to_function),
       inline_id_to_token_pos_(inline_id_to_token_pos),
       caller_inline_id_(caller_inline_id),
       trace_inlining_(ShouldTraceInlining(flow_graph)),
       use_speculative_inlining_(use_speculative_inlining),
-      inlining_black_list_(inlining_black_list) {
+      inlining_black_list_(inlining_black_list),
+      precompiler_(precompiler) {
   ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
 }
 
@@ -2181,6 +2184,7 @@
                                   new(Z) Value(index),
                                   index_scale,
                                   array_cid,
+                                  kAlignedAccess,
                                   deopt_id,
                                   call->token_pos());
   cursor = flow_graph->AppendTo(
@@ -2365,6 +2369,7 @@
                                    needs_store_barrier,
                                    index_scale,
                                    array_cid,
+                                   kAlignedAccess,
                                    call->deopt_id(),
                                    call->token_pos());
   flow_graph->AppendTo(cursor,
@@ -2595,6 +2600,7 @@
                                   new(Z) Value(index),
                                   1,
                                   view_cid,
+                                  kUnalignedAccess,
                                   deopt_id,
                                   call->token_pos());
   cursor = flow_graph->AppendTo(
@@ -2766,6 +2772,7 @@
                                    needs_store_barrier,
                                    1,  // Index scale
                                    view_cid,
+                                   kUnalignedAccess,
                                    call->deopt_id(),
                                    call->token_pos());
 
@@ -2834,6 +2841,7 @@
       new(Z) Value(index),
       Instance::ElementSizeFor(cid),
       cid,
+      kAlignedAccess,
       Thread::kNoDeoptId,
       call->token_pos());
 
@@ -3810,6 +3818,36 @@
       return false;
     }
 
+    case MethodRecognizer::kObjectRuntimeType: {
+      Type& type = Type::ZoneHandle(Z);
+      if (RawObject::IsStringClassId(receiver_cid)) {
+        type = Type::StringType();
+      } else if (receiver_cid == kDoubleCid) {
+        type = Type::Double();
+      } else if (RawObject::IsIntegerClassId(receiver_cid)) {
+        type = Type::IntType();
+      } else if (receiver_cid != kClosureCid) {
+        const Class& cls = Class::Handle(Z,
+            flow_graph->isolate()->class_table()->At(receiver_cid));
+        if (!cls.IsGeneric()) {
+          type = cls.CanonicalType();
+        }
+      }
+
+      if (!type.IsNull()) {
+          *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                           call->GetBlock()->try_index());
+          (*entry)->InheritDeoptTarget(Z, call);
+          *last = new(Z) ConstantInstr(type);
+          flow_graph->AppendTo(*entry, *last,
+                               call->deopt_id() != Thread::kNoDeoptId ?
+                               call->env() : NULL,
+                               FlowGraph::kValue);
+          return true;
+      }
+      return false;
+    }
+
     case MethodRecognizer::kOneByteStringSetAt: {
       // This is an internal method, no need to check argument types nor
       // range.
@@ -3826,6 +3864,7 @@
           kNoStoreBarrier,
           1,  // Index scale
           kOneByteStringCid,
+          kAlignedAccess,
           call->deopt_id(),
           call->token_pos());
       flow_graph->AppendTo(*entry,
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index ccf7d39..ad1b222 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -19,6 +19,7 @@
 class Instruction;
 class StaticCallInstr;
 class TargetEntryInstr;
+class Precompiler;
 
 class FlowGraphInliner : ValueObject {
  public:
@@ -27,7 +28,8 @@
                    GrowableArray<TokenPosition>* inline_id_to_token_pos,
                    GrowableArray<intptr_t>* caller_inline_id,
                    bool use_speculative_inlining,
-                   GrowableArray<intptr_t>* inlining_black_list);
+                   GrowableArray<intptr_t>* inlining_black_list,
+                   Precompiler* precompiler);
 
   // The flow graph is destructively updated upon inlining.
   void Inline();
@@ -77,6 +79,7 @@
   const bool trace_inlining_;
   const bool use_speculative_inlining_;
   GrowableArray<intptr_t>* inlining_black_list_;
+  Precompiler* precompiler_;
 
   DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
 };
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 7a6874f..01515639 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -704,6 +704,15 @@
 }
 
 
+void CheckedSmiComparisonInstr::PrintOperandsTo(BufferFormatter* f) const {
+  f->Print("%s", Token::Str(kind()));
+  f->Print(", ");
+  left()->PrintTo(f);
+  f->Print(", ");
+  right()->PrintTo(f);
+}
+
+
 void BinaryIntegerOpInstr::PrintOperandsTo(BufferFormatter* f) const {
   f->Print("%s", Token::Str(op_kind()));
   if (is_truncating()) {
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index c3359f1..20362bd 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -975,8 +975,7 @@
 }
 
 
-bool BlockEntryInstr::PruneUnreachable(FlowGraphBuilder* builder,
-                                       GraphEntryInstr* graph_entry,
+bool BlockEntryInstr::PruneUnreachable(GraphEntryInstr* graph_entry,
                                        Instruction* parent,
                                        intptr_t osr_id,
                                        BitVector* block_marks) {
@@ -1012,8 +1011,7 @@
 
   // Recursively search the successors.
   for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) {
-    if (instr->SuccessorAt(i)->PruneUnreachable(builder,
-                                                graph_entry,
+    if (instr->SuccessorAt(i)->PruneUnreachable(graph_entry,
                                                 instr,
                                                 osr_id,
                                                 block_marks)) {
@@ -1759,14 +1757,34 @@
       default:
         break;
     }
-    if (Token::IsRelationalOperator(op_kind())) {
-      replacement = new RelationalOpInstr(token_pos(), op_kind(),
+    if (replacement != NULL) {
+      flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue);
+      return replacement;
+    }
+  }
+  return this;
+}
+
+
+ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(
+    Value* left, Value* right) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) {
+  if ((left()->Type()->ToCid() == kSmiCid) &&
+      (right()->Type()->ToCid() == kSmiCid)) {
+    Definition* replacement = NULL;
+    if (Token::IsRelationalOperator(kind())) {
+      replacement = new RelationalOpInstr(token_pos(), kind(),
                                           new Value(left()->definition()),
                                           new Value(right()->definition()),
                                           kSmiCid,
                                           Thread::kNoDeoptId);
-    } else if (Token::IsEqualityOperator(op_kind())) {
-      replacement = new EqualityCompareInstr(token_pos(), op_kind(),
+    } else if (Token::IsEqualityOperator(kind())) {
+      replacement = new EqualityCompareInstr(token_pos(), kind(),
                                              new Value(left()->definition()),
                                              new Value(right()->definition()),
                                              kSmiCid,
@@ -2358,9 +2376,9 @@
 
 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) {
   Definition* defn = value()->definition();
-  if (defn->IsComparison() && defn->HasOnlyUse(value())) {
-    // Comparisons always have a bool result.
-    ASSERT(value()->definition()->Type()->ToCid() == kBoolCid);
+  if (defn->IsComparison() &&
+      defn->HasOnlyUse(value()) &&
+      defn->Type()->ToCid() == kBoolCid) {
     defn->AsComparison()->NegateComparison();
     return defn;
   }
@@ -2389,7 +2407,8 @@
 // Returns a replacement for a strict comparison and signals if the result has
 // to be negated.
 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare,
-                                             bool* negated) {
+                                             bool* negated,
+                                             bool is_branch) {
   // Use propagated cid and type information to eliminate number checks.
   // If one of the inputs is not a boxable number (Mint, Double, Bigint), or
   // is not a subtype of num, no need for number checks.
@@ -2402,7 +2421,6 @@
       compare->set_needs_number_check(false);
     }
   }
-
   *negated = false;
   PassiveObject& constant = PassiveObject::Handle();
   Value* other = NULL;
@@ -2416,25 +2434,26 @@
     return compare;
   }
 
+  const bool can_merge = is_branch || (other->Type()->ToCid() == kBoolCid);
   Definition* other_defn = other->definition();
   Token::Kind kind = compare->kind();
   // Handle e === true.
   if ((kind == Token::kEQ_STRICT) &&
       (constant.raw() == Bool::True().raw()) &&
-      (other->Type()->ToCid() == kBoolCid)) {
+      can_merge) {
     return other_defn;
   }
   // Handle e !== false.
   if ((kind == Token::kNE_STRICT) &&
       (constant.raw() == Bool::False().raw()) &&
-      (other->Type()->ToCid() == kBoolCid)) {
+      can_merge) {
     return other_defn;
   }
   // Handle e !== true.
   if ((kind == Token::kNE_STRICT) &&
       (constant.raw() == Bool::True().raw()) &&
       other_defn->IsComparison() &&
-      (other->Type()->ToCid() == kBoolCid) &&
+      can_merge &&
       other_defn->HasOnlyUse(other)) {
     *negated = true;
     return other_defn;
@@ -2443,7 +2462,7 @@
   if ((kind == Token::kEQ_STRICT) &&
       (constant.raw() == Bool::False().raw()) &&
       other_defn->IsComparison() &&
-      (other->Type()->ToCid() == kBoolCid) &&
+      can_merge &&
       other_defn->HasOnlyUse(other)) {
     *negated = true;
     return other_defn;
@@ -2503,7 +2522,8 @@
   if (comparison()->IsStrictCompare()) {
     bool negated = false;
     Definition* replacement =
-        CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated);
+        CanonicalizeStrictCompare(comparison()->AsStrictCompare(),
+                                  &negated, /* is_branch = */ true);
     if (replacement == comparison()) {
       return this;
     }
@@ -2575,7 +2595,8 @@
 Definition* StrictCompareInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!HasUses()) return NULL;
   bool negated = false;
-  Definition* replacement = CanonicalizeStrictCompare(this, &negated);
+  Definition* replacement = CanonicalizeStrictCompare(this, &negated,
+                                                      /* is_branch = */ false);
   if (negated && replacement->IsComparison()) {
     ASSERT(replacement != this);
     replacement->AsComparison()->NegateComparison();
@@ -3022,13 +3043,13 @@
                                        Value* left,
                                        Value* right,
                                        bool needs_number_check)
-    : ComparisonInstr(token_pos,
-                      kind,
-                      left,
-                      right,
-                      Thread::Current()->GetNextDeoptId()),
+    : TemplateComparison(token_pos,
+                         kind,
+                         Thread::Current()->GetNextDeoptId()),
       needs_number_check_(needs_number_check) {
   ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT));
+  SetInputAt(0, left);
+  SetInputAt(1, right);
 }
 
 
@@ -3231,6 +3252,67 @@
 #endif
 
 
+RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType(
+    const ICData& ic_data) {
+  bool is_string = true;
+  bool is_integer = true;
+  bool is_double = true;
+
+  const intptr_t num_checks = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < num_checks; i++) {
+    const intptr_t cid = ic_data.GetReceiverClassIdAt(i);
+    is_string = is_string && RawObject::IsStringClassId(cid);
+    is_integer = is_integer && RawObject::IsIntegerClassId(cid);
+    is_double = is_double && (cid == kDoubleCid);
+  }
+
+  if (is_string) {
+    return Type::StringType();
+  } else if (is_integer) {
+    return Type::IntType();
+  } else if (is_double) {
+    return Type::Double();
+  }
+
+  return Type::null();
+}
+
+
+Definition* PolymorphicInstanceCallInstr::Canonicalize(FlowGraph* flow_graph) {
+  if (!HasSingleRecognizedTarget() || with_checks()) {
+    return this;
+  }
+
+  const Function& target = Function::Handle(ic_data().GetTargetAt(0));
+  if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
+    const AbstractType& type =
+        AbstractType::Handle(ComputeRuntimeType(ic_data()));
+    if (!type.IsNull()) {
+      return flow_graph->GetConstant(type);
+    }
+  }
+
+  return this;
+}
+
+
+Definition* StaticCallInstr::Canonicalize(FlowGraph* flow_graph) {
+  if (!FLAG_precompiled_mode) {
+    return this;
+  }
+
+  if (function().recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
+    if (input_use_list() == NULL) {
+      // This function has only environment uses. In precompiled mode it is
+      // fine to remove it - because we will never deoptimize.
+      return flow_graph->constant_dead();
+    }
+  }
+
+  return this;
+}
+
+
 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone,
                                                       bool optimizing) const {
   return MakeCallSummary(zone);
@@ -3424,6 +3506,13 @@
 }
 
 
+ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left,
+                                                        Value* new_right) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left,
                                                            Value* new_right) {
   return new EqualityCompareInstr(token_pos(),
@@ -3659,6 +3748,71 @@
 }
 
 
+static AlignmentType StrengthenAlignment(intptr_t cid,
+                                         AlignmentType alignment) {
+  switch (cid) {
+    case kTypedDataInt8ArrayCid:
+    case kTypedDataUint8ArrayCid:
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalTypedDataUint8ArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+    case kOneByteStringCid:
+    case kExternalOneByteStringCid:
+      // Don't need to worry about alignment for accessing bytes.
+      return kAlignedAccess;
+    case kTypedDataFloat32ArrayCid:
+    case kTypedDataFloat64ArrayCid:
+    case kTypedDataFloat64x2ArrayCid:
+    case kTypedDataInt32x4ArrayCid:
+    case kTypedDataFloat32x4ArrayCid:
+      // TODO(rmacnak): Investigate alignment requirements of floating point
+      // loads.
+      return kAlignedAccess;
+  }
+
+  return alignment;
+}
+
+
+LoadIndexedInstr::LoadIndexedInstr(Value* array,
+                                   Value* index,
+                                   intptr_t index_scale,
+                                   intptr_t class_id,
+                                   AlignmentType alignment,
+                                   intptr_t deopt_id,
+                                   TokenPosition token_pos)
+    : TemplateDefinition(deopt_id),
+      index_scale_(index_scale),
+      class_id_(class_id),
+      alignment_(StrengthenAlignment(class_id, alignment)),
+      token_pos_(token_pos) {
+  SetInputAt(0, array);
+  SetInputAt(1, index);
+}
+
+
+
+StoreIndexedInstr::StoreIndexedInstr(Value* array,
+                                     Value* index,
+                                     Value* value,
+                                     StoreBarrierType emit_store_barrier,
+                                     intptr_t index_scale,
+                                     intptr_t class_id,
+                                     AlignmentType alignment,
+                                     intptr_t deopt_id,
+                                     TokenPosition token_pos)
+    : TemplateDefinition(deopt_id),
+      emit_store_barrier_(emit_store_barrier),
+      index_scale_(index_scale),
+      class_id_(class_id),
+      alignment_(StrengthenAlignment(class_id, alignment)),
+      token_pos_(token_pos) {
+  SetInputAt(kArrayPos, array);
+  SetInputAt(kIndexPos, index);
+  SetInputAt(kValuePos, value);
+}
+
+
 InvokeMathCFunctionInstr::InvokeMathCFunctionInstr(
     ZoneGrowableArray<Value*>* inputs,
     intptr_t deopt_id,
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 8e7241a..add487e 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -477,6 +477,7 @@
   M(AllocateUninitializedContext)                                              \
   M(CloneContext)                                                              \
   M(BinarySmiOp)                                                               \
+  M(CheckedSmiComparison)                                                      \
   M(CheckedSmiOp)                                                              \
   M(BinaryInt32Op)                                                             \
   M(UnarySmiOp)                                                                \
@@ -910,6 +911,9 @@
   }
 
  private:
+  friend class BranchInstr;  // For RawSetInputAt.
+  friend class IfThenElseInstr;  // For RawSetInputAt.
+
   virtual void RawSetInputAt(intptr_t i, Value* value) = 0;
 
   enum {
@@ -1176,8 +1180,7 @@
 
   // Perform a depth first search to prune code not reachable from an OSR
   // entry point.
-  bool PruneUnreachable(FlowGraphBuilder* builder,
-                        GraphEntryInstr* graph_entry,
+  bool PruneUnreachable(GraphEntryInstr* graph_entry,
                         Instruction* parent,
                         intptr_t osr_id,
                         BitVector* block_marks);
@@ -2355,10 +2358,10 @@
 };
 
 
-class ComparisonInstr : public TemplateDefinition<2, NoThrow, Pure> {
+class ComparisonInstr : public Definition {
  public:
-  Value* left() const { return inputs_[0]; }
-  Value* right() const { return inputs_[1]; }
+  Value* left() const { return InputAt(0); }
+  Value* right() const { return InputAt(1); }
 
   virtual TokenPosition token_pos() const { return token_pos_; }
   Token::Kind kind() const { return kind_; }
@@ -2379,7 +2382,7 @@
   void set_operation_cid(intptr_t value) { operation_cid_ = value; }
   intptr_t operation_cid() const { return operation_cid_; }
 
-  void NegateComparison() {
+  virtual void NegateComparison() {
     kind_ = Token::NegateComparison(kind_);
   }
 
@@ -2397,17 +2400,11 @@
  protected:
   ComparisonInstr(TokenPosition token_pos,
                   Token::Kind kind,
-                  Value* left,
-                  Value* right,
                   intptr_t deopt_id = Thread::kNoDeoptId)
-      : TemplateDefinition(deopt_id),
+      : Definition(deopt_id),
         token_pos_(token_pos),
         kind_(kind),
         operation_cid_(kIllegalCid) {
-    SetInputAt(0, left);
-    if (right != NULL) {
-      SetInputAt(1, right);
-    }
   }
 
  private:
@@ -2419,6 +2416,47 @@
 };
 
 
+class PureComparison : public ComparisonInstr {
+ public:
+  virtual bool AllowsCSE() const { return true; }
+  virtual EffectSet Dependencies() const { return EffectSet::None(); }
+
+  virtual EffectSet Effects() const { return EffectSet::None(); }
+
+ protected:
+  PureComparison(TokenPosition token_pos, Token::Kind kind, intptr_t deopt_id)
+      : ComparisonInstr(token_pos, kind, deopt_id) { }
+};
+
+
+template<intptr_t N,
+         typename ThrowsTrait,
+         template<typename Impure, typename Pure> class CSETrait = NoCSE>
+class TemplateComparison : public CSETrait<
+    ComparisonInstr, PureComparison>::Base {
+ public:
+  TemplateComparison(TokenPosition token_pos,
+                     Token::Kind kind,
+                     intptr_t deopt_id = Thread::kNoDeoptId)
+      : CSETrait<ComparisonInstr, PureComparison>::Base(
+            token_pos, kind, deopt_id),
+        inputs_() { }
+
+  virtual intptr_t InputCount() const { return N; }
+  virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
+
+  virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
+
+ protected:
+  EmbeddedArray<Value*, N> inputs_;
+
+ private:
+  virtual void RawSetInputAt(intptr_t i, Value* value) {
+    inputs_[i] = value;
+  }
+};
+
+
 class BranchInstr : public Instruction {
  public:
   explicit BranchInstr(ComparisonInstr* comparison)
@@ -2965,6 +3003,10 @@
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
+  virtual Definition* Canonicalize(FlowGraph* graph);
+
+  static RawType* ComputeRuntimeType(const ICData& ic_data);
+
   PRINT_OPERANDS_TO_SUPPORT
 
  private:
@@ -2977,7 +3019,7 @@
 };
 
 
-class StrictCompareInstr : public ComparisonInstr {
+class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
  public:
   StrictCompareInstr(TokenPosition token_pos,
                      Token::Kind kind,
@@ -3019,14 +3061,16 @@
 
 // Comparison instruction that is equivalent to the (left & right) == 0
 // comparison pattern.
-class TestSmiInstr : public ComparisonInstr {
+class TestSmiInstr : public TemplateComparison<2, NoThrow, Pure> {
  public:
   TestSmiInstr(TokenPosition token_pos,
                Token::Kind kind,
                Value* left,
                Value* right)
-      : ComparisonInstr(token_pos, kind, left, right) {
+      : TemplateComparison(token_pos, kind) {
     ASSERT(kind == Token::kEQ || kind == Token::kNE);
+    SetInputAt(0, left);
+    SetInputAt(1, right);
   }
 
   DECLARE_INSTRUCTION(TestSmi);
@@ -3054,24 +3098,21 @@
 
 // Checks the input value cid against cids stored in a table and returns either
 // a result or deoptimizes.
-// TODO(srdjan): Modify ComparisonInstr to allow 1 or 2 arguments, since
-// TestCidInstr needs only one argument
-class TestCidsInstr : public ComparisonInstr {
+class TestCidsInstr : public TemplateComparison<1, NoThrow, Pure> {
  public:
   TestCidsInstr(TokenPosition token_pos,
                 Token::Kind kind,
                 Value* value,
                 const ZoneGrowableArray<intptr_t>& cid_results,
                 intptr_t deopt_id)
-      : ComparisonInstr(token_pos, kind, value, NULL, deopt_id),
+      : TemplateComparison(token_pos, kind, deopt_id),
         cid_results_(cid_results),
         licm_hoisted_(false) {
     ASSERT((kind == Token::kIS) || (kind == Token::kISNOT));
+    SetInputAt(0, value);
     set_operation_cid(kObjectCid);
   }
 
-  virtual intptr_t InputCount() const { return 1; }
-
   const ZoneGrowableArray<intptr_t>& cid_results() const {
     return cid_results_;
   }
@@ -3111,7 +3152,7 @@
 };
 
 
-class EqualityCompareInstr : public ComparisonInstr {
+class EqualityCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
  public:
   EqualityCompareInstr(TokenPosition token_pos,
                        Token::Kind kind,
@@ -3119,8 +3160,10 @@
                        Value* right,
                        intptr_t cid,
                        intptr_t deopt_id)
-      : ComparisonInstr(token_pos, kind, left, right, deopt_id) {
+      : TemplateComparison(token_pos, kind, deopt_id) {
     ASSERT(Token::IsEqualityOperator(kind));
+    SetInputAt(0, left);
+    SetInputAt(1, right);
     set_operation_cid(cid);
   }
 
@@ -3152,7 +3195,7 @@
 };
 
 
-class RelationalOpInstr : public ComparisonInstr {
+class RelationalOpInstr : public TemplateComparison<2, NoThrow, Pure> {
  public:
   RelationalOpInstr(TokenPosition token_pos,
                     Token::Kind kind,
@@ -3160,8 +3203,10 @@
                     Value* right,
                     intptr_t cid,
                     intptr_t deopt_id)
-      : ComparisonInstr(token_pos, kind, left, right, deopt_id) {
+      : TemplateComparison(token_pos, kind, deopt_id) {
     ASSERT(Token::IsRelationalOperator(kind));
+    SetInputAt(0, left);
+    SetInputAt(1, right);
     set_operation_cid(cid);
   }
 
@@ -3324,6 +3369,7 @@
 
   DECLARE_INSTRUCTION(StaticCall)
   virtual CompileType ComputeType() const;
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   // Accessors forwarded to the AST node.
   const Function& function() const { return function_; }
@@ -3840,6 +3886,10 @@
   DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldInstr);
 };
 
+enum AlignmentType {
+  kUnalignedAccess,
+  kAlignedAccess,
+};
 
 class LoadIndexedInstr : public TemplateDefinition<2, NoThrow> {
  public:
@@ -3847,15 +3897,9 @@
                    Value* index,
                    intptr_t index_scale,
                    intptr_t class_id,
+                   AlignmentType alignment,
                    intptr_t deopt_id,
-                   TokenPosition token_pos)
-      : TemplateDefinition(deopt_id),
-        index_scale_(index_scale),
-        class_id_(class_id),
-        token_pos_(token_pos) {
-    SetInputAt(0, array);
-    SetInputAt(1, index);
-  }
+                   TokenPosition token_pos);
 
   TokenPosition token_pos() const { return token_pos_; }
 
@@ -3877,6 +3921,7 @@
   Value* index() const { return inputs_[1]; }
   intptr_t index_scale() const { return index_scale_; }
   intptr_t class_id() const { return class_id_; }
+  bool aligned() const { return alignment_ == kAlignedAccess; }
 
   virtual bool CanDeoptimize() const {
     return GetDeoptId() != Thread::kNoDeoptId;
@@ -3890,6 +3935,7 @@
  private:
   const intptr_t index_scale_;
   const intptr_t class_id_;
+  const AlignmentType alignment_;
   const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadIndexedInstr);
@@ -4053,18 +4099,9 @@
                     StoreBarrierType emit_store_barrier,
                     intptr_t index_scale,
                     intptr_t class_id,
+                    AlignmentType alignment,
                     intptr_t deopt_id,
-                    TokenPosition token_pos)
-      : TemplateDefinition(deopt_id),
-        emit_store_barrier_(emit_store_barrier),
-        index_scale_(index_scale),
-        class_id_(class_id),
-        token_pos_(token_pos) {
-    SetInputAt(kArrayPos, array);
-    SetInputAt(kIndexPos, index);
-    SetInputAt(kValuePos, value);
-  }
-
+                    TokenPosition token_pos);
   DECLARE_INSTRUCTION(StoreIndexed)
 
   enum {
@@ -4079,6 +4116,7 @@
 
   intptr_t index_scale() const { return index_scale_; }
   intptr_t class_id() const { return class_id_; }
+  bool aligned() const { return alignment_ == kAlignedAccess; }
 
   bool ShouldEmitStoreBarrier() const {
     return value()->NeedsStoreBuffer()
@@ -4105,6 +4143,7 @@
   const StoreBarrierType emit_store_barrier_;
   const intptr_t index_scale_;
   const intptr_t class_id_;
+  const AlignmentType alignment_;
   const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(StoreIndexedInstr);
@@ -5344,24 +5383,21 @@
 };
 
 
-class DoubleTestOpInstr : public TemplateDefinition<1, NoThrow, Pure> {
+class DoubleTestOpInstr : public TemplateComparison<1, NoThrow, Pure> {
  public:
   DoubleTestOpInstr(MethodRecognizer::Kind op_kind,
-                    Value* d,
+                    Value* value,
                     intptr_t deopt_id,
                     TokenPosition token_pos)
-      : TemplateDefinition(deopt_id),
-        op_kind_(op_kind),
-        token_pos_(token_pos) {
-    SetInputAt(0, d);
+      : TemplateComparison(token_pos, Token::kEQ, deopt_id),
+        op_kind_(op_kind) {
+    SetInputAt(0, value);
   }
 
-  Value* value() const { return inputs_[0]; }
+  Value* value() const { return InputAt(0); }
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual TokenPosition token_pos() const { return token_pos_; }
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
@@ -5369,12 +5405,6 @@
     return kUnboxedDouble;
   }
 
-  virtual intptr_t DeoptimizationTarget() const {
-    // Direct access since this instruction cannot deoptimize, and the deopt-id
-    // was inherited from another instruction that could deoptimize.
-    return GetDeoptId();
-  }
-
   PRINT_OPERANDS_TO_SUPPORT
 
   DECLARE_INSTRUCTION(DoubleTestOp)
@@ -5383,12 +5413,20 @@
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AttributesEqual(Instruction* other) const {
-    return op_kind_ == other->AsDoubleTestOp()->op_kind();
+    return op_kind_ == other->AsDoubleTestOp()->op_kind()
+        && ComparisonInstr::AttributesEqual(other);
   }
 
+  virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
+
+  virtual void EmitBranchCode(FlowGraphCompiler* compiler,
+                              BranchInstr* branch);
+
+  virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler,
+                                       BranchLabels labels);
+
  private:
   const MethodRecognizer::Kind op_kind_;
-  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(DoubleTestOpInstr);
 };
@@ -6965,7 +7003,7 @@
   Value* left() const { return inputs_[0]; }
   Value* right() const { return inputs_[1]; }
 
-  virtual bool CanDeoptimize() const { return true; }
+  virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
@@ -6982,6 +7020,53 @@
 };
 
 
+class CheckedSmiComparisonInstr : public TemplateComparison<2, Throws> {
+ public:
+  CheckedSmiComparisonInstr(Token::Kind op_kind,
+                            Value* left,
+                            Value* right,
+                            InstanceCallInstr* call)
+      : TemplateComparison(call->token_pos(), op_kind, call->deopt_id()),
+        call_(call),
+        is_negated_(false) {
+    SetInputAt(0, left);
+    SetInputAt(1, right);
+  }
+
+  InstanceCallInstr* call() const { return call_; }
+
+  virtual bool CanDeoptimize() const { return false; }
+
+  virtual Definition* Canonicalize(FlowGraph* flow_graph);
+
+  virtual void NegateComparison() {
+    ComparisonInstr::NegateComparison();
+    is_negated_ = !is_negated_;
+  }
+
+  bool is_negated() const { return is_negated_; }
+
+  virtual EffectSet Effects() const { return EffectSet::All(); }
+
+  PRINT_OPERANDS_TO_SUPPORT
+
+  DECLARE_INSTRUCTION(CheckedSmiComparison)
+
+  virtual void EmitBranchCode(FlowGraphCompiler* compiler,
+                              BranchInstr* branch);
+
+  virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler,
+                                       BranchLabels labels);
+
+  virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
+
+ private:
+  InstanceCallInstr* call_;
+  bool is_negated_;
+  DISALLOW_COPY_AND_ASSIGN(CheckedSmiComparisonInstr);
+};
+
+
 class BinaryIntegerOpInstr : public TemplateDefinition<2, NoThrow, Pure> {
  public:
   BinaryIntegerOpInstr(Token::Kind op_kind,
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 6550738..fd50a14 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1,3 +1,4 @@
+
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -124,6 +125,8 @@
     case LS: return HI;
     case HI: return LS;
     case CS: return CC;
+    case VC: return VS;
+    case VS: return VC;
     default:
       UNREACHABLE();
       return EQ;
@@ -1208,7 +1211,7 @@
 LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = aligned() ? 0 : 1;
   LocationSummary* locs = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1243,6 +1246,9 @@
     ASSERT(representation() == kTagged);
     locs->set_out(0, Location::RequiresRegister());
   }
+  if (!aligned()) {
+    locs->set_temp(0, Location::RequiresRegister());
+  }
   return locs;
 }
 
@@ -1251,8 +1257,11 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
+  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
 
-  Address element_address = index.IsRegister()
+  Address element_address(kNoRegister);
+  if (aligned()) {
+    element_address = index.IsRegister()
       ? __ ElementAddressForRegIndex(true,  // Load.
                                      IsExternal(), class_id(), index_scale(),
                                      array,
@@ -1261,7 +1270,22 @@
                                      IsExternal(), class_id(), index_scale(),
                                      array, Smi::Cast(index.constant()).Value(),
                                      IP);  // Temp register.
-  // Warning: element_address may use register IP as base.
+    // Warning: element_address may use register IP as base.
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(address,
+                                       true,  // Load.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(address,
+                                       true,  // Load.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   if ((representation() == kUnboxedDouble)    ||
       (representation() == kUnboxedFloat32x4) ||
@@ -1297,11 +1321,19 @@
     switch (class_id()) {
       case kTypedDataInt32ArrayCid:
         ASSERT(representation() == kUnboxedInt32);
-        __ ldr(result, element_address);
+        if (aligned()) {
+          __ ldr(result, element_address);
+        } else {
+          __ LoadWordUnaligned(result, address, TMP);
+        }
       break;
       case kTypedDataUint32ArrayCid:
         ASSERT(representation() == kUnboxedUint32);
-        __ ldr(result, element_address);
+        if (aligned()) {
+          __ ldr(result, element_address);
+        } else {
+          __ LoadWordUnaligned(result, address, TMP);
+        }
       break;
       default:
         UNREACHABLE();
@@ -1315,6 +1347,7 @@
   switch (class_id()) {
     case kTypedDataInt8ArrayCid:
       ASSERT(index_scale() == 1);
+      ASSERT(aligned());
       __ ldrsb(result, element_address);
       __ SmiTag(result);
       break;
@@ -1325,17 +1358,26 @@
     case kOneByteStringCid:
     case kExternalOneByteStringCid:
       ASSERT(index_scale() == 1);
+      ASSERT(aligned());
       __ ldrb(result, element_address);
       __ SmiTag(result);
       break;
     case kTypedDataInt16ArrayCid:
-      __ ldrsh(result, element_address);
+      if (aligned()) {
+        __ ldrsh(result, element_address);
+      } else {
+        __ LoadHalfWordUnaligned(result, address, TMP);
+      }
       __ SmiTag(result);
       break;
     case kTypedDataUint16ArrayCid:
     case kTwoByteStringCid:
     case kExternalTwoByteStringCid:
-      __ ldrh(result, element_address);
+      if (aligned()) {
+        __ ldrh(result, element_address);
+      } else {
+        __ LoadHalfWordUnsignedUnaligned(result, address, TMP);
+      }
       __ SmiTag(result);
       break;
     default:
@@ -1392,7 +1434,7 @@
   if (CanBeImmediateIndex(index(), class_id(), IsExternal(),
                           false,  // Store.
                           &needs_base)) {
-    const intptr_t kNumTemps = needs_base ? 1 : 0;
+    const intptr_t kNumTemps = aligned() ? (needs_base ? 1 : 0) : 2;
     locs = new(zone) LocationSummary(
         zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 
@@ -1401,12 +1443,20 @@
     if (needs_base) {
       locs->set_temp(0, Location::RequiresRegister());
     }
+    if (!aligned()) {
+      locs->set_temp(0, Location::RequiresRegister());
+      locs->set_temp(1, Location::RequiresRegister());
+    }
   } else {
-    const intptr_t kNumTemps = 0;
+    const intptr_t kNumTemps = aligned() ? 0 : 2;
     locs = new(zone) LocationSummary(
         zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 
     locs->set_in(1, Location::WritableRegister());
+    if (!aligned()) {
+      locs->set_temp(0, Location::RequiresRegister());
+      locs->set_temp(1, Location::RequiresRegister());
+    }
   }
   locs->set_in(0, Location::RequiresRegister());
 
@@ -1452,8 +1502,12 @@
   const Location index = locs()->in(1);
   const Register temp =
       (locs()->temp_count() > 0) ? locs()->temp(0).reg() : kNoRegister;
+  const Register temp2 =
+      (locs()->temp_count() > 1) ? locs()->temp(1).reg() : kNoRegister;
 
-  Address element_address = index.IsRegister()
+  Address element_address(kNoRegister);
+  if (aligned()) {
+    element_address = index.IsRegister()
       ? __ ElementAddressForRegIndex(false,  // Store.
                                      IsExternal(), class_id(), index_scale(),
                                      array,
@@ -1462,6 +1516,21 @@
                                      IsExternal(), class_id(), index_scale(),
                                      array, Smi::Cast(index.constant()).Value(),
                                      temp);
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(temp,
+                                       false,  // Store.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(temp,
+                                       false,  // Store.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   switch (class_id()) {
     case kArrayCid:
@@ -1520,13 +1589,21 @@
     case kTypedDataUint16ArrayCid: {
       const Register value = locs()->in(2).reg();
       __ SmiUntag(IP, value);
-      __ strh(IP, element_address);
+      if (aligned()) {
+        __ strh(IP, element_address);
+      } else {
+        __ StoreHalfWordUnaligned(IP, temp, temp2);
+      }
       break;
     }
     case kTypedDataInt32ArrayCid:
     case kTypedDataUint32ArrayCid: {
       const Register value = locs()->in(2).reg();
-      __ str(value, element_address);
+      if (aligned()) {
+        __ str(value, element_address);
+      } else {
+        __ StoreWordUnaligned(value, temp, temp2);
+      }
       break;
     }
     case kTypedDataFloat32ArrayCid: {
@@ -3182,24 +3259,138 @@
     case Token::kBIT_XOR:
       __ eor(result, left, Operand(right));
       break;
-    case Token::kEQ:
-    case Token::kLT:
-    case Token::kLTE:
-    case Token::kGT:
-    case Token::kGTE: {
-      Condition true_condition =
-          EmitSmiComparisonOp(compiler, locs(), op_kind());
-      __ LoadObject(result, Bool::True(), true_condition);
-      __ LoadObject(result, Bool::False(), NegateCondition(true_condition));
-      break;
-    }
     default:
-      UNIMPLEMENTED();
+      UNREACHABLE();
   }
   __ Bind(slow_path->exit_label());
 }
 
 
+class CheckedSmiComparisonSlowPath : public SlowPathCode {
+ public:
+  CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               intptr_t try_index,
+                               BranchLabels labels,
+                               bool merged)
+      : instruction_(instruction),
+        try_index_(try_index),
+        labels_(labels),
+        merged_(merged) { }
+
+  virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+    if (Assembler::EmittingComments()) {
+      __ Comment("slow path smi operation");
+    }
+    __ Bind(entry_label());
+    LocationSummary* locs = instruction_->locs();
+    Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
+    locs->live_registers()->Remove(Location::RegisterLocation(result));
+
+    compiler->SaveLiveRegisters(locs);
+    __ Push(locs->in(0).reg());
+    __ Push(locs->in(1).reg());
+    compiler->EmitMegamorphicInstanceCall(
+        *instruction_->call()->ic_data(),
+        instruction_->call()->ArgumentCount(),
+        instruction_->call()->deopt_id(),
+        instruction_->call()->token_pos(),
+        locs,
+        try_index_,
+        /* slow_path_argument_count = */ 2);
+    __ mov(result, Operand(R0));
+    compiler->RestoreLiveRegisters(locs);
+    if (merged_) {
+      __ CompareObject(result, Bool::True());
+      __ b(instruction_->is_negated()
+           ? labels_.false_label : labels_.true_label, EQ);
+      __ b(instruction_->is_negated()
+           ? labels_.true_label : labels_.false_label);
+    } else {
+      __ b(exit_label());
+    }
+  }
+
+ private:
+  CheckedSmiComparisonInstr* instruction_;
+  intptr_t try_index_;
+  BranchLabels labels_;
+  bool merged_;
+};
+
+
+LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
+    Zone* zone, bool opt) const {
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 1;
+  LocationSummary* summary = new(zone) LocationSummary(
+      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RequiresRegister());
+  summary->set_temp(0, Location::RequiresRegister());
+  summary->set_out(0, Location::RequiresRegister());
+  return summary;
+}
+
+
+Condition CheckedSmiComparisonInstr::EmitComparisonCode(
+    FlowGraphCompiler* compiler, BranchLabels labels) {
+  return EmitSmiComparisonOp(compiler, locs(), kind());
+}
+
+
+#define EMIT_SMI_CHECK                                                         \
+  Register left = locs()->in(0).reg();                                         \
+  Register right = locs()->in(1).reg();                                        \
+  Register temp = locs()->temp(0).reg();                                       \
+  intptr_t left_cid = this->left()->Type()->ToCid();                           \
+  intptr_t right_cid = this->right()->Type()->ToCid();                         \
+  if (this->left()->definition() == this->right()->definition()) {             \
+    __ tst(left, Operand(kSmiTagMask));                                        \
+  } else if (left_cid == kSmiCid) {                                            \
+    __ tst(right, Operand(kSmiTagMask));                                       \
+  } else if (right_cid == kSmiCid) {                                           \
+    __ tst(left, Operand(kSmiTagMask));                                        \
+  } else {                                                                     \
+    __ orr(temp, left, Operand(right));                                        \
+    __ tst(temp, Operand(kSmiTagMask));                                        \
+  }                                                                            \
+  __ b(slow_path->entry_label(), NE)
+
+
+void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                               BranchInstr* branch) {
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ true);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  __ Bind(slow_path->exit_label());
+}
+
+
+void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  BranchLabels labels = { NULL, NULL, NULL };
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ false);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  Register result = locs()->out(0).reg();
+  __ LoadObject(result, Bool::True(), true_condition);
+  __ LoadObject(result, Bool::False(), NegateCondition(true_condition));
+  __ Bind(slow_path->exit_label());
+}
+#undef EMIT_SMI_CHECK
+
+
 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -4145,40 +4336,70 @@
 LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps =
+      (op_kind() == MethodRecognizer::kDouble_getIsInfinite) ? 1 : 0;
   LocationSummary* summary = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresFpuRegister());
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    summary->set_temp(0, Location::RequiresRegister());
+  }
   summary->set_out(0, Location::RequiresRegister());
   return summary;
 }
 
 
-void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  ASSERT(compiler->is_optimizing());
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
   const DRegister value = EvenDRegisterOf(locs()->in(0).fpu_reg());
-  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
   if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
-    __ LoadObject(result, Bool::False());
     __ vcmpd(value, value);
     __ vmstat();
-    __ LoadObject(result, Bool::True(), VS);
+    return is_negated ? VC : VS;
   } else {
     ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
+    const Register temp = locs()->temp(0).reg();
     Label done;
     // TMP <- value[0:31], result <- value[32:63]
-    __ vmovrrd(TMP, result, value);
+    __ vmovrrd(TMP, temp, value);
     __ cmp(TMP, Operand(0));
-    __ LoadObject(result, Bool::False(), NE);
-    __ b(&done, NE);
+    __ b(is_negated ? labels.true_label : labels.false_label, NE);
 
     // Mask off the sign bit.
-    __ AndImmediate(result, result, 0x7FFFFFFF);
+    __ AndImmediate(temp, temp, 0x7FFFFFFF);
     // Compare with +infinity.
-    __ CompareImmediate(result, 0x7FF00000);
-    __ LoadObject(result, Bool::False(), NE);
-    __ b(&done, NE);
+    __ CompareImmediate(temp, 0x7FF00000);
+    return is_negated ? NE : EQ;
+  }
+}
 
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
+  ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(compiler->is_optimizing());
+  Label is_true, is_false;
+  BranchLabels labels = { &is_true, &is_false, &is_false };
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  const Register result = locs()->out(0).reg();
+  if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
+    __ LoadObject(result, Bool::True(), true_condition);
+    __ LoadObject(result, Bool::False(), NegateCondition(true_condition));
+  } else {
+    ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
+    EmitBranchOnCondition(compiler, true_condition, labels);
+    Label done;
+    __ Bind(&is_false);
+    __ LoadObject(result, Bool::False());
+    __ b(&done);
+    __ Bind(&is_true);
     __ LoadObject(result, Bool::True());
     __ Bind(&done);
   }
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 22fac28..1e4baa2 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -123,6 +123,8 @@
     case LS: return HI;
     case HI: return LS;
     case CS: return CC;
+    case VS: return VC;
+    case VC: return VS;
     default:
       UNREACHABLE();
       return EQ;
@@ -1043,7 +1045,7 @@
 LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = aligned() ? 0 : 1;
   LocationSummary* locs = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1060,6 +1062,9 @@
   } else {
     locs->set_out(0, Location::RequiresRegister());
   }
+  if (!aligned()) {
+    locs->set_temp(0, Location::RequiresRegister());
+  }
   return locs;
 }
 
@@ -1068,15 +1073,31 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
+  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
 
-  Address element_address = index.IsRegister()
-      ? __ ElementAddressForRegIndex(true,  // Load.
-                                     IsExternal(), class_id(), index_scale(),
-                                     array, index.reg())
-      : __ ElementAddressForIntIndex(
-            IsExternal(), class_id(), index_scale(),
-            array, Smi::Cast(index.constant()).Value());
-  // Warning: element_address may use register TMP as base.
+  Address element_address(TMP);  // Bad address.
+  if (aligned()) {
+    element_address = index.IsRegister()
+        ? __ ElementAddressForRegIndex(true,  // Load.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array, index.reg())
+        : __ ElementAddressForIntIndex(
+              IsExternal(), class_id(), index_scale(),
+              array, Smi::Cast(index.constant()).Value());
+    // Warning: element_address may use register TMP as base.
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(address,
+                                       true,  // Load.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array, index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(address,
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   if ((representation() == kUnboxedDouble)    ||
       (representation() == kUnboxedFloat32x4) ||
@@ -1084,6 +1105,7 @@
       (representation() == kUnboxedFloat64x2)) {
     const VRegister result = locs()->out(0).fpu_reg();
     switch (class_id()) {
+      ASSERT(aligned());
       case kTypedDataFloat32ArrayCid:
         // Load single precision float.
         __ fldrs(result, element_address);
@@ -1109,11 +1131,19 @@
     switch (class_id()) {
       case kTypedDataInt32ArrayCid:
         ASSERT(representation() == kUnboxedInt32);
-        __ ldr(result, element_address, kWord);
+        if (aligned()) {
+          __ ldr(result, element_address, kWord);
+        } else {
+          __ LoadUnaligned(result, address, TMP, kWord);
+        }
         break;
       case kTypedDataUint32ArrayCid:
         ASSERT(representation() == kUnboxedUint32);
-        __ ldr(result, element_address, kUnsignedWord);
+        if (aligned()) {
+          __ ldr(result, element_address, kUnsignedWord);
+        } else {
+          __ LoadUnaligned(result, address, TMP, kUnsignedWord);
+        }
         break;
       default:
         UNREACHABLE();
@@ -1140,17 +1170,26 @@
       __ SmiTag(result);
       break;
     case kTypedDataInt16ArrayCid:
-      __ ldr(result, element_address, kHalfword);
+      if (aligned()) {
+        __ ldr(result, element_address, kHalfword);
+      } else {
+        __ LoadUnaligned(result, address, TMP, kHalfword);
+      }
       __ SmiTag(result);
       break;
     case kTypedDataUint16ArrayCid:
     case kTwoByteStringCid:
     case kExternalTwoByteStringCid:
-      __ ldr(result, element_address, kUnsignedHalfword);
+      if (aligned()) {
+        __ ldr(result, element_address, kUnsignedHalfword);
+      } else {
+        __ LoadUnaligned(result, address, TMP, kUnsignedHalfword);
+      }
       __ SmiTag(result);
       break;
     default:
       ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
+      ASSERT(aligned());
       __ ldr(result, element_address);
       break;
   }
@@ -1247,7 +1286,7 @@
 LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 3;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = aligned() ? 0 : 2;
   LocationSummary* locs = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1287,6 +1326,10 @@
       UNREACHABLE();
       return NULL;
   }
+  if (!aligned()) {
+    locs->set_temp(0, Location::RequiresRegister());
+    locs->set_temp(1, Location::RequiresRegister());
+  }
   return locs;
 }
 
@@ -1295,17 +1338,35 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
+  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
+  const Register scratch = aligned() ? kNoRegister : locs()->temp(1).reg();
 
-  Address element_address = index.IsRegister()
+  Address element_address(TMP);  // Bad address.
+  if (aligned()) {
+    element_address = index.IsRegister()
       ? __ ElementAddressForRegIndex(false,  // Store.
                                      IsExternal(), class_id(), index_scale(),
                                      array, index.reg())
       : __ ElementAddressForIntIndex(
             IsExternal(), class_id(), index_scale(),
             array, Smi::Cast(index.constant()).Value());
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(address,
+                                       false,  // Store.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array, index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(address,
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   switch (class_id()) {
     case kArrayCid:
+      ASSERT(aligned());
       if (ShouldEmitStoreBarrier()) {
         const Register value = locs()->in(2).reg();
         __ StoreIntoObject(array, element_address, value);
@@ -1321,6 +1382,7 @@
     case kTypedDataUint8ArrayCid:
     case kExternalTypedDataUint8ArrayCid:
     case kOneByteStringCid: {
+      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()));
@@ -1334,6 +1396,7 @@
     }
     case kTypedDataUint8ClampedArrayCid:
     case kExternalTypedDataUint8ClampedArrayCid: {
+      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         intptr_t value = constant.Value();
@@ -1360,21 +1423,31 @@
     case kTypedDataUint16ArrayCid: {
       const Register value = locs()->in(2).reg();
       __ SmiUntag(TMP, value);
-      __ str(TMP, element_address, kUnsignedHalfword);
+      if (aligned()) {
+        __ str(TMP, element_address, kUnsignedHalfword);
+      } else {
+        __ StoreUnaligned(TMP, address, scratch, kUnsignedHalfword);
+      }
       break;
     }
     case kTypedDataInt32ArrayCid:
     case kTypedDataUint32ArrayCid: {
       const Register value = locs()->in(2).reg();
-      __ str(value, element_address, kUnsignedWord);
+      if (aligned()) {
+        __ str(value, element_address, kUnsignedWord);
+      } else {
+        __ StoreUnaligned(value, address, scratch, kUnsignedWord);
+      }
       break;
     }
     case kTypedDataFloat32ArrayCid: {
+      ASSERT(aligned());
       const VRegister value_reg = locs()->in(2).fpu_reg();
       __ fstrs(value_reg, element_address);
       break;
     }
     case kTypedDataFloat64ArrayCid: {
+      ASSERT(aligned());
       const VRegister value_reg = locs()->in(2).fpu_reg();
       __ fstrd(value_reg, element_address);
       break;
@@ -1382,6 +1455,7 @@
     case kTypedDataFloat64x2ArrayCid:
     case kTypedDataInt32x4ArrayCid:
     case kTypedDataFloat32x4ArrayCid: {
+      ASSERT(aligned());
       const VRegister value_reg = locs()->in(2).fpu_reg();
       __ fstrq(value_reg, element_address);
       break;
@@ -2880,24 +2954,6 @@
     case Token::kBIT_XOR:
       __ eor(result, left, Operand(right));
       break;
-    case Token::kEQ:
-    case Token::kLT:
-    case Token::kLTE:
-    case Token::kGT:
-    case Token::kGTE: {
-      Label true_label, false_label, done;
-      BranchLabels labels = { &true_label, &false_label, &false_label };
-      Condition true_condition =
-          EmitSmiComparisonOp(compiler, locs(), op_kind());
-      EmitBranchOnCondition(compiler, true_condition, labels);
-      __ Bind(&false_label);
-      __ LoadObject(result, Bool::False());
-      __ b(&done);
-      __ Bind(&true_label);
-      __ LoadObject(result, Bool::True());
-      __ Bind(&done);
-      break;
-    }
     default:
       UNIMPLEMENTED();
   }
@@ -2905,6 +2961,137 @@
 }
 
 
+class CheckedSmiComparisonSlowPath : public SlowPathCode {
+ public:
+  CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               intptr_t try_index,
+                               BranchLabels labels,
+                               bool merged)
+      : instruction_(instruction),
+        try_index_(try_index),
+        labels_(labels),
+        merged_(merged) { }
+
+  virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+    if (Assembler::EmittingComments()) {
+      __ Comment("slow path smi operation");
+    }
+    __ Bind(entry_label());
+    LocationSummary* locs = instruction_->locs();
+    Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
+    locs->live_registers()->Remove(Location::RegisterLocation(result));
+
+    compiler->SaveLiveRegisters(locs);
+    __ Push(locs->in(0).reg());
+    __ Push(locs->in(1).reg());
+    compiler->EmitMegamorphicInstanceCall(
+        *instruction_->call()->ic_data(),
+        instruction_->call()->ArgumentCount(),
+        instruction_->call()->deopt_id(),
+        instruction_->call()->token_pos(),
+        locs,
+        try_index_,
+        /* slow_path_argument_count = */ 2);
+    __ mov(result, R0);
+    compiler->RestoreLiveRegisters(locs);
+    if (merged_) {
+      __ CompareObject(result, Bool::True());
+      __ b(instruction_->is_negated()
+           ? labels_.false_label : labels_.true_label, EQ);
+      __ b(instruction_->is_negated()
+           ? labels_.true_label : labels_.false_label);
+    } else {
+      __ b(exit_label());
+    }
+  }
+
+ private:
+  CheckedSmiComparisonInstr* instruction_;
+  intptr_t try_index_;
+  BranchLabels labels_;
+  bool merged_;
+};
+
+
+LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
+    Zone* zone, bool opt) const {
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 1;
+  LocationSummary* summary = new(zone) LocationSummary(
+      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RequiresRegister());
+  summary->set_temp(0, Location::RequiresRegister());
+  summary->set_out(0, Location::RequiresRegister());
+  return summary;
+}
+
+
+Condition CheckedSmiComparisonInstr::EmitComparisonCode(
+    FlowGraphCompiler* compiler, BranchLabels labels) {
+  return EmitSmiComparisonOp(compiler, locs(), kind());
+}
+
+
+#define EMIT_SMI_CHECK                                                         \
+  Register left = locs()->in(0).reg();                                         \
+  Register right = locs()->in(1).reg();                                        \
+  Register temp = locs()->temp(0).reg();                                       \
+  intptr_t left_cid = this->left()->Type()->ToCid();                           \
+  intptr_t right_cid = this->right()->Type()->ToCid();                         \
+  if (this->left()->definition() == this->right()->definition()) {             \
+    __ tsti(left, Immediate(kSmiTagMask));                                     \
+  } else if (left_cid == kSmiCid) {                                            \
+    __ tsti(right, Immediate(kSmiTagMask));                                    \
+  } else if (right_cid == kSmiCid) {                                           \
+    __ tsti(left, Immediate(kSmiTagMask));                                     \
+  } else {                                                                     \
+    __ orr(temp, left, Operand(right));                                        \
+    __ tsti(temp, Immediate(kSmiTagMask));                                     \
+  }                                                                            \
+  __ b(slow_path->entry_label(), NE)
+
+
+void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                               BranchInstr* branch) {
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ true);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  __ Bind(slow_path->exit_label());
+}
+
+
+void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label true_label, false_label, done;
+  BranchLabels labels = { &true_label, &false_label, &false_label };
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ false);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition =
+      EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  Register result = locs()->out(0).reg();
+  __ Bind(&false_label);
+  __ LoadObject(result, Bool::False());
+  __ b(&done);
+  __ Bind(&true_label);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+  __ Bind(slow_path->exit_label());
+}
+
+
 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -3485,34 +3672,63 @@
 LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps =
+      op_kind() == MethodRecognizer::kDouble_getIsInfinite ? 1 : 0;
   LocationSummary* summary = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresFpuRegister());
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    summary->set_temp(0, Location::RequiresRegister());
+  }
   summary->set_out(0, Location::RequiresRegister());
   return summary;
 }
 
 
-void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
   ASSERT(compiler->is_optimizing());
   const VRegister value = locs()->in(0).fpu_reg();
-  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
   if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
     __ fcmpd(value, value);
-    __ LoadObject(result, Bool::False());
-    __ LoadObject(TMP, Bool::True());
-    __ csel(result, TMP, result, VS);
+    return is_negated ? VC : VS;
   } else {
     ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
-    __ vmovrd(result, value, 0);
+    const Register temp = locs()->temp(0).reg();
+    __ vmovrd(temp, value, 0);
     // Mask off the sign.
-    __ AndImmediate(result, result, 0x7FFFFFFFFFFFFFFFLL);
+    __ AndImmediate(temp, temp, 0x7FFFFFFFFFFFFFFFLL);
     // Compare with +infinity.
-    __ CompareImmediate(result, 0x7FF0000000000000LL);
+    __ CompareImmediate(temp, 0x7FF0000000000000LL);
+    return is_negated ? NE : EQ;
+  }
+}
+
+
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
+  ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ASSERT(compiler->is_optimizing());
+  Label is_true, is_false;
+  BranchLabels labels = { &is_true, &is_false, &is_false };
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  const Register result = locs()->out(0).reg();
+  if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
     __ LoadObject(result, Bool::False());
     __ LoadObject(TMP, Bool::True());
-    __ csel(result, TMP, result, EQ);
+    __ csel(result, TMP, result, true_condition);
+  } else {
+    __ LoadObject(result, Bool::False());
+    __ LoadObject(TMP, Bool::True());
+    __ csel(result, TMP, result, true_condition);
   }
 }
 
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index 26c8fec..ec13a83 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -92,6 +92,7 @@
   M(Float64x2ZeroArg)                                                          \
   M(Float64x2OneArg)                                                           \
   M(CheckedSmiOp)                                                              \
+  M(CheckedSmiComparison)                                                      \
 
 // Location summaries actually are not used by the unoptimizing DBC compiler
 // because we don't allocate any registers.
@@ -179,6 +180,10 @@
 #undef DEFINE_UNREACHABLE
 
 
+// Only used in AOT compilation.
+DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(CheckedSmiComparison)
+
+
 EMIT_NATIVE_CODE(InstanceOf, 2, Location::SameAsFirstInput(),
                  LocationSummary::kCall) {
   SubtypeTestCache& test_cache = SubtypeTestCache::Handle();
@@ -334,7 +339,9 @@
 
 EMIT_NATIVE_CODE(Constant, 0, Location::RequiresRegister()) {
   if (compiler->is_optimizing()) {
-    __ LoadConstant(locs()->out(0).reg(), value());
+    if (locs()->out(0).IsRegister()) {
+      __ LoadConstant(locs()->out(0).reg(), value());
+    }
   } else {
     __ PushConstant(value());
   }
@@ -1649,20 +1656,51 @@
 }
 
 
-EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) {
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
+  UNREACHABLE();
+  return Condition();
+}
+
+
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
   ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
   const Register value = locs()->in(0).reg();
-  const Register result = locs()->out(0).reg();
   switch (op_kind()) {
     case MethodRecognizer::kDouble_getIsNaN:
-      __ DoubleIsNaN(result, value);
+      __ DoubleIsNaN(value);
       break;
     case MethodRecognizer::kDouble_getIsInfinite:
-      __ DoubleIsInfinite(result, value);
+      __ DoubleIsInfinite(value);
       break;
     default:
       UNREACHABLE();
   }
+  const bool is_negated = kind() != Token::kEQ;
+  EmitBranchOnCondition(
+      compiler, is_negated ? NEXT_IS_FALSE : NEXT_IS_TRUE, labels);
+}
+
+
+EMIT_NATIVE_CODE(DoubleTestOp, 1, Location::RequiresRegister()) {
+  ASSERT(compiler->is_optimizing());
+  const Register value = locs()->in(0).reg();
+  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
+  __ LoadConstant(result, is_negated ? Bool::True() : Bool::False());
+  switch (op_kind()) {
+    case MethodRecognizer::kDouble_getIsNaN:
+      __ DoubleIsNaN(value);
+      break;
+    case MethodRecognizer::kDouble_getIsInfinite:
+      __ DoubleIsInfinite(value);
+      break;
+    default:
+      UNREACHABLE();
+  }
+  __ LoadConstant(result, is_negated ? Bool::False() : Bool::True());
 }
 
 
@@ -1832,8 +1870,7 @@
 
 static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
                                         LocationSummary* locs,
-                                        Token::Kind kind,
-                                        BranchLabels labels) {
+                                        Token::Kind kind) {
   const Register left = locs->in(0).reg();
   const Register right = locs->in(1).reg();
   Token::Kind comparison = kind;
@@ -1854,7 +1891,7 @@
     return EmitSmiComparisonOp(compiler, locs(), kind(), labels);
   } else {
     ASSERT(operation_cid() == kDoubleCid);
-    return EmitDoubleComparisonOp(compiler, locs(), kind(), labels);
+    return EmitDoubleComparisonOp(compiler, locs(), kind());
   }
 }
 
@@ -1890,7 +1927,7 @@
     return EmitSmiComparisonOp(compiler, locs(), kind(), labels);
   } else {
     ASSERT(operation_cid() == kDoubleCid);
-    return EmitDoubleComparisonOp(compiler, locs(), kind(), labels);
+    return EmitDoubleComparisonOp(compiler, locs(), kind());
   }
 }
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 965cbeb..e281ab5 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -388,6 +388,8 @@
     case BELOW_EQUAL:   return ABOVE;
     case ABOVE:         return BELOW_EQUAL;
     case ABOVE_EQUAL:   return BELOW;
+    case PARITY_ODD:    return PARITY_EVEN;
+    case PARITY_EVEN:   return PARITY_ODD;
     default:
       UNIMPLEMENTED();
       return EQUAL;
@@ -2800,6 +2802,35 @@
 }
 
 
+LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
+    Zone* zone, bool opt) const {
+  // Only for precompiled code, not on ia32 currently.
+  UNIMPLEMENTED();
+  return NULL;
+}
+
+
+Condition CheckedSmiComparisonInstr::EmitComparisonCode(
+    FlowGraphCompiler* compiler, BranchLabels labels) {
+  // Only for precompiled code, not on ia32 currently.
+  UNIMPLEMENTED();
+  return ZERO;
+}
+
+
+void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                               BranchInstr* instr) {
+  // Only for precompiled code, not on ia32 currently.
+  UNIMPLEMENTED();
+}
+
+
+void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  // Only for precompiled code, not on ia32 currently.
+  UNIMPLEMENTED();
+}
+
+
 static bool IsSmiValue(const Object& constant, intptr_t value) {
   return constant.IsSmi() && (Smi::Cast(constant).Value() == value);
 }
@@ -3902,53 +3933,79 @@
 LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps =
+      (op_kind() == MethodRecognizer::kDouble_getIsInfinite) ? 1 : 0;
   LocationSummary* summary = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresFpuRegister());
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    summary->set_temp(0, Location::RequiresRegister());
+  }
   summary->set_out(0, Location::RequiresRegister());
   return summary;
 }
 
 
-void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
   ASSERT(compiler->is_optimizing());
   const XmmRegister value = locs()->in(0).fpu_reg();
-  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
   if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
     Label is_nan;
-    __ LoadObject(result, Bool::True());
     __ comisd(value, value);
-    __ j(PARITY_EVEN, &is_nan, Assembler::kNearJump);
-    __ LoadObject(result, Bool::False());
-    __ Bind(&is_nan);
+    return is_negated ? PARITY_ODD : PARITY_EVEN;
   } else {
     ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
-    Label not_inf, done;
+    const Register temp = locs()->temp(0).reg();
+    Label check_upper;
     __ AddImmediate(ESP, Immediate(-kDoubleSize));
     __ movsd(Address(ESP, 0), value);
-    __ movl(result, Address(ESP, 0));
+    __ movl(temp, Address(ESP, 0));
     // If the low word isn't zero, then it isn't infinity.
-    __ cmpl(result, Immediate(0));
-    __ j(NOT_EQUAL, &not_inf, Assembler::kNearJump);
-    // Check the high word.
-    __ movl(result, Address(ESP, kWordSize));
-    // Mask off sign bit.
-    __ andl(result, Immediate(0x7FFFFFFF));
-    // Compare with +infinity.
-    __ cmpl(result, Immediate(0x7FF00000));
-    __ j(NOT_EQUAL, &not_inf, Assembler::kNearJump);
-    __ LoadObject(result, Bool::True());
-    __ jmp(&done);
-
-    __ Bind(&not_inf);
-    __ LoadObject(result, Bool::False());
-    __ Bind(&done);
+    __ cmpl(temp, Immediate(0));
+    __ j(EQUAL, &check_upper, Assembler::kNearJump);
     __ AddImmediate(ESP, Immediate(kDoubleSize));
+    __ jmp(is_negated ? labels.true_label : labels.false_label);
+    __ Bind(&check_upper);
+    // Check the high word.
+    __ movl(temp, Address(ESP, kWordSize));
+    __ AddImmediate(ESP, Immediate(kDoubleSize));
+    // Mask off sign bit.
+    __ andl(temp, Immediate(0x7FFFFFFF));
+    // Compare with +infinity.
+    __ cmpl(temp, Immediate(0x7FF00000));
+    return is_negated ? NOT_EQUAL : EQUAL;
   }
 }
 
 
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
+  ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label is_true, is_false;
+  BranchLabels labels = { &is_true, &is_false, &is_false };
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler,  true_condition, labels);
+
+  Register result = locs()->out(0).reg();
+  Label done;
+  __ Bind(&is_false);
+  __ LoadObject(result, Bool::False());
+  __ jmp(&done);
+  __ Bind(&is_true);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+}
+
+
 LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone,
                                                              bool opt) const {
   const intptr_t kNumInputs = 2;
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 793c1b4..ed03d1d 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1240,7 +1240,7 @@
 LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = aligned() ? 0 : 1;
   LocationSummary* locs = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1256,6 +1256,9 @@
   } else {
     locs->set_out(0, Location::RequiresRegister());
   }
+  if (!aligned()) {
+    locs->set_temp(0, Location::RequiresRegister());
+  }
   return locs;
 }
 
@@ -1265,15 +1268,31 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
+  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
 
-  Address element_address = index.IsRegister()
+  Address element_address(kNoRegister);
+  if (aligned()) {
+    element_address = index.IsRegister()
       ? __ ElementAddressForRegIndex(true,  // Load.
                                      IsExternal(), class_id(), index_scale(),
                                      array, index.reg())
       : __ ElementAddressForIntIndex(
             IsExternal(), class_id(), index_scale(),
             array, Smi::Cast(index.constant()).Value());
-  // Warning: element_address may use register TMP as base.
+    // Warning: element_address may use register TMP as base.
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(address,
+                                       true,  // Load.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array, index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(address,
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   if ((representation() == kUnboxedDouble) ||
       (representation() == kUnboxedFloat32x4) ||
@@ -1302,11 +1321,19 @@
     switch (class_id()) {
       case kTypedDataInt32ArrayCid:
         ASSERT(representation() == kUnboxedInt32);
-        __ lw(result, element_address);
+        if (aligned()) {
+          __ lw(result, element_address);
+        } else {
+          __ LoadWordUnaligned(result, address, TMP);
+        }
         break;
       case kTypedDataUint32ArrayCid:
         ASSERT(representation() == kUnboxedUint32);
-        __ lw(result, element_address);
+        if (aligned()) {
+          __ lw(result, element_address);
+        } else {
+          __ LoadWordUnaligned(result, address, TMP);
+        }
         break;
       default:
         UNREACHABLE();
@@ -1334,17 +1361,26 @@
       __ SmiTag(result);
       break;
     case kTypedDataInt16ArrayCid:
-      __ lh(result, element_address);
+      if (aligned()) {
+        __ lh(result, element_address);
+      } else {
+        __ LoadHalfWordUnaligned(result, address, TMP);
+      }
       __ SmiTag(result);
       break;
     case kTypedDataUint16ArrayCid:
     case kTwoByteStringCid:
     case kExternalTwoByteStringCid:
-      __ lhu(result, element_address);
+      if (aligned()) {
+        __ lhu(result, element_address);
+      } else {
+        __ LoadHalfWordUnsignedUnaligned(result, address, TMP);
+      }
       __ SmiTag(result);
       break;
     default:
       ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
+      ASSERT(aligned());
       __ lw(result, element_address);
       break;
   }
@@ -1444,7 +1480,7 @@
 LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 3;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = aligned() ? 0 : 2;
   LocationSummary* locs = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1481,6 +1517,10 @@
       UNREACHABLE();
       return NULL;
   }
+  if (!aligned()) {
+    locs->set_temp(0, Location::RequiresRegister());
+    locs->set_temp(1, Location::RequiresRegister());
+  }
   return locs;
 }
 
@@ -1490,18 +1530,36 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
+  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
+  const Register scratch = aligned() ? kNoRegister : locs()->temp(1).reg();
 
-  Address element_address = index.IsRegister()
+  Address element_address(kNoRegister);
+  if (aligned()) {
+    element_address = index.IsRegister()
       ? __ ElementAddressForRegIndex(false,  // Store.
                                      IsExternal(), class_id(), index_scale(),
                                      array, index.reg())
       : __ ElementAddressForIntIndex(
             IsExternal(), class_id(), index_scale(),
             array, Smi::Cast(index.constant()).Value());
-  ASSERT(element_address.base() != TMP);  // Allowed for load only.
+    ASSERT(element_address.base() != TMP);  // Allowed for load only.
+  } else {
+    if (index.IsRegister()) {
+      __ LoadElementAddressForRegIndex(address,
+                                       false,  // Store.
+                                       IsExternal(), class_id(), index_scale(),
+                                       array, index.reg());
+    } else {
+      __ LoadElementAddressForIntIndex(address,
+                                       IsExternal(), class_id(), index_scale(),
+                                       array,
+                                       Smi::Cast(index.constant()).Value());
+    }
+  }
 
   switch (class_id()) {
     case kArrayCid:
+      ASSERT(aligned());
       if (ShouldEmitStoreBarrier()) {
         Register value = locs()->in(2).reg();
         __ StoreIntoObject(array, element_address, value);
@@ -1517,6 +1575,7 @@
     case kTypedDataUint8ArrayCid:
     case kExternalTypedDataUint8ArrayCid:
     case kOneByteStringCid: {
+      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()));
@@ -1530,6 +1589,7 @@
     }
     case kTypedDataUint8ClampedArrayCid:
     case kExternalTypedDataUint8ClampedArrayCid: {
+      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         intptr_t value = constant.Value();
@@ -1558,20 +1618,30 @@
     case kTypedDataUint16ArrayCid: {
       Register value = locs()->in(2).reg();
       __ SmiUntag(TMP, value);
-      __ sh(TMP, element_address);
+      if (aligned()) {
+        __ sh(TMP, element_address);
+      } else {
+        __ StoreHalfWordUnaligned(TMP, address, scratch);
+      }
       break;
     }
     case kTypedDataInt32ArrayCid:
     case kTypedDataUint32ArrayCid: {
-      __ sw(locs()->in(2).reg(), element_address);
+      if (aligned()) {
+        __ sw(locs()->in(2).reg(), element_address);
+      } else {
+        __ StoreWordUnaligned(locs()->in(2).reg(), address, scratch);
+      }
       break;
     }
     case kTypedDataFloat32ArrayCid: {
+      ASSERT(aligned());
       FRegister value = EvenFRegisterOf(locs()->in(2).fpu_reg());
       __ swc1(value, element_address);
       break;
     }
     case kTypedDataFloat64ArrayCid:
+      ASSERT(aligned());
       __ StoreDToOffset(locs()->in(2).fpu_reg(),
                         element_address.base(), element_address.offset());
       break;
@@ -2993,24 +3063,6 @@
     case Token::kBIT_XOR:
       __ xor_(result, left, right);
       break;
-    case Token::kEQ:
-    case Token::kLT:
-    case Token::kLTE:
-    case Token::kGT:
-    case Token::kGTE: {
-      Label true_label, false_label, done;
-      BranchLabels labels = { &true_label, &false_label, &false_label };
-      Condition true_condition =
-          EmitSmiComparisonOp(compiler, *locs(), op_kind());
-      EmitBranchOnCondition(compiler, true_condition, labels);
-      __ Bind(&false_label);
-      __ LoadObject(result, Bool::False());
-      __ b(&done);
-      __ Bind(&true_label);
-      __ LoadObject(result, Bool::True());
-      __ Bind(&done);
-      break;
-    }
     default:
       UNIMPLEMENTED();
   }
@@ -3018,6 +3070,135 @@
 }
 
 
+class CheckedSmiComparisonSlowPath : public SlowPathCode {
+ public:
+  CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               intptr_t try_index,
+                               BranchLabels labels,
+                               bool merged)
+      : instruction_(instruction),
+        try_index_(try_index),
+        labels_(labels),
+        merged_(merged) { }
+
+  virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+    if (Assembler::EmittingComments()) {
+      __ Comment("slow path smi operation");
+    }
+    __ Bind(entry_label());
+    LocationSummary* locs = instruction_->locs();
+    Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
+    locs->live_registers()->Remove(Location::RegisterLocation(result));
+
+    compiler->SaveLiveRegisters(locs);
+    __ Push(locs->in(0).reg());
+    __ Push(locs->in(1).reg());
+    compiler->EmitMegamorphicInstanceCall(
+        *instruction_->call()->ic_data(),
+        instruction_->call()->ArgumentCount(),
+        instruction_->call()->deopt_id(),
+        instruction_->call()->token_pos(),
+        locs,
+        try_index_,
+        /* slow_path_argument_count = */ 2);
+    __ mov(result, V0);
+    compiler->RestoreLiveRegisters(locs);
+    if (merged_) {
+      __ BranchEqual(result, Bool::True(),
+         instruction_->is_negated() ? labels_.false_label : labels_.true_label);
+      __ b(instruction_->is_negated()
+           ? labels_.true_label : labels_.false_label);
+    } else {
+      __ b(exit_label());
+    }
+  }
+
+ private:
+  CheckedSmiComparisonInstr* instruction_;
+  intptr_t try_index_;
+  BranchLabels labels_;
+  bool merged_;
+};
+
+
+LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
+    Zone* zone, bool opt) const {
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 1;
+  LocationSummary* summary = new(zone) LocationSummary(
+      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RequiresRegister());
+  summary->set_temp(0, Location::RequiresRegister());
+  summary->set_out(0, Location::RequiresRegister());
+  return summary;
+}
+
+
+Condition CheckedSmiComparisonInstr::EmitComparisonCode(
+    FlowGraphCompiler* compiler, BranchLabels labels) {
+  return EmitSmiComparisonOp(compiler, *locs(), kind());
+}
+
+
+#define EMIT_SMI_CHECK                                                         \
+  Register left = locs()->in(0).reg();                                         \
+  Register right = locs()->in(1).reg();                                        \
+  Register temp = locs()->temp(0).reg();                                       \
+  intptr_t left_cid = this->left()->Type()->ToCid();                           \
+  intptr_t right_cid = this->right()->Type()->ToCid();                         \
+  if (this->left()->definition() == this->right()->definition()) {             \
+    __ andi(CMPRES1, left, Immediate(kSmiTagMask));                            \
+  } else if (left_cid == kSmiCid) {                                            \
+    __ andi(CMPRES1, right, Immediate(kSmiTagMask));                           \
+  } else if (right_cid == kSmiCid) {                                           \
+    __ andi(CMPRES1, left, Immediate(kSmiTagMask));                            \
+  } else {                                                                     \
+    __ or_(temp, left, right);                                                 \
+    __ andi(CMPRES1, temp, Immediate(kSmiTagMask));                            \
+  }                                                                            \
+  __ bne(CMPRES1, ZR, slow_path->entry_label());                               \
+
+
+void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                               BranchInstr* branch) {
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ true);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  __ Bind(slow_path->exit_label());
+}
+
+
+void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label true_label, false_label, done;
+  BranchLabels labels = { &true_label, &false_label, &false_label };
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ false);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  Register result = locs()->out(0).reg();
+  __ Bind(&false_label);
+  __ LoadObject(result, Bool::False());
+  __ b(&done);
+  __ Bind(&true_label);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+  __ Bind(slow_path->exit_label());
+}
+
+
 LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -3704,38 +3885,78 @@
 }
 
 
-void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  ASSERT(compiler->is_optimizing());
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
   const DRegister value = locs()->in(0).fpu_reg();
-  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
   if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
-    Label is_not_nan;
-    __ LoadObject(result, Bool::False());
     __ cund(value, value);
-    __ bc1f(&is_not_nan);
-    __ LoadObject(result, Bool::True());
-    __ Bind(&is_not_nan);
+    if (labels.fall_through == labels.true_label) {
+      if (is_negated) {
+        __ bc1t(labels.false_label);
+      } else {
+        __ bc1f(labels.false_label);
+      }
+    } else if (labels.fall_through == labels.false_label) {
+      if (is_negated) {
+        __ bc1f(labels.true_label);
+      } else {
+        __ bc1t(labels.true_label);
+      }
+    } else {
+      if (is_negated) {
+        __ bc1t(labels.false_label);
+      } else {
+        __ bc1f(labels.false_label);
+      }
+      __ b(labels.true_label);
+    }
+    return Condition();  // Unused.
   } else {
     ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
-    Label not_inf, done;
-    __ mfc1(TMP, EvenFRegisterOf(value));
-    __ mfc1(result, OddFRegisterOf(value));
+    __ mfc1(CMPRES1, EvenFRegisterOf(value));
     // If the low word isn't zero, then it isn't infinity.
-    __ bne(TMP, ZR, &not_inf);
+    __ bne(CMPRES1, ZR, is_negated ? labels.true_label : labels.false_label);
+    __ mfc1(CMPRES1, OddFRegisterOf(value));
     // Mask off the sign bit.
-    __ AndImmediate(result, result, 0x7FFFFFFF);
+    __ AndImmediate(CMPRES1, CMPRES1, 0x7FFFFFFF);
     // Compare with +infinity.
-    __ BranchNotEqual(result, Immediate(0x7FF00000), &not_inf);
-
-    __ LoadObject(result, Bool::True());
-    __ b(&done);
-
-    __ Bind(&not_inf);
-    __ LoadObject(result, Bool::False());
-    __ Bind(&done);
+    __ LoadImmediate(CMPRES2, 0x7FF00000);
+    return Condition(CMPRES1, CMPRES2, is_negated ? NE : EQ);
   }
 }
 
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
+  ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  // Branches for isNaN are emitted in EmitComparisonCode already.
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    EmitBranchOnCondition(compiler, true_condition, labels);
+  }
+}
+
+
+void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label is_true, is_false;
+  BranchLabels labels = { &is_true, &is_false, &is_false };
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  // Branches for isNaN are emitted in EmitComparisonCode already.
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    EmitBranchOnCondition(compiler,  true_condition, labels);
+  }
+  const Register result = locs()->out(0).reg();
+  Label done;
+  __ Comment("return bool");
+  __ Bind(&is_false);
+  __ LoadObject(result, Bool::False());
+  __ b(&done);
+  __ Bind(&is_true);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+}
+
 
 LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone,
                                                              bool opt) const {
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 2b75b2a..4fc3b68 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -121,6 +121,8 @@
     case BELOW_EQUAL:   return ABOVE;
     case ABOVE:         return BELOW_EQUAL;
     case ABOVE_EQUAL:   return BELOW;
+    case PARITY_EVEN:   return PARITY_ODD;
+    case PARITY_ODD:    return PARITY_EVEN;
     default:
       UNIMPLEMENTED();
       return EQUAL;
@@ -2884,11 +2886,6 @@
   summary->set_in(0, Location::RequiresRegister());
   summary->set_in(1, Location::RequiresRegister());
   switch (op_kind()) {
-    case Token::kEQ:
-    case Token::kLT:
-    case Token::kLTE:
-    case Token::kGT:
-    case Token::kGTE:
     case Token::kADD:
     case Token::kSUB:
     case Token::kMUL:
@@ -2958,24 +2955,6 @@
       ASSERT(left == result);
       __ xorq(result, right);
       break;
-    case Token::kEQ:
-    case Token::kLT:
-    case Token::kLTE:
-    case Token::kGT:
-    case Token::kGTE: {
-      Label true_label, false_label, done;
-      BranchLabels labels = { &true_label, &false_label, &false_label };
-      Condition true_condition =
-          EmitInt64ComparisonOp(compiler, *locs(), op_kind());
-      EmitBranchOnCondition(compiler, true_condition, labels);
-      __ Bind(&false_label);
-      __ LoadObject(result, Bool::False());
-      __ jmp(&done);
-      __ Bind(&true_label);
-      __ LoadObject(result, Bool::True());
-      __ Bind(&done);
-      break;
-    }
     default:
       UNIMPLEMENTED();
   }
@@ -2983,6 +2962,136 @@
 }
 
 
+class CheckedSmiComparisonSlowPath : public SlowPathCode {
+ public:
+  CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               intptr_t try_index,
+                               BranchLabels labels,
+                               bool merged = false)
+      : instruction_(instruction),
+        try_index_(try_index),
+        labels_(labels),
+        merged_(merged) { }
+
+  virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+    if (Assembler::EmittingComments()) {
+      __ Comment("slow path smi comparison");
+    }
+    __ Bind(entry_label());
+    LocationSummary* locs = instruction_->locs();
+    Register result = merged_ ? locs->temp(0).reg() : locs->out(0).reg();
+    locs->live_registers()->Remove(Location::RegisterLocation(result));
+
+    compiler->SaveLiveRegisters(locs);
+    __ pushq(locs->in(0).reg());
+    __ pushq(locs->in(1).reg());
+    compiler->EmitMegamorphicInstanceCall(
+        *instruction_->call()->ic_data(),
+        instruction_->call()->ArgumentCount(),
+        instruction_->call()->deopt_id(),
+        instruction_->call()->token_pos(),
+        locs,
+        try_index_,
+        /* slow_path_argument_count = */ 2);
+    __ MoveRegister(result, RAX);
+    compiler->RestoreLiveRegisters(locs);
+    if (merged_) {
+      __ CompareObject(result, Bool::True());
+      __ j(EQUAL, instruction_->is_negated()
+                  ? labels_.false_label : labels_.true_label);
+      __ jmp(instruction_->is_negated()
+             ? labels_.true_label : labels_.false_label);
+    } else {
+      __ jmp(exit_label());
+    }
+  }
+
+ private:
+  CheckedSmiComparisonInstr* instruction_;
+  intptr_t try_index_;
+  BranchLabels labels_;
+  bool merged_;
+};
+
+
+LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
+    Zone* zone, bool opt) const {
+  const intptr_t kNumInputs = 2;
+  const intptr_t kNumTemps = 1;
+  LocationSummary* summary = new(zone) LocationSummary(
+      zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_in(1, Location::RequiresRegister());
+  summary->set_temp(0, Location::RequiresRegister());
+  summary->set_out(0, Location::RequiresRegister());
+  return summary;
+}
+
+
+Condition CheckedSmiComparisonInstr::EmitComparisonCode(
+    FlowGraphCompiler* compiler, BranchLabels labels) {
+  return EmitInt64ComparisonOp(compiler, *locs(), kind());
+}
+
+
+#define EMIT_SMI_CHECK \
+  intptr_t left_cid = left()->Type()->ToCid();                                 \
+  intptr_t right_cid = right()->Type()->ToCid();                               \
+  Register left = locs()->in(0).reg();                                         \
+  Register right = locs()->in(1).reg();                                        \
+  if (this->left()->definition() == this->right()->definition()) {             \
+    __ testq(left, Immediate(kSmiTagMask));                                    \
+  } else if (left_cid == kSmiCid) {                                            \
+    __ testq(right, Immediate(kSmiTagMask));                                   \
+  } else if (right_cid == kSmiCid) {                                           \
+    __ testq(left, Immediate(kSmiTagMask));                                    \
+  } else {                                                                     \
+    __ movq(TMP, left);                                                        \
+    __ orq(TMP, right);                                                        \
+    __ testq(TMP, Immediate(kSmiTagMask));                                     \
+  }                                                                            \
+  __ j(NOT_ZERO, slow_path->entry_label())
+
+
+void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                               BranchInstr* branch) {
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ true);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  __ Bind(slow_path->exit_label());
+}
+
+
+void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label true_label, false_label, done;
+  BranchLabels labels = { &true_label, &false_label, &false_label };
+  CheckedSmiComparisonSlowPath* slow_path =
+      new CheckedSmiComparisonSlowPath(this,
+                                       compiler->CurrentTryIndex(),
+                                       labels,
+                                       /* merged = */ false);
+  compiler->AddSlowPathCode(slow_path);
+  EMIT_SMI_CHECK;
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+  Register result = locs()->out(0).reg();
+  __ Bind(&false_label);
+  __ LoadObject(result, Bool::False());
+  __ jmp(&done);
+  __ Bind(&true_label);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+  __ Bind(slow_path->exit_label());
+}
+
+
 static bool CanBeImmediate(const Object& constant) {
   return constant.IsSmi() &&
     Immediate(reinterpret_cast<int64_t>(constant.raw())).is_int32();
@@ -3763,49 +3872,70 @@
 LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps =
+      (op_kind() == MethodRecognizer::kDouble_getIsInfinite) ? 1 : 0;
   LocationSummary* summary = new(zone) LocationSummary(
       zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresFpuRegister());
+  if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
+    summary->set_temp(0, Location::RequiresRegister());
+  }
   summary->set_out(0, Location::RequiresRegister());
   return summary;
 }
 
 
-void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+Condition DoubleTestOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+                                                BranchLabels labels) {
   ASSERT(compiler->is_optimizing());
   const XmmRegister value = locs()->in(0).fpu_reg();
-  const Register result = locs()->out(0).reg();
+  const bool is_negated = kind() != Token::kEQ;
   if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
     Label is_nan;
-    __ LoadObject(result, Bool::True());
     __ comisd(value, value);
-    __ j(PARITY_EVEN, &is_nan, Assembler::kNearJump);
-    __ LoadObject(result, Bool::False());
-    __ Bind(&is_nan);
+    return is_negated ? PARITY_ODD : PARITY_EVEN;
   } else {
     ASSERT(op_kind() == MethodRecognizer::kDouble_getIsInfinite);
-    Label is_inf, done;
+    const Register temp = locs()->temp(0).reg();
     __ AddImmediate(RSP, Immediate(-kDoubleSize));
     __ movsd(Address(RSP, 0), value);
-    __ movq(result, Address(RSP, 0));
-    // Mask off the sign.
-    __ AndImmediate(result, Immediate(0x7FFFFFFFFFFFFFFFLL));
-    // Compare with +infinity.
-    __ CompareImmediate(result, Immediate(0x7FF0000000000000LL));
-    __ j(EQUAL, &is_inf, Assembler::kNearJump);
-    __ LoadObject(result, Bool::False());
-    __ jmp(&done);
-
-    __ Bind(&is_inf);
-    __ LoadObject(result, Bool::True());
-
-    __ Bind(&done);
+    __ movq(temp, Address(RSP, 0));
     __ AddImmediate(RSP, Immediate(kDoubleSize));
+    // Mask off the sign.
+    __ AndImmediate(temp, Immediate(0x7FFFFFFFFFFFFFFFLL));
+    // Compare with +infinity.
+    __ CompareImmediate(temp, Immediate(0x7FF0000000000000LL));
+    return is_negated ? NOT_EQUAL : EQUAL;
   }
 }
 
 
+void DoubleTestOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+                                       BranchInstr* branch) {
+  ASSERT(compiler->is_optimizing());
+  BranchLabels labels = compiler->CreateBranchLabels(branch);
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+void DoubleTestOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Label is_true, is_false;
+  BranchLabels labels = { &is_true, &is_false, &is_false };
+  Condition true_condition = EmitComparisonCode(compiler, labels);
+  EmitBranchOnCondition(compiler,  true_condition, labels);
+
+  Register result = locs()->out(0).reg();
+  Label done;
+  __ Bind(&is_false);
+  __ LoadObject(result, Bool::False());
+  __ jmp(&done);
+  __ Bind(&is_true);
+  __ LoadObject(result, Bool::True());
+  __ Bind(&done);
+}
+
+
 LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(Zone* zone,
                                                              bool opt) const {
   const intptr_t kNumInputs = 2;
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index e0355c9..331dd84 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -419,6 +419,7 @@
                            new Value(index),
                            Instance::ElementSizeFor(array_cid),  // index scale
                            array_cid,
+                           kAlignedAccess,
                            Thread::kNoDeoptId,
                            builder.TokenPos()));
   // Box and/or convert result if necessary.
@@ -581,6 +582,7 @@
                             kNoStoreBarrier,
                             Instance::ElementSizeFor(array_cid),  // index scale
                             array_cid,
+                            kAlignedAccess,
                             Thread::kNoDeoptId,
                             builder.TokenPos()));
   // Return null.
@@ -733,6 +735,7 @@
                            new Value(index),
                            Instance::ElementSizeFor(cid),
                            cid,
+                           kAlignedAccess,
                            Thread::kNoDeoptId,
                            builder.TokenPos()));
   builder.AddIntrinsicReturn(new Value(result));
@@ -962,6 +965,7 @@
                            new Value(index),
                            Instance::ElementSizeFor(kArrayCid),  // index scale
                            kArrayCid,
+                           kAlignedAccess,
                            Thread::kNoDeoptId,
                            builder.TokenPos()));
   builder.AddIntrinsicReturn(new Value(result));
@@ -998,6 +1002,7 @@
                             kEmitStoreBarrier,
                             Instance::ElementSizeFor(kArrayCid),  // index scale
                             kArrayCid,
+                            kAlignedAccess,
                             Thread::kNoDeoptId,
                             builder.TokenPos()));
   // Return null.
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 80756ef..3be8564 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -1579,16 +1579,103 @@
 }
 
 
+static void RangeCheck(Assembler* assembler,
+                       Register val,
+                       Register tmp,
+                       intptr_t low,
+                       intptr_t high,
+                       Condition cc,
+                       Label* target) {
+  __ AddImmediate(tmp, val, -low);
+  __ CompareImmediate(tmp, high - low);
+  __ b(target, cc);
+}
+
+
+const Condition kIfNotInRange = HI;
+const Condition kIfInRange = LS;
+
+
+static void JumpIfInteger(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfInRange, target);
+}
+
+
+static void JumpIfNotInteger(Assembler* assembler,
+                             Register cid,
+                             Register tmp,
+                             Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfNotInRange, target);
+}
+
+
+static void JumpIfString(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfInRange,
+             target);
+}
+
+
+static void JumpIfNotString(Assembler* assembler,
+                            Register cid,
+                            Register tmp,
+                            Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfNotInRange,
+             target);
+}
+
+
 // Return type quickly for simple types (not parameterized and not signature).
 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
-  Label fall_through;
+  Label fall_through, use_canonical_type, not_double, not_integer;
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
+
   __ CompareImmediate(R1, kClosureCid);
   __ b(&fall_through, EQ);  // Instance is a closure.
-  __ LoadClassById(R2, R1);
-  // R2: class of instance (R0).
 
+  __ CompareImmediate(R1, kNumPredefinedCids);
+  __ b(&use_canonical_type, HI);
+
+  __ CompareImmediate(R1, kDoubleCid);
+  __ b(&not_double, NE);
+
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(kWord, R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(kWord, R0, R0, ObjectStore::double_type_offset());
+  __ Ret();
+
+  __ Bind(&not_double);
+  JumpIfNotInteger(assembler, R1, R0, &not_integer);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(kWord, R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(kWord, R0, R0, ObjectStore::int_type_offset());
+  __ Ret();
+
+  __ Bind(&not_integer);
+  JumpIfNotString(assembler, R1, R0, &use_canonical_type);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(kWord, R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(kWord, R0, R0, ObjectStore::string_type_offset());
+  __ Ret();
+
+  __ Bind(&use_canonical_type);
+  __ LoadClassById(R2, R1);
   __ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
   __ CompareImmediate(R3, 0);
   __ b(&fall_through, NE);
@@ -1602,6 +1689,61 @@
 }
 
 
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
+  Label fall_through, different_cids, equal, not_equal, not_integer;
+  __ ldr(R0, Address(SP, 0 * kWordSize));
+  __ LoadClassIdMayBeSmi(R1, R0);
+
+  // Check if left hand size is a closure. Closures are handled in the runtime.
+  __ CompareImmediate(R1, kClosureCid);
+  __ b(&fall_through, EQ);
+
+  __ ldr(R0, Address(SP, 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(R2, R0);
+
+  // Check whether class ids match. If class ids don't match objects can still
+  // have the same runtime type (e.g. multiple string implementation classes
+  // map to a single String type).
+  __ cmp(R1, Operand(R2));
+  __ b(&different_cids, NE);
+
+  // Objects have the same class and neither is a closure.
+  // Check if there are no type arguments. In this case we can return true.
+  // Otherwise fall through into the runtime to handle comparison.
+  __ LoadClassById(R3, R1);
+  __ ldrh(R3, FieldAddress(R3, Class::num_type_arguments_offset()));
+  __ CompareImmediate(R3, 0);
+  __ b(&fall_through, NE);
+
+  __ Bind(&equal);
+  __ LoadObject(R0, Bool::True());
+  __ Ret();
+
+  // Class ids are different. Check if we are comparing runtime types of
+  // two strings (with different representations) or two integers.
+  __ Bind(&different_cids);
+  __ CompareImmediate(R1, kNumPredefinedCids);
+  __ b(&not_equal, HI);
+
+  // Check if both are integers.
+  JumpIfNotInteger(assembler, R1, R0, &not_integer);
+  JumpIfInteger(assembler, R2, R0, &equal);
+  __ b(&not_equal);
+
+  __ Bind(&not_integer);
+  // Check if both are strings.
+  JumpIfNotString(assembler, R1, R0, &not_equal);
+  JumpIfString(assembler, R2, R0, &equal);
+
+  // Neither strings nor integers and have different class ids.
+  __ Bind(&not_equal);
+  __ LoadObject(R0, Bool::False());
+  __ Ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ ldr(R0, FieldAddress(R0, String::hash_offset()));
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 050ae73..756010b 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -1653,16 +1653,103 @@
 }
 
 
+static void RangeCheck(Assembler* assembler,
+                       Register val,
+                       Register tmp,
+                       intptr_t low,
+                       intptr_t high,
+                       Condition cc,
+                       Label* target) {
+  __ AddImmediate(tmp, val, -low);
+  __ CompareImmediate(tmp, high - low);
+  __ b(target, cc);
+}
+
+
+const Condition kIfNotInRange = HI;
+const Condition kIfInRange = LS;
+
+
+static void JumpIfInteger(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfInRange, target);
+}
+
+
+static void JumpIfNotInteger(Assembler* assembler,
+                             Register cid,
+                             Register tmp,
+                             Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfNotInRange, target);
+}
+
+
+static void JumpIfString(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfInRange,
+             target);
+}
+
+
+static void JumpIfNotString(Assembler* assembler,
+                            Register cid,
+                            Register tmp,
+                            Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfNotInRange,
+             target);
+}
+
+
 // Return type quickly for simple types (not parameterized and not signature).
 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
-  Label fall_through;
+  Label fall_through, use_canonical_type, not_double, not_integer;
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
+
   __ CompareImmediate(R1, kClosureCid);
   __ b(&fall_through, EQ);  // Instance is a closure.
-  __ LoadClassById(R2, R1);
-  // R2: class of instance (R0).
 
+  __ CompareImmediate(R1, kNumPredefinedCids);
+  __ b(&use_canonical_type, HI);
+
+  __ CompareImmediate(R1, kDoubleCid);
+  __ b(&not_double, NE);
+
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(R0, R0, ObjectStore::double_type_offset());
+  __ ret();
+
+  __ Bind(&not_double);
+  JumpIfNotInteger(assembler, R1, R0, &not_integer);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(R0, R0, ObjectStore::int_type_offset());
+  __ ret();
+
+  __ Bind(&not_integer);
+  JumpIfNotString(assembler, R1, R0, &use_canonical_type);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(R0, R0, Isolate::object_store_offset());
+  __ LoadFromOffset(R0, R0, ObjectStore::string_type_offset());
+  __ ret();
+
+  __ Bind(&use_canonical_type);
+  __ LoadClassById(R2, R1);
   __ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
   __ CompareImmediate(R3, 0);
   __ b(&fall_through, NE);
@@ -1676,6 +1763,61 @@
 }
 
 
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
+  Label fall_through, different_cids, equal, not_equal, not_integer;
+  __ ldr(R0, Address(SP, 0 * kWordSize));
+  __ LoadClassIdMayBeSmi(R1, R0);
+
+  // Check if left hand size is a closure. Closures are handled in the runtime.
+  __ CompareImmediate(R1, kClosureCid);
+  __ b(&fall_through, EQ);
+
+  __ ldr(R0, Address(SP, 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(R2, R0);
+
+  // Check whether class ids match. If class ids don't match objects can still
+  // have the same runtime type (e.g. multiple string implementation classes
+  // map to a single String type).
+  __ cmp(R1, Operand(R2));
+  __ b(&different_cids, NE);
+
+  // Objects have the same class and neither is a closure.
+  // Check if there are no type arguments. In this case we can return true.
+  // Otherwise fall through into the runtime to handle comparison.
+  __ LoadClassById(R3, R1);
+  __ ldr(R3, FieldAddress(R3, Class::num_type_arguments_offset()), kHalfword);
+  __ CompareImmediate(R3, 0);
+  __ b(&fall_through, NE);
+
+  __ Bind(&equal);
+  __ LoadObject(R0, Bool::True());
+  __ ret();
+
+  // Class ids are different. Check if we are comparing runtime types of
+  // two strings (with different representations) or two integers.
+  __ Bind(&different_cids);
+  __ CompareImmediate(R1, kNumPredefinedCids);
+  __ b(&not_equal, HI);
+
+  // Check if both are integers.
+  JumpIfNotInteger(assembler, R1, R0, &not_integer);
+  JumpIfInteger(assembler, R2, R0, &equal);
+  __ b(&not_equal);
+
+  __ Bind(&not_integer);
+  // Check if both are strings.
+  JumpIfNotString(assembler, R1, R0, &not_equal);
+  JumpIfString(assembler, R2, R0, &equal);
+
+  // Neither strings nor integers and have different class ids.
+  __ Bind(&not_equal);
+  __ LoadObject(R0, Bool::False());
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ ldr(R0, Address(SP, 0 * kWordSize));
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index a114996..8f4d865 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -1709,16 +1709,105 @@
 }
 
 
+static void RangeCheck(Assembler* assembler,
+                       Register reg,
+                       intptr_t low,
+                       intptr_t high,
+                       Condition cc,
+                       Label* target) {
+  __ subl(reg, Immediate(low));
+  __ cmpl(reg, Immediate(high - low));
+  __ j(cc, target);
+}
+
+
+const Condition kIfNotInRange = ABOVE;
+const Condition kIfInRange = BELOW_EQUAL;
+
+
+static void JumpIfInteger(Assembler* assembler,
+                          Register cid,
+                          Label* target) {
+  RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target);
+}
+
+
+static void JumpIfNotInteger(Assembler* assembler,
+                             Register cid,
+                             Label* target) {
+  RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target);
+}
+
+
+static void JumpIfString(Assembler* assembler,
+                          Register cid,
+                          Label* target) {
+  RangeCheck(assembler,
+             cid,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfInRange,
+             target);
+}
+
+
+static void JumpIfNotString(Assembler* assembler,
+                            Register cid,
+                            Label* target) {
+  RangeCheck(assembler,
+             cid,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfNotInRange,
+             target);
+}
+
+
 // Return type quickly for simple types (not parameterized and not signature).
 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
-  Label fall_through;
+  Label fall_through, use_canonical_type, not_double, not_integer;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));
   __ LoadClassIdMayBeSmi(EDI, EAX);
-  __ cmpl(EDI, Immediate(kClosureCid));
-  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Instance is a closure.
-  __ LoadClassById(EBX, EDI);
-  // EBX: class of instance (EAX).
 
+  __ cmpl(EDI, Immediate(kClosureCid));
+  __ j(EQUAL, &fall_through);  // Instance is a closure.
+
+  __ cmpl(EDI, Immediate(kNumPredefinedCids));
+  __ j(ABOVE, &use_canonical_type);
+
+  // If object is a instance of _Double return double type.
+  __ cmpl(EDI, Immediate(kDoubleCid));
+  __ j(NOT_EQUAL, &not_double);
+
+  __ LoadIsolate(EAX);
+  __ movl(EAX, Address(EAX, Isolate::object_store_offset()));
+  __ movl(EAX, Address(EAX, ObjectStore::double_type_offset()));
+  __ ret();
+
+  __ Bind(&not_double);
+  // If object is an integer (smi, mint or bigint) return int type.
+  __ movl(EAX, EDI);
+  JumpIfNotInteger(assembler, EAX, &not_integer);
+
+  __ LoadIsolate(EAX);
+  __ movl(EAX, Address(EAX, Isolate::object_store_offset()));
+  __ movl(EAX, Address(EAX, ObjectStore::int_type_offset()));
+  __ ret();
+
+  __ Bind(&not_integer);
+  // If object is a string (one byte, two byte or external variants) return
+  // string type.
+  __ movl(EAX, EDI);
+  JumpIfNotString(assembler, EAX, &use_canonical_type);
+
+  __ LoadIsolate(EAX);
+  __ movl(EAX, Address(EAX, Isolate::object_store_offset()));
+  __ movl(EAX, Address(EAX, ObjectStore::string_type_offset()));
+  __ ret();
+
+  // Object is neither double, nor integer, nor string.
+  __ Bind(&use_canonical_type);
+  __ LoadClassById(EBX, EDI);
   __ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
   __ cmpl(EDI, Immediate(0));
   __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
@@ -1731,6 +1820,70 @@
 }
 
 
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
+  Label fall_through, different_cids, equal, not_equal, not_integer;
+
+  __ movl(EAX, Address(ESP, + 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(EDI, EAX);
+
+  // Check if left hand size is a closure. Closures are handled in the runtime.
+  __ cmpl(EDI, Immediate(kClosureCid));
+  __ j(EQUAL, &fall_through);
+
+  __ movl(EAX, Address(ESP, + 2 * kWordSize));
+  __ LoadClassIdMayBeSmi(EBX, EAX);
+
+  // Check whether class ids match. If class ids don't match objects can still
+  // have the same runtime type (e.g. multiple string implementation classes
+  // map to a single String type).
+  __ cmpl(EDI, EBX);
+  __ j(NOT_EQUAL, &different_cids);
+
+  // Objects have the same class and neither is a closure.
+  // Check if there are no type arguments. In this case we can return true.
+  // Otherwise fall through into the runtime to handle comparison.
+  __ LoadClassById(EBX, EDI);
+  __ movzxw(EBX, FieldAddress(EBX, Class::num_type_arguments_offset()));
+  __ cmpl(EBX, Immediate(0));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ Bind(&equal);
+  __ LoadObject(EAX, Bool::True());
+  __ ret();
+
+  // Class ids are different. Check if we are comparing runtime types of
+  // two strings (with different representations) or two integers.
+  __ Bind(&different_cids);
+  __ cmpl(EDI, Immediate(kNumPredefinedCids));
+  __ j(ABOVE_EQUAL, &not_equal);
+
+  __ movl(EAX, EDI);
+  JumpIfNotInteger(assembler, EAX, &not_integer);
+
+  // First object is an integer. Check if the second is an integer too.
+  // Otherwise types are unequal because only integers have the same runtime
+  // type as other integers.
+  JumpIfInteger(assembler, EBX, &equal);
+  __ jmp(&not_equal);
+
+  __ Bind(&not_integer);
+  // Check if the first object is a string. If it is not then
+  // objects don't have the same runtime type because they have
+  // different class ids and they are not strings or integers.
+  JumpIfNotString(assembler, EDI, &not_equal);
+  // First object is a string. Check if the second is a string too.
+  JumpIfString(assembler, EBX, &equal);
+  // Strings only have the same runtime type as other strings.
+  // Fall-through to the not equal case.
+
+  __ Bind(&not_equal);
+  __ LoadObject(EAX, Bool::False());
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));  // String object.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index ff354af..aa512ad 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -1689,15 +1689,109 @@
 }
 
 
+enum RangeCheckCondition {
+  kIfNotInRange, kIfInRange
+};
+
+
+static void RangeCheck(Assembler* assembler,
+                       Register val,
+                       Register tmp,
+                       intptr_t low,
+                       intptr_t high,
+                       RangeCheckCondition cc,
+                       Label* target) {
+  __ AddImmediate(tmp, val, -low);
+  if (cc == kIfInRange) {
+    __ BranchUnsignedLessEqual(tmp, Immediate(high - low), target);
+  } else {
+    ASSERT(cc == kIfNotInRange);
+    __ BranchUnsignedGreater(tmp, Immediate(high - low), target);
+  }
+}
+
+
+static void JumpIfInteger(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfInRange, target);
+}
+
+
+static void JumpIfNotInteger(Assembler* assembler,
+                             Register cid,
+                             Register tmp,
+                             Label* target) {
+  RangeCheck(assembler, cid, tmp, kSmiCid, kBigintCid, kIfNotInRange, target);
+}
+
+
+static void JumpIfString(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfInRange,
+             target);
+}
+
+
+static void JumpIfNotString(Assembler* assembler,
+                            Register cid,
+                            Register tmp,
+                            Label* target) {
+  RangeCheck(assembler,
+             cid,
+             tmp,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfNotInRange,
+             target);
+}
+
+
 // Return type quickly for simple types (not parameterized and not signature).
 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
-  Label fall_through;
+  Label fall_through, use_canonical_type, not_integer, not_double;
   __ lw(T0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(T1, T0);
-  __ BranchEqual(T1, Immediate(kClosureCid), &fall_through);
-  __ LoadClassById(T2, T1);
-  // T2: class of instance (T0).
 
+  // Closures are handled in the runtime.
+  __ BranchEqual(T1, Immediate(kClosureCid), &fall_through);
+
+  __ BranchUnsignedGreaterEqual(
+      T1, Immediate(kNumPredefinedCids), &use_canonical_type);
+
+  __ BranchNotEqual(T1, Immediate(kDoubleCid), &not_double);
+  // Object is a double.
+  __ LoadIsolate(T1);
+  __ LoadFromOffset(T1, T1, Isolate::object_store_offset());
+  __ LoadFromOffset(V0, T1, ObjectStore::double_type_offset());
+  __ Ret();
+
+  __ Bind(&not_double);
+  JumpIfNotInteger(assembler, T1, T2, &not_integer);
+  // Object is an integer.
+  __ LoadIsolate(T1);
+  __ LoadFromOffset(T1, T1, Isolate::object_store_offset());
+  __ LoadFromOffset(V0, T1, ObjectStore::int_type_offset());
+  __ Ret();
+
+  __ Bind(&not_integer);
+  JumpIfNotString(assembler, T1, T2, &use_canonical_type);
+  // Object is a string.
+  __ LoadIsolate(T1);
+  __ LoadFromOffset(T1, T1, Isolate::object_store_offset());
+  __ LoadFromOffset(V0, T1, ObjectStore::string_type_offset());
+  __ Ret();
+
+  __ Bind(&use_canonical_type);
+  __ LoadClassById(T2, T1);
   __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
   __ BranchNotEqual(T1, Immediate(0), &fall_through);
 
@@ -1709,6 +1803,59 @@
 }
 
 
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
+  Label fall_through, different_cids, equal, not_equal, not_integer;
+
+  __ lw(T0, Address(SP, 0 * kWordSize));
+  __ LoadClassIdMayBeSmi(T1, T0);
+
+  // Closures are handled in the runtime.
+  __ BranchEqual(T1, Immediate(kClosureCid), &fall_through);
+
+  __ lw(T0, Address(SP, 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(T2, T0);
+
+  // Check whether class ids match. If class ids don't match objects can still
+  // have the same runtime type (e.g. multiple string implementation classes
+  // map to a single String type).
+  __ BranchNotEqual(T1, T2, &different_cids);
+
+  // Objects have the same class and neither is a closure.
+  // Check if there are no type arguments. In this case we can return true.
+  // Otherwise fall through into the runtime to handle comparison.
+  __ LoadClassById(T2, T1);
+  __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
+  __ BranchNotEqual(T1, Immediate(0), &fall_through);
+
+  __ Bind(&equal);
+  __ LoadObject(V0, Bool::True());
+  __ Ret();
+
+  // Class ids are different. Check if we are comparing runtime types of
+  // two strings (with different representations) or two integers.
+  __ Bind(&different_cids);
+  __ BranchUnsignedGreaterEqual(
+      T1, Immediate(kNumPredefinedCids), &not_equal);
+
+  // Check if both are integers.
+  JumpIfNotInteger(assembler, T1, T0, &not_integer);
+  JumpIfInteger(assembler, T2, T0, &equal);
+  __ b(&not_equal);
+
+  __ Bind(&not_integer);
+  // Check if both are strings.
+  JumpIfNotString(assembler, T1, T0, &not_equal);
+  JumpIfString(assembler, T2, T0, &equal);
+
+  // Neither strings nor integers and have different class ids.
+  __ Bind(&not_equal);
+  __ LoadObject(V0, Bool::False());
+  __ Ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ lw(T0, Address(SP, 0 * kWordSize));
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 0810847..288d5e4 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -1573,19 +1573,106 @@
 }
 
 
+static void RangeCheck(Assembler* assembler,
+                       Register reg,
+                       intptr_t low,
+                       intptr_t high,
+                       Condition cc,
+                       Label* target) {
+  __ subq(reg, Immediate(low));
+  __ cmpq(reg, Immediate(high - low));
+  __ j(cc, target);
+}
+
+
+const Condition kIfNotInRange = ABOVE;
+const Condition kIfInRange = BELOW_EQUAL;
+
+
+static void JumpIfInteger(Assembler* assembler,
+                          Register cid,
+                          Label* target) {
+  RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfInRange, target);
+}
+
+
+static void JumpIfNotInteger(Assembler* assembler,
+                             Register cid,
+                             Label* target) {
+  RangeCheck(assembler, cid, kSmiCid, kBigintCid, kIfNotInRange, target);
+}
+
+
+static void JumpIfString(Assembler* assembler,
+                          Register cid,
+                          Label* target) {
+  RangeCheck(assembler,
+             cid,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfInRange,
+             target);
+}
+
+
+static void JumpIfNotString(Assembler* assembler,
+                            Register cid,
+                            Label* target) {
+  RangeCheck(assembler,
+             cid,
+             kOneByteStringCid,
+             kExternalTwoByteStringCid,
+             kIfNotInRange,
+             target);
+}
+
+
 // Return type quickly for simple types (not parameterized and not signature).
 void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
-  Label fall_through;
+  Label fall_through, use_canonical_type, not_integer, not_double;
   __ movq(RAX, Address(RSP, + 1 * kWordSize));
   __ LoadClassIdMayBeSmi(RCX, RAX);
 
   // RCX: untagged cid of instance (RAX).
   __ cmpq(RCX, Immediate(kClosureCid));
-  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Instance is a closure.
+  __ j(EQUAL, &fall_through);  // Instance is a closure.
 
+  __ cmpl(RCX, Immediate(kNumPredefinedCids));
+  __ j(ABOVE, &use_canonical_type);
+
+  // If object is a instance of _Double return double type.
+  __ cmpl(RCX, Immediate(kDoubleCid));
+  __ j(NOT_EQUAL, &not_double);
+
+  __ LoadIsolate(RAX);
+  __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+  __ movq(RAX, Address(RAX, ObjectStore::double_type_offset()));
+  __ ret();
+
+  __ Bind(&not_double);
+  // If object is an integer (smi, mint or bigint) return int type.
+  __ movl(RAX, RCX);
+  JumpIfNotInteger(assembler, RAX, &not_integer);
+
+  __ LoadIsolate(RAX);
+  __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+  __ movq(RAX, Address(RAX, ObjectStore::int_type_offset()));
+  __ ret();
+
+  __ Bind(&not_integer);
+  // If object is a string (one byte, two byte or external variants) return
+  // string type.
+  __ movq(RAX, RCX);
+  JumpIfNotString(assembler, RAX, &use_canonical_type);
+
+  __ LoadIsolate(RAX);
+  __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+  __ movq(RAX, Address(RAX, ObjectStore::string_type_offset()));
+  __ ret();
+
+  // Object is neither double, nor integer, nor string.
+  __ Bind(&use_canonical_type);
   __ LoadClassById(RDI, RCX);
-  // RDI: class of instance (RAX).
-
   __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
   __ cmpq(RCX, Immediate(0));
   __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
@@ -1598,6 +1685,70 @@
 }
 
 
+void Intrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler) {
+  Label fall_through, different_cids, equal, not_equal, not_integer;
+
+  __ movq(RAX, Address(RSP, + 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(RCX, RAX);
+
+  // Check if left hand size is a closure. Closures are handled in the runtime.
+  __ cmpq(RCX, Immediate(kClosureCid));
+  __ j(EQUAL, &fall_through);
+
+  __ movq(RAX, Address(RSP, + 2 * kWordSize));
+  __ LoadClassIdMayBeSmi(RDX, RAX);
+
+  // Check whether class ids match. If class ids don't match objects can still
+  // have the same runtime type (e.g. multiple string implementation classes
+  // map to a single String type).
+  __ cmpq(RCX, RDX);
+  __ j(NOT_EQUAL, &different_cids);
+
+  // Objects have the same class and neither is a closure.
+  // Check if there are no type arguments. In this case we can return true.
+  // Otherwise fall through into the runtime to handle comparison.
+  __ LoadClassById(RDI, RCX);
+  __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
+  __ cmpq(RCX, Immediate(0));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ Bind(&equal);
+  __ LoadObject(RAX, Bool::True());
+  __ ret();
+
+  // Class ids are different. Check if we are comparing runtime types of
+  // two strings (with different representations) or two integers.
+  __ Bind(&different_cids);
+  __ cmpq(RCX, Immediate(kNumPredefinedCids));
+  __ j(ABOVE_EQUAL, &not_equal);
+
+  __ movq(RAX, RCX);
+  JumpIfNotInteger(assembler, RAX, &not_integer);
+
+  // First object is an integer. Check if the second is an integer too.
+  // Otherwise types are unequal because only integers have the same runtime
+  // type as other integers.
+  JumpIfInteger(assembler, RDX, &equal);
+  __ jmp(&not_equal);
+
+  __ Bind(&not_integer);
+  // Check if the first object is a string. If it is not then
+  // objects don't have the same runtime type because they have
+  // different class ids and they are not strings or integers.
+  JumpIfNotString(assembler, RCX, &not_equal);
+  // First object is a string. Check if the second is a string too.
+  JumpIfString(assembler, RDX, &equal);
+  // Strings only have the same runtime type as other strings.
+  // Fall-through to the not equal case.
+
+  __ Bind(&not_equal);
+  __ LoadObject(RAX, Bool::False());
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ movq(RAX, Address(RSP, + 1 * kWordSize));  // String object.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 7fdbe56b..bfc902e 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -777,6 +777,7 @@
       user_tag_(0),
       current_tag_(UserTag::null()),
       default_tag_(UserTag::null()),
+      object_store_(NULL),
       class_table_(),
       single_step_(false),
       thread_registry_(new ThreadRegistry()),
@@ -790,8 +791,6 @@
       pause_capability_(0),
       terminate_capability_(0),
       errors_fatal_(true),
-      object_store_(NULL),
-      top_exit_frame_info_(0),
       init_callback_data_(NULL),
       environment_callback_(NULL),
       library_tag_handler_(NULL),
@@ -816,8 +815,6 @@
       pending_deopts_(new MallocGrowableArray<PendingLazyDeopt>),
       deopt_context_(NULL),
       is_service_isolate_(false),
-      stacktrace_(NULL),
-      stack_frame_index_(-1),
       last_allocationprofile_accumulator_reset_timestamp_(0),
       last_allocationprofile_gc_timestamp_(0),
       object_id_ring_(NULL),
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index f29f666..d3fe58a 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -224,6 +224,9 @@
 
   ObjectStore* object_store() const { return object_store_; }
   void set_object_store(ObjectStore* value) { object_store_ = value; }
+  static intptr_t object_store_offset() {
+    return OFFSET_OF(Isolate, object_store_);
+  }
 
   ApiState* api_state() const { return api_state_; }
   void set_api_state(ApiState* value) { api_state_ = value; }
@@ -733,9 +736,9 @@
   RawUserTag* current_tag_;
   RawUserTag* default_tag_;
   RawCode* ic_miss_code_;
+  ObjectStore* object_store_;
   ClassTable class_table_;
   bool single_step_;
-  bool skip_step_;  // skip the next single step.
 
   ThreadRegistry* thread_registry_;
   SafepointHandler* safepoint_handler_;
@@ -748,8 +751,6 @@
   uint64_t pause_capability_;
   uint64_t terminate_capability_;
   bool errors_fatal_;
-  ObjectStore* object_store_;
-  uword top_exit_frame_info_;
   void* init_callback_data_;
   Dart_EnvironmentCallback environment_callback_;
   Dart_LibraryTagHandler library_tag_handler_;
@@ -784,10 +785,6 @@
     bool error_on_bad_override_;
   )
 
-  // Status support.
-  char* stacktrace_;
-  intptr_t stack_frame_index_;
-
   // Timestamps of last operation via service.
   int64_t last_allocationprofile_accumulator_reset_timestamp_;
   int64_t last_allocationprofile_gc_timestamp_;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 6bd57d7..139c6d4 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -1082,6 +1082,10 @@
         new_lib = Library::RawCast(lib_map.GetKey(entry));
         lib = Library::RawCast(lib_map.GetPayload(entry, 0));
         new_lib.set_debuggable(lib.IsDebuggable());
+        // Native extension support.
+        new_lib.set_native_entry_resolver(lib.native_entry_resolver());
+        new_lib.set_native_entry_symbol_resolver(
+            lib.native_entry_symbol_resolver());
       }
     }
 
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index c8282e4..7fabfe7 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -3083,6 +3083,52 @@
   EXPECT_STREQ("bossy pants", SimpleInvokeStr(lib, "main"));
 }
 
+
+TEST_CASE(IsolateReload_SimpleConstFieldUpdate) {
+    const char* kScript =
+      "const value = 'a';\n"
+      "main() {\n"
+      "  return 'value=${value}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("value=a", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "const value = 'b';\n"
+      "main() {\n"
+      "  return 'value=${value}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("value=b", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_ConstFieldUpdate) {
+    const char* kScript =
+      "const value = const Duration(seconds: 1);\n"
+      "main() {\n"
+      "  return 'value=${value}';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("value=0:00:01.000000", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "const value = const Duration(seconds: 2);\n"
+      "main() {\n"
+      "  return 'value=${value}';\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("value=0:00:02.000000", SimpleInvokeStr(lib, "main"));
+}
+
 #endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
index 00f1588..63c79bc 100644
--- a/runtime/vm/jit_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -1707,13 +1707,20 @@
     // we don't have one target.
     const Function& target =
         Function::Handle(Z, unary_checks.GetTargetAt(0));
-    const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
-    has_one_target = !polymorphic_target;
+    if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
+      has_one_target =
+          PolymorphicInstanceCallInstr::ComputeRuntimeType(unary_checks) !=
+              Type::null();
+    } else {
+      const bool polymorphic_target =
+          MethodRecognizer::PolymorphicTarget(target);
+      has_one_target = !polymorphic_target;
+    }
   }
 
   if (has_one_target) {
-    RawFunction::Kind function_kind =
-        Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
+    const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
+    const RawFunction::Kind function_kind = target.kind();
     if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
       PolymorphicInstanceCallInstr* call =
           new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 4eb6001..d9d7679 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -225,6 +225,9 @@
 
 void KernelReader::ReadPreliminaryClass(dart::Class* klass,
                                         Class* kernel_klass) {
+  ASSERT(kernel_klass->IsNormalClass());
+  NormalClass* kernel_normal_class = NormalClass::Cast(kernel_klass);
+
   ActiveClassScope active_class_scope(&active_class_, kernel_klass, klass);
 
   // First setup the type parameters, so if any of the following code uses it
@@ -250,8 +253,8 @@
     // Step b) Fill in the bounds of all [TypeParameter]s.
     for (intptr_t i = 0; i < num_type_parameters; i++) {
       TypeParameter* kernel_parameter = kernel_klass->type_parameters()[i];
-      // There is no dynamic bound, only Object.
-      // TODO(27590): Should we fix this in the kernel IR generator?
+      // TODO(github.com/dart-lang/kernel/issues/42): This should be handled
+      // by the frontend.
       if (kernel_parameter->bound()->IsDynamicType()) {
         parameter ^= type_parameters.TypeAt(i);
         parameter.set_bound(Type::Handle(Z, I->object_store()->object_type()));
@@ -268,33 +271,12 @@
     }
   }
 
-  if (kernel_klass->IsNormalClass()) {
-    NormalClass* kernel_normal_class = NormalClass::Cast(kernel_klass);
-
-    // Set super type.  Some classes (e.g., Object) do not have one.
-    if (kernel_normal_class->super_class() != NULL) {
-      AbstractType& super_type = T.TranslateTypeWithoutFinalization(
-          kernel_normal_class->super_class());
-      if (super_type.IsMalformed()) H.ReportError("Malformed super type");
-      klass->set_super_type(super_type);
-    }
-  } else {
-    MixinClass* kernel_mixin = MixinClass::Cast(kernel_klass);
-
-    // Set super type.
-    AbstractType& super_type =
-        T.TranslateTypeWithoutFinalization(kernel_mixin->first());
-    if (super_type.IsMalformed()) H.ReportError("Malformed super type.");
+  // Set super type.  Some classes (e.g., Object) do not have one.
+  if (kernel_normal_class->super_class() != NULL) {
+    AbstractType& super_type = T.TranslateTypeWithoutFinalization(
+        kernel_normal_class->super_class());
+    if (super_type.IsMalformed()) H.ReportError("Malformed super type");
     klass->set_super_type(super_type);
-
-    // Tell the rest of the system there is nothing to resolve.
-    super_type.SetIsResolved();
-
-    // Set mixin type.
-    AbstractType& mixin_type =
-        T.TranslateTypeWithoutFinalization(kernel_mixin->second());
-    if (mixin_type.IsMalformed()) H.ReportError("Malformed mixin type.");
-    klass->set_mixin(Type::Cast(mixin_type));
   }
 
   // Build implemented interface types
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 0aff92b..38900f1 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -71,8 +71,10 @@
 
 void ScopeBuilder::AddParameter(VariableDeclaration* declaration,
                                 intptr_t pos) {
-  // TODO(27590): Handle final.
   LocalVariable* variable = MakeVariable(H.DartSymbol(declaration->name()));
+  if (declaration->IsFinal()) {
+    variable->set_is_final();
+  }
   scope_->InsertParameterAt(pos, variable);
   result_->locals.Insert(declaration, variable);
 
@@ -205,11 +207,16 @@
 
 
 void ScopeBuilder::AddVariable(VariableDeclaration* declaration) {
-  // TODO(27590): Handle final and const, including function declarations.
+  // In case `declaration->IsConst()` the flow graph building will take care of
+  // evaluating the constant and setting it via
+  // `declaration->SetConstantValue()`.
   const dart::String& name = declaration->name()->is_empty()
                                  ? GenerateName(":var", name_index_++)
                                  : H.DartSymbol(declaration->name());
   LocalVariable* variable = MakeVariable(name);
+  if (declaration->IsFinal()) {
+    variable->set_is_final();
+  }
   scope_->AddVariable(variable);
   result_->locals.Insert(declaration, variable);
 }
@@ -237,8 +244,12 @@
         ContextScope::Handle(Z, function.context_scope()));
   }
   current_function_scope_ = scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
+
+  LocalVariable* context_var = parsed_function->current_context_var();
+  context_var->set_is_forced_stack();
+  scope_->AddVariable(context_var);
   scope_->AddVariable(parsed_function->EnsureExpressionTemp());
-  scope_->AddVariable(parsed_function->current_context_var());
+
   parsed_function->SetNodeSequence(
       new SequenceNode(TokenPosition::kNoSource, scope_));
 
@@ -261,6 +272,7 @@
       intptr_t pos = 0;
       if (function.IsClosureFunction()) {
         LocalVariable* variable = MakeVariable(Symbols::ClosureParameter());
+        variable->set_is_forced_stack();
         scope_->InsertParameterAt(pos++, variable);
       } else if (!function.is_static()) {
         // We use [is_static] instead of [IsStaticFunction] because the latter
@@ -517,6 +529,7 @@
 void ScopeBuilder::AddSwitchVariable() {
   if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) {
     LocalVariable* variable = MakeVariable(Symbols::SwitchExpr());
+    variable->set_is_forced_stack();
     current_function_scope_->AddVariable(variable);
     result_->switch_variable = variable;
   }
@@ -928,45 +941,9 @@
 
 const dart::String& TranslationHelper::DartClassName(
     kernel::Class* kernel_klass) {
-  if (kernel_klass->name() != NULL) {
-    ASSERT(kernel_klass->IsNormalClass());
-    dart::String& name = DartString(kernel_klass->name());
-    return ManglePrivateName(kernel_klass->parent(), &name);
-  } else {
-    // Mixin class names are not mangled.
-    ASSERT(kernel_klass->IsMixinClass());
-
-    // We construct the string from right to left:
-    //     "Base&Mixin1&Mixin2&...&MixinN"
-    dart::String& partial = dart::String::Handle(Z, dart::String::New(""));
-    dart::String& amp = dart::String::Handle(Z, dart::String::New("&"));
-    dart::String& tmp = dart::String::Handle(Z);
-    while (kernel_klass->name() == NULL) {
-      ASSERT(kernel_klass->IsMixinClass());
-
-      MixinClass* kernel_mixin_class = MixinClass::Cast(kernel_klass);
-      InterfaceType* base_type = kernel_mixin_class->first();
-      InterfaceType* mixin_type = kernel_mixin_class->second();
-
-      String* mixin_name = NormalClass::Cast(mixin_type->klass())->name();
-
-      tmp = dart::String::FromUTF8(mixin_name->buffer(), mixin_name->size());
-
-      partial = dart::String::Concat(amp, partial);
-      partial = dart::String::Concat(tmp, partial);
-
-      kernel_klass = base_type->klass();
-    }
-
-    tmp = dart::String::FromUTF8(kernel_klass->name()->buffer(),
-                                 kernel_klass->name()->size());
-
-    partial = dart::String::Concat(amp, partial);
-    partial = dart::String::Concat(tmp, partial);
-
-    partial = dart::Symbols::New(thread_, partial);
-    return partial;
-  }
+  ASSERT(kernel_klass->IsNormalClass());
+  dart::String& name = DartString(kernel_klass->name());
+  return ManglePrivateName(kernel_klass->parent(), &name);
 }
 
 
@@ -1004,8 +981,8 @@
   if (content->buffer()[content->size() - 1] == '=') {
     skip = 1;
   }
-  dart::String& name = dart::String::ZoneHandle(
-      Z, dart::String::FromUTF8(content->buffer(), content->size() - skip));
+  dart::String& name = dart::String::ZoneHandle(Z, dart::String::FromUTF8(
+        content->buffer(), content->size() - skip, allocation_space_));
   ManglePrivateName(kernel_name->library(), &name, false);
   name = dart::Field::SetterSymbol(name);
   return name;
@@ -1044,15 +1021,12 @@
 const dart::String& TranslationHelper::DartFactoryName(Class* klass,
                                                        Name* method_name) {
   // [DartMethodName] will mangle the name.
-  dart::String& name =
-      dart::String::Handle(Z, DartMethodName(method_name).raw());
-
-  // We build a String which looks like <classname>.<constructor-name>.
-  // [DartClassName] will mangle the name.
-  dart::String& temp = dart::String::Handle(Z, DartClassName(klass).raw());
-  temp = dart::String::Concat(temp, Symbols::Dot());
-  temp = dart::String::Concat(temp, name);
-  return dart::String::ZoneHandle(Z, dart::Symbols::New(thread_, temp));
+  GrowableHandlePtrArray<const dart::String> pieces(Z, 3);
+  pieces.Add(DartClassName(klass));
+  pieces.Add(Symbols::Dot());
+  pieces.Add(DartMethodName(method_name));
+  return dart::String::ZoneHandle(
+      Z, dart::Symbols::FromConcatAll(thread_, pieces));
 }
 
 
@@ -1217,7 +1191,8 @@
 const Array& TranslationHelper::ArgumentNames(List<NamedExpression>* named) {
   if (named->length() == 0) return Array::ZoneHandle(Z);
 
-  const Array& names = Array::ZoneHandle(Z, Array::New(named->length()));
+  const Array& names = Array::ZoneHandle(Z,
+      Array::New(named->length(), allocation_space_));
   for (intptr_t i = 0; i < named->length(); ++i) {
     names.SetAt(i, DartSymbol((*named)[i]->name()));
   }
@@ -1225,8 +1200,25 @@
 }
 
 
+ConstantEvaluator::ConstantEvaluator(FlowGraphBuilder* builder,
+                                     Zone* zone,
+                                     TranslationHelper* h,
+                                     DartTypeTranslator* type_translator)
+    : builder_(builder),
+      isolate_(Isolate::Current()),
+      zone_(zone),
+      translation_helper_(*h),
+      type_translator_(*type_translator),
+      script_(dart::Script::Handle(
+            zone, builder_->parsed_function_->function().script())),
+      result_(dart::Instance::Handle(zone)) {}
+
+
 Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) {
-  expression->AcceptExpressionVisitor(this);
+  if (!GetCachedConstant(expression, &result_)) {
+    expression->AcceptExpressionVisitor(this);
+    CacheConstantValue(expression, result_);
+  }
   // We return a new `ZoneHandle` here on purpose: The intermediate language
   // instructions do not make a copy of the handle, so we do it.
   return dart::Instance::ZoneHandle(Z, result_.raw());
@@ -1249,7 +1241,10 @@
 
 Instance& ConstantEvaluator::EvaluateConstructorInvocation(
     ConstructorInvocation* node) {
-  VisitConstructorInvocation(node);
+  if (!GetCachedConstant(node, &result_)) {
+    VisitConstructorInvocation(node);
+    CacheConstantValue(node, result_);
+  }
   // We return a new `ZoneHandle` here on purpose: The intermediate language
   // instructions do not make a copy of the handle, so we do it.
   return dart::Instance::ZoneHandle(Z, result_.raw());
@@ -1257,7 +1252,10 @@
 
 
 Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) {
-  VisitListLiteral(node);
+  if (!GetCachedConstant(node, &result_)) {
+    VisitListLiteral(node);
+    CacheConstantValue(node, result_);
+  }
   // We return a new `ZoneHandle` here on purpose: The intermediate language
   // instructions do not make a copy of the handle, so we do it.
   return dart::Instance::ZoneHandle(Z, result_.raw());
@@ -1265,7 +1263,10 @@
 
 
 Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) {
-  VisitMapLiteral(node);
+  if (!GetCachedConstant(node, &result_)) {
+    VisitMapLiteral(node);
+    CacheConstantValue(node, result_);
+  }
   // We return a new `ZoneHandle` here on purpose: The intermediate language
   // instructions do not make a copy of the handle, so we do it.
   return dart::Instance::ZoneHandle(Z, result_.raw());
@@ -1353,6 +1354,56 @@
 }
 
 
+bool ConstantEvaluator::GetCachedConstant(TreeNode* node, Instance* value) {
+  const Function& function = builder_->parsed_function_->function();
+  if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
+    // Don't cache constants in initializer expressions. They get
+    // evaluated only once.
+    return false;
+  }
+
+  bool is_present = false;
+  ASSERT(!script_.InVMHeap());
+  if (script_.compile_time_constants() == Array::null()) {
+    return false;
+  }
+  KernelConstantsMap constants(script_.compile_time_constants());
+  *value ^= constants.GetOrNull(node, &is_present);
+  // Mutator compiler thread may add constants while background compiler
+  // is running, and thus change the value of 'compile_time_constants';
+  // do not assert that 'compile_time_constants' has not changed.
+  constants.Release();
+  if (FLAG_compiler_stats && is_present) {
+    H.thread()->compiler_stats()->num_const_cache_hits++;
+  }
+  return is_present;
+}
+
+
+void ConstantEvaluator::CacheConstantValue(TreeNode* node,
+                                           const Instance& value) {
+  ASSERT(Thread::Current()->IsMutatorThread());
+
+  const Function& function = builder_->parsed_function_->function();
+  if (function.kind() == RawFunction::kImplicitStaticFinalGetter) {
+    // Don't cache constants in initializer expressions. They get
+    // evaluated only once.
+    return;
+  }
+  const intptr_t kInitialConstMapSize = 16;
+  ASSERT(!script_.InVMHeap());
+  if (script_.compile_time_constants() == Array::null()) {
+    const Array& array =
+        Array::Handle(HashTables::New<KernelConstantsMap>(kInitialConstMapSize,
+                                                          Heap::kNew));
+    script_.set_compile_time_constants(array);
+  }
+  KernelConstantsMap constants(script_.compile_time_constants());
+  constants.InsertNewOrGetValue(node, value);
+  script_.set_compile_time_constants(constants.Release());
+}
+
+
 void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) {
   const dart::String& symbol_value = H.DartSymbol(node->value());
 
@@ -1470,7 +1521,6 @@
   ASSERT(!klass.IsNull());
 
   // Search the superclass chain for the selector.
-  // TODO(27590): Can we assume this will never be a no-such-method error?
   dart::Function& function = dart::Function::Handle(Z);
   const dart::String& method_name = H.DartMethodName(node->name());
   while (!klass.IsNull()) {
@@ -1478,6 +1528,9 @@
     if (!function.IsNull()) break;
     klass = klass.SuperClass();
   }
+
+  // The frontend should guarantee that [MethodInvocation]s inside constant
+  // expressions are always valid.
   ASSERT(!function.IsNull());
 
   // Run the method and canonicalize the result.
@@ -2347,31 +2400,54 @@
 Fragment FlowGraphBuilder::StoreIndexed(intptr_t class_id) {
   Value* value = Pop();
   Value* index = Pop();
-  // TODO(27590): Omit store barrier when possible (e.g., storing
-  // some constants).
+  const StoreBarrierType emit_store_barrier =
+      value->BindsToConstant()
+          ? kNoStoreBarrier
+          : kEmitStoreBarrier;
   StoreIndexedInstr* store = new (Z) StoreIndexedInstr(
       Pop(),  // Array.
-      index, value, kEmitStoreBarrier, Instance::ElementSizeFor(class_id),
-      class_id, Thread::kNoDeoptId, TokenPosition::kNoSource);
+      index, value, emit_store_barrier, Instance::ElementSizeFor(class_id),
+      class_id, kAlignedAccess, Thread::kNoDeoptId, TokenPosition::kNoSource);
   Push(store);
   return Fragment(store);
 }
 
 
-Fragment FlowGraphBuilder::StoreInstanceField(const dart::Field& field) {
+Fragment FlowGraphBuilder::StoreInstanceField(
+    const dart::Field& field, StoreBarrierType emit_store_barrier) {
   Value* value = Pop();
-  // TODO(27590): Omit store barrier when possible (e.g., storing
-  // some constants).
+  if (value->BindsToConstant()) {
+    emit_store_barrier = kNoStoreBarrier;
+  }
   StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr(
-      field, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource);
+      field, Pop(), value, emit_store_barrier, TokenPosition::kNoSource);
   return Fragment(store);
 }
 
 
-Fragment FlowGraphBuilder::StoreInstanceField(intptr_t offset) {
+Fragment FlowGraphBuilder::StoreInstanceFieldGuarded(const dart::Field& field) {
+  Fragment instructions;
+  if (FLAG_use_field_guards) {
+    LocalVariable* store_expression = MakeTemporary();
+    instructions += LoadLocal(store_expression);
+    instructions += GuardFieldClass(field, Thread::Current()->GetNextDeoptId());
+    instructions += LoadLocal(store_expression);
+    instructions +=
+        GuardFieldLength(field, Thread::Current()->GetNextDeoptId());
+  }
+  instructions += StoreInstanceField(field);
+  return instructions;
+}
+
+
+Fragment FlowGraphBuilder::StoreInstanceField(
+    intptr_t offset, StoreBarrierType emit_store_barrier) {
   Value* value = Pop();
+  if (value->BindsToConstant()) {
+    emit_store_barrier = kNoStoreBarrier;
+  }
   StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr(
-      offset, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource);
+      offset, Pop(), value, emit_store_barrier, TokenPosition::kNoSource);
   return Fragment(store);
 }
 
@@ -2750,7 +2826,7 @@
   const Function& dart_function = parsed_function_->function();
   TargetEntryInstr* normal_entry = BuildTargetEntry();
   graph_entry_ = new (Z)
-      GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
+      GraphEntryInstr(*parsed_function_, normal_entry, osr_id_);
 
   SetupDefaultParameterValues(function);
 
@@ -2917,6 +2993,15 @@
   }
   normal_entry->LinkTo(body.entry);
 
+  // When compiling for OSR, use a depth first search to prune instructions
+  // unreachable from the OSR entry. Catch entries are always considered
+  // reachable, even if they become unreachable after OSR.
+  if (osr_id_ != Compiler::kNoOSRDeoptId) {
+    BitVector* block_marks = new(Z) BitVector(Z, next_block_id_);
+    bool found = graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_,
+                                                block_marks);
+    ASSERT(found);
+  }
   return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
 }
 
@@ -3032,8 +3117,8 @@
       body += LoadLocal(scopes_->this_variable);
       body += LoadLocal(
           LookupVariable(kernel_function->positional_parameters()[0]));
-      // TODO(27590): This store does not need a store barrier.
-      body += StoreInstanceField(LinkedHashMap::hash_mask_offset());
+      body += StoreInstanceField(LinkedHashMap::hash_mask_offset(),
+                                 kNoStoreBarrier);
       body += NullConstant();
       break;
     case MethodRecognizer::kLinkedHashMap_getUsedData:
@@ -3045,8 +3130,8 @@
       body += LoadLocal(scopes_->this_variable);
       body += LoadLocal(
           LookupVariable(kernel_function->positional_parameters()[0]));
-      // TODO(27590): This store does not need a store barrier.
-      body += StoreInstanceField(LinkedHashMap::used_data_offset());
+      body += StoreInstanceField(LinkedHashMap::used_data_offset(),
+                                 kNoStoreBarrier);
       body += NullConstant();
       break;
     case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
@@ -3058,8 +3143,8 @@
       body += LoadLocal(scopes_->this_variable);
       body += LoadLocal(
           LookupVariable(kernel_function->positional_parameters()[0]));
-      // TODO(27590): This store does not need a store barrier.
-      body += StoreInstanceField(LinkedHashMap::deleted_keys_offset());
+      body += StoreInstanceField(LinkedHashMap::deleted_keys_offset(),
+                                 kNoStoreBarrier);
       body += NullConstant();
       break;
     case MethodRecognizer::kBigint_getNeg:
@@ -3090,13 +3175,12 @@
   graph_entry_ = new (Z)
       GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
 
-  // TODO(27590): Add support for FLAG_use_field_guards.
   Fragment body(normal_entry);
   if (is_setter) {
     if (is_method) {
       body += LoadLocal(scopes_->this_variable);
       body += LoadLocal(setter_value);
-      body += StoreInstanceField(field);
+      body += StoreInstanceFieldGuarded(field);
     } else {
       body += LoadLocal(setter_value);
       body += StoreStaticField(field);
@@ -3184,6 +3268,18 @@
 }
 
 
+Fragment FlowGraphBuilder::GuardFieldLength(const dart::Field& field,
+                                            intptr_t deopt_id) {
+  return Fragment(new (Z) GuardFieldLengthInstr(Pop(), field, deopt_id));
+}
+
+
+Fragment FlowGraphBuilder::GuardFieldClass(const dart::Field& field,
+                                           intptr_t deopt_id) {
+  return Fragment(new (Z) GuardFieldClassInstr(Pop(), field, deopt_id));
+}
+
+
 FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
     const Function& method) {
   // A method extractor is the implicit getter for a method.
@@ -3506,10 +3602,9 @@
           dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
 
       EnterScope(kernel_field);
-      // TODO(27590): Support FLAG_use_field_guards.
       instructions += LoadLocal(scopes_->this_variable);
       instructions += TranslateExpression(init);
-      instructions += StoreInstanceField(field);
+      instructions += StoreInstanceFieldGuarded(field);
       ExitScope(kernel_field);
     }
   }
@@ -3527,10 +3622,9 @@
       dart::Field& field =
           dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(init->field()));
 
-      // TODO(27590): Support FLAG_use_field_guards.
       instructions += LoadLocal(scopes_->this_variable);
       instructions += TranslateExpression(init->value());
-      instructions += StoreInstanceField(field);
+      instructions += StoreInstanceFieldGuarded(field);
     } else if (initializer->IsSuperInitializer()) {
       SuperInitializer* init = SuperInitializer::Cast(initializer);
 
@@ -3646,9 +3740,9 @@
 
 
 void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) {
-  // TODO(27590): Once we have better error information we might need to
-  // make some invalid expressions not NSM errors but type/compile-time/...
-  // errors.
+  // The frontend will take care of emitting normal errors (like
+  // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
+  // situations (e.g. an invalid annotation).
   fragment_ = ThrowNoSuchMethodError();
 }
 
@@ -3719,15 +3813,22 @@
 
 
 void DartTypeTranslator::VisitFunctionType(FunctionType* node) {
-  // TODO(27590): Fix function types which are composed of malformed types.
-  // We might need to convert them to dynamic types instead of making the
-  // function type malformed.
+  // The spec describes in section "19.1 Static Types":
+  //
+  //     Any use of a malformed type gives rise to a static warning. A
+  //     malformed type is then interpreted as dynamic by the static type
+  //     checker and the runtime unless explicitly specified otherwise.
+  //
+  // So we convert malformed return/parameter types to `dynamic`.
+
   const Function& signature_function = Function::ZoneHandle(
       Z, Function::NewSignatureFunction(*active_class_->klass,
                                         TokenPosition::kNoSource));
 
   node->return_type()->AcceptDartTypeVisitor(this);
-  if (result_.IsMalformed()) return;
+  if (result_.IsMalformed()) {
+    result_ = AbstractType::dynamic_type().raw();
+  }
   signature_function.set_result_type(result_);
 
   const intptr_t positional_count = node->positional_parameters().length();
@@ -3753,14 +3854,18 @@
   pos++;
   for (intptr_t i = 0; i < positional_count; i++, pos++) {
     node->positional_parameters()[i]->AcceptDartTypeVisitor(this);
-    if (result_.IsMalformed()) return;
+    if (result_.IsMalformed()) {
+      result_ = AbstractType::dynamic_type().raw();
+    }
     parameter_types.SetAt(pos, result_);
     parameter_names.SetAt(pos, H.DartSymbol("noname"));
   }
   for (intptr_t i = 0; i < named_count; i++, pos++) {
     Tuple<String, DartType>* tuple = node->named_parameters()[i];
     tuple->second()->AcceptDartTypeVisitor(this);
-    if (result_.IsMalformed()) return;
+    if (result_.IsMalformed()) {
+      result_ = AbstractType::dynamic_type().raw();
+    }
     parameter_types.SetAt(pos, result_);
     parameter_names.SetAt(pos, H.DartSymbol(tuple->first()));
   }
@@ -3935,15 +4040,8 @@
 
 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
   Fragment instructions = TranslateExpression(node->expression());
-  // The IR should not include assignments to final or const variables.
-  // This is https://github.com/dart-lang/rasta/issues/83.
-  //
-  // TODO(27590): simply ASSERT that the variable is not const or final
-  // when that issue is fixed.
-  fragment_ = instructions +
-              ((node->variable()->IsFinal() || node->variable()->IsConst())
-                   ? Drop() + ThrowNoSuchMethodError()
-                   : StoreLocal(LookupVariable(node->variable())));
+  instructions += StoreLocal(LookupVariable(node->variable()));
+  fragment_ = instructions;
 }
 
 
@@ -3964,7 +4062,6 @@
         Fragment instructions = Constant(field);
         fragment_ = instructions + LoadStaticField();
       } else {
-        // TODO(27590): figure out how to trigger this case and add tests.
         fragment_ = StaticCall(getter, 0);
       }
     }
@@ -4104,30 +4201,14 @@
     // every factory constructor.
     ++argument_count;
   }
+
   List<NamedExpression>& named = node->arguments()->named();
   const Array& argument_names = H.ArgumentNames(&named);
 
+  // The frontend ensures we the [StaticInvocation] has matching arguments.
+  ASSERT(target.AreValidArguments(argument_count, argument_names, NULL));
+
   Fragment instructions;
-  if (!target.AreValidArguments(argument_count, argument_names, NULL)) {
-    // An argument mismatch for a static invocation really should not occur
-    // in the IR.  This is issue https://github.com/dart-lang/rasta/issues/76.
-    //
-    // TODO(27590): Change this to an ASSERT when that issue is fixed.
-    List<Expression>& positional = node->arguments()->positional();
-    for (intptr_t i = 0; i < positional.length(); ++i) {
-      instructions += TranslateExpression(positional[i]);
-      instructions += Drop();
-    }
-
-    for (intptr_t i = 0; i < named.length(); ++i) {
-      instructions += TranslateExpression(named[i]->expression());
-      instructions += Drop();
-    }
-
-    fragment_ = instructions + ThrowNoSuchMethodError();
-    return;
-  }
-
   LocalVariable* instance_variable = NULL;
 
   // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
@@ -5487,6 +5568,9 @@
     ASSERT(stack_trace_var->name().raw() ==
            Symbols::StackTraceParameter().raw());
 
+    exception_var->set_is_forced_stack();
+    stack_trace_var->set_is_forced_stack();
+
     TargetEntryInstr* no_error;
     TargetEntryInstr* error;
 
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 20b9aeb..eb3beca 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -16,6 +16,46 @@
 namespace dart {
 namespace kernel {
 
+// TODO(27590): Instead of using [dart::kernel::TreeNode]s as keys we
+// should use [TokenPosition]s.
+class KernelConstMapKeyEqualsTraits {
+ public:
+  static const char* Name() { return "KernelConstMapKeyEqualsTraits"; }
+  static bool ReportStats() { return false; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    const Smi& key1 = Smi::Cast(a);
+    const Smi& key2 = Smi::Cast(b);
+    return (key1.Value() == key2.Value());
+  }
+  static bool IsMatch(const TreeNode* key1, const Object& b) {
+    return KeyAsSmi(key1) == Smi::Cast(b).raw();
+  }
+  static uword Hash(const Object& obj) {
+    const Smi& key = Smi::Cast(obj);
+    return HashValue(key.Value());
+  }
+  static uword Hash(const TreeNode* key) {
+    return HashValue(Smi::Value(KeyAsSmi(key)));
+  }
+  static RawObject* NewKey(const TreeNode* key) {
+    return KeyAsSmi(key);
+  }
+
+ private:
+  static uword HashValue(intptr_t pos) {
+    return pos % (Smi::kMaxValue - 13);
+  }
+
+  static RawSmi* KeyAsSmi(const TreeNode* key) {
+    // We exploit that all [TreeNode] objects will be aligned and therefore are
+    // already [Smi]s!
+    return reinterpret_cast<RawSmi*>(const_cast<TreeNode*>(key));
+  }
+};
+typedef UnorderedHashMap<KernelConstMapKeyEqualsTraits> KernelConstantsMap;
+
+
 template <typename K, typename V>
 class Map : public DirectChainedHashMap<RawPointerKeyValueTrait<K, V> > {
  public:
@@ -150,7 +190,11 @@
 class TranslationHelper {
  public:
   TranslationHelper(dart::Thread* thread, dart::Zone* zone, Isolate* isolate)
-      : thread_(thread), zone_(zone), isolate_(isolate) {}
+      : thread_(thread),
+        zone_(zone),
+        isolate_(isolate),
+        allocation_space_(
+            thread_->IsMutatorThread() ? Heap::kNew : Heap::kOld) {}
   virtual ~TranslationHelper() {}
 
   Thread* thread() { return thread_; }
@@ -159,6 +203,8 @@
 
   Isolate* isolate() { return isolate_; }
 
+  Heap::Space allocation_space() { return allocation_space_; }
+
   // Set whether unfinalized classes should be finalized.  The base class
   // implementation used at flow graph construction time looks up classes in the
   // VM's heap, all of which should already be finalized.
@@ -166,9 +212,16 @@
 
   RawInstance* Canonicalize(const Instance& instance);
 
-  const dart::String& DartString(const char* content,
-                                 Heap::Space space = Heap::kNew);
-  dart::String& DartString(String* content, Heap::Space space = Heap::kNew);
+  const dart::String& DartString(const char* content) {
+    return DartString(content, allocation_space_);
+  }
+  const dart::String& DartString(const char* content, Heap::Space space);
+
+  dart::String& DartString(String* content) {
+    return DartString(content, allocation_space_);
+  }
+  dart::String& DartString(String* content, Heap::Space space);
+
   const dart::String& DartSymbol(const char* content) const;
   dart::String& DartSymbol(String* content) const;
 
@@ -212,6 +265,7 @@
   dart::Thread* thread_;
   dart::Zone* zone_;
   dart::Isolate* isolate_;
+  Heap::Space allocation_space_;
 };
 
 // Regarding malformed types:
@@ -302,13 +356,7 @@
 class ConstantEvaluator : public ExpressionVisitor {
  public:
   ConstantEvaluator(FlowGraphBuilder* builder, Zone* zone, TranslationHelper* h,
-                    DartTypeTranslator* type_translator)
-      : builder_(builder),
-        isolate_(Isolate::Current()),
-        zone_(zone),
-        translation_helper_(*h),
-        type_translator_(*type_translator),
-        result_(dart::Instance::Handle(zone)) {}
+                    DartTypeTranslator* type_translator);
   virtual ~ConstantEvaluator() {}
 
   Instance& EvaluateExpression(Expression* node);
@@ -364,12 +412,19 @@
                                           const Function& constructor,
                                           const Object& argument);
 
+  // TODO(27590): Instead of using [dart::kernel::TreeNode]s as keys we
+  // should use [TokenPosition]s as well as the existing functionality in
+  // `Parser::CacheConstantValue`.
+  bool GetCachedConstant(TreeNode* node, Instance* value);
+  void CacheConstantValue(TreeNode* node, const Instance& value);
+
   FlowGraphBuilder* builder_;
   Isolate* isolate_;
   Zone* zone_;
   TranslationHelper& translation_helper_;
   DartTypeTranslator& type_translator_;
 
+  Script& script_;
   Instance& result_;
 };
 
@@ -708,14 +763,21 @@
   Fragment StaticCall(const Function& target, intptr_t argument_count,
                       const Array& argument_names);
   Fragment StoreIndexed(intptr_t class_id);
-  Fragment StoreInstanceField(const dart::Field& field);
-  Fragment StoreInstanceField(intptr_t offset);
+  Fragment StoreInstanceFieldGuarded(const dart::Field& field);
+  Fragment StoreInstanceField(
+      const dart::Field& field,
+      StoreBarrierType emit_store_barrier = kEmitStoreBarrier);
+  Fragment StoreInstanceField(
+      intptr_t offset,
+      StoreBarrierType emit_store_barrier = kEmitStoreBarrier);
   Fragment StoreLocal(LocalVariable* variable);
   Fragment StoreStaticField(const dart::Field& field);
   Fragment StringInterpolate();
   Fragment ThrowTypeError();
   Fragment ThrowNoSuchMethodError();
   Fragment BuildImplicitClosureCreation(const Function& target);
+  Fragment GuardFieldLength(const dart::Field& field, intptr_t deopt_id);
+  Fragment GuardFieldClass(const dart::Field& field, intptr_t deopt_id);
 
   dart::RawFunction* LookupMethodByMember(Member* target,
                                           const dart::String& method_name);
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index e3d34dd..8a4e6af 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -65,7 +65,7 @@
   const Function& function =
       Function::Handle(Function::New(Symbols::MegamorphicMiss(),
                                      RawFunction::kRegularFunction,
-                                     false,  // Not static.
+                                     true,  // Static, but called as a method.
                                      false,  // Not const.
                                      false,  // Not abstract.
                                      false,  // Not external.
@@ -75,7 +75,7 @@
   function.set_result_type(Type::Handle(Type::DynamicType()));
   function.set_is_debuggable(false);
   function.set_is_visible(false);
-  function.AttachCode(code);
+  function.AttachCode(code);  // Has a single entry point, as a static function.
   // For inclusion in Snapshot::kAppWithJIT.
   function.set_unoptimized_code(code);
 
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index b110916..9051240 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -167,6 +167,7 @@
   V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, Dynamic, 0x6036d7fa)          \
   V(Object, ==, ObjectEquals, Bool, 0x11662ed8)                                \
   V(Object, get:runtimeType, ObjectRuntimeType, Type, 0x00e7c26b)              \
+  V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, Bool, 0x72aad7e2) \
   V(_StringBase, get:hashCode, String_getHashCode, Smi, 0x78c2eb88)            \
   V(_StringBase, get:isEmpty, StringBaseIsEmpty, Bool, 0x74c21fca)             \
   V(_StringBase, _substringMatches, StringBaseSubstringMatches, Bool,          \
@@ -489,6 +490,7 @@
   V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x4765edda)              \
   V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x7cca4533)          \
   V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0x7631bdbc)              \
+  V(Object, get:runtimeType, ObjectRuntimeType, 0x00e7c26b)                    \
 
 // Forward declarations.
 class Function;
diff --git a/runtime/vm/native_symbol_fuchsia.cc b/runtime/vm/native_symbol_fuchsia.cc
index 084c00b..22db3f7 100644
--- a/runtime/vm/native_symbol_fuchsia.cc
+++ b/runtime/vm/native_symbol_fuchsia.cc
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-#include "platform/globals.h"
+#include "vm/globals.h"
 #if defined(TARGET_OS_FUCHSIA)
 
+#include "platform/memory_sanitizer.h"
 #include "vm/native_symbol.h"
 
+#include <cxxabi.h>  // NOLINT
 #include <dlfcn.h>  // NOLINT
 
 namespace dart {
@@ -31,6 +33,13 @@
   if (start != NULL) {
     *start = reinterpret_cast<uintptr_t>(info.dli_saddr);
   }
+  int status = 0;
+  size_t len = 0;
+  char* demangled = abi::__cxa_demangle(info.dli_sname, NULL, &len, &status);
+  MSAN_UNPOISON(demangled, len);
+  if (status == 0) {
+    return demangled;
+  }
   return strdup(info.dli_sname);
 }
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 819ee3c..bf063f3 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -72,12 +72,12 @@
 DECLARE_FLAG(bool, write_protect_code);
 DECLARE_FLAG(bool, support_externalizable_strings);
 
-
 static const char* const kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
 static const char* const kSetterPrefix = "set:";
 static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
 
+
 // A cache of VM heap allocated preinitialized empty ic data entry arrays.
 RawArray* ICData::cached_icdata_arrays_[kCachedICDataArrayCount];
 
@@ -11579,7 +11579,8 @@
 #endif  // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
 
 
-RawInstructions* Instructions::New(intptr_t size) {
+RawInstructions* Instructions::New(intptr_t size, bool has_single_entry_point) {
+  ASSERT(size >= 0);
   ASSERT(Object::instructions_class() != Class::null());
   if (size < 0 || size > kMaxElements) {
     // This should be caught before we reach here.
@@ -11593,7 +11594,7 @@
                                       Heap::kCode);
     NoSafepointScope no_safepoint;
     result ^= raw;
-    result.set_size(size);
+    result.set_size(has_single_entry_point ? size : -size);
   }
   return result.raw();
 }
@@ -14264,8 +14265,9 @@
 #ifdef TARGET_ARCH_IA32
   assembler->set_code_object(code);
 #endif
-  Instructions& instrs =
-      Instructions::ZoneHandle(Instructions::New(assembler->CodeSize()));
+  Instructions& instrs = Instructions::ZoneHandle(
+      Instructions::New(assembler->CodeSize(),
+                        assembler->has_single_entry_point()));
   INC_STAT(Thread::Current(), total_instr_size, assembler->CodeSize());
   INC_STAT(Thread::Current(), total_code_size, assembler->CodeSize());
 
@@ -14572,7 +14574,12 @@
       return map->raw();  // We found a stack map for this frame.
     }
   }
-  ASSERT(!is_optimized() || (pc_offset == Instructions::kUncheckedEntryOffset));
+  // If we are missing a stack map, this must either be unoptimized code, or
+  // the entry to an osr function. (In which case all stack slots are
+  // considered to have tagged pointers.)
+  // Running with --verify-on-transition should hit this.
+  ASSERT(!is_optimized() ||
+         (pc_offset == UncheckedEntryPoint() - PayloadStart()));
   return Stackmap::null();
 }
 
@@ -19740,7 +19747,7 @@
 }
 
 
-const char* Bigint::ToDecCString(uword (*allocator)(intptr_t size)) const {
+const char* Bigint::ToDecCString(Zone* zone) const {
   // log10(2) ~= 0.30102999566398114.
   const intptr_t kLog2Dividend = 30103;
   const intptr_t kLog2Divisor = 100000;
@@ -19755,7 +19762,7 @@
   const int64_t dec_len = (bit_len * kLog2Dividend / kLog2Divisor) + 1;
   // Add one byte for the minus sign and for the trailing \0 character.
   const int64_t len = (Neg() ? 1 : 0) + dec_len + 1;
-  char* chars = reinterpret_cast<char*>(allocator(len));
+  char* chars = zone->Alloc<char>(len);
   intptr_t pos = 0;
   const intptr_t kDivisor = 100000000;
   const intptr_t kDigits = 8;
@@ -19763,10 +19770,9 @@
   ASSERT(kDivisor < kDigitBase);
   ASSERT(Smi::IsValid(kDivisor));
   // Allocate a copy of the digits.
-  const TypedData& rest_digits = TypedData::Handle(
-      TypedData::New(kTypedDataUint32ArrayCid, used));
+  uint32_t* rest_digits = zone->Alloc<uint32_t>(used);
   for (intptr_t i = 0; i < used; i++) {
-    rest_digits.SetUint32(i << 2, DigitAt(i));
+    rest_digits[i] = DigitAt(i);
   }
   if (used == 0) {
     chars[pos++] = '0';
@@ -19775,14 +19781,14 @@
     uint32_t remainder = 0;
     for (intptr_t i = used - 1; i >= 0; i--) {
       uint64_t dividend = (static_cast<uint64_t>(remainder) << kBitsPerDigit) +
-          rest_digits.GetUint32(i << 2);
+          rest_digits[i];
       uint32_t quotient = static_cast<uint32_t>(dividend / kDivisor);
       remainder = static_cast<uint32_t>(
           dividend - static_cast<uint64_t>(quotient) * kDivisor);
-      rest_digits.SetUint32(i << 2, quotient);
+      rest_digits[i] = quotient;
     }
     // Clamp rest_digits.
-    while ((used > 0) && (rest_digits.GetUint32((used - 1) << 2) == 0)) {
+    while ((used > 0) && (rest_digits[used - 1] == 0)) {
       used--;
     }
     for (intptr_t i = 0; i < kDigits; i++) {
@@ -19813,12 +19819,12 @@
 }
 
 
-const char* Bigint::ToHexCString(uword (*allocator)(intptr_t size)) const {
+const char* Bigint::ToHexCString(Zone* zone) const {
   const intptr_t used = Used();
   if (used == 0) {
     const char* zero = "0x0";
     const size_t len = strlen(zero) + 1;
-    char* chars = reinterpret_cast<char*>(allocator(len));
+    char* chars = zone->Alloc<char>(len);
     strncpy(chars, zero, len);
     return chars;
   }
@@ -19839,7 +19845,7 @@
   }
   // Add bytes for '0x', for the minus sign, and for the trailing \0 character.
   const int32_t len = (Neg() ? 1 : 0) + 2 + hex_len + 1;
-  char* chars = reinterpret_cast<char*>(allocator(len));
+  char* chars = zone->Alloc<char>(len);
   intptr_t pos = len;
   chars[--pos] = '\0';
   for (intptr_t i = 0; i < (used - 1); i++) {
@@ -19864,14 +19870,8 @@
 }
 
 
-static uword BigintAllocator(intptr_t size) {
-  Zone* zone = Thread::Current()->zone();
-  return zone->AllocUnsafe(size);
-}
-
-
 const char* Bigint::ToCString() const {
-  return ToDecCString(&BigintAllocator);
+  return ToDecCString(Thread::Current()->zone());
 }
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index dcc86c7..32c4a6c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4139,17 +4139,19 @@
 
 class Instructions : public Object {
  public:
-  intptr_t size() const { return raw_ptr()->size_; }  // Excludes HeaderSize().
+  // Excludes HeaderSize().
+  intptr_t size() const { return abs(raw_ptr()->size_); }
+  bool HasSingleEntryPoint() const { return raw_ptr()->size_ >= 0; }
 
   uword PayloadStart() const {
     return PayloadStart(raw());
   }
-  uword UncheckedEntryPoint() const {
-    return UncheckedEntryPoint(raw());
-  }
   uword CheckedEntryPoint() const {
     return CheckedEntryPoint(raw());
   }
+  uword UncheckedEntryPoint() const {
+    return UncheckedEntryPoint(raw());
+  }
   static uword PayloadStart(RawInstructions* instr) {
     return reinterpret_cast<uword>(instr->ptr()) + HeaderSize();
   }
@@ -4176,11 +4178,19 @@
 #error Missing entry offsets for current architecture
 #endif
 
-  static uword UncheckedEntryPoint(RawInstructions* instr) {
-    return PayloadStart(instr) + kUncheckedEntryOffset;
-  }
   static uword CheckedEntryPoint(RawInstructions* instr) {
-    return PayloadStart(instr) + kCheckedEntryOffset;
+    uword entry = PayloadStart(instr);
+    if (instr->ptr()->size_ < 0) {
+      entry += kCheckedEntryOffset;
+    }
+    return entry;
+  }
+  static uword UncheckedEntryPoint(RawInstructions* instr) {
+    uword entry = PayloadStart(instr);
+    if (instr->ptr()->size_ < 0) {
+      entry += kUncheckedEntryOffset;
+    }
+    return entry;
   }
 
   static const intptr_t kMaxElements = (kMaxInt32 -
@@ -4207,9 +4217,9 @@
     return Utils::RoundUp(sizeof(RawInstructions), alignment);
   }
 
-  static RawInstructions* FromUncheckedEntryPoint(uword entry_point) {
+  static RawInstructions* FromPayloadStart(uword payload_start) {
     return reinterpret_cast<RawInstructions*>(
-        entry_point - HeaderSize() - kUncheckedEntryOffset + kHeapObjectTag);
+        payload_start - HeaderSize() + kHeapObjectTag);
   }
 
   bool Equals(const Instructions& other) const {
@@ -4229,7 +4239,7 @@
   // only be created using the Code::FinalizeCode method. This method creates
   // the RawInstruction and RawCode objects, sets up the pointer offsets
   // and links the two in a GC safe manner.
-  static RawInstructions* New(intptr_t size);
+  static RawInstructions* New(intptr_t size, bool has_single_entry_point);
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Instructions, Object);
   friend class Class;
@@ -4689,13 +4699,16 @@
   void set_is_alive(bool value) const;
 
   uword PayloadStart() const {
-    return Instructions::PayloadStart(instructions());
+    const Instructions& instr = Instructions::Handle(instructions());
+    return instr.PayloadStart();
   }
   uword UncheckedEntryPoint() const {
-    return Instructions::UncheckedEntryPoint(instructions());
+    const Instructions& instr = Instructions::Handle(instructions());
+    return instr.UncheckedEntryPoint();
   }
   uword CheckedEntryPoint() const {
-    return Instructions::CheckedEntryPoint(instructions());
+    const Instructions& instr = Instructions::Handle(instructions());
+    return instr.CheckedEntryPoint();
   }
   intptr_t Size() const {
     const Instructions& instr = Instructions::Handle(instructions());
@@ -6637,8 +6650,8 @@
   intptr_t Used() const;
   uint32_t DigitAt(intptr_t index) const;
 
-  const char* ToDecCString(uword (*allocator)(intptr_t size)) const;
-  const char* ToHexCString(uword (*allocator)(intptr_t size)) const;
+  const char* ToDecCString(Zone* zone) const;
+  const char* ToHexCString(Zone* zone) const;
 
   static const intptr_t kBitsPerDigit = 32;  // Same as _Bigint._DIGIT_BITS
   static const intptr_t kBytesPerDigit = 4;
@@ -7930,6 +7943,7 @@
   virtual bool CanonicalizeEquals(const Instance& other) const;
   virtual uword ComputeCanonicalTableHash() const;
 
+#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
 #define TYPED_GETTER_SETTER(name, type)                                        \
   type Get##name(intptr_t byte_offset) const {                                 \
     NoSafepointScope no_safepoint;                                             \
@@ -7939,6 +7953,20 @@
     NoSafepointScope no_safepoint;                                             \
     *reinterpret_cast<type*>(DataAddr(byte_offset)) = value;                   \
   }
+#else  // defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+#define TYPED_GETTER_SETTER(name, type)                                        \
+  type Get##name(intptr_t byte_offset) const {                                 \
+    NoSafepointScope no_safepoint;                                             \
+    type result;                                                               \
+    memmove(&result, DataAddr(byte_offset), sizeof(type));                     \
+    return result;                                                             \
+  }                                                                            \
+  void Set##name(intptr_t byte_offset, type value) const {                     \
+    NoSafepointScope no_safepoint;                                             \
+    memmove(DataAddr(byte_offset), &value, sizeof(type));                      \
+  }
+#endif  // defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+
   TYPED_GETTER_SETTER(Int8, int8_t)
   TYPED_GETTER_SETTER(Uint8, uint8_t)
   TYPED_GETTER_SETTER(Int16, int16_t)
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index f3b06e0..0429adf 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -128,7 +128,9 @@
         old_field = Field::RawCast(old_field_list.At(j));
         old_name = old_field.name();
         if (name.Equals(old_name)) {
-          if (update_values) {
+          // We only copy values if requested and if the field is not a const
+          // field. We let const fields be updated with a reload.
+          if (update_values && !field.is_const()) {
             value = old_field.StaticValue();
             field.SetStaticValue(value);
           }
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 8b5555a..0ff6a8e 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -81,6 +81,9 @@
   void set_int_type(const Type& value) {
     int_type_ = value.raw();
   }
+  static intptr_t int_type_offset() {
+    return OFFSET_OF(ObjectStore, int_type_);
+  }
 
   RawClass* integer_implementation_class() const {
     return integer_implementation_class_;
@@ -93,14 +96,16 @@
   void set_smi_class(const Class& value) { smi_class_ = value.raw(); }
 
   RawType* smi_type() const { return smi_type_; }
-  void set_smi_type(const Type& value) { smi_type_ = value.raw();
-  }
+  void set_smi_type(const Type& value) { smi_type_ = value.raw(); }
 
   RawClass* double_class() const { return double_class_; }
   void set_double_class(const Class& value) { double_class_ = value.raw(); }
 
   RawType* double_type() const { return double_type_; }
   void set_double_type(const Type& value) { double_type_ = value.raw(); }
+  static intptr_t double_type_offset() {
+    return OFFSET_OF(ObjectStore, double_type_);
+  }
 
   RawClass* mint_class() const { return mint_class_; }
   void set_mint_class(const Class& value) { mint_class_ = value.raw(); }
@@ -115,6 +120,9 @@
   void set_string_type(const Type& value) {
     string_type_ = value.raw();
   }
+  static intptr_t string_type_offset() {
+    return OFFSET_OF(ObjectStore, string_type_);
+  }
 
   RawClass* compiletime_error_class() const {
     return compiletime_error_class_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 86852f4..0cd21ea 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2721,9 +2721,8 @@
   Code& code = Code::Handle(Code::FinalizeCode(function, &_assembler_));
   function.AttachCode(code);
   const Instructions& instructions = Instructions::Handle(code.instructions());
-  uword entry_point = instructions.UncheckedEntryPoint();
-  EXPECT_EQ(instructions.raw(),
-            Instructions::FromUncheckedEntryPoint(entry_point));
+  uword payload_start = instructions.PayloadStart();
+  EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
   const Object& result = Object::Handle(
       DartEntry::InvokeFunction(function, Array::empty_array()));
   EXPECT_EQ(1, Smi::Cast(result).Value());
@@ -2740,11 +2739,10 @@
   Code& code = Code::Handle(Code::FinalizeCode(function, &_assembler_));
   function.AttachCode(code);
   Instructions& instructions = Instructions::Handle(code.instructions());
-  uword entry_point = instructions.UncheckedEntryPoint();
-  EXPECT_EQ(instructions.raw(),
-            Instructions::FromUncheckedEntryPoint(entry_point));
+  uword payload_start = instructions.PayloadStart();
+  EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
   // Try writing into the generated code, expected to crash.
-  *(reinterpret_cast<char*>(entry_point) + 1) = 1;
+  *(reinterpret_cast<char*>(payload_start) + 1) = 1;
   if (!FLAG_write_protect_code) {
     // Since this test is expected to crash, crash if write protection of code
     // is switched off.
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index f9049265..41a5d96 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -75,12 +75,12 @@
 
 
 int64_t OS::GetCurrentTimeMicros() {
-  return mx_current_time() / 1000;
+  return mx_time_get(MX_CLOCK_MONOTONIC) / 1000;
 }
 
 
 int64_t OS::GetCurrentMonotonicTicks() {
-  return mx_current_time();
+  return mx_time_get(MX_CLOCK_MONOTONIC);
 }
 
 
diff --git a/runtime/vm/os_thread_fuchsia.cc b/runtime/vm/os_thread_fuchsia.cc
index 536f11f..481e59f 100644
--- a/runtime/vm/os_thread_fuchsia.cc
+++ b/runtime/vm/os_thread_fuchsia.cc
@@ -47,7 +47,7 @@
 
 static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
   // time in nanoseconds.
-  mx_time_t now = mx_current_time();
+  mx_time_t now = mx_time_get(MX_CLOCK_MONOTONIC);
   mx_time_t target = now + (micros * kNanosecondsPerMicrosecond);
   int64_t secs = target / kNanosecondsPerSecond;
   int64_t nanos = target - (secs * kNanosecondsPerSecond);
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index de1f353..6f57ab8 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -152,9 +152,11 @@
 
 class PrecompileParsedFunctionHelper : public ValueObject {
  public:
-  PrecompileParsedFunctionHelper(ParsedFunction* parsed_function,
+  PrecompileParsedFunctionHelper(Precompiler* precompiler,
+                                 ParsedFunction* parsed_function,
                                  bool optimized)
-      : parsed_function_(parsed_function),
+      : precompiler_(precompiler),
+        parsed_function_(parsed_function),
         optimized_(optimized),
         thread_(Thread::Current()) {
   }
@@ -171,6 +173,7 @@
                            FlowGraphCompiler* graph_compiler,
                            FlowGraph* flow_graph);
 
+  Precompiler* precompiler_;
   ParsedFunction* parsed_function_;
   const bool optimized_;
   Thread* const thread_;
@@ -314,7 +317,8 @@
     types_to_retain_(),
     consts_to_retain_(),
     field_type_map_(),
-    error_(Error::Handle()) {
+    error_(Error::Handle()),
+    get_runtime_type_is_unique_(false) {
 }
 
 
@@ -483,9 +487,8 @@
 void Precompiler::PrecompileConstructors() {
   class ConstructorVisitor : public FunctionVisitor {
    public:
-    explicit ConstructorVisitor(Zone* zone, FieldTypeMap* map)
-        : zone_(zone), field_type_map_(map) {
-      ASSERT(map != NULL);
+    explicit ConstructorVisitor(Precompiler* precompiler, Zone* zone)
+        : precompiler_(precompiler), zone_(zone) {
     }
     void Visit(const Function& function) {
       if (!function.IsGenerativeConstructor()) return;
@@ -497,18 +500,20 @@
       if (FLAG_trace_precompiler) {
         THR_Print("Precompiling constructor %s\n", function.ToCString());
       }
-      CompileFunction(Thread::Current(),
+      CompileFunction(precompiler_,
+                      Thread::Current(),
                       zone_,
                       function,
-                      field_type_map_);
+                      precompiler_->field_type_map());
     }
+
    private:
+    Precompiler* precompiler_;
     Zone* zone_;
-    FieldTypeMap* field_type_map_;
   };
 
   HANDLESCOPE(T);
-  ConstructorVisitor visitor(zone_, &field_type_map_);
+  ConstructorVisitor visitor(this, zone_);
   VisitFunctions(&visitor);
 
   FieldTypeMap::Iterator it(field_type_map_.GetIterator());
@@ -796,7 +801,7 @@
     ASSERT(!function.is_abstract());
     ASSERT(!function.IsRedirectingFactory());
 
-    error_ = CompileFunction(thread_, zone_, function);
+    error_ = CompileFunction(this, thread_, zone_, function);
     if (!error_.IsNull()) {
       Jump(error_);
     }
@@ -1134,7 +1139,8 @@
 
   parsed_function->AllocateVariables();
   DartPrecompilationPipeline pipeline(zone.GetZone());
-  PrecompileParsedFunctionHelper helper(parsed_function,
+  PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
+                                        parsed_function,
                                         /* optimized = */ true);
   bool success = helper.Compile(&pipeline);
   ASSERT(success);
@@ -1235,7 +1241,8 @@
 
     // Non-optimized code generator.
     DartPrecompilationPipeline pipeline(Thread::Current()->zone());
-    PrecompileParsedFunctionHelper helper(parsed_function,
+    PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
+                                          parsed_function,
                                           /* optimized = */ false);
     helper.Compile(&pipeline);
     Code::Handle(func.unoptimized_code()).set_var_descriptors(
@@ -1511,6 +1518,10 @@
     }
   }
 
+  farray ^= table.GetOrNull(Symbols::GetRuntimeType());
+
+  get_runtime_type_is_unique_ = !farray.IsNull() && (farray.Length() == 1);
+
   if (FLAG_print_unique_targets) {
     UniqueFunctionsSet::Iterator unique_iter(&functions_set);
     while (unique_iter.MoveNext()) {
@@ -2819,7 +2830,8 @@
         caller_inline_id.Add(-1);
         CSTAT_TIMER_SCOPE(thread(), graphoptimizer_timer);
 
-        AotOptimizer optimizer(flow_graph,
+        AotOptimizer optimizer(precompiler_,
+                               flow_graph,
                                use_speculative_inlining,
                                &inlining_black_list);
         optimizer.PopulateWithICData();
@@ -2861,7 +2873,8 @@
                                    &inline_id_to_token_pos,
                                    &caller_inline_id,
                                    use_speculative_inlining,
-                                   &inlining_black_list);
+                                   &inlining_black_list,
+                                   precompiler_);
           inliner.Inline();
           // Use lists are maintained and validated by the inliner.
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -3240,7 +3253,8 @@
 }
 
 
-static RawError* PrecompileFunctionHelper(CompilationPipeline* pipeline,
+static RawError* PrecompileFunctionHelper(Precompiler* precompiler,
+                                          CompilationPipeline* pipeline,
                                           const Function& function,
                                           bool optimized) {
   // Check that we optimize, except if the function is not optimizable.
@@ -3282,7 +3296,8 @@
                num_tokens_after - num_tokens_before);
     }
 
-    PrecompileParsedFunctionHelper helper(parsed_function, optimized);
+    PrecompileParsedFunctionHelper helper(
+        precompiler, parsed_function, optimized);
     const bool success = helper.Compile(pipeline);
     if (!success) {
       // Encountered error.
@@ -3330,7 +3345,8 @@
 }
 
 
-RawError* Precompiler::CompileFunction(Thread* thread,
+RawError* Precompiler::CompileFunction(Precompiler* precompiler,
+                                       Thread* thread,
                                        Zone* zone,
                                        const Function& function,
                                        FieldTypeMap* field_type_map) {
@@ -3340,7 +3356,7 @@
   ASSERT(FLAG_precompiled_mode);
   const bool optimized = function.IsOptimizable();  // False for natives.
   DartPrecompilationPipeline pipeline(zone, field_type_map);
-  return PrecompileFunctionHelper(&pipeline, function, optimized);
+  return PrecompileFunctionHelper(precompiler, &pipeline, function, optimized);
 }
 
 #endif  // DART_PRECOMPILER
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index e10247c..f3a8d02 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -356,7 +356,8 @@
       Dart_QualifiedFunctionName embedder_entry_points[],
       bool reset_fields);
 
-  static RawError* CompileFunction(Thread* thread,
+  static RawError* CompileFunction(Precompiler* precompiler,
+                                   Thread* thread,
                                    Zone* zone,
                                    const Function& function,
                                    FieldTypeMap* field_type_map = NULL);
@@ -367,6 +368,15 @@
   static RawFunction* CompileStaticInitializer(const Field& field,
                                                bool compute_type);
 
+  // Returns true if get:runtimeType is not overloaded by any class.
+  bool get_runtime_type_is_unique() const {
+    return get_runtime_type_is_unique_;
+  }
+
+  FieldTypeMap* field_type_map() {
+    return &field_type_map_;
+  }
+
  private:
   Precompiler(Thread* thread, bool reset_fields);
 
@@ -466,6 +476,8 @@
   InstanceSet consts_to_retain_;
   FieldTypeMap field_type_map_;
   Error& error_;
+
+  bool get_runtime_type_is_unique_;
 };
 
 
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 8bb6232..3f9c92a 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -459,7 +459,7 @@
       "  }\n"
       "}\n"
       "main() {\n"
-      "  B.boo();\n"
+      "  return B.boo();\n"
       "}\n";
 
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
@@ -558,7 +558,7 @@
       "  }\n"
       "}\n"
       "main() {\n"
-      "  B.boo();\n"
+      "  return B.boo();\n"
       "}\n";
 
   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index d777f68..dea8f2d 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -68,7 +68,7 @@
     case kInstructionsCid: {
       const RawInstructions* raw_instructions =
           reinterpret_cast<const RawInstructions*>(this);
-      intptr_t instructions_size = raw_instructions->ptr()->size_;
+      intptr_t instructions_size = abs(raw_instructions->ptr()->size_);
       instance_size = Instructions::InstanceSize(instructions_size);
       break;
     }
@@ -574,14 +574,14 @@
 intptr_t RawInstructions::VisitInstructionsPointers(
     RawInstructions* raw_obj, ObjectPointerVisitor* visitor) {
   RawInstructions* obj = raw_obj->ptr();
-  return Instructions::InstanceSize(obj->size_);
+  return Instructions::InstanceSize(abs(obj->size_));
 }
 
 
 bool RawInstructions::ContainsPC(RawInstructions* raw_instr, uword pc) {
   uword start_pc =
       reinterpret_cast<uword>(raw_instr->ptr()) + Instructions::HeaderSize();
-  uword end_pc = start_pc + raw_instr->ptr()->size_;
+  uword end_pc = start_pc + abs(raw_instr->ptr()->size_);
   ASSERT(end_pc > start_pc);
   return (pc >= start_pc) && (pc < end_pc);
 }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index c01256e..bb9ada1 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -3833,8 +3833,10 @@
 static bool GetVersion(Thread* thread, JSONStream* js) {
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "Version");
-  jsobj.AddProperty("major", static_cast<intptr_t>(3));
-  jsobj.AddProperty("minor", static_cast<intptr_t>(5));
+  jsobj.AddProperty("major",
+                    static_cast<intptr_t>(SERVICE_PROTOCOL_MAJOR_VERSION));
+  jsobj.AddProperty("minor",
+                    static_cast<intptr_t>(SERVICE_PROTOCOL_MINOR_VERSION));
   jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
   jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
   return true;
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 657fe76..830d2ee 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -13,6 +13,9 @@
 
 namespace dart {
 
+#define SERVICE_PROTOCOL_MAJOR_VERSION 3
+#define SERVICE_PROTOCOL_MINOR_VERSION 5
+
 class Array;
 class EmbedderServiceHandler;
 class Error;
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index c5e2e75..5a3b1d4 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -43,6 +43,9 @@
 #define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
 #define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
 
+#define VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID 3
+#define VM_SERVICE_SERVER_INFO_MESSAGE_ID 4
+
 static RawArray* MakeServiceControlMessage(Dart_Port port_id, intptr_t code,
                                            const String& name) {
   const Array& list = Array::Handle(Array::New(4));
@@ -58,6 +61,18 @@
 }
 
 
+static RawArray* MakeServerControlMessage(const SendPort& sp,
+                                          intptr_t code,
+                                          bool enable = false) {
+  const Array& list = Array::Handle(Array::New(3));
+  ASSERT(!list.IsNull());
+  list.SetAt(0, Integer::Handle(Integer::New(code)));
+  list.SetAt(1, sp);
+  list.SetAt(2, Bool::Get(enable));
+  return list.raw();
+}
+
+
 static RawArray* MakeServiceExitMessage() {
   const Array& list = Array::Handle(Array::New(1));
   ASSERT(!list.IsNull());
@@ -81,6 +96,36 @@
 bool ServiceIsolate::shutting_down_ = false;
 char* ServiceIsolate::server_address_ = NULL;
 
+void ServiceIsolate::RequestServerInfo(const SendPort& sp) {
+  const Array& message =
+      Array::Handle(
+          MakeServerControlMessage(sp,
+                                   VM_SERVICE_SERVER_INFO_MESSAGE_ID,
+                                   false /* ignored */));
+  ASSERT(!message.IsNull());
+  uint8_t* data = NULL;
+  MessageWriter writer(&data, &allocator, false);
+  writer.WriteMessage(message);
+  intptr_t len = writer.BytesWritten();
+  PortMap::PostMessage(new Message(port_, data, len, Message::kNormalPriority));
+}
+
+
+void ServiceIsolate::ControlWebServer(const SendPort& sp, bool enable) {
+  const Array& message =
+      Array::Handle(
+          MakeServerControlMessage(sp,
+                                   VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID,
+                                   enable));
+  ASSERT(!message.IsNull());
+  uint8_t* data = NULL;
+  MessageWriter writer(&data, &allocator, false);
+  writer.WriteMessage(message);
+  intptr_t len = writer.BytesWritten();
+  PortMap::PostMessage(new Message(port_, data, len, Message::kNormalPriority));
+}
+
+
 void ServiceIsolate::SetServerAddress(const char* address) {
   if (server_address_ != NULL) {
     free(server_address_);
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index c79d88b..fdcb26c 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -13,6 +13,7 @@
 namespace dart {
 
 class ObjectPointerVisitor;
+class SendPort;
 
 class ServiceIsolate : public AllStatic {
  public:
@@ -36,6 +37,9 @@
 
   static void BootVmServiceLibrary();
 
+  static void RequestServerInfo(const SendPort& sp);
+  static void ControlWebServer(const SendPort& sp, bool enable);
+
   static void SetServerAddress(const char* address);
 
   // Returns the server's web address or NULL if none is running.
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index c3998af..c02e1bf 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -279,6 +279,18 @@
     if (cid == kClosureCid) {
       return false;
     }
+    if (cid < kNumPredefinedCids) {
+      if (cid == kDoubleCid) {
+        *result = thread->isolate()->object_store()->double_type();
+        return true;
+      } else if (RawObject::IsStringClassId(cid)) {
+        *result = thread->isolate()->object_store()->string_type();
+        return true;
+      } else if (RawObject::IsIntegerClassId(cid)) {
+        *result = thread->isolate()->object_store()->int_type();
+        return true;
+      }
+    }
     RawClass* cls = thread->isolate()->class_table()->At(cid);
     if (cls->ptr()->num_type_arguments_ != 0) {
       return false;
@@ -2229,16 +2241,20 @@
   }
 
   {
-    BYTECODE(DoubleIsNaN, A_D);
-    const double v = bit_cast<double, RawObject*>(FP[rD]);
-    FP[rA] = isnan(v) ? true_value : false_value;
+    BYTECODE(DoubleIsNaN, A);
+    const double v = bit_cast<double, RawObject*>(FP[rA]);
+    if (!isnan(v)) {
+      pc++;
+    }
     DISPATCH();
   }
 
   {
-    BYTECODE(DoubleIsInfinite, A_D);
-    const double v = bit_cast<double, RawObject*>(FP[rD]);
-    FP[rA] = isinf(v) ? true_value : false_value;
+    BYTECODE(DoubleIsInfinite, A);
+    const double v = bit_cast<double, RawObject*>(FP[rA]);
+    if (!isinf(v)) {
+      pc++;
+    }
     DISPATCH();
   }
 
@@ -2786,12 +2802,12 @@
       RawObject* type_args = SP[0];
       const intptr_t type_args_offset = Bytecode::DecodeD(*pc);
       *reinterpret_cast<uword*>(start + Instance::tags_offset()) = tags;
-      *reinterpret_cast<RawObject**>(start + type_args_offset) = type_args;
       for (intptr_t current_offset = sizeof(RawInstance);
            current_offset < instance_size;
            current_offset += kWordSize) {
         *reinterpret_cast<RawObject**>(start + current_offset) = null_value;
       }
+      *reinterpret_cast<RawObject**>(start + type_args_offset) = type_args;
       FP[rA] = reinterpret_cast<RawObject*>(start + kHeapObjectTag);
       SP -= 1;  // Consume the type arguments on the stack.
       pc += 4;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index adc8e1f..39450e4 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -377,11 +377,6 @@
 }
 
 
-static uword allocator(intptr_t size) {
-  return reinterpret_cast<uword>(malloc(size));
-}
-
-
 TEST_CASE(SerializeCapability) {
   // Write snapshot with object content.
   const Capability& capability = Capability::Handle(Capability::New(12345));
@@ -425,7 +420,8 @@
   Bigint& obj = Bigint::Handle();
   obj ^= reader.ReadObject();
 
-  EXPECT_STREQ(bigint.ToHexCString(allocator), obj.ToHexCString(allocator));
+  Zone* zone = Thread::Current()->zone();
+  EXPECT_STREQ(bigint.ToHexCString(zone), obj.ToHexCString(zone));
 
   // Read object back from the snapshot into a C structure.
   ApiNativeScope scope;
@@ -455,11 +451,9 @@
     MessageSnapshotReader reader(buffer, buffer_len, thread);
     Bigint& serialized_bigint = Bigint::Handle();
     serialized_bigint ^= reader.ReadObject();
-    const char* str1 = bigint.ToHexCString(allocator);
-    const char* str2 = serialized_bigint.ToHexCString(allocator);
+    const char* str1 = bigint.ToHexCString(thread->zone());
+    const char* str2 = serialized_bigint.ToHexCString(thread->zone());
     EXPECT_STREQ(str1, str2);
-    free(const_cast<char*>(str1));
-    free(const_cast<char*>(str2));
   }
 
   // Read object back from the snapshot into a C structure.
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 49dcfab..6831e9a 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -2031,8 +2031,6 @@
 //  CODE_REG: target Code
 //  R4: arguments descriptor
 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ LoadTaggedClassIdMayBeSmi(R0, R0);
   // R0: receiver cid as Smi.
   __ ldr(R2, FieldAddress(R9, MegamorphicCache::buckets_offset()));
@@ -2088,8 +2086,6 @@
 //  CODE_REG: target Code object
 //  R4: arguments descriptor
 void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
   __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
@@ -2125,8 +2121,6 @@
 
 
 void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset()));
   __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset()));
@@ -2165,8 +2159,6 @@
 //  R0: receiver
 //  R9: UnlinkedCall
 void StubCode::GenerateUnlinkedCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ EnterStubFrame();
   __ Push(R0);  // Preserve receiver.
 
@@ -2193,10 +2185,7 @@
 // Passed to target:
 //  CODE_REG: target Code object
 void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label miss;
-
   __ LoadClassIdMayBeSmi(R1, R0);
   __ ldrh(R2, FieldAddress(R9, SingleTargetCache::lower_limit_offset()));
   __ ldrh(R3, FieldAddress(R9, SingleTargetCache::upper_limit_offset()));
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 7211745..443ab1c 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -2073,8 +2073,6 @@
 //  CODE_REG: target Code
 //  R4: arguments descriptor
 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   // Jump if receiver is a smi.
   Label smi_case;
   __ TestImmediate(R0, kSmiTagMask);
@@ -2148,8 +2146,6 @@
 //  CODE_REG: target Code object
 //  R4: arguments descriptor
 void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
   __ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
@@ -2185,8 +2181,6 @@
 
 
 void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset()));
   __ ldr(R8, FieldAddress(R5, ICData::ic_data_offset()));
@@ -2225,8 +2219,6 @@
 //  R0: receiver
 //  R5: SingleTargetCache
 void StubCode::GenerateUnlinkedCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ EnterStubFrame();
   __ Push(R0);  // Preserve receiver.
 
@@ -2252,10 +2244,7 @@
 // Passed to target:
 //  CODE_REG: target Code object
 void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label miss;
-
   __ LoadClassIdMayBeSmi(R1, R0);
   __ ldr(R2, FieldAddress(R5, SingleTargetCache::lower_limit_offset()),
          kUnsignedWord);
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 5c99655..692d91a 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -2178,8 +2178,6 @@
 //  CODE_REG: target Code object
 //  S4: arguments descriptor
 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ LoadTaggedClassIdMayBeSmi(T0, T0);
   // T0: class ID of the receiver (smi).
   __ lw(S4, FieldAddress(S5, MegamorphicCache::arguments_descriptor_offset()));
@@ -2231,8 +2229,6 @@
 //  CODE_REG: target Code object
 //  S4: arguments descriptor
 void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ lw(T6, FieldAddress(S5, ICData::ic_data_offset()));
   __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset()));
@@ -2267,8 +2263,6 @@
 
 
 void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
   __ lw(T6, FieldAddress(S5, ICData::ic_data_offset()));
   __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset()));
@@ -2306,8 +2300,6 @@
 //  T0: receiver
 //  S5: SingleTargetCache
 void StubCode::GenerateUnlinkedCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ EnterStubFrame();
   __ Push(T0);  // Preserve receiver.
 
@@ -2333,10 +2325,7 @@
 // Passed to target:
 //  CODE_REG: target Code object
 void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label miss;
-
   __ LoadClassIdMayBeSmi(T1, T0);
   __ lhu(T2, FieldAddress(S5, SingleTargetCache::lower_limit_offset()));
   __ lhu(T3, FieldAddress(S5, SingleTargetCache::upper_limit_offset()));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 7ff72e2..f5692b7 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -2041,8 +2041,6 @@
 //  CODE_REG: target Code
 //  R10: arguments descriptor
 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   // Jump if receiver is a smi.
   Label smi_case;
   __ testq(RDI, Immediate(kSmiTagMask));
@@ -2114,10 +2112,7 @@
 //  CODE_REG: target Code object
 //  R10: arguments descriptor
 void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
-
   __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
   __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
   __ leaq(R13, FieldAddress(R13, Array::data_offset()));
@@ -2154,10 +2149,7 @@
 
 
 void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label loop, found, miss;
-
   __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
   __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
   __ leaq(R13, FieldAddress(R13, Array::data_offset()));
@@ -2196,8 +2188,6 @@
 //  RDI: receiver
 //  RBX: UnlinkedCall
 void StubCode::GenerateUnlinkedCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   __ EnterStubFrame();
   __ pushq(RDI);  // Preserve receiver.
 
@@ -2224,8 +2214,6 @@
 // Passed to target::
 //  CODE_REG: target Code object
 void StubCode::GenerateSingleTargetCallStub(Assembler* assembler) {
-  __ NoMonomorphicCheckedEntry();
-
   Label miss;
   __ LoadClassIdMayBeSmi(RAX, RDI);
   __ movl(R9, FieldAddress(RBX, SingleTargetCache::lower_limit_offset()));
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c419851..afcb3ff 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -403,6 +403,8 @@
   V(_name, "_name")                                                            \
   V(_classRangeCheck, "_classRangeCheck")                                      \
   V(_classRangeCheckNegative, "_classRangeCheckNegative")                      \
+  V(GetRuntimeType, "get:runtimeType")                                         \
+  V(HaveSameRuntimeType, "_haveSameRuntimeType")                               \
 
 
 // Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index c06bd4f..4e3741e 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -115,7 +115,7 @@
   V(uword, call_to_runtime_entry_point_,                                       \
     StubCode::CallToRuntime_entry()->EntryPoint(), 0)                          \
   V(uword, megamorphic_call_checked_entry_,                                    \
-    StubCode::MegamorphicCall_entry()->CheckedEntryPoint(), 0)                 \
+    StubCode::MegamorphicCall_entry()->EntryPoint(), 0)                        \
   V(uword, monomorphic_miss_entry_,                                            \
     StubCode::MonomorphicMiss_entry()->EntryPoint(), 0)                        \
 
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 9047f02..61d0715 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -174,10 +174,11 @@
     reinterpret_cast<name>(entry)(double_arg)
 #define EXECUTE_TEST_CODE_INTPTR_INTPTR(name, entry, pointer_arg)              \
     reinterpret_cast<name>(entry)(pointer_arg)
+#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg)               \
+    reinterpret_cast<name>(entry)(pointer_arg)
 #else
 // Not running on ARM or MIPS hardware, call simulator to execute code.
 #if defined(ARCH_IS_64_BIT)
-// TODO(zra): Supply more macros for 64-bit as tests are added for ARM64.
 #define EXECUTE_TEST_CODE_INT64(name, entry)                                   \
   static_cast<int64_t>(Simulator::Current()->Call(                             \
       bit_cast<int64_t, uword>(entry), 0, 0, 0, 0))
@@ -189,6 +190,11 @@
       bit_cast<int64_t, uword>(entry),                                         \
       bit_cast<int64_t, intptr_t>(pointer_arg),                                \
       0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg)               \
+  static_cast<int32_t>(Simulator::Current()->Call(                             \
+      bit_cast<int64_t, uword>(entry),                                         \
+      bit_cast<int64_t, intptr_t>(pointer_arg),                                \
+      0, 0, 0))
 #else
 #define EXECUTE_TEST_CODE_INT32(name, entry)                                   \
   static_cast<int32_t>(Simulator::Current()->Call(                             \
@@ -201,6 +207,11 @@
       bit_cast<int32_t, uword>(entry),                                         \
       bit_cast<int32_t, intptr_t>(pointer_arg),                                \
       0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_INTPTR(name, entry, pointer_arg)               \
+  static_cast<int32_t>(Simulator::Current()->Call(                             \
+      bit_cast<int32_t, uword>(entry),                                         \
+      bit_cast<int32_t, intptr_t>(pointer_arg),                                \
+      0, 0, 0))
 #endif  // defined(ARCH_IS_64_BIT)
 #define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1)          \
   static_cast<int64_t>(Simulator::Current()->Call(                             \
diff --git a/runtime/vm/virtual_memory_fuchsia.cc b/runtime/vm/virtual_memory_fuchsia.cc
index 8cbc836..49b6e4a 100644
--- a/runtime/vm/virtual_memory_fuchsia.cc
+++ b/runtime/vm/virtual_memory_fuchsia.cc
@@ -7,7 +7,6 @@
 
 #include "vm/virtual_memory.h"
 
-#include <magenta/process.h>
 #include <magenta/syscalls.h>
 #include <unistd.h>  // NOLINT
 
@@ -26,8 +25,9 @@
 
 
 VirtualMemory* VirtualMemory::ReserveInternal(intptr_t size) {
-  mx_handle_t vmo = mx_vmo_create(size);
-  if (vmo <= 0) {
+  mx_handle_t vmo = MX_HANDLE_INVALID;
+  mx_status_t status = mx_vmo_create(size, 0u, &vmo);
+  if (status != NO_ERROR) {
     return NULL;
   }
 
@@ -38,7 +38,7 @@
                    MX_VM_FLAG_PERM_WRITE |
                    MX_VM_FLAG_PERM_EXECUTE;
   uintptr_t addr;
-  mx_status_t status = mx_process_map_vm(
+  status = mx_process_map_vm(
       mx_process_self(), vmo, 0, size, &addr, prot);
   if (status != NO_ERROR) {
     mx_handle_close(vmo);
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 01b729e..a072f65 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -1290,7 +1290,7 @@
           ],
           'outputs': [
             # Instead of listing all outputs we list a single well-known one.
-            '<(gen_source_dir)/patched_sdk/lib/core/core.dart',
+            '<(PRODUCT_DIR)/patched_sdk/lib/core/core.dart',
           ],
           'action': [
             'python',
@@ -1300,7 +1300,7 @@
             'vm',
             '../sdk',
             '<(gen_source_dir)/patches',
-            '<(gen_source_dir)/patched_sdk',
+            '<(PRODUCT_DIR)/patched_sdk',
           ],
         },
       ],
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index b1073b2..b9e35b2 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -105,3 +105,23 @@
                       String argumentsAsJson) {
  // TODO.
 }
+
+@patch
+int _getServiceMajorVersion() {
+  return 0;
+}
+
+@patch
+int _getServiceMinorVersion() {
+  return 0;
+}
+
+@patch
+void _getServerInfo(SendPort sp) {
+  sp.send(null);
+}
+
+@patch
+void _webServerControl(SendPort sp, bool enable) {
+  sp.send(null);
+}
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 9a9487a..4f0d9f0 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -511,7 +511,7 @@
    * Creates a wrapper Stream that intercepts some errors from this stream.
    *
    * If this stream sends an error that matches [test], then it is intercepted
-   * by the [handle] function.
+   * by the [onError] function.
    *
    * The [onError] callback must be of type `void onError(error)` or
    * `void onError(error, StackTrace stackTrace)`. Depending on the function
@@ -519,10 +519,11 @@
    * trace. The stack trace argument might be `null` if the stream itself
    * received an error without stack trace.
    *
-   * An asynchronous error [:e:] is matched by a test function if [:test(e):]
-   * returns true. If [test] is omitted, every error is considered matching.
+   * An asynchronous error `error` is matched by a test function if
+   *`test(error)` returns true. If [test] is omitted, every error is considered
+   * matching.
    *
-   * If the error is intercepted, the [handle] function can decide what to do
+   * If the error is intercepted, the [onError] function can decide what to do
    * with it. It can throw if it wants to raise a new (or the same) error,
    * or simply return to make the stream forget the error.
    *
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index 74c9d50..47ea5ba 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.dart
@@ -17,10 +17,12 @@
 
 import 'dart:async';
 import 'dart:convert';
+import 'dart:isolate' show RawReceivePort, SendPort;
 
 part 'extension.dart';
 part 'profiler.dart';
 part 'timeline.dart';
+part 'service.dart';
 
 /// If [when] is true, stop the program as if a breakpoint were hit at the
 /// following statement.
diff --git a/sdk/lib/developer/developer_sources.gypi b/sdk/lib/developer/developer_sources.gypi
index 5bdfe3d..91596a3 100644
--- a/sdk/lib/developer/developer_sources.gypi
+++ b/sdk/lib/developer/developer_sources.gypi
@@ -8,6 +8,7 @@
     # The above file needs to be first if additional parts are added to the lib.
     'extension.dart',
     'profiler.dart',
+    'service.dart',
     'timeline.dart',
   ],
 }
diff --git a/sdk/lib/developer/service.dart b/sdk/lib/developer/service.dart
new file mode 100644
index 0000000..2934afe
--- /dev/null
+++ b/sdk/lib/developer/service.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.developer;
+
+/// Information about the service protocol.
+class ServiceProtocolInfo {
+  /// The major version of the protocol. If the running Dart environment does
+  /// not support the service protocol, this is 0.
+  final int majorVersion = _getServiceMajorVersion();
+  /// The minor version of the protocol. If the running Dart environment does
+  /// not support the service protocol, this is 0.
+  final int minorVersion = _getServiceMinorVersion();
+  /// The Uri to access the service. If the web server is not running, this
+  /// will be null.
+  final Uri serverUri;
+
+  ServiceProtocolInfo(this.serverUri);
+
+  String toString() {
+    if (serverUri != null) {
+      return 'Dart VM Service Protocol v$majorVersion.$minorVersion '
+             'listening on $serverUri';
+    } else {
+      return 'Dart VM Service Protocol v$majorVersion.$minorVersion';
+    }
+  }
+}
+
+/// Access information about the service protocol and control the web server.
+class Service {
+  /// Get information about the service protocol.
+  static Future<ServiceProtocolInfo> getInfo() async {
+    // Port to receive response from service isolate.
+    final RawReceivePort receivePort = new RawReceivePort();
+    final Completer<Uri> uriCompleter = new Completer<Uri>();
+    receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+    // Request the information from the service isolate.
+    _getServerInfo(receivePort.sendPort);
+    // Await the response from the service isolate.
+    Uri uri = await uriCompleter.future;
+    // Close the port.
+    receivePort.close();
+    return new ServiceProtocolInfo(uri);
+  }
+
+  /// Control the web server that the service protocol is accessed through.
+  static Future<ServiceProtocolInfo> controlWebServer(
+      {bool enable: false}) async {
+    if (enable is! bool) {
+      throw new ArgumentError.value(enable,
+                                    'enable',
+                                    'Must be a bool');
+    }
+    // Port to receive response from service isolate.
+    final RawReceivePort receivePort = new RawReceivePort();
+    final Completer<Uri> uriCompleter = new Completer<Uri>();
+    receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
+    // Request the information from the service isolate.
+    _webServerControl(receivePort.sendPort, enable);
+    // Await the response from the service isolate.
+    Uri uri = await uriCompleter.future;
+    // Close the port.
+    receivePort.close();
+    return new ServiceProtocolInfo(uri);
+  }
+}
+
+/// [sp] will receive a Uri or null.
+external void _getServerInfo(SendPort sp);
+
+/// [sp] will receive a Uri or null.
+external void _webServerControl(SendPort sp, bool enable);
+
+/// Returns the major version of the service protocol.
+external int _getServiceMajorVersion();
+
+/// Returns the minor version of the service protocol.
+external int _getServiceMinorVersion();
+
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index f8eacb7..71eff21 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -1668,13 +1668,13 @@
                                            int port));
 
   /**
-   * Shutdown the HTTP client. If [force] is [:false:] (the default)
+   * Shut down the HTTP client. If [force] is [:false:] (the default)
    * the [:HttpClient:] will be kept alive until all active
    * connections are done. If [force] is [:true:] any active
    * connections will be closed to immediately release all
    * resources. These closed connections will receive an [:onError:]
-   * callback to indicate that the client was shutdown. In both cases
-   * trying to establish a new connection after calling [shutdown]
+   * callback to indicate that the client was shut down. In both cases
+   * trying to establish a new connection after calling [close]
    * will throw an exception.
    */
   void close({bool force: false});
diff --git a/sdk/lib/vmservice/constants.dart b/sdk/lib/vmservice/constants.dart
index e899dd1..bc985cd 100644
--- a/sdk/lib/vmservice/constants.dart
+++ b/sdk/lib/vmservice/constants.dart
@@ -9,4 +9,6 @@
   static const int SERVICE_EXIT_MESSAGE_ID = 0;
   static const int ISOLATE_STARTUP_MESSAGE_ID = 1;
   static const int ISOLATE_SHUTDOWN_MESSAGE_ID = 2;
+  static const int WEB_SERVER_CONTROL_MESSAGE_ID = 3;
+  static const int SERVER_INFO_MESSAGE_ID = 4;
 }
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index a56c293..41e8017 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -7,7 +7,9 @@
 import 'dart:async';
 import 'dart:collection';
 import 'dart:convert';
+import 'dart:developer' show ServiceProtocolInfo;
 import 'dart:isolate';
+import 'dart:math';
 import 'dart:typed_data';
 
 part 'asset.dart';
@@ -19,13 +21,29 @@
 part 'message.dart';
 part 'message_router.dart';
 
-final RawReceivePort isolateLifecyclePort = new RawReceivePort();
+final RawReceivePort isolateControlPort = new RawReceivePort();
 final RawReceivePort scriptLoadPort = new RawReceivePort();
 
 abstract class IsolateEmbedderData {
   void cleanup();
 }
 
+String _makeAuthToken() {
+  final kTokenByteSize = 8;
+  Uint8List bytes = new Uint8List(kTokenByteSize);
+  Random random = new Random.secure();
+  for (int i = 0; i < kTokenByteSize; i++) {
+    bytes[i] = random.nextInt(256);
+  }
+  return BASE64URL.encode(bytes);
+}
+
+// The randomly generated auth token used to access the VM service.
+final String serviceAuthToken = _makeAuthToken();
+
+// TODO(johnmccutchan): Enable the auth token and drop the origin check.
+final bool useAuthToken = false;
+
 // This is for use by the embedder. It is a map from the isolateId to
 // anything implementing IsolateEmbedderData. When an isolate goes away,
 // the cleanup method will be invoked after being removed from the map.
@@ -125,6 +143,12 @@
 /// Called to list all files under some path.
 typedef Future<List<Map<String,String>>> ListFilesCallback(Uri path);
 
+/// Called when we need information about the server.
+typedef Future<Uri> ServerInformationCallback();
+
+/// Called when we want to [enable] or disable the web server.
+typedef Future<Uri> WebServerControlCallback(bool enable);
+
 /// Hooks that are setup by the embedder.
 class VMServiceEmbedderHooks {
   static ServerStartCallback serverStart;
@@ -136,6 +160,8 @@
   static WriteStreamFileCallback writeStreamFile;
   static ReadFileCallback readFile;
   static ListFilesCallback listFiles;
+  static ServerInformationCallback serverInformation;
+  static WebServerControlCallback webServerControl;
 }
 
 class VMService extends MessageRouter {
@@ -194,6 +220,27 @@
     }
   }
 
+  Future<Null> _serverMessageHandler(int code, SendPort sp, bool enable) async {
+    switch (code) {
+      case Constants.WEB_SERVER_CONTROL_MESSAGE_ID:
+        if (VMServiceEmbedderHooks.webServerControl == null) {
+          sp.send(null);
+          return;
+        }
+        Uri uri = await VMServiceEmbedderHooks.webServerControl(enable);
+        sp.send(uri);
+      break;
+      case Constants.SERVER_INFO_MESSAGE_ID:
+        if (VMServiceEmbedderHooks.serverInformation == null) {
+          sp.send(null);
+          return;
+        }
+        Uri uri = await VMServiceEmbedderHooks.serverInformation();
+        sp.send(uri);
+      break;
+    }
+  }
+
   Future _exit() async {
     // Stop the server.
     if (VMServiceEmbedderHooks.serverStop != null) {
@@ -201,7 +248,7 @@
     }
 
     // Close receive ports.
-    isolateLifecyclePort.close();
+    isolateControlPort.close();
     scriptLoadPort.close();
 
     // Create a copy of the set as a list because client.disconnect() will
@@ -233,6 +280,13 @@
         _exit();
         return;
       }
+      if (message.length == 3) {
+        // This is a message interacting with the web server.
+        assert((message[0] == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
+               (message[0] == Constants.SERVER_INFO_MESSAGE_ID));
+        _serverMessageHandler(message[0], message[1], message[2]);
+        return;
+      }
       if (message.length == 4) {
         // This is a message informing us of the birth or death of an
         // isolate.
@@ -244,7 +298,7 @@
   }
 
   VMService._internal()
-      : eventPort = isolateLifecyclePort {
+      : eventPort = isolateControlPort {
     eventPort.handler = messageHandler;
   }
 
@@ -425,8 +479,8 @@
 }
 
 RawReceivePort boot() {
-  // Return the port we expect isolate startup and shutdown messages on.
-  return isolateLifecyclePort;
+  // Return the port we expect isolate control messages on.
+  return isolateControlPort;
 }
 
 void _registerIsolate(int port_id, SendPort sp, String name) {
diff --git a/tests/compiler/dart2js/constant_expression_test.dart b/tests/compiler/dart2js/constant_expression_test.dart
index 7013167..d0cefd8 100644
--- a/tests/compiler/dart2js/constant_expression_test.dart
+++ b/tests/compiler/dart2js/constant_expression_test.dart
@@ -147,8 +147,6 @@
 }
 class B<S> implements C {
   const factory B({field1}) = A<B<S>>;
-  // TODO(johnniwinther): Enable this when the constructor evaluator doesn't 
-  // crash:
   const factory B.named() = A<S>;
 }
 class C<U> {
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index bf18bce..491356c3 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -57,7 +57,7 @@
         setThrows: (b) => actualThrows = b,
         setIsAllocation: (b) => actualNew = b,
         setUseGvn: (b) => actualGvn = b,
-        resolveType: (t) => t,
+        lookupType: (t) => t,
         typesReturned: actualReturns,
         typesInstantiated: actualCreates,
         objectType: OBJECT,
diff --git a/tests/compiler/dart2js/kernel/impact_test.dart b/tests/compiler/dart2js/kernel/impact_test.dart
index 3d5f56f..60a95b9 100644
--- a/tests/compiler/dart2js/kernel/impact_test.dart
+++ b/tests/compiler/dart2js/kernel/impact_test.dart
@@ -39,6 +39,8 @@
   testStringInterpolationConst();
   testStringJuxtaposition();
   testSymbol();
+  testTypeLiteral();
+  testBoolFromEnvironment();
   testEmptyListLiteral();
   testEmptyListLiteralDynamic();
   testEmptyListLiteralTyped();
@@ -56,23 +58,26 @@
   testPostDec(null);
   testPreInc(null);
   testPreDec(null);
-  testIs(null);
-  testIsGeneric(null);
-  testIsGenericRaw(null);
-  testIsGenericDynamic(null);
-  testIsNot(null);
-  testIsNotGeneric(null);
-  testIsNotGenericRaw(null);
-  testIsNotGenericDynamic(null);
-  testIsTypedef(null);
-  testIsTypedefGeneric(null);
-  testIsTypedefGenericRaw(null);
-  testIsTypedefGenericDynamic(null);
-  testAs(null);
-  testAsGeneric(null);
-  testAsGenericRaw(null);
-  testAsGenericDynamic(null);
+  testIs();
+  testIsGeneric();
+  testIsGenericRaw();
+  testIsGenericDynamic();
+  testIsNot();
+  testIsNotGeneric();
+  testIsNotGenericRaw();
+  testIsNotGenericDynamic();
+  testIsTypedef();
+  testIsTypedefGeneric();
+  testIsTypedefGenericRaw();
+  testIsTypedefGenericDynamic();
+  testIsTypedefDeep();
+  testAs();
+  testAsGeneric();
+  testAsGenericRaw();
+  testAsGenericDynamic();
   testThrow();
+  testIfNotNull(null);
+  testIfNotNullSet(null);
   testIfNull(null);
   testSetIfNull(null);
   testSyncStar();
@@ -107,6 +112,7 @@
   testTopLevelFieldGeneric2();
   testTopLevelFieldGeneric3();
   testTopLevelFieldWrite();
+  testStaticFunctionGet();
   testDynamicInvoke(null);
   testDynamicGet(null);
   testDynamicSet(null);
@@ -143,6 +149,22 @@
   testFactoryConstructor();
   testDefaultValuesPositional();
   testDefaultValuesNamed();
+  testFieldInitializer1();
+  testFieldInitializer2();
+  testInstanceFieldWithInitializer();
+  testInstanceFieldTyped();
+  testThisInitializer();
+  testSuperInitializer();
+  testGenericClass();
+  testSuperCall();
+  testSuperGet();
+  testSuperFieldSet();
+  testSuperSetterSet();
+  testSuperClosurization();
+  testForwardingConstructor();
+  testForwardingConstructorTyped();
+  testForwardingConstructorGeneric();
+  testEnum();
 }
 
 testEmpty() {}
@@ -158,6 +180,8 @@
 }
 testStringJuxtaposition() => 'a' 'b';
 testSymbol() => #main;
+testTypeLiteral() => Object;
+testBoolFromEnvironment() => const bool.fromEnvironment('FOO');
 testEmptyListLiteral() => [];
 testEmptyListLiteralDynamic() => <dynamic>[];
 testEmptyListLiteralTyped() => <String>[];
@@ -176,23 +200,26 @@
 testPreInc(o) => ++o;
 testPreDec(o) => --o;
 
-testIs(o) => o is Class;
-testIsGeneric(o) => o is GenericClass<int, String>;
-testIsGenericRaw(o) => o is GenericClass;
-testIsGenericDynamic(o) => o is GenericClass<dynamic, dynamic>;
-testIsNot(o) => o is! Class;
-testIsNotGeneric(o) => o is! GenericClass<int, String>;
-testIsNotGenericRaw(o) => o is! GenericClass;
-testIsNotGenericDynamic(o) => o is! GenericClass<dynamic, dynamic>;
-testIsTypedef(o) => o is Typedef;
-testIsTypedefGeneric(o) => o is GenericTypedef<int, String>;
-testIsTypedefGenericRaw(o) => o is GenericTypedef;
-testIsTypedefGenericDynamic(o) => o is GenericTypedef<dynamic, dynamic>;
-testAs(o) => o as Class;
-testAsGeneric(o) => o as GenericClass<int, String>;
-testAsGenericRaw(o) => o as GenericClass;
-testAsGenericDynamic(o) => o as GenericClass<dynamic, dynamic>;
+testIs() => null is Class;
+testIsGeneric() => null is GenericClass<int, String>;
+testIsGenericRaw() => null is GenericClass;
+testIsGenericDynamic() => null is GenericClass<dynamic, dynamic>;
+testIsNot() => null is! Class;
+testIsNotGeneric() => null is! GenericClass<int, String>;
+testIsNotGenericRaw() => null is! GenericClass;
+testIsNotGenericDynamic() => null is! GenericClass<dynamic, dynamic>;
+testIsTypedef() => null is Typedef;
+testIsTypedefGeneric() => null is GenericTypedef<int, String>;
+testIsTypedefGenericRaw() => null is GenericTypedef;
+testIsTypedefGenericDynamic() => null is GenericTypedef<dynamic, dynamic>;
+testIsTypedefDeep() => null is List<GenericTypedef<int, GenericTypedef>>;
+testAs() => null as Class;
+testAsGeneric() => null as GenericClass<int, String>;
+testAsGenericRaw() => null as GenericClass;
+testAsGenericDynamic() => null as GenericClass<dynamic, dynamic>;
 testThrow() => throw '';
+testIfNotNull(o) => o?.foo;
+testIfNotNullSet(o) => o?.foo = 42;
 testIfNull(o) => o ?? 42;
 testSetIfNull(o) => o ??= 42;
 
@@ -244,6 +271,8 @@
     o = 3;
     return;
   case 3:
+    throw '';
+  case 4:
   default:
   }
 }
@@ -327,6 +356,11 @@
 GenericClass<int, String> topLevelFieldGeneric3;
 testTopLevelFieldGeneric3() => topLevelFieldGeneric3;
 testTopLevelFieldWrite() => topLevelField = 3;
+class StaticFunctionGetClass {
+  static foo() {}
+}
+testStaticFunctionGet() => StaticFunctionGetClass.foo;
+
 testDynamicInvoke(o) {
   o.f1(0);
   o.f2(1);
@@ -433,6 +467,110 @@
 testFactoryConstructor() => new ClassFactoryConstructor();
 testDefaultValuesPositional([bool value = false]) {}
 testDefaultValuesNamed({bool value: false}) {}
+
+class ClassFieldInitializer1 {
+  var field;
+  ClassFieldInitializer1(this.field);
+}
+testFieldInitializer1() => new ClassFieldInitializer1(42);
+class ClassFieldInitializer2 {
+  var field;
+  ClassFieldInitializer2(value) : field = value;
+}
+testFieldInitializer2() => new ClassFieldInitializer2(42);
+class ClassInstanceFieldWithInitializer {
+  var field = false;
+}
+testInstanceFieldWithInitializer() => new ClassInstanceFieldWithInitializer();
+class ClassInstanceFieldTyped {
+  int field;
+}
+testInstanceFieldTyped() => new ClassInstanceFieldTyped();
+class ClassGeneric<T> {
+  ClassGeneric(T arg);
+}
+class ClassThisInitializer {
+  ClassThisInitializer() : this.internal();
+  ClassThisInitializer.internal();
+}
+testThisInitializer() => new ClassThisInitializer();
+class ClassSuperInitializer extends ClassThisInitializer {
+  ClassSuperInitializer() : super.internal();
+}
+testSuperInitializer() => new ClassSuperInitializer();
+testGenericClass() => new ClassGeneric<int>(0);
+class Super1 {
+  foo() {}
+}
+class Sub1 extends Super1 {
+  Sub1() {
+    super.foo();
+  }
+}
+testSuperCall() => new Sub1();
+class Super2 {
+  var foo;
+}
+class Sub2 extends Super2 {
+  Sub2() {
+    super.foo;
+  }
+}
+testSuperGet() => new Sub2();
+class Super3 {
+  var foo;
+}
+class Sub3 extends Super3 {
+  Sub3() {
+    super.foo = 42;
+  }
+}
+testSuperFieldSet() => new Sub3();
+class Super4 {
+  set foo(_) {}
+}
+class Sub4 extends Super4 {
+  Sub4() {
+    super.foo = 42;
+  }
+}
+testSuperSetterSet() => new Sub4();
+class Super5 {
+  foo() {}
+}
+class Sub5 extends Super5 {
+  Sub5() {
+    super.foo;
+  }
+}
+testSuperClosurization() => new Sub5();
+
+class EmptyMixin {}
+class ForwardingConstructorSuperClass {
+  ForwardingConstructorSuperClass(arg);
+}
+class ForwardingConstructorClass =
+    ForwardingConstructorSuperClass with EmptyMixin;
+testForwardingConstructor() => new ForwardingConstructorClass(null);
+
+class ForwardingConstructorTypedSuperClass {
+  ForwardingConstructorTypedSuperClass(int arg);
+}
+class ForwardingConstructorTypedClass =
+    ForwardingConstructorTypedSuperClass with EmptyMixin;
+testForwardingConstructorTyped() => new ForwardingConstructorTypedClass(null);
+
+class ForwardingConstructorGenericSuperClass<T> {
+  ForwardingConstructorGenericSuperClass(T arg);
+}
+class ForwardingConstructorGenericClass<S> =
+    ForwardingConstructorGenericSuperClass<S> with EmptyMixin;
+testForwardingConstructorGeneric() {
+  new ForwardingConstructorGenericClass<int>(null);
+}
+
+enum Enum { A }
+testEnum() => Enum.A;
 ''',
   'helper.dart': '''
 class Class {
@@ -464,7 +602,9 @@
         ]);
     compiler.resolution.retainCachesForTesting = true;
     await compiler.run(entryPoint);
-    checkLibrary(compiler, compiler.mainApp);
+    compiler.libraryLoader.libraries.forEach((LibraryElement library) {
+      checkLibrary(compiler, library);
+    });
   });
 }
 
@@ -484,6 +624,13 @@
 }
 
 void checkElement(Compiler compiler, AstElement element) {
+  if (element.isConstructor) {
+    ConstructorElement constructor = element;
+    if (constructor.isRedirectingFactory) {
+      // Skip redirecting constructors for now; they might not be supported.
+      return;
+    }
+  }
   ResolutionImpact astImpact = compiler.resolution.getResolutionImpact(element);
   astImpact = laxImpact(compiler, element, astImpact);
   ResolutionImpact kernelImpact = build(compiler, element.resolvedAst);
@@ -506,7 +653,7 @@
         DartType effectiveTargetType =
             constructor.computeEffectiveTargetType(staticUse.type);
         builder.registerStaticUse(new StaticUse.constConstructorInvoke(
-            effectiveTarget, null, effectiveTargetType));
+            effectiveTarget.declaration, null, effectiveTargetType));
         break;
       default:
         builder.registerStaticUse(staticUse);
@@ -515,10 +662,8 @@
   }
   impact.dynamicUses.forEach(builder.registerDynamicUse);
   for (TypeUse typeUse in impact.typeUses) {
-    if (typeUse.type.isTypedef) {
-      typeUse = new TypeUse.internal(typeUse.type.unaliased, typeUse.kind);
-    }
-    builder.registerTypeUse(typeUse);
+    builder.registerTypeUse(new TypeUse.internal(
+        const Unaliaser().visit(typeUse.type), typeUse.kind));
   }
   impact.constantLiterals.forEach(builder.registerConstantLiteral);
   impact.constSymbolNames.forEach(builder.registerConstSymbolName);
@@ -551,3 +696,37 @@
   impact.nativeData.forEach(builder.registerNativeData);
   return builder;
 }
+
+/// Visitor the performers unaliasing of all typedefs nested within a
+/// [DartType].
+class Unaliaser extends BaseDartTypeVisitor<dynamic, DartType> {
+  const Unaliaser();
+
+  @override
+  DartType visit(DartType type, [_]) => type.accept(this, null);
+
+  @override
+  DartType visitType(DartType type, _) => type;
+
+  List<DartType> visitList(List<DartType> types) => types.map(visit).toList();
+
+  @override
+  DartType visitInterfaceType(InterfaceType type, _) {
+    return type.createInstantiation(visitList(type.typeArguments));
+  }
+
+  @override
+  DartType visitTypedefType(TypedefType type, _) {
+    return visit(type.unaliased);
+  }
+
+  @override
+  DartType visitFunctionType(FunctionType type, _) {
+    return new FunctionType.synthesized(
+        visit(type.returnType),
+        visitList(type.parameterTypes),
+        visitList(type.optionalParameterTypes),
+        type.namedParameters,
+        visitList(type.namedParameterTypes));
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/diff_view.dart b/tests/compiler/dart2js/sourcemaps/diff_view.dart
index bd29b49..db07f93 100644
--- a/tests/compiler/dart2js/sourcemaps/diff_view.dart
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -69,9 +69,8 @@
     // deleted.
     // Use default options; comparing SSA and CPS output using the new
     // source information strategy.
+    options.add(commonArguments);
     options.add([Flags.useNewSourceInfo]..addAll(commonArguments));
-    options.add([Flags.useNewSourceInfo]..addAll(commonArguments));
-    throw "missing options: please specify options for the second column";
   } else if (optionSegments.length == 2) {
     // Use alternative options for the second output column.
     options.add(commonArguments);
@@ -793,7 +792,7 @@
     if (!added) {
       int offset;
       if (options.contains(Flags.useNewSourceInfo)) {
-        offset = step.offset.subexpressionOffset;
+        offset = step.offset.value;
       } else {
         offset = info.jsCodePositions[step.node].startPosition;
       }
diff --git a/tests/compiler/dart2js/sourcemaps/lax_json.dart b/tests/compiler/dart2js/sourcemaps/lax_json.dart
new file mode 100644
index 0000000..fb79973
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/lax_json.dart
@@ -0,0 +1,296 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Decode a lax JSON encoded text, that is, JSON with Dart-like comments and
+/// trailing commas.
+///
+/// This is used together with `load.dart` and `save.dart` to allow for an easy
+/// editing of a human-readable source-map file.
+
+library lazon;
+
+decode(String text) {
+  return new _Decoder(text)._decode();
+}
+
+class _Decoder {
+  static final int LF = '\n'.codeUnits.single;
+  static final int CR = '\r'.codeUnits.single;
+  static final int BACKSPACE = '\b'.codeUnits.single;
+  static final int FORMFEED = '\f'.codeUnits.single;
+  static final int TAB = '\t'.codeUnits.single;
+  static final int SPACE = ' '.codeUnits.single;
+  static final int SLASH = '/'.codeUnits.single;
+  static final int STAR = '*'.codeUnits.single;
+  static final int QUOTE = '"'.codeUnits.single;
+  static final int BACKSLASH = '\\'.codeUnits.single;
+  static final int COMMA = ','.codeUnits.single;
+  static final int COLON = ':'.codeUnits.single;
+  static final int LEFT_BRACE = '{'.codeUnits.single;
+  static final int RIGHT_BRACE = '}'.codeUnits.single;
+  static final int LEFT_BRACKET = '['.codeUnits.single;
+  static final int RIGHT_BRACKET = ']'.codeUnits.single;
+  static final int T = 't'.codeUnits.single;
+  static final List<int> TRUE = 'true'.codeUnits;
+  static final int F = 'f'.codeUnits.single;
+  static final List<int> FALSE = 'false'.codeUnits;
+  static final int N = 'n'.codeUnits.single;
+  static final List<int> NULL = 'null'.codeUnits;
+  static final int _0 = '0'.codeUnits.single;
+  static final int _9 = '9'.codeUnits.single;
+  static final int B = 'b'.codeUnits.single;
+  static final int R = 'r'.codeUnits.single;
+  static final int U = 'u'.codeUnits.single;
+
+  final List<int> codeUnits;
+  final int length;
+  int position = 0;
+
+  _Decoder(String text)
+      : codeUnits = text.codeUnits,
+        length = text.length;
+
+  _decode() {
+    var result = _decodeValue();
+    _trimWhitespace();
+    if (position != codeUnits.length) {
+      throw new ArgumentError("Unexpected trailing text: "
+          "'${new String.fromCharCodes(codeUnits, position)}'.");
+    }
+    return result;
+  }
+
+  _decodeValue() {
+    var result;
+    _trimWhitespace();
+    if (position < codeUnits.length) {
+      int codeUnit = codeUnits[position];
+      if (codeUnit == QUOTE) {
+        result = _decodeString();
+      } else if (codeUnit == LEFT_BRACE) {
+        result = _decodeMap();
+      } else if (codeUnit == LEFT_BRACKET) {
+        result = _decodeList();
+      } else if (codeUnit == T) {
+        result = _decodeTrue();
+      } else if (codeUnit == F) {
+        result = _decodeFalse();
+      } else if (codeUnit == N) {
+        result = _decodeNull();
+      } else {
+        result = _decodeNumber();
+      }
+    } else {
+      throw new ArgumentError("No value found in text: "
+          "'${new String.fromCharCodes(codeUnits, 0)}'.");
+    }
+    return result;
+  }
+
+  void _trimWhitespace() {
+    OUTER:
+    while (position < codeUnits.length) {
+      int codeUnit = codeUnits[position];
+      if (codeUnit == SLASH) {
+        if (position + 1 < codeUnits.length) {
+          int nextCodeUnit = codeUnits[position + 1];
+          if (nextCodeUnit == SLASH) {
+            position += 2;
+            while (position < codeUnits.length) {
+              codeUnit = codeUnits[position];
+              if (codeUnit == LF || codeUnit == CR) {
+                continue OUTER;
+              }
+              position++;
+            }
+          } else if (nextCodeUnit == STAR) {
+            position += 2;
+            while (position < codeUnits.length) {
+              codeUnit = codeUnits[position];
+              if (codeUnit == STAR &&
+                  position + 1 < codeUnits.length &&
+                  codeUnits[position + 1] == SLASH) {
+                position += 2;
+                continue OUTER;
+              }
+              position++;
+            }
+          }
+        }
+        break;
+      } else if (codeUnit == LF ||
+          codeUnit == CR ||
+          codeUnit == TAB ||
+          codeUnit == SPACE) {
+        position++;
+      } else {
+        break;
+      }
+    }
+  }
+
+  String _decodeString() {
+    int codeUnit = codeUnits[position];
+    if (codeUnit != QUOTE) {
+      _fail();
+    }
+    position++;
+    List<int> charCodes = <int>[];
+    while (position < length) {
+      codeUnit = codeUnits[position];
+      if (codeUnit == QUOTE) {
+        break;
+      } else if (codeUnit == BACKSLASH) {
+        if (position + 1 >= length) {
+          _fail();
+        }
+        codeUnit = codeUnits[++position];
+        if (codeUnit == B) {
+          codeUnit = BACKSPACE;
+        } else if (codeUnit == F) {
+          codeUnit = FORMFEED;
+        } else if (codeUnit == N) {
+          codeUnit = LF;
+        } else if (codeUnit == R) {
+          codeUnit = CR;
+        } else if (codeUnit == T) {
+          codeUnit = TAB;
+        } else if (codeUnit == U) {
+          throw new UnsupportedError('unicode escapes');
+        } else if (codeUnit == QUOTE ||
+            codeUnit == SLASH ||
+            codeUnit == BACKSLASH) {
+          // Ok.
+        } else {
+          _fail();
+        }
+      }
+      charCodes.add(codeUnit);
+      position++;
+    }
+    if (codeUnit != QUOTE) {
+      _fail();
+    }
+    position++;
+    return new String.fromCharCodes(charCodes);
+  }
+
+  Map _decodeMap() {
+    int codeUnit = codeUnits[position];
+    if (codeUnit != LEFT_BRACE) {
+      _fail();
+    }
+    position++;
+    _trimWhitespace();
+    Map result = {};
+    while (position < length) {
+      codeUnit = codeUnits[position];
+      if (codeUnit == RIGHT_BRACE) {
+        break;
+      }
+      String key = _decodeString();
+      _trimWhitespace();
+      if (position < length) {
+        codeUnit = codeUnits[position];
+        if (codeUnit == COLON) {
+          position++;
+          _trimWhitespace();
+        } else {
+          _fail();
+        }
+      } else {
+        _fail();
+      }
+      var value = _decodeValue();
+      result[key] = value;
+      _trimWhitespace();
+      if (position < length) {
+        codeUnit = codeUnits[position];
+        if (codeUnit == COMMA) {
+          position++;
+          _trimWhitespace();
+          continue;
+        } else {
+          break;
+        }
+      }
+    }
+
+    if (codeUnit != RIGHT_BRACE) {
+      _fail();
+    }
+    position++;
+    return result;
+  }
+
+  List _decodeList() {
+    int codeUnit = codeUnits[position];
+    if (codeUnit != LEFT_BRACKET) {
+      _fail();
+    }
+    position++;
+    _trimWhitespace();
+    List result = [];
+    while (position < length) {
+      codeUnit = codeUnits[position];
+      if (codeUnit == RIGHT_BRACKET) {
+        break;
+      }
+      result.add(_decodeValue());
+      _trimWhitespace();
+      if (position < length) {
+        codeUnit = codeUnits[position];
+        if (codeUnit == COMMA) {
+          position++;
+          _trimWhitespace();
+          continue;
+        } else {
+          break;
+        }
+      }
+    }
+
+    if (codeUnit != RIGHT_BRACKET) {
+      _fail();
+    }
+    position++;
+    return result;
+  }
+
+  bool _decodeTrue() {
+    match(TRUE);
+    return true;
+  }
+
+  bool _decodeFalse() {
+    match(FALSE);
+    return false;
+  }
+
+  Null _decodeNull() {
+    match(NULL);
+    return null;
+  }
+
+  void match(List<int> codes) {
+    if (position + codes.length > length) {
+      _fail();
+    }
+    for (int i = 0; i < codes.length; i++) {
+      if (codes[i] != codeUnits[position + i]) {
+        _fail();
+      }
+    }
+    position += codes.length;
+  }
+
+  num _decodeNumber() {
+    throw new UnsupportedError('_decodeNumber');
+  }
+
+  void _fail() {
+    throw new ArgumentError("Unexpected value: "
+        "'${new String.fromCharCodes(codeUnits, position)}'.");
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/lax_json_test.dart b/tests/compiler/dart2js/sourcemaps/lax_json_test.dart
new file mode 100644
index 0000000..3d78c7e
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/lax_json_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:unittest/unittest.dart';
+import 'lax_json.dart';
+
+void main() {
+  test('primitives', () {
+    expect(decode('true'), equals(true));
+    expect(decode(' true'), equals(true));
+    expect(decode('true '), equals(true));
+    expect(decode('true// '), equals(true));
+    expect(decode('// \ntrue'), equals(true));
+    expect(decode('\ttrue\r'), equals(true));
+    expect(decode('\t\ntrue\r\n'), equals(true));
+    expect(decode('true/* */'), equals(true));
+    expect(decode('/* */true'), equals(true));
+    expect(decode('/* false */true '), equals(true));
+
+    expect(decode('false'), equals(false));
+    expect(decode('null'), equals(null));
+  });
+
+  test('string', () {
+    expect(decode('"foo"'), equals("foo"));
+    expect(decode('"foo bar baz"'), equals("foo bar baz"));
+    expect(decode(r'"\""'), equals(r'"'));
+    expect(decode(r'"\\"'), equals(r'\'));
+    expect(decode(r'"\/"'), equals('/'));
+    expect(decode(r'"\b"'), equals('\b'));
+    expect(decode(r'"\f"'), equals('\f'));
+    expect(decode(r'"\r"'), equals('\r'));
+    expect(decode(r'"\n"'), equals('\n'));
+    expect(decode(r'"\t"'), equals('\t'));
+    expect(decode(r'"\t\"\\\/\f\nfoo\r\t"'), equals('\t\"\\/\f\nfoo\r\t'));
+  });
+
+  test('list', () {
+    expect(decode('[]'), equals([]));
+    expect(decode('[\n]'), equals([]));
+    expect(decode('["foo"]'), equals(['foo']));
+    expect(decode('["foo",]'), equals(['foo']));
+    expect(decode('["foo", "bar", true, \nnull\n,false,]'),
+        equals(['foo', 'bar', true, null, false]));
+  });
+
+  test('map', () {
+    expect(decode('{}'), equals({}));
+    expect(decode('{\n}'), equals({}));
+    expect(decode('{"foo":"bar"}'), equals({'foo': 'bar'}));
+    expect(decode('{"foo":"bar",}'), equals({'foo': 'bar'}));
+    expect(
+        decode(
+            '{"foo":true, "bar": false, "baz": true, '
+                '"boz": \nnull\n,"qux": false,}'),
+        equals({
+          'foo': true,
+          'bar': false,
+          'baz': true,
+          'boz': null,
+          'qux': false
+        }));
+  });
+}
diff --git a/tests/compiler/dart2js/sourcemaps/load.dart b/tests/compiler/dart2js/sourcemaps/load.dart
new file mode 100644
index 0000000..29cb8e0
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/load.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Loads a source map file and outputs a human-readable version of it.
+
+library load;
+
+import 'dart:convert';
+import 'dart:io';
+import 'package:source_maps/source_maps.dart';
+
+void main(List<String> args) {
+  if (args.isEmpty) {
+    print('''
+Usage: load <dir-containing 'out.js.map'>
+   or: load <source-map-file> [<human-readable-source-map-file>]''');
+    exit(1);
+  }
+
+  File humanReadableSourceMapFile;
+  File sourceMapFile;
+  if (args.length == 1 && new Directory(args[0]).existsSync()) {
+    humanReadableSourceMapFile = new File('${args[0]}/out.js.map2');
+    sourceMapFile = new File('${args[0]}/out.js.map');
+  } else {
+    sourceMapFile = new File(args[0]);
+    if (args.length > 1) {
+      humanReadableSourceMapFile = new File(args[1]);
+    }
+  }
+  mainInternal(sourceMapFile, humanReadableSourceMapFile);
+}
+
+void mainInternal(File sourceMapFile, File humanReadableSourceMapFile) {
+  SingleMapping sourceMap =
+      new SingleMapping.fromJson(JSON.decode(sourceMapFile.readAsStringSync()));
+  String humanReadableSourceMap = convertToHumanReadableSourceMap(sourceMap);
+  if (humanReadableSourceMapFile != null) {
+    humanReadableSourceMapFile.writeAsStringSync(humanReadableSourceMap);
+  } else {
+    print(humanReadableSourceMap);
+  }
+}
+
+String convertToHumanReadableSourceMap(SingleMapping sourceMap) {
+  StringBuffer sb = new StringBuffer();
+  sb.write('{\n');
+  sb.write('  "file": "${sourceMap.targetUrl}",\n');
+  sb.write('  "sourceRoot": "${sourceMap.sourceRoot}",\n');
+  sb.write('  "sources": {\n');
+  for (int index = 0; index < sourceMap.urls.length; index++) {
+    if (index > 0) {
+      sb.write(',\n');
+    }
+    sb.write('    "$index": "${sourceMap.urls[index]}"');
+  }
+  sb.write('\n  },\n');
+  sb.write('  "lines": [\n');
+  bool needsComma = false;
+  for (int lineIndex = 0; lineIndex < sourceMap.lines.length; lineIndex++) {
+    TargetLineEntry lineEntry = sourceMap.lines[lineIndex];
+    int line = lineEntry.line + 1;
+    for (int entryIndex = 0;
+        entryIndex < lineEntry.entries.length;
+        entryIndex++) {
+      TargetEntry entry = lineEntry.entries[entryIndex];
+      int columnStart = entry.column + 1;
+      int columnEnd;
+      String position;
+      if (entryIndex + 1 < lineEntry.entries.length) {
+        columnEnd = lineEntry.entries[entryIndex + 1].column + 1;
+        position = '$line,$columnStart-$columnEnd';
+      } else {
+        position = '$line,$columnStart-';
+      }
+      if (entry.sourceUrlId != null) {
+        int sourceUrlId = entry.sourceUrlId;
+        int sourceLine = entry.sourceLine + 1;
+        int sourceColumn = entry.sourceColumn + 1;
+        if (needsComma) {
+          sb.write(',\n');
+        }
+        sb.write('    {"target": "$position"');
+        sb.write(', "source": "$sourceUrlId:$sourceLine,$sourceColumn"');
+        if (entry.sourceNameId != null) {
+          sb.write(', "name": "${sourceMap.names[entry.sourceNameId]}"');
+        }
+        sb.write('}');
+        needsComma = true;
+      }
+    }
+  }
+  sb.write('\n  ]\n');
+  sb.write('}');
+  return sb.toString();
+}
diff --git a/tests/compiler/dart2js/sourcemaps/load_save_test.dart b/tests/compiler/dart2js/sourcemaps/load_save_test.dart
new file mode 100644
index 0000000..380f7f2
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/load_save_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'package:source_maps/source_maps.dart';
+import 'package:unittest/unittest.dart';
+import 'load.dart';
+import 'save.dart';
+
+const String SOURCEMAP = '''
+{
+  "version": 3,
+  "file": "out.js",
+  "sourceRoot": "",
+  "sources": ["sdk/lib/_internal/compiler/js_lib/js_primitives.dart","hello_world.dart","sdk/lib/_internal/compiler/js_lib/internal_patch.dart"],
+  "names": ["printString","main","printToConsole"],
+  "mappings": "A;A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A;;eAoBAA;;;AAIIA;;;;AAOAA;;;AAKAA;;;AAMAA;;;GAOJA;;sC;;QC5CAC;;ICYEC;GDRFD;;;;A;A;A;;;A;;;A;A;A;A;A;A;A;;;;;;A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A;C;;;;;;;;;;;;;;;;;;;;;;;;;;;;A"
+}''';
+
+const String HUMAN_READABLE_SOURCE_MAP = '''
+{
+  "file": "out.js",
+  "sourceRoot": "",
+  "sources": {
+    "0": "out.js.map",
+    "1": "test.dart",
+    "2": "out.js"
+  },
+  "lines": [
+    {"target": "3,3-", "source": "1:2,17"},
+    {"target": "4,3-", "source": "1:3,17"},
+    {"target": "5,3-15", "source": "1:4,17"},
+    {"target": "5,15-20", "source": "1:5,17"},
+    {"target": "5,20-", "source": "1:6,4"},
+    {"target": "6,3-", "source": "1:7,17"},
+    {"target": "7,3-", "source": "1:8,17"},
+    {"target": "8,1-", "source": "1:9,1"},
+    {"target": "10,3-", "source": "1:11,17"},
+    {"target": "11,3-", "source": "1:12,17"},
+    {"target": "12,3-", "source": "1:13,17"},
+    {"target": "13,3-", "source": "1:14,17"},
+    {"target": "14,1-", "source": "1:15,4"}
+  ]
+}''';
+
+void main() {
+  test('read/write', () {
+    SingleMapping sourceMap =
+        new SingleMapping.fromJson(JSON.decode(SOURCEMAP));
+    String humanReadable = convertToHumanReadableSourceMap(sourceMap);
+    SingleMapping sourceMap2 = convertFromHumanReadableSourceMap(humanReadable);
+    String humanReadable2 = convertToHumanReadableSourceMap(sourceMap2);
+    SingleMapping sourceMap3 =
+        convertFromHumanReadableSourceMap(humanReadable2);
+    String humanReadable3 = convertToHumanReadableSourceMap(sourceMap3);
+
+    // Target line entries without sourceUrl are removed.
+    //expect(sourceMap.toJson(), equals(sourceMap2.toJson()));
+    expect(sourceMap2.toJson(), equals(sourceMap3.toJson()));
+    expect(JSON.decode(humanReadable), equals(JSON.decode(humanReadable2)));
+    expect(JSON.decode(humanReadable2), equals(JSON.decode(humanReadable3)));
+  });
+
+  test('write/read', () {
+    SingleMapping sourceMap =
+        convertFromHumanReadableSourceMap(HUMAN_READABLE_SOURCE_MAP);
+    print(sourceMap);
+    String humanReadable = convertToHumanReadableSourceMap(sourceMap);
+    print(humanReadable);
+    SingleMapping sourceMap2 = convertFromHumanReadableSourceMap(humanReadable);
+    expect(JSON.decode(HUMAN_READABLE_SOURCE_MAP),
+        equals(JSON.decode(humanReadable)));
+    expect(sourceMap.toJson(), equals(sourceMap2.toJson()));
+  });
+}
diff --git a/tests/compiler/dart2js/sourcemaps/save.dart b/tests/compiler/dart2js/sourcemaps/save.dart
new file mode 100644
index 0000000..4c2c296
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/save.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Loads a human-readable source map and outputs the source map file for it.
+
+library save;
+
+import 'dart:convert';
+import 'dart:io';
+import 'package:source_maps/source_maps.dart';
+import 'lax_json.dart' as lazon;
+
+void main(List<String> args) {
+  if (args.isEmpty) {
+    print('''
+Usage: save <dir-containing 'out.js.map2'>
+   or: save <human-readable-source-map-file> [<source-map-file>]''');
+    exit(1);
+  }
+
+  File humanReadableSourceMapFile;
+  File sourceMapFile;
+  if (args.length == 1 && new Directory(args[0]).existsSync()) {
+    humanReadableSourceMapFile = new File('${args[0]}/out.js.map2');
+    sourceMapFile = new File('${args[0]}/out.js.map');
+  } else {
+    humanReadableSourceMapFile = new File(args[0]);
+    if (args.length > 1) {
+      sourceMapFile = new File(args[1]);
+    }
+  }
+
+  String humanReadableSourceMap = humanReadableSourceMapFile.readAsStringSync();
+  SingleMapping mapping =
+      convertFromHumanReadableSourceMap(humanReadableSourceMap);
+
+  if (sourceMapFile != null) {
+    sourceMapFile.writeAsStringSync(JSON.encoder.convert(mapping.toJson()));
+  } else {
+    print(new JsonEncoder.withIndent('  ').convert(mapping.toJson()));
+  }
+}
+
+SingleMapping convertFromHumanReadableSourceMap(String json) {
+  Map inputMap = lazon.decode(json);
+  String file = inputMap['file'];
+  Map urls = inputMap['sources'];
+  List<String> sources = new List<String>.filled(urls.length, null);
+  urls.forEach((String index, String url) {
+    int i = int.parse(index);
+    assert(sources[i] == null);
+    sources[i] = url;
+  });
+  List lines = inputMap['lines'];
+  Map<String, int> names = <String, int>{};
+  Map<int, TargetLineEntry> lineEntryMap = {};
+
+  for (Map line in lines) {
+    String targetString = line['target'];
+    String sourceString = line['source'];
+    String name = line['name'];
+    int nameIndex;
+    if (name != null) {
+      nameIndex = names.putIfAbsent(name, () => names.length);
+    }
+
+    int lineNo;
+    int columnStart;
+    int columnEnd;
+    if (targetString != null) {
+      int commaPos = targetString.indexOf(',');
+      lineNo = int.parse(targetString.substring(0, commaPos)) - 1;
+      if (lineNo < 0) {
+        throw new ArgumentError('target line must be > 0: $lineNo');
+      }
+      targetString = targetString.substring(commaPos + 1);
+      int dashPos = targetString.indexOf('-');
+      columnStart = int.parse(targetString.substring(0, dashPos)) - 1;
+      if (columnStart < 0) {
+        throw new ArgumentError(
+            'target column start must be > 0: $columnStart');
+      }
+      targetString = targetString.substring(dashPos + 1);
+      if (!targetString.isEmpty) {
+        columnEnd = int.parse(targetString) - 1;
+        if (columnEnd < 0) {
+          throw new ArgumentError('target column end must be > 0: $columnEnd');
+        }
+      }
+    }
+    int sourceUrlId;
+    int sourceLine;
+    int sourceColumn;
+    if (sourceString != null) {
+      int colonPos = sourceString.indexOf(':');
+      sourceUrlId = int.parse(sourceString.substring(0, colonPos));
+      if (sourceUrlId < 0) {
+        throw new ArgumentError('source url id end must be > 0: $sourceUrlId');
+      } else if (sourceUrlId >= sources.length) {
+        throw new ArgumentError(
+            'source url id end must be < ${sources.length}: $sourceUrlId');
+      }
+
+      sourceString = sourceString.substring(colonPos + 1);
+      int commaPos = sourceString.indexOf(',');
+      sourceLine = int.parse(sourceString.substring(0, commaPos)) - 1;
+      if (sourceLine < 0) {
+        throw new ArgumentError('source line end must be > 0: $sourceLine');
+      }
+      sourceString = sourceString.substring(commaPos + 1);
+      sourceColumn = int.parse(sourceString) - 1;
+      if (sourceColumn < 0) {
+        throw new ArgumentError('source column must be > 0: $sourceColumn');
+      }
+    }
+
+    TargetLineEntry lineEntry =
+        lineEntryMap.putIfAbsent(lineNo, () => new TargetLineEntry(lineNo, []));
+    lineEntry.entries.add(new TargetEntry(
+        columnStart, sourceUrlId, sourceLine, sourceColumn, nameIndex));
+    if (columnEnd != null) {
+      lineEntry.entries.add(new TargetEntry(columnEnd));
+    }
+  }
+
+  List<TargetLineEntry> lineEntries = lineEntryMap.values.toList();
+
+  Map outputMap = {
+    'version': 3,
+    'sourceRoot': inputMap['sourceRoot'],
+    'file': inputMap['file'],
+    'sources': sources,
+    'names': names.keys.toList(),
+    'mappings': '',
+  };
+
+  SingleMapping mapping = new SingleMapping.fromJson(outputMap);
+  mapping.lines.addAll(lineEntries);
+  return mapping;
+}
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
new file mode 100644
index 0000000..9fcebdc
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -0,0 +1,344 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/compiler_new.dart';
+import 'package:compiler/src/apiimpl.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/dart2js.dart' as entry;
+import 'package:expect/expect.dart';
+import 'package:source_maps/source_maps.dart';
+import 'package:source_maps/src/utils.dart';
+
+import '../source_map_validator_helper.dart';
+
+const String EXCEPTION_MARKER = '>ExceptionMarker<';
+const String INPUT_FILE_NAME = 'in.dart';
+
+const List<String> TESTS = const <String>[
+  '''
+main() {
+  @{1:main}throw '$EXCEPTION_MARKER';
+}
+''',
+  '''
+main() {
+  @{1:main}test();
+}
+test() {
+  @{2:test}throw '$EXCEPTION_MARKER';
+}
+''',
+  '''
+main() {
+  @{1:main}Class.test();
+}
+class Class {
+  static test() {
+    @{2:Class.test}throw '$EXCEPTION_MARKER';
+  }
+}
+''',
+  '''
+main() {
+  var c = new Class();
+  c.@{1:main}test();
+}
+class Class {
+  test() {
+    @{2:Class.test}throw '$EXCEPTION_MARKER';
+  }
+}
+''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  var c = @{1:main}new Class();
+}
+class Class {
+  @NoInline()
+  Class() {
+    @{2:Class}throw '$EXCEPTION_MARKER';
+  }
+}
+''',
+];
+
+class Test {
+  final String code;
+  final List<StackTraceLine> expectedLines;
+
+  Test(this.code, this.expectedLines);
+}
+
+const int _LF = 0x0A;
+const int _CR = 0x0D;
+const int _LBRACE = 0x7B;
+
+
+Test processTestCode(String code) {
+  StringBuffer codeBuffer = new StringBuffer();
+  Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
+  int index = 0;
+  int lineNo = 1;
+  int columnNo = 1;
+  while (index < code.length) {
+    int charCode = code.codeUnitAt(index);
+    switch (charCode) {
+      case _LF:
+        codeBuffer.write('\n');
+        lineNo++;
+        columnNo = 1;
+        break;
+      case _CR:
+        if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LF) {
+          index++;
+        }
+        codeBuffer.write('\n');
+        lineNo++;
+        columnNo = 1;
+        break;
+      case 0x40:
+        if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LBRACE) {
+          int colonIndex = code.indexOf(':', index);
+          int endIndex = code.indexOf('}', index);
+          int stackTraceIndex =
+              int.parse(code.substring(index + 2, colonIndex));
+          String methodName = code.substring(colonIndex + 1, endIndex);
+          assert(!stackTraceMap.containsKey(stackTraceIndex));
+          stackTraceMap[stackTraceIndex] =
+              new StackTraceLine(methodName, INPUT_FILE_NAME, lineNo, columnNo);
+          index = endIndex;
+        } else {
+          codeBuffer.writeCharCode(charCode);
+          columnNo++;
+        }
+        break;
+      default:
+        codeBuffer.writeCharCode(charCode);
+        columnNo++;
+    }
+    index++;
+  }
+  List<StackTraceLine> expectedLines = <StackTraceLine>[];
+  for (int stackTraceIndex in (stackTraceMap.keys.toList()..sort()).reversed) {
+    expectedLines.add(stackTraceMap[stackTraceIndex]);
+  }
+  return new Test(codeBuffer.toString(), expectedLines);
+}
+
+void main(List<String> arguments) {
+  asyncTest(() async {
+    for (String code in TESTS) {
+      await runTest(processTestCode(code));
+    }
+  });
+}
+
+Future runTest(Test test) async {
+  Directory tmpDir = await createTempDir();
+  String input = '${tmpDir.path}/$INPUT_FILE_NAME';
+  new File(input).writeAsStringSync(test.code);
+  String output = '${tmpDir.path}/out.js';
+  List<String> arguments = [
+    '-o$output',
+    '--library-root=sdk',
+    '--packages=${Platform.packageConfig}',
+    Flags.useNewSourceInfo,
+    input,
+  ];
+  print("--------------------------------------------------------------------");
+  print("Compiling dart2js ${arguments.join(' ')}\n${test.code}");
+  CompilationResult compilationResult = await entry.internalMain(arguments);
+  Expect.isTrue(compilationResult.isSuccess,
+      "Unsuccessful compilation of test:\n${test.code}");
+  CompilerImpl compiler = compilationResult.compiler;
+  SingleMapping sourceMap = new SingleMapping.fromJson(
+      JSON.decode(new File('$output.map').readAsStringSync()));
+
+  print("Running d8 $output");
+  ProcessResult runResult =
+      Process.runSync(d8executable, [output]);
+  String out = '${runResult.stderr}\n${runResult.stdout}';
+  List<String> lines = out.split(new RegExp(r'(\r|\n|\r\n)'));
+  List<StackTraceLine> jsStackTrace = <StackTraceLine>[];
+  bool seenMarker = false;
+  for (String line in lines) {
+    if (seenMarker) {
+      line = line.trim();
+      if (line.startsWith('at ')) {
+        jsStackTrace.add(new StackTraceLine.fromText(line));
+      }
+    } else if (line == EXCEPTION_MARKER) {
+      seenMarker = true;
+    }
+  }
+
+  List<StackTraceLine> dartStackTrace = <StackTraceLine>[];
+  for (StackTraceLine line in jsStackTrace) {
+    TargetEntry targetEntry = _findColumn(line.lineNo - 1, line.columnNo - 1,
+        _findLine(sourceMap, line.lineNo - 1));
+    if (targetEntry == null) {
+      dartStackTrace.add(line);
+    } else {
+      String methodName;
+      if (targetEntry.sourceNameId != 0) {
+        methodName = sourceMap.names[targetEntry.sourceNameId];
+      }
+      String fileName;
+      if (targetEntry.sourceUrlId != 0) {
+        fileName = sourceMap.urls[targetEntry.sourceUrlId];
+      }
+      dartStackTrace.add(new StackTraceLine(methodName, fileName,
+          targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1));
+    }
+  }
+
+  int expectedIndex = 0;
+  for (StackTraceLine line in dartStackTrace) {
+    if (expectedIndex < test.expectedLines.length) {
+      StackTraceLine expectedLine = test.expectedLines[expectedIndex];
+      if (line.methodName == expectedLine.methodName &&
+          line.lineNo == expectedLine.lineNo &&
+          line.columnNo == expectedLine.columnNo) {
+        expectedIndex++;
+      }
+    }
+  }
+  Expect.equals(
+      expectedIndex,
+      test.expectedLines.length,
+      "Missing stack trace lines for test:\n${test.code}\n"
+      "Actual:\n${dartStackTrace.join('\n')}\n"
+      "Expected:\n${test.expectedLines.join('\n')}\n");
+
+  print("Deleting '${tmpDir.path}'.");
+  tmpDir.deleteSync(recursive: true);
+}
+
+class StackTraceLine {
+  String methodName;
+  String fileName;
+  int lineNo;
+  int columnNo;
+
+  StackTraceLine(this.methodName, this.fileName, this.lineNo, this.columnNo);
+
+  /// Creates a [StackTraceLine] by parsing a d8 stack trace line [text]. The
+  /// expected formats are
+  ///
+  ///     at <methodName>(<fileName>:<lineNo>:<columnNo>)
+  ///     at <methodName>(<fileName>:<lineNo>)
+  ///     at <methodName>(<fileName>)
+  ///     at <fileName>:<lineNo>:<columnNo>
+  ///     at <fileName>:<lineNo>
+  ///     at <fileName>
+  ///
+  factory StackTraceLine.fromText(String text) {
+    text = text.trim();
+    assert(text.startsWith('at '));
+    text = text.substring('at '.length);
+    String methodName;
+    if (text.endsWith(')')) {
+      int nameEnd = text.indexOf(' (');
+      methodName = text.substring(0, nameEnd);
+      text = text.substring(nameEnd + 2, text.length - 1);
+    }
+    int lineNo;
+    int columnNo;
+    String fileName;
+    int lastColon = text.lastIndexOf(':');
+    if (lastColon != -1) {
+      int lastValue =
+          int.parse(text.substring(lastColon + 1), onError: (_) => null);
+      if (lastValue != null) {
+        int secondToLastColon = text.lastIndexOf(':', lastColon - 1);
+        if (secondToLastColon != -1) {
+          int secondToLastValue = int.parse(
+              text.substring(secondToLastColon + 1, lastColon),
+              onError: (_) => null);
+          if (secondToLastValue != null) {
+            lineNo = secondToLastValue;
+            columnNo = lastValue;
+            fileName = text.substring(0, secondToLastColon);
+          } else {
+            lineNo = lastValue;
+            fileName = text.substring(0, lastColon);
+          }
+        } else {
+          lineNo = lastValue;
+          fileName = text.substring(0, lastColon);
+        }
+      } else {
+        fileName = text;
+      }
+    } else {
+      fileName = text;
+    }
+    return new StackTraceLine(methodName, fileName, lineNo, columnNo);
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('  at ');
+    if (methodName != null) {
+      sb.write(methodName);
+      sb.write(' (');
+      sb.write(fileName ?? '?');
+      sb.write(':');
+      sb.write(lineNo);
+      sb.write(':');
+      sb.write(columnNo);
+      sb.write(')');
+    } else {
+      sb.write(fileName ?? '?');
+      sb.write(':');
+      sb.write(lineNo);
+      sb.write(':');
+      sb.write(columnNo);
+    }
+    return sb.toString();
+  }
+}
+
+/// Returns [TargetLineEntry] which includes the location in the target [line]
+/// number. In particular, the resulting entry is the last entry whose line
+/// number is lower or equal to [line].
+///
+/// Copied from [SingleMapping._findLine].
+TargetLineEntry _findLine(SingleMapping sourceMap, int line) {
+  int index = binarySearch(sourceMap.lines, (e) => e.line > line);
+  return (index <= 0) ? null : sourceMap.lines[index - 1];
+}
+
+/// Returns [TargetEntry] which includes the location denoted by
+/// [line], [column]. If [lineEntry] corresponds to [line], then this will be
+/// the last entry whose column is lower or equal than [column]. If
+/// [lineEntry] corresponds to a line prior to [line], then the result will be
+/// the very last entry on that line.
+///
+/// Copied from [SingleMapping._findColumn].
+TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) {
+  if (lineEntry == null || lineEntry.entries.length == 0) return null;
+  if (lineEntry.line != line) return lineEntry.entries.last;
+  var entries = lineEntry.entries;
+  int index = binarySearch(entries, (e) => e.column > column);
+  return (index <= 0) ? null : entries[index - 1];
+}
+
+/// Returns the path of the d8 executable.
+String get d8executable {
+  if (Platform.isWindows) {
+    return 'third_party/d8/windows/d8.exe';
+  } else if (Platform.isLinux) {
+    return 'third_party/d8/linux/d8';
+  } else if (Platform.isMacOS) {
+    return 'third_party/d8/macos/d8';
+  }
+  throw new UnsupportedError('Unsupported platform.');
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/trace_graph.dart b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
index 0db1e18..feceab2 100644
--- a/tests/compiler/dart2js/sourcemaps/trace_graph.dart
+++ b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
@@ -20,7 +20,7 @@
 
   void addStep(TraceStep step) {
     steps.add(step);
-    int offset = step.offset.subexpressionOffset;
+    int offset = step.offset.value;
     TraceStep existingStep = offsetMap[offset];
     if (existingStep != null) {
       // TODO(johnniwinther): Fix problems with reuse of JS nodes from
diff --git a/tests/compiler/dart2js_extra/multi_global_def_single_instantiation_test.dart b/tests/compiler/dart2js_extra/multi_global_def_single_instantiation_test.dart
new file mode 100644
index 0000000..f118b61
--- /dev/null
+++ b/tests/compiler/dart2js_extra/multi_global_def_single_instantiation_test.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+var y, w, z, x = [], q, r = [];
+main() => [x, r];
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index a714329..97426fe 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -209,3 +209,4 @@
 regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
 big_integer_arith_vm_test/gcd: Pass, RuntimeError # Issue #27474
 big_integer_arith_vm_test/modPow: Pass, RuntimeError # Issue #27474
+collection_length_test: Skip # Issue #27746
diff --git a/tests/kernel/kernel.status b/tests/kernel/kernel.status
index c05aa3d..ab88299 100644
--- a/tests/kernel/kernel.status
+++ b/tests/kernel/kernel.status
@@ -14,6 +14,7 @@
 
 [ $compiler == dart2js ]
 unsorted/invocation_errors_test: Pass
+unsorted/nsm_dispatcher_test: Skip # The test uses Symbol without MirrorsUsed
 unsorted/super_initializer_test: Skip
 unsorted/super_mixin_test: CompileTimeError
 unsorted/loop_test: Skip
diff --git a/tests/language/language.status b/tests/language/language.status
index 34791b41..2357dd9 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -141,6 +141,9 @@
 
 [ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_app) && ( $arch == simarm || $arch == arm || $arch == simarmv6 || $arch == armv6 || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
 vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
+vm/unaligned_float_access_literal_index_test: Pass, Crash # Unaligned offset. Issue 22151
+vm/unaligned_float_access_literal_index_test: Pass, Crash # Unaligned offset. Issue 22151
+
 
 [ $compiler == none && ($runtime == dartium || $runtime == drt) ]
 issue23244_test: Fail # Issue 23244
@@ -148,6 +151,9 @@
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app || $compiler == dart2appjit) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_app) || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
 vm/regress_24517_test: Pass, Fail # Issue 24517.
 
+[ $compiler == precompiler && $runtime == dart_precompiled ]
+vm/regress_27671_test: Skip # Unsupported
+
 [ $noopt || $compiler == precompiler ]
 # Stacktraces in precompilation omit inlined frames.
 full_stacktrace1_test: Pass, RuntimeError
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index 2002d17..3571c0c 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -353,7 +353,6 @@
 type_variable_function_type_test: RuntimeError
 vm/debug_break_enabled_vm_test/01: CompileTimeError
 vm/debug_break_enabled_vm_test/none: CompileTimeError
-vm/optimized_guarded_field_isolates_test: Crash
 vm/reflect_core_vm_test: CompileTimeError
 vm/type_cast_vm_test: RuntimeError
 vm/type_vm_test: RuntimeError
diff --git a/tests/language/vm/unaligned_float_access_literal_index_test.dart b/tests/language/vm/unaligned_float_access_literal_index_test.dart
new file mode 100644
index 0000000..c224dc9
--- /dev/null
+++ b/tests/language/vm/unaligned_float_access_literal_index_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization_counter_threshold=10 --no-background_compilation
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+unalignedFloat32() {
+  var bytes = new ByteData(64);
+  bytes.setFloat32(0, 16.25);
+  Expect.equals(16.25, bytes.getFloat32(0));
+  bytes.setFloat32(1, 32.125);
+  Expect.equals(32.125, bytes.getFloat32(1));
+  bytes.setFloat32(2, 16.25);
+  Expect.equals(16.25, bytes.getFloat32(2));
+  bytes.setFloat32(3, 32.125);
+  Expect.equals(32.125, bytes.getFloat32(3));
+}
+
+unalignedFloat64() {
+  var bytes = new ByteData(64);
+  bytes.setFloat64(0, 16.25);
+  Expect.equals(16.25, bytes.getFloat64(0));
+  bytes.setFloat64(1, 32.125);
+  Expect.equals(32.125, bytes.getFloat64(1));
+  bytes.setFloat64(2, 16.25);
+  Expect.equals(16.25, bytes.getFloat64(2));
+  bytes.setFloat64(3, 32.125);
+  Expect.equals(32.125, bytes.getFloat64(3));
+  bytes.setFloat64(4, 16.25);
+  Expect.equals(16.25, bytes.getFloat64(4));
+  bytes.setFloat64(5, 32.125);
+  Expect.equals(32.125, bytes.getFloat64(5));
+  bytes.setFloat64(6, 16.25);
+  Expect.equals(16.25, bytes.getFloat64(6));
+  bytes.setFloat64(7, 32.125);
+  Expect.equals(32.125, bytes.getFloat64(7));
+}
+
+main() {
+  for (var i = 0; i < 20; i++) {
+    unalignedFloat32();
+    unalignedFloat64();
+  }
+}
diff --git a/tests/language/vm/unaligned_float_access_register_index_test.dart b/tests/language/vm/unaligned_float_access_register_index_test.dart
new file mode 100644
index 0000000..334efe5
--- /dev/null
+++ b/tests/language/vm/unaligned_float_access_register_index_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization_counter_threshold=10 --no-background_compilation
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+unalignedFloat32() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 4; i++) {
+    bytes.setFloat32(i, 16.25);
+    Expect.equals(16.25, bytes.getFloat32(i));
+  }
+}
+
+unalignedFloat64() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 8; i++) {
+    bytes.setFloat64(i, 16.25);
+    Expect.equals(16.25, bytes.getFloat64(i));
+  }
+}
+
+main() {
+  for (var i = 0; i < 20; i++) {
+    unalignedFloat32();
+    unalignedFloat64();
+  }
+}
diff --git a/tests/language/vm/unaligned_integer_access_literal_index_test.dart b/tests/language/vm/unaligned_integer_access_literal_index_test.dart
new file mode 100644
index 0000000..6373a24
--- /dev/null
+++ b/tests/language/vm/unaligned_integer_access_literal_index_test.dart
@@ -0,0 +1,98 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization_counter_threshold=10 --no-background_compilation
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+unalignedUint16() {
+  var bytes = new ByteData(64);
+  bytes.setUint16(0, 0xABCD);
+  Expect.equals(0xABCD, bytes.getUint16(0));
+  bytes.setUint16(1, 0xBCDE);
+  Expect.equals(0xBCDE, bytes.getUint16(1));
+}
+
+unalignedInt16() {
+  var bytes = new ByteData(64);
+  bytes.setInt16(0, -0x1234);
+  Expect.equals(-0x1234, bytes.getInt16(0));
+  bytes.setInt16(1, -0x2345);
+  Expect.equals(-0x2345, bytes.getInt16(1));
+}
+
+unalignedUint32() {
+  var bytes = new ByteData(64);
+  bytes.setUint32(0, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint32(0));
+  bytes.setUint32(1, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint32(1));
+  bytes.setUint32(2, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint32(2));
+  bytes.setUint32(3, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint32(3));
+}
+
+unalignedInt32() {
+  var bytes = new ByteData(64);
+  bytes.setInt32(0, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt32(0));
+  bytes.setInt32(1, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt32(1));
+  bytes.setInt32(2, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt32(2));
+  bytes.setInt32(3, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt32(3));
+}
+
+unalignedUint64() {
+  var bytes = new ByteData(64);
+  bytes.setUint64(0, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint64(0));
+  bytes.setUint64(1, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint64(1));
+  bytes.setUint64(2, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint64(2));
+  bytes.setUint64(3, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint64(3));
+  bytes.setUint64(4, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint64(4));
+  bytes.setUint64(5, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint64(5));
+  bytes.setUint64(6, 0xABCDABCD);
+  Expect.equals(0xABCDABCD, bytes.getUint64(6));
+  bytes.setUint64(7, 0xBCDEBCDE);
+  Expect.equals(0xBCDEBCDE, bytes.getUint64(7));
+}
+
+unalignedInt64() {
+  var bytes = new ByteData(64);
+  bytes.setInt64(0, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt64(0));
+  bytes.setInt64(1, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt64(1));
+  bytes.setInt64(2, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt64(2));
+  bytes.setInt64(3, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt64(3));
+  bytes.setInt64(4, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt64(4));
+  bytes.setInt64(5, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt64(5));
+  bytes.setInt64(6, -0x12341234);
+  Expect.equals(-0x12341234, bytes.getInt64(6));
+  bytes.setInt64(7, -0x23452345);
+  Expect.equals(-0x23452345, bytes.getInt64(7));
+}
+
+main() {
+  for (var i = 0; i < 20; i++) {
+    unalignedUint16();
+    unalignedInt16();
+    unalignedUint32();
+    unalignedInt32();
+    unalignedUint64();
+    unalignedInt64();
+  }
+}
diff --git a/tests/language/vm/unaligned_integer_access_register_index_test.dart b/tests/language/vm/unaligned_integer_access_register_index_test.dart
new file mode 100644
index 0000000..7c49cce
--- /dev/null
+++ b/tests/language/vm/unaligned_integer_access_register_index_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization_counter_threshold=10 --no-background_compilation
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+unalignedUint16() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 2; i++) {
+    bytes.setUint16(i, 0xABCD);
+    Expect.equals(0xABCD, bytes.getUint16(i));
+  }
+}
+
+unalignedInt16() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 2; i++) {
+    bytes.setInt16(i, -0x1234);
+    Expect.equals(-0x1234, bytes.getInt16(i));
+  }
+}
+
+unalignedUint32() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 4; i++) {
+    bytes.setUint32(i, 0xABCDABCD);
+    Expect.equals(0xABCDABCD, bytes.getUint32(i));
+  }
+}
+
+unalignedInt32() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 4; i++) {
+    bytes.setInt32(i, -0x12341234);
+    Expect.equals(-0x12341234, bytes.getInt32(i));
+  }
+}
+
+unalignedUint64() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 8; i++) {
+    bytes.setUint64(i, 0xABCDABCD);
+    Expect.equals(0xABCDABCD, bytes.getUint64(i));
+  }
+}
+
+unalignedInt64() {
+  var bytes = new ByteData(64);
+  for (var i = 0; i < 8; i++) {
+    bytes.setInt64(i, -0x12341234);
+    Expect.equals(-0x12341234, bytes.getInt64(i));
+  }
+}
+
+main() {
+  for (var i = 0; i < 20; i++) {
+    unalignedUint16();
+    unalignedInt16();
+    unalignedUint32();
+    unalignedInt32();
+    unalignedUint64();
+    unalignedInt64();
+  }
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index f5bfade..8b3ac69 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -394,11 +394,6 @@
 convert/chunked_conversion_utf88_test: Pass, Timeout
 convert/utf85_test: Pass, Timeout
 
-[ $arch == simdbc || $arch == simdbc64 ]
-# TODO(vegorov) LoadField bytecode supports only up to 256 fields. Need a long
-# version.
-mirrors/accessor_cache_overflow_test: Skip
-
 [ $hot_reload || $hot_reload_rollback ]
 async/multiple_timer_test: Pass, Fail # Timing related
 async/stream_transformer_test: Pass, Fail # Closure identity
diff --git a/tests/standalone/http_launch_test.dart b/tests/standalone/http_launch_test.dart
index 31c524b..40fd509 100644
--- a/tests/standalone/http_launch_test.dart
+++ b/tests/standalone/http_launch_test.dart
@@ -5,6 +5,10 @@
 // VMOptions=--short_socket_read
 // VMOptions=--short_socket_write
 // VMOptions=--short_socket_read --short_socket_write
+// OtherResources=http_launch_data/http_isolate_main.dart
+// OtherResources=http_launch_data/http_launch_main.dart
+// OtherResources=http_launch_data/http_spawn_main.dart
+// OtherResources=http_launch_data/packages/simple/simple.dart
 //
 // Test:
 //   *) Launching a script fetched over HTTP.
diff --git a/tests/standalone/io/addlatexhash_test.dart b/tests/standalone/io/addlatexhash_test.dart
index 5c1c740..861f496 100755
--- a/tests/standalone/io/addlatexhash_test.dart
+++ b/tests/standalone/io/addlatexhash_test.dart
@@ -9,8 +9,8 @@
 import 'package:path/path.dart' as path;
 import '../../../tools/addlatexhash.dart';
 
-final scriptDir = path.dirname(path.fromUri(Platform.script));
-final dartRootDir = path.dirname(path.dirname(path.dirname(scriptDir)));
+final execDir = path.dirname(path.fromUri(Platform.executable));
+final dartRootDir = path.dirname(path.dirname(execDir));
 final dartRootPath = dartRootDir.toString();
 
 List<String> packageOptions() {
diff --git a/tests/standalone/io/empty_file b/tests/standalone/io/empty_file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/standalone/io/empty_file
diff --git a/tests/standalone/io/file_blocking_lock_test.dart b/tests/standalone/io/file_blocking_lock_test.dart
index 9cd6689..aa44bd1 100644
--- a/tests/standalone/io/file_blocking_lock_test.dart
+++ b/tests/standalone/io/file_blocking_lock_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=file_blocking_lock_script.dart
+
 // This test works by spawning a new process running
 // file_blocking_lock_script.dart, trading the file lock back and forth,
 // writing bytes 1 ... 25 in order to the file. There are checks to ensure
diff --git a/tests/standalone/io/file_lock_test.dart b/tests/standalone/io/file_lock_test.dart
index ca590c1..c24cbe2 100644
--- a/tests/standalone/io/file_lock_test.dart
+++ b/tests/standalone/io/file_lock_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=file_lock_script.dart
+
 import 'dart:async';
 import 'dart:io';
 
diff --git a/tests/standalone/io/file_read_special_device_test.dart b/tests/standalone/io/file_read_special_device_test.dart
index 482ac57..e57f777 100644
--- a/tests/standalone/io/file_read_special_device_test.dart
+++ b/tests/standalone/io/file_read_special_device_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=file_read_stdio_script.dart
+
 import 'package:expect/expect.dart';
 import 'package:path/path.dart';
 import 'dart:io';
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 0519b92..8a8d681 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -4,6 +4,12 @@
 //
 // Dart test program for testing file I/O.
 
+// OtherResources=empty_file
+// OtherResources=file_test.txt
+// OtherResources=fixed_length_file
+// OtherResources=read_as_text.dat
+// OtherResources=readline_test1.dat
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:collection';
@@ -59,7 +65,7 @@
   // Test for file read functionality.
   static void testReadStream() {
     // Read a file and check part of it's contents.
-    String filename = getFilename("bin/file_test.cc");
+    String filename = getFilename("file_test.txt");
     File file = new File(filename);
     Expect.isTrue('$file'.contains(file.path));
     var subscription;
@@ -90,7 +96,7 @@
     asyncTestStarted();
 
     // Read a file.
-    String inFilename = getFilename("tests/vm/data/fixed_length_file");
+    String inFilename = getFilename("fixed_length_file");
     File file;
     int bytesRead;
 
@@ -226,7 +232,7 @@
   static void testRead() {
     asyncStart();
     // Read a file and check part of it's contents.
-    String filename = getFilename("bin/file_test.cc");
+    String filename = getFilename("file_test.txt");
     File file = new File(filename);
     file.open(mode: READ).then((RandomAccessFile file) {
       List<int> buffer = new List<int>(10);
@@ -252,7 +258,7 @@
 
   static void testReadSync() {
     // Read a file and check part of it's contents.
-    String filename = getFilename("bin/file_test.cc");
+    String filename = getFilename("file_test.txt");
     RandomAccessFile raf = (new File(filename)).openSync();
     List<int> buffer = new List<int>(42);
     int bytes_read = 0;
@@ -274,7 +280,7 @@
     Expect.equals(116, buffer[11]);  // represents 't' in the file.
     raf.closeSync();
 
-    filename = getFilename("tests/vm/data/fixed_length_file");
+    filename = getFilename("fixed_length_file");
     File file = new File(filename);
     int len = file.lengthSync();
     int read(int length) {
@@ -296,7 +302,7 @@
   static void testReadWrite() {
     asyncTestStarted();
     // Read a file.
-    String inFilename = getFilename("tests/vm/data/fixed_length_file");
+    String inFilename = getFilename("fixed_length_file");
     final File file = new File(inFilename);
     file.open(mode: READ).then((openedFile) {
       List<int> buffer1 = new List<int>(42);
@@ -437,7 +443,7 @@
 
   static void testReadWriteSync() {
     // Read a file.
-    String inFilename = getFilename("tests/vm/data/fixed_length_file");
+    String inFilename = getFilename("fixed_length_file");
     RandomAccessFile file = (new File(inFilename)).openSync();
     List<int> buffer1 = new List<int>(42);
     int bytes_read = 0;
@@ -475,7 +481,7 @@
 
   static void testReadWriteNoArgsSync() {
     // Read a file.
-    String inFilename = getFilename("tests/vm/data/fixed_length_file");
+    String inFilename = getFilename("fixed_length_file");
     RandomAccessFile file = (new File(inFilename)).openSync();
     List<int> buffer1 = new List<int>(42);
     int bytes_read = 0;
@@ -615,7 +621,7 @@
   // Test for file length functionality.
   static void testLength() {
     asyncTestStarted();
-    String filename = getFilename("tests/vm/data/fixed_length_file");
+    String filename = getFilename("fixed_length_file");
     File file = new File(filename);
     RandomAccessFile openedFile = file.openSync();
     openedFile.length().then((length) {
@@ -628,7 +634,7 @@
   }
 
   static void testLengthSync() {
-    String filename = getFilename("tests/vm/data/fixed_length_file");
+    String filename = getFilename("fixed_length_file");
     File file = new File(filename);
     RandomAccessFile openedFile = file.openSync();
     Expect.equals(42, file.lengthSync());
@@ -639,7 +645,7 @@
   // Test for file position functionality.
   static void testPosition() {
     asyncTestStarted();
-    String filename = getFilename("tests/vm/data/fixed_length_file");
+    String filename = getFilename("fixed_length_file");
     RandomAccessFile input = (new File(filename)).openSync();
     input.position().then((position) {
       Expect.equals(0, position);
@@ -664,7 +670,7 @@
   }
 
   static void testPositionSync() {
-    String filename = getFilename("tests/vm/data/fixed_length_file");
+    String filename = getFilename("fixed_length_file");
     RandomAccessFile input = (new File(filename)).openSync();
     Expect.equals(0, input.positionSync());
     List<int> buffer = new List<int>(100);
@@ -1056,7 +1062,7 @@
 
   static void testReadAsBytes() {
     asyncTestStarted();
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var f = new File(name);
     f.readAsBytes().then((bytes) {
       Expect.isTrue(new String.fromCharCodes(bytes).endsWith("42 bytes."));
@@ -1067,7 +1073,7 @@
 
   static void testReadAsBytesEmptyFile() {
     asyncTestStarted();
-    var name = getFilename("tests/vm/data/empty_file");
+    var name = getFilename("empty_file");
     var f = new File(name);
     f.readAsBytes().then((bytes) {
       Expect.equals(0, bytes.length);
@@ -1076,26 +1082,26 @@
   }
 
   static void testReadAsBytesSync() {
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var bytes = new File(name).readAsBytesSync();
     Expect.isTrue(new String.fromCharCodes(bytes).endsWith("42 bytes."));
     Expect.equals(bytes.length, 42);
   }
 
   static void testReadAsBytesSyncEmptyFile() {
-    var name = getFilename("tests/vm/data/empty_file");
+    var name = getFilename("empty_file");
     var bytes = new File(name).readAsBytesSync();
     Expect.equals(bytes.length, 0);
   }
 
   static void testReadAsText() {
     asyncTestStarted();
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var f = new File(name);
     f.readAsString(encoding: UTF8).then((text) {
       Expect.isTrue(text.endsWith("42 bytes."));
       Expect.equals(42, text.length);
-      var name = getFilename("tests/standalone/io/read_as_text.dat");
+      var name = getFilename("read_as_text.dat");
       var f = new File(name);
       f.readAsString(encoding: UTF8).then((text) {
         Expect.equals(6, text.length);
@@ -1118,7 +1124,7 @@
 
   static void testReadAsTextEmptyFile() {
     asyncTestStarted();
-    var name = getFilename("tests/vm/data/empty_file");
+    var name = getFilename("empty_file");
     var f = new File(name);
     f.readAsString(encoding: UTF8).then((text) {
       Expect.equals(0, text.length);
@@ -1128,11 +1134,11 @@
   }
 
   static void testReadAsTextSync() {
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var text = new File(name).readAsStringSync();
     Expect.isTrue(text.endsWith("42 bytes."));
     Expect.equals(42, text.length);
-    name = getFilename("tests/standalone/io/read_as_text.dat");
+    name = getFilename("read_as_text.dat");
     text = new File(name).readAsStringSync();
     Expect.equals(6, text.length);
     var expected = [955, 120, 46, 32, 120, 10];
@@ -1155,14 +1161,14 @@
   }
 
   static void testReadAsTextSyncEmptyFile() {
-    var name = getFilename("tests/vm/data/empty_file");
+    var name = getFilename("empty_file");
     var text = new File(name).readAsStringSync();
     Expect.equals(0, text.length);
   }
 
   static void testReadAsLines() {
     asyncTestStarted();
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var f = new File(name);
     f.readAsLines(encoding: UTF8).then((lines) {
       Expect.equals(1, lines.length);
@@ -1174,13 +1180,13 @@
   }
 
   static void testReadAsLinesSync() {
-    var name = getFilename("tests/vm/data/fixed_length_file");
+    var name = getFilename("fixed_length_file");
     var lines = new File(name).readAsLinesSync();
     Expect.equals(1, lines.length);
     var line = lines[0];
     Expect.isTrue(line.endsWith("42 bytes."));
     Expect.equals(42, line.length);
-    name = getFilename("tests/standalone/io/readline_test1.dat");
+    name = getFilename("readline_test1.dat");
     lines = new File(name).readAsLinesSync();
     Expect.equals(10, lines.length);
   }
@@ -1398,13 +1404,8 @@
     }
   }
 
-  // Helper method to be able to run the test from the runtime
-  // directory, or the top directory.
   static String getFilename(String path) {
-    var testPath = Platform.script.resolve('../../../$path');
-    return new File.fromUri(testPath).existsSync()
-        ? testPath.toFilePath()
-        : Platform.script.resolve('../../../runtime/$path').toFilePath();
+    return Platform.script.resolve(path).toFilePath();
   }
 
   // Main test entrypoint.
diff --git a/tests/standalone/io/file_test.txt b/tests/standalone/io/file_test.txt
new file mode 100644
index 0000000..4c2c0d1
--- /dev/null
+++ b/tests/standalone/io/file_test.txt
@@ -0,0 +1,63 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "bin/file.h"
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+namespace bin {
+
+// Helper method to be able to run the test from the runtime
+// directory, or the top directory.
+static const char* GetFileName(const char* name) {
+  if (File::Exists(name)) {
+    return name;
+  } else {
+    static const int kRuntimeLength = strlen("runtime/");
+    return name + kRuntimeLength;
+  }
+}
+
+
+TEST_CASE(Read) {
+  const char* kFilename = GetFileName("runtime/bin/file_test.cc");
+  File* file = File::Open(kFilename, File::kRead);
+  EXPECT(file != NULL);
+  char buffer[16];
+  buffer[0] = '\0';
+  EXPECT(file->ReadFully(buffer, 13));  // ReadFully returns true.
+  buffer[13] = '\0';
+  EXPECT_STREQ("// Copyright ", buffer);
+  EXPECT(!file->WriteByte(1));  // Cannot write to a read-only file.
+  file->Release();
+}
+
+
+TEST_CASE(FileLength) {
+  const char* kFilename =
+      GetFileName("runtime/tests/vm/data/fixed_length_file");
+  File* file = File::Open(kFilename, File::kRead);
+  EXPECT(file != NULL);
+  EXPECT_EQ(42, file->Length());
+  file->Release();
+}
+
+
+TEST_CASE(FilePosition) {
+  char buf[42];
+  const char* kFilename =
+      GetFileName("runtime/tests/vm/data/fixed_length_file");
+  File* file = File::Open(kFilename, File::kRead);
+  EXPECT(file != NULL);
+  EXPECT(file->ReadFully(buf, 12));
+  EXPECT_EQ(12, file->Position());
+  EXPECT(file->ReadFully(buf, 6));
+  EXPECT_EQ(18, file->Position());
+  file->Release();
+}
+
+}  // namespace bin
+}  // namespace dart
diff --git a/tests/standalone/io/http_client_stays_alive_test.dart b/tests/standalone/io/http_client_stays_alive_test.dart
index 7355667..171eb38 100644
--- a/tests/standalone/io/http_client_stays_alive_test.dart
+++ b/tests/standalone/io/http_client_stays_alive_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=http_client_stays_alive_test.dart
+
 import 'dart:io';
 
 import "package:async_helper/async_helper.dart";
@@ -39,7 +41,9 @@
     });
 
     var sw = new Stopwatch()..start();
-    var arguments = packageOptions()..add(Platform.script.toString())..add(url);
+    var script = Platform.script.resolve('http_client_stays_alive_test.dart')
+        .toFilePath();
+    var arguments = packageOptions()..add(script)..add(url);
     Process.run(Platform.executable, arguments).then((res) {
       subscription.cancel();
       if (res.exitCode != 0) {
diff --git a/tests/standalone/io/http_server_close_response_after_error_test.dart b/tests/standalone/io/http_server_close_response_after_error_test.dart
index c5cdcec..f768325 100644
--- a/tests/standalone/io/http_server_close_response_after_error_test.dart
+++ b/tests/standalone/io/http_server_close_response_after_error_test.dart
@@ -6,6 +6,7 @@
 // VMOptions=--short_socket_read
 // VMOptions=--short_socket_write
 // VMOptions=--short_socket_read --short_socket_write
+// OtherResources=http_server_close_response_after_error_client.dart
 
 import 'dart:async';
 import 'dart:io';
diff --git a/tests/standalone/io/https_unauthorized_test.dart b/tests/standalone/io/https_unauthorized_test.dart
index f415a83..6bded12 100644
--- a/tests/standalone/io/https_unauthorized_test.dart
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -4,6 +4,10 @@
 //
 // OtherResources=certificates/server_chain.pem
 // OtherResources=certificates/server_key.pem
+// OtherResources=certificates/untrusted_server_chain.pem
+// OtherResources=certificates/untrusted_server_key.pem
+// OtherResources=certificates/trusted_certs.pem
+// OtherResources=https_unauthorized_client.dart
 
 // This test verifies that secure connections that fail due to
 // unauthenticated certificates throw exceptions in HttpClient.
@@ -38,9 +42,7 @@
 }
 
 void main() {
-  var clientScript = Platform.script
-                             .resolve('https_unauthorized_client.dart')
-                             .toFilePath();
+  var clientScript = localFile('https_unauthorized_client.dart');
   Future clientProcess(int port) {
     return Process.run(Platform.executable,
         [clientScript, port.toString()])
diff --git a/tests/standalone/io/print_sync_test.dart b/tests/standalone/io/print_sync_test.dart
index f709df6..f076f41c 100644
--- a/tests/standalone/io/print_sync_test.dart
+++ b/tests/standalone/io/print_sync_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=print_sync_script.dart
+
 import 'dart:io';
 
 import "package:expect/expect.dart";
diff --git a/tests/standalone/io/process_detached_test.dart b/tests/standalone/io/process_detached_test.dart
index 194e756..b72f26a 100644
--- a/tests/standalone/io/process_detached_test.dart
+++ b/tests/standalone/io/process_detached_test.dart
@@ -1,7 +1,9 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-//
+
+// OtherResources=process_detached_script.dart
+
 // Process test program to test detached processes.
 
 import 'dart:async';
diff --git a/tests/standalone/io/process_set_exit_code_test.dart b/tests/standalone/io/process_set_exit_code_test.dart
index 4dded0c..64182c1 100644
--- a/tests/standalone/io/process_set_exit_code_test.dart
+++ b/tests/standalone/io/process_set_exit_code_test.dart
@@ -1,7 +1,9 @@
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-//
+
+// OtherResources=process_set_exit_code_script.dart
+
 // Process test program to test process communication.
 
 library ProcessSetExitCodeTest;
diff --git a/tests/standalone/io/process_shell_test.dart b/tests/standalone/io/process_shell_test.dart
index 91442fe..f1acdc9 100644
--- a/tests/standalone/io/process_shell_test.dart
+++ b/tests/standalone/io/process_shell_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=process_echo_util.dart
+
 import "package:path/path.dart";
 import "package:async_helper/async_helper.dart";
 import "dart:io";
@@ -11,9 +13,9 @@
 void testRunShell() {
   test(args) {
     asyncStart();
-    var path = Platform.script.resolve("process_echo_util.dart").toFilePath();
+    var script = Platform.script.resolve("process_echo_util.dart").toFilePath();
     Process.run(Platform.executable,
-                [path]..addAll(args),
+                [script]..addAll(args),
                 runInShell: true)
         .then((result) {
           if (Platform.operatingSystem == "windows") {
diff --git a/tests/standalone/io/process_sync_test.dart b/tests/standalone/io/process_sync_test.dart
index 7601ddf..4d4b10f 100644
--- a/tests/standalone/io/process_sync_test.dart
+++ b/tests/standalone/io/process_sync_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=process_sync_script.dart
+
 import "package:expect/expect.dart";
 import 'package:path/path.dart';
 import "dart:io";
diff --git a/tests/standalone/io/regress_7191_test.dart b/tests/standalone/io/regress_7191_test.dart
index 5a8a7ea..be15856 100644
--- a/tests/standalone/io/regress_7191_test.dart
+++ b/tests/standalone/io/regress_7191_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=regress_7191_script.dart
+
 // Regression test for http://dartbug.com/7191.
 
 // Starts a sub-process which in turn starts another sub-process and then closes
diff --git a/tests/standalone/io/secure_unauthorized_test.dart b/tests/standalone/io/secure_unauthorized_test.dart
index a600d74..b0d8823 100644
--- a/tests/standalone/io/secure_unauthorized_test.dart
+++ b/tests/standalone/io/secure_unauthorized_test.dart
@@ -2,6 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=certificates/untrusted_server_chain.pem
+// OtherResources=certificates/untrusted_server_key.pem
+// OtherResources=certificates/untrusted_server_chain.pem
+// OtherResources=certificates/trusted_certs.pem
+// OtherResources=secure_unauthorized_client.dart
+
 // This test verifies that failing secure connection attempts always complete
 // their returned future.
 
@@ -32,9 +38,7 @@
 }
 
 void main() {
-  var clientScript = Platform.script
-                             .resolve('secure_unauthorized_client.dart')
-                             .toFilePath();
+  var clientScript = localFile('secure_unauthorized_client.dart');
 
   Future clientProcess(int port) {
     return Process.run(Platform.executable,
diff --git a/tests/standalone/io/signals_test.dart b/tests/standalone/io/signals_test.dart
index a811208..910c2c4 100644
--- a/tests/standalone/io/signals_test.dart
+++ b/tests/standalone/io/signals_test.dart
@@ -2,6 +2,9 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=signal_test_script.dart
+// OtherResources=signals_test_script.dart
+
 import "dart:io";
 import "dart:convert";
 
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index c175383..da24696 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=skipping_dart2js_compilations_helper.dart
+
 /*
  * This test makes sure that the "skipping Dart2Js compilations if the output is
  * already up to date" feature does work as it should.
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index 470f34b..e9e5610 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=stdin_sync_script.dart
+
 import "dart:convert";
 import "dart:io";
 
diff --git a/tests/standalone/io/stdio_implicit_close_test.dart b/tests/standalone/io/stdio_implicit_close_test.dart
index dc67f0e..07e8dc0 100644
--- a/tests/standalone/io/stdio_implicit_close_test.dart
+++ b/tests/standalone/io/stdio_implicit_close_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=stdio_implicit_close_script.dart
+
 import "package:async_helper/async_helper.dart";
 import "package:expect/expect.dart";
 import "dart:convert";
diff --git a/tests/standalone/io/stdio_nonblocking_test.dart b/tests/standalone/io/stdio_nonblocking_test.dart
index 69220e9..d788fb5 100644
--- a/tests/standalone/io/stdio_nonblocking_test.dart
+++ b/tests/standalone/io/stdio_nonblocking_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=stdio_nonblocking_script.dart
+
 import "dart:convert";
 import "dart:io";
 
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index f145e17..c8a29f7 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -243,7 +243,7 @@
 [ $runtime == dart_app ]
 io/stdout_bad_argument_test: Skip # Test exits and so can't generate snapshot.
 
-[ $runtime == dart_precompiled || $runtime == dart_app ]
+[ $runtime == dart_precompiled ]
 full_coverage_test: Skip # Platform.executable
 http_launch_test: Skip # Platform.executable
 io/addlatexhash_test: Skip # Platform.executable
diff --git a/tests/standalone/verbose_gc_to_bmu_script.dart b/tests/standalone/verbose_gc_to_bmu_script.dart
new file mode 100644
index 0000000..b64a4e3
--- /dev/null
+++ b/tests/standalone/verbose_gc_to_bmu_script.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Testing GC, issue 1469.
+
+
+main() {
+  var div;
+  for (int i = 0; i < 200; ++i) {
+    List l = new List(1000000);
+    var m  = 2;
+    div = (_) {
+      var b = l;  // Was causing OutOfMemory.
+    };
+    var lSmall = new List(3);
+    // Circular reference between new and old gen objects.
+    lSmall[0] = l;
+    l[0] = lSmall;
+  }
+}
diff --git a/tests/standalone/verbose_gc_to_bmu_test.dart b/tests/standalone/verbose_gc_to_bmu_test.dart
index 1442739..92d41a5 100644
--- a/tests/standalone/verbose_gc_to_bmu_test.dart
+++ b/tests/standalone/verbose_gc_to_bmu_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// OtherResources=verbose_gc_to_bmu_script.dart
+
 // This test forks a second vm process that runs the BMU tool and verifies that
 // it produces some output. This test is mainly here to ensure that the BMU
 // tool compiles and runs.
@@ -13,13 +15,15 @@
 import "package:path/path.dart";
 
 // Tool script relative to the path of this test.
-var toolScript = "../../runtime/tools/verbose_gc_to_bmu.dart";
+var toolScript = Uri.parse(Platform.executable)
+    .resolve("../../runtime/tools/verbose_gc_to_bmu.dart").toFilePath();
 
 // Target script relative to this test.
-var targetScript = "../language/gc_test.dart";
+var targetScript = Platform.script
+    .resolve("verbose_gc_to_bmu_script.dart").toFilePath();
 const minOutputLines = 20;
 
-void checkExitCode(exitCode) {
+void checkExitCode(targetResult) {
   if (exitCode != 0) {
     print("Process terminated with exit code ${exitCode}.");
     exit(-1);
@@ -28,14 +32,11 @@
 
 void main() {
   // Compute paths for tool and target relative to the path of this script.
-  var scriptDir = dirname(Platform.script.toFilePath());
-  var targPath = normalize(join(scriptDir, targetScript));
   var targetResult =
-      Process.runSync(Platform.executable, ["--verbose_gc", targPath]);
-  checkExitCode(targetResult.exitCode);
+      Process.runSync(Platform.executable, ["--verbose_gc", targetScript]);
+  checkExitCode(targetResult);
   var gcLog = targetResult.stderr;
-  var toolPath = normalize(join(scriptDir, toolScript));
-  Process.start(Platform.executable, [toolPath]).then((Process process) {
+  Process.start(Platform.executable, [toolScript]).then((Process process) {
     // Feed the GC log of the target to the BMU tool.
     process.stdin.write(gcLog);
     process.stdin.close();
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index acd7a5b..6ad1ebf 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -25,5 +25,9 @@
 recursive_import_test: Skip # Running dart2js under frequent reloads is slow.
 dummy_compiler_test: Skip # Running dart2js under frequent reloads is slow.
 
+[ $runtime == dartium ]
+dummy_compiler_test: Skip # Issue 27744
+recursive_import_test: Skip # Issue 27744
+
 [ $builder_tag == asan ]
 recursive_import_test: Skip # Issue 27441
diff --git a/tools/VERSION b/tools/VERSION
index d489bbc..0993f30 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,5 +28,5 @@
 MAJOR 1
 MINOR 21
 PATCH 0
-PRERELEASE 3
+PRERELEASE 4
 PRERELEASE_PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 54cb4dd..25c7aba 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -171,8 +171,10 @@
            join(lib, '_internal', 'strong.sum'))
 
 def CopyDevCompilerSdk(home, lib):
+  copyfile(join(home, 'pkg', 'dev_compiler', 'lib', 'sdk', 'ddc_sdk.sum'),
+           join(lib, '_internal', 'ddc_sdk.sum'))
   copytree(join(home, 'pkg', 'dev_compiler', 'lib', 'js'),
-           join(lib, '_internal', 'dev_compiler'))
+           join(lib, 'dev_compiler'))
 
 def Main():
   # Pull in all of the gypi files which will be munged into the sdk.
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 60e81ca..cafe953 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -9,7 +9,7 @@
 
 vars.update({
   "dartium_chromium_commit": "7558afb6379171d7f96b2db68ae9d2b64b2c5544",
-  "dartium_webkit_commit": "4cc16a03bf8c40ec67bff039b7fc80ed608d7604",
+  "dartium_webkit_commit": "e46ac6cf905ae6be30852fbee231cfd385c24420",
   "chromium_base_revision": "338390",
 
   # We use mirrors of all github repos to guarantee reproducibility and
diff --git a/tools/gn.py b/tools/gn.py
index 6155b8d..1ee3d33 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -72,14 +72,10 @@
   gn_args['target_cpu'] = target_cpu_for_arch(arch, target_os)
   gn_args['host_cpu'] = host_cpu_for_arch(arch)
 
-  # TODO(zra): This is for the observatory, which currently builds using the
-  # checked-in sdk. If/when the observatory no longer builds with the
-  # checked-in sdk, this can be removed.
-  pub = 'pub'
-  if host_os == 'win':
-    pub = pub + ".bat"
-  gn_args['dart_host_pub_exe'] = os.path.join(
-      DART_ROOT, 'tools', 'sdks', host_os, 'dart-sdk', 'bin', pub)
+  # See: runtime/observatory/BUILD.gn.
+  # This allows the standalone build of the observatory to fall back on
+  # dart_bootstrap if the prebuilt SDK doesn't work.
+  gn_args['dart_host_pub_exe'] = ""
 
   # For Fuchsia support, the default is to not compile in the root
   # certificates.
diff --git a/tools/patch_sdk.py b/tools/patch_sdk.py
index faa2bd0..f87addb 100755
--- a/tools/patch_sdk.py
+++ b/tools/patch_sdk.py
@@ -11,6 +11,18 @@
 
 usage = """patch_sdk.py [options]"""
 
+def DisplayBootstrapWarning():
+  print """\
+
+
+WARNING: Your system cannot run the checked-in Dart SDK. Using the
+bootstrap Dart executable will make debug builds slow.
+Please see the Wiki for instructions on replacing the checked-in Dart SDK.
+
+https://github.com/dart-lang/sdk/wiki/The-checked-in-SDK-in-tools
+
+"""
+
 def BuildArguments():
   result = argparse.ArgumentParser(usage=usage)
   result.add_argument("--dart-executable", help="dart executable", default=None)
@@ -20,12 +32,17 @@
   # Parse the options.
   parser = BuildArguments()
   (options, args) = parser.parse_known_args()
-  if options.dart_executable is not None:
+  if utils.CheckedInSdkCheckExecutable():
+    options.dart_executable = utils.CheckedInSdkExecutable()
+  elif options.dart_executable is not None:
+    DisplayBootstrapWarning()
     options.dart_executable = os.path.abspath(options.dart_executable)
   else:
-    options.dart_executable = os.path.join(utils.CheckedInSdkPath(), 'bin', 'dart')
+    print >> sys.stderr, 'ERROR: cannot locate dart executable'
+    return -1
   dart_file = os.path.join(os.path.dirname(__file__), 'patch_sdk.dart')
-  subprocess.check_call([options.dart_executable, dart_file] + args);
+  subprocess.check_call([options.dart_executable, dart_file] + args)
+  return 0
 
 if __name__ == '__main__':
-  main()
+  sys.exit(main())
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 3613dcd..868c74c 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -228,7 +228,7 @@
       Map<String, String> environmentOverrides) {
     var extraArguments = [
       '--sdk',
-      '$buildDir/obj/gen/patched_sdk',
+      '$buildDir/patched_sdk',
       '--link',
       '--target=vm',
       '--out',
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 9b1bdbe..34aaf88 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -9,6 +9,8 @@
   training_args = [
     "--dart-sdk",
     rebase_path("../../sdk"),
+    "--dart-sdk-summary",
+    rebase_path("../../pkg/dev_compiler/lib/sdk/ddc_sdk.sum"),
     "--help",
   ]
   inputs = exec_script("../../tools/list_dart_files.py",
diff --git a/utils/invoke_dart.gni b/utils/invoke_dart.gni
index ad3a7f8..bc4747a 100644
--- a/utils/invoke_dart.gni
+++ b/utils/invoke_dart.gni
@@ -4,6 +4,12 @@
 
 _dart_root = rebase_path("..")
 
+if (defined(is_win) && is_win) {
+  dart_executable_suffix = ".exe"
+} else {
+  dart_executable_suffix = ""
+}
+
 template("invoke_dart") {
   assert(defined(invoker.outputs), "invoke_dart must specify outputs")
   extra_deps = []
@@ -29,11 +35,7 @@
     dart_out_dir =
         get_label_info("$relative_dart_root/runtime/bin:dart($host_toolchain)",
                        "root_out_dir")
-    if (is_win) {
-      dart = rebase_path("$dart_out_dir/dart.exe")
-    } else {
-      dart = rebase_path("$dart_out_dir/dart")
-    }
+    dart = rebase_path("$dart_out_dir/dart$dart_executable_suffix")
 
     inputs = [ dart ] + extra_inputs