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, ¬_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, ¬_inf, Assembler::kNearJump);
- __ LoadObject(result, Bool::True());
- __ jmp(&done);
-
- __ Bind(¬_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, ¬_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), ¬_inf);
-
- __ LoadObject(result, Bool::True());
- __ b(&done);
-
- __ Bind(¬_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(¬_double, NE);
+
+ __ LoadIsolate(R0);
+ __ LoadFromOffset(kWord, R0, R0, Isolate::object_store_offset());
+ __ LoadFromOffset(kWord, R0, R0, ObjectStore::double_type_offset());
+ __ Ret();
+
+ __ Bind(¬_double);
+ JumpIfNotInteger(assembler, R1, R0, ¬_integer);
+ __ LoadIsolate(R0);
+ __ LoadFromOffset(kWord, R0, R0, Isolate::object_store_offset());
+ __ LoadFromOffset(kWord, R0, R0, ObjectStore::int_type_offset());
+ __ Ret();
+
+ __ Bind(¬_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(¬_equal, HI);
+
+ // Check if both are integers.
+ JumpIfNotInteger(assembler, R1, R0, ¬_integer);
+ JumpIfInteger(assembler, R2, R0, &equal);
+ __ b(¬_equal);
+
+ __ Bind(¬_integer);
+ // Check if both are strings.
+ JumpIfNotString(assembler, R1, R0, ¬_equal);
+ JumpIfString(assembler, R2, R0, &equal);
+
+ // Neither strings nor integers and have different class ids.
+ __ Bind(¬_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(¬_double, NE);
+
+ __ LoadIsolate(R0);
+ __ LoadFromOffset(R0, R0, Isolate::object_store_offset());
+ __ LoadFromOffset(R0, R0, ObjectStore::double_type_offset());
+ __ ret();
+
+ __ Bind(¬_double);
+ JumpIfNotInteger(assembler, R1, R0, ¬_integer);
+ __ LoadIsolate(R0);
+ __ LoadFromOffset(R0, R0, Isolate::object_store_offset());
+ __ LoadFromOffset(R0, R0, ObjectStore::int_type_offset());
+ __ ret();
+
+ __ Bind(¬_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(¬_equal, HI);
+
+ // Check if both are integers.
+ JumpIfNotInteger(assembler, R1, R0, ¬_integer);
+ JumpIfInteger(assembler, R2, R0, &equal);
+ __ b(¬_equal);
+
+ __ Bind(¬_integer);
+ // Check if both are strings.
+ JumpIfNotString(assembler, R1, R0, ¬_equal);
+ JumpIfString(assembler, R2, R0, &equal);
+
+ // Neither strings nor integers and have different class ids.
+ __ Bind(¬_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, ¬_double);
+
+ __ LoadIsolate(EAX);
+ __ movl(EAX, Address(EAX, Isolate::object_store_offset()));
+ __ movl(EAX, Address(EAX, ObjectStore::double_type_offset()));
+ __ ret();
+
+ __ Bind(¬_double);
+ // If object is an integer (smi, mint or bigint) return int type.
+ __ movl(EAX, EDI);
+ JumpIfNotInteger(assembler, EAX, ¬_integer);
+
+ __ LoadIsolate(EAX);
+ __ movl(EAX, Address(EAX, Isolate::object_store_offset()));
+ __ movl(EAX, Address(EAX, ObjectStore::int_type_offset()));
+ __ ret();
+
+ __ Bind(¬_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, ¬_equal);
+
+ __ movl(EAX, EDI);
+ JumpIfNotInteger(assembler, EAX, ¬_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(¬_equal);
+
+ __ Bind(¬_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, ¬_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(¬_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), ¬_double);
+ // Object is a double.
+ __ LoadIsolate(T1);
+ __ LoadFromOffset(T1, T1, Isolate::object_store_offset());
+ __ LoadFromOffset(V0, T1, ObjectStore::double_type_offset());
+ __ Ret();
+
+ __ Bind(¬_double);
+ JumpIfNotInteger(assembler, T1, T2, ¬_integer);
+ // Object is an integer.
+ __ LoadIsolate(T1);
+ __ LoadFromOffset(T1, T1, Isolate::object_store_offset());
+ __ LoadFromOffset(V0, T1, ObjectStore::int_type_offset());
+ __ Ret();
+
+ __ Bind(¬_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), ¬_equal);
+
+ // Check if both are integers.
+ JumpIfNotInteger(assembler, T1, T0, ¬_integer);
+ JumpIfInteger(assembler, T2, T0, &equal);
+ __ b(¬_equal);
+
+ __ Bind(¬_integer);
+ // Check if both are strings.
+ JumpIfNotString(assembler, T1, T0, ¬_equal);
+ JumpIfString(assembler, T2, T0, &equal);
+
+ // Neither strings nor integers and have different class ids.
+ __ Bind(¬_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, ¬_double);
+
+ __ LoadIsolate(RAX);
+ __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+ __ movq(RAX, Address(RAX, ObjectStore::double_type_offset()));
+ __ ret();
+
+ __ Bind(¬_double);
+ // If object is an integer (smi, mint or bigint) return int type.
+ __ movl(RAX, RCX);
+ JumpIfNotInteger(assembler, RAX, ¬_integer);
+
+ __ LoadIsolate(RAX);
+ __ movq(RAX, Address(RAX, Isolate::object_store_offset()));
+ __ movq(RAX, Address(RAX, ObjectStore::int_type_offset()));
+ __ ret();
+
+ __ Bind(¬_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, ¬_equal);
+
+ __ movq(RAX, RCX);
+ JumpIfNotInteger(assembler, RAX, ¬_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(¬_equal);
+
+ __ Bind(¬_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, ¬_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(¬_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