Version 0.5.18.0
svn merge -r 23890:24018 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@24022 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index 5d3392c..c7360e9 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -104,7 +104,13 @@
cmds = [sys.executable, toolsBuildScript,
'--mode=' + mode, '--revision=' + version,
'--name=' + name, '--out=' + outdir]
- local_env = os.environ
+ local_env = os.environ.copy()
+ # The buildbot sets AWS_CREDENTIAL_FILE/BOTO_CONFIG to the chromium specific
+ # file, we use the one in home.
+ if 'BOTO_CONFIG' in local_env:
+ del local_env['BOTO_CONFIG']
+ if 'AWS_CREDENTIAL_FILE' in local_env:
+ del local_env['AWS_CREDENTIAL_FILE']
#if 'linux' in name:
# javahome = os.path.join(os.path.expanduser('~'), 'jdk1.6.0_25')
# local_env['JAVA_HOME'] = javahome
diff --git a/pkg/docgen/README.md b/pkg/docgen/README.md
new file mode 100644
index 0000000..a26d1e9
--- /dev/null
+++ b/pkg/docgen/README.md
@@ -0,0 +1,11 @@
+A documentation generator for Dart.
+
+The docgen tool takes in a library as input and produces documentation
+for it as well as all libraries it imports and uses.
+
+This outputs information about all classes, variables, functions, and
+methods defined in the library and its imported libraries.
+
+## USAGE
+
+ dart docgen.dart path/to/file.dart
\ No newline at end of file
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
new file mode 100644
index 0000000..308df28
--- /dev/null
+++ b/pkg/docgen/bin/docgen.dart
@@ -0,0 +1,393 @@
+// 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.
+
+/**
+ * The docgen tool takes in a library as input and produces documentation
+ * for the library as well as all libraries it imports and uses. The tool can
+ * be run by passing in the path to a .dart file like this:
+ *
+ * ./dart docgen.dart path/to/file.dart
+ *
+ * This outputs information about all classes, variables, functions, and
+ * methods defined in the library and its imported libraries.
+ */
+library docgen;
+
+// TODO(tmandel): Use 'package:' references for imports with relative paths.
+import 'dart:io';
+import 'dart:json';
+import 'dart:async';
+import '../lib/dart2yaml.dart';
+import '../lib/src/dart2js_mirrors.dart';
+import 'package:markdown/markdown.dart' as markdown;
+import '../../args/lib/args.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
+
+/**
+ * Entry function to create YAML documentation from Dart files.
+ */
+void main() {
+ // TODO(tmandel): Use args library once flags are clear.
+ Options opts = new Options();
+ Docgen docgen = new Docgen();
+
+ if (opts.arguments.length > 0) {
+ List<Path> libraries = [new Path(opts.arguments[0])];
+ Path sdkDirectory = new Path("../../../sdk/");
+ var workingMirrors = analyze(libraries, sdkDirectory,
+ options: ['--preserve-comments', '--categories=Client,Server']);
+ workingMirrors.then( (MirrorSystem mirrorSystem) {
+ var mirrors = mirrorSystem.libraries.values;
+ if (mirrors.isEmpty) {
+ print("no LibraryMirrors");
+ } else {
+ docgen.libraries = mirrors;
+ docgen.documentLibraries();
+ }
+ });
+ }
+}
+
+/**
+ * This class documents a list of libraries.
+ */
+class Docgen {
+
+ /// Libraries to be documented.
+ List<LibraryMirror> _libraries;
+
+ /// Saves list of libraries for Docgen object.
+ void set libraries(value) => _libraries = value;
+
+ /// Current library being documented to be used for comment links.
+ LibraryMirror _currentLibrary;
+
+ /// Current class being documented to be used for comment links.
+ ClassMirror _currentClass;
+
+ /// Current member being documented to be used for comment links.
+ MemberMirror _currentMember;
+
+ /// Should the output file type be JSON?
+ // TODO(tmandel): Add flag to allow for output to JSON.
+ bool outputToJson = false;
+
+ /// Resolves reference links
+ markdown.Resolver linkResolver;
+
+ /**
+ * Docgen constructor initializes the link resolver for markdown parsing.
+ */
+ Docgen() {
+ this.linkResolver = (name) =>
+ fixReference(name, _currentLibrary, _currentClass, _currentMember);
+ }
+
+ /**
+ * Creates documentation for filtered libraries.
+ */
+ void documentLibraries() {
+ //TODO(tmandel): Filter libraries and determine output type using flags.
+ _libraries.forEach((library) {
+ _currentLibrary = library;
+ var result = new Library(library.qualifiedName, _getComment(library),
+ _getVariables(library.variables), _getMethods(library.functions),
+ _getClasses(library.classes));
+ if (outputToJson) {
+ _writeToFile(stringify(result.toMap()), "${result.name}.json");
+ } else {
+ _writeToFile(getYamlString(result.toMap()), "${result.name}.yaml");
+ }
+ });
+ }
+
+ /**
+ * Returns any documentation comments associated with a mirror with
+ * simple markdown converted to html.
+ */
+ String _getComment(DeclarationMirror mirror) {
+ String commentText;
+ mirror.metadata.forEach((metadata) {
+ if (metadata is CommentInstanceMirror) {
+ CommentInstanceMirror comment = metadata;
+ if (comment.isDocComment) {
+ if (commentText == null) {
+ commentText = comment.trimmedText;
+ } else {
+ commentText = "$commentText ${comment.trimmedText}";
+ }
+ }
+ }
+ });
+ return commentText == null ? "" :
+ markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver);
+ }
+
+ /**
+ * Converts all [_] references in comments to <code>_</code>.
+ */
+ // TODO(tmandel): Create proper links for [_] style markdown based
+ // on scope once layout of viewer is finished.
+ markdown.Node fixReference(String name, LibraryMirror currentLibrary,
+ ClassMirror currentClass, MemberMirror currentMember) {
+ return new markdown.Element.text('code', name);
+ }
+
+ /**
+ * Returns a map of [Variable] objects constructed from inputted mirrors.
+ */
+ Map<String, Variable> _getVariables(Map<String, VariableMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
+ _currentMember = mirror;
+ data[mirrorName] = new Variable(mirrorName, mirror.isFinal,
+ mirror.isStatic, mirror.type.toString(), _getComment(mirror));
+ });
+ return data;
+ }
+
+ /**
+ * Returns a map of [Method] objects constructed from inputted mirrors.
+ */
+ Map<String, Method> _getMethods(Map<String, MethodMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
+ _currentMember = mirror;
+ data[mirrorName] = new Method(mirrorName, mirror.isSetter,
+ mirror.isGetter, mirror.isConstructor, mirror.isOperator,
+ mirror.isStatic, mirror.returnType.toString(), _getComment(mirror),
+ _getParameters(mirror.parameters));
+ });
+ return data;
+ }
+
+ /**
+ * Returns a map of [Class] objects constructed from inputted mirrors.
+ */
+ Map<String, Class> _getClasses(Map<String, ClassMirror> mirrorMap) {
+ var data = {};
+ mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
+ _currentClass = mirror;
+ var superclass;
+ if (mirror.superclass != null) {
+ superclass = mirror.superclass.qualifiedName;
+ }
+ var interfaces =
+ mirror.superinterfaces.map((interface) => interface.qualifiedName);
+ data[mirrorName] = new Class(mirrorName, superclass, mirror.isAbstract,
+ mirror.isTypedef, _getComment(mirror), interfaces,
+ _getVariables(mirror.variables), _getMethods(mirror.methods));
+ });
+ return data;
+ }
+
+ /**
+ * Returns a map of [Parameter] objects constructed from inputted mirrors.
+ */
+ Map<String, Parameter> _getParameters(List<ParameterMirror> mirrorList) {
+ var data = {};
+ mirrorList.forEach((ParameterMirror mirror) {
+ _currentMember = mirror;
+ data[mirror.simpleName] = new Parameter(mirror.simpleName,
+ mirror.isOptional, mirror.isNamed, mirror.hasDefaultValue,
+ mirror.type.toString(), mirror.defaultValue);
+ });
+ return data;
+ }
+}
+
+/**
+ * Transforms the map by calling toMap on each value in it.
+ */
+Map recurseMap(Map inputMap) {
+ var outputMap = {};
+ inputMap.forEach((key, value) {
+ outputMap[key] = value.toMap();
+ });
+ return outputMap;
+}
+
+/**
+ * A class containing contents of a Dart library.
+ */
+class Library {
+
+ /// Documentation comment with converted markdown.
+ String comment;
+
+ /// Top-level variables in the library.
+ Map<String, Variable> variables;
+
+ /// Top-level functions in the library.
+ Map<String, Method> functions;
+
+ /// Classes defined within the library
+ Map<String, Class> classes;
+
+ String name;
+
+ Library(this.name, this.comment, this.variables,
+ this.functions, this.classes);
+
+ /// Generates a map describing the [Library] object.
+ Map toMap() {
+ var libraryMap = {};
+ libraryMap["name"] = name;
+ libraryMap["comment"] = comment;
+ libraryMap["variables"] = recurseMap(variables);
+ libraryMap["functions"] = recurseMap(functions);
+ libraryMap["classes"] = recurseMap(classes);
+ return libraryMap;
+ }
+}
+
+/**
+ * A class containing contents of a Dart class.
+ */
+// TODO(tmandel): Figure out how to do typedefs (what is needed)
+class Class {
+
+ /// Documentation comment with converted markdown.
+ String comment;
+
+ /// List of the names of interfaces that this class implements.
+ List<String> interfaces;
+
+ /// Top-level variables in the class.
+ Map<String, Variable> variables;
+
+ /// Methods in the class.
+ Map<String, Method> methods;
+
+ String name;
+ String superclass;
+ bool isAbstract;
+ bool isTypedef;
+
+ Class(this.name, this.superclass, this.isAbstract, this.isTypedef,
+ this.comment, this.interfaces, this.variables, this.methods);
+
+ /// Generates a map describing the [Class] object.
+ Map toMap() {
+ var classMap = {};
+ classMap["name"] = name;
+ classMap["comment"] = comment;
+ classMap["superclass"] = superclass;
+ classMap["abstract"] = isAbstract.toString();
+ classMap["typedef"] = isTypedef.toString();
+ classMap["implements"] = new List.from(interfaces);
+ classMap["variables"] = recurseMap(variables);
+ classMap["methods"] = recurseMap(methods);
+ return classMap;
+ }
+}
+
+/**
+ * A class containing properties of a Dart variable.
+ */
+class Variable {
+
+ /// Documentation comment with converted markdown.
+ String comment;
+
+ String name;
+ bool isFinal;
+ bool isStatic;
+ String type;
+
+ Variable(this.name, this.isFinal, this.isStatic, this.type, this.comment);
+
+ /// Generates a map describing the [Variable] object.
+ Map toMap() {
+ var variableMap = {};
+ variableMap["name"] = name;
+ variableMap["comment"] = comment;
+ variableMap["final"] = isFinal.toString();
+ variableMap["static"] = isStatic.toString();
+ variableMap["type"] = type;
+ return variableMap;
+ }
+}
+
+/**
+ * A class containing properties of a Dart method.
+ */
+class Method {
+
+ /// Documentation comment with converted markdown.
+ String comment;
+
+ /// Parameters for this method.
+ Map<String, Parameter> parameters;
+
+ String name;
+ bool isSetter;
+ bool isGetter;
+ bool isConstructor;
+ bool isOperator;
+ bool isStatic;
+ String returnType;
+
+ Method(this.name, this.isSetter, this.isGetter, this.isConstructor,
+ this.isOperator, this.isStatic, this.returnType, this.comment,
+ this.parameters);
+
+ /// Generates a map describing the [Method] object.
+ Map toMap() {
+ var methodMap = {};
+ methodMap["name"] = name;
+ methodMap["comment"] = comment;
+ methodMap["type"] = isSetter ? "setter" : isGetter ? "getter" :
+ isOperator ? "operator" : isConstructor ? "constructor" : "method";
+ methodMap["static"] = isStatic.toString();
+ methodMap["return"] = returnType;
+ methodMap["parameters"] = recurseMap(parameters);
+ return methodMap;
+ }
+}
+
+/**
+ * A class containing properties of a Dart method/function parameter.
+ */
+class Parameter {
+
+ String name;
+ bool isOptional;
+ bool isNamed;
+ bool hasDefaultValue;
+ String type;
+ String defaultValue;
+
+ Parameter(this.name, this.isOptional, this.isNamed, this.hasDefaultValue,
+ this.type, this.defaultValue);
+
+ /// Generates a map describing the [Parameter] object.
+ Map toMap() {
+ var parameterMap = {};
+ parameterMap["name"] = name;
+ parameterMap["optional"] = isOptional.toString();
+ parameterMap["named"] = isNamed.toString();
+ parameterMap["default"] = hasDefaultValue.toString();
+ parameterMap["type"] = type;
+ parameterMap["value"] = defaultValue;
+ return parameterMap;
+ }
+}
+
+/**
+ * Writes text to a file in the 'docs' directory.
+ */
+void _writeToFile(String text, String filename) {
+ Directory dir = new Directory('docs');
+ if (!dir.existsSync()) {
+ dir.createSync();
+ }
+ File file = new File('docs/$filename');
+ if (!file.exists()) {
+ file.createSync();
+ }
+ file.openSync();
+ file.writeAsString(text);
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/docgen/examples/test.dart b/pkg/docgen/example/test.dart
similarity index 73%
rename from sdk/lib/_internal/docgen/examples/test.dart
rename to pkg/docgen/example/test.dart
index 026663e..d93b63f 100755
--- a/sdk/lib/_internal/docgen/examples/test.dart
+++ b/pkg/docgen/example/test.dart
@@ -1,3 +1,7 @@
+// 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.
+
/**
* This library is used solely for testing during development and is not
* intended to be run by the testing machines.
@@ -6,6 +10,7 @@
library DummyLibrary;
import 'dart:json';
+import 'dart:math';
/// Doc comment for top-level variable.
int _variable1 = 0;
@@ -24,6 +29,9 @@
*/
class A implements B {
+ /**
+ * Markdown _test_ for **class** [A]
+ */
int _someNumber;
A() {
diff --git a/sdk/lib/_internal/docgen/lib/dart2yaml.dart b/pkg/docgen/lib/dart2yaml.dart
similarity index 81%
rename from sdk/lib/_internal/docgen/lib/dart2yaml.dart
rename to pkg/docgen/lib/dart2yaml.dart
index a8be283..a03c7f1 100644
--- a/sdk/lib/_internal/docgen/lib/dart2yaml.dart
+++ b/pkg/docgen/lib/dart2yaml.dart
@@ -1,3 +1,7 @@
+// 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.
+
/**
* This library is used to convert data from a map to a YAML string.
*/
@@ -45,14 +49,10 @@
}
/**
- * Writes to a StringBuffer the correct output for the inputted element.
+ * Returns an escaped String form of the inputted element.
*/
String _processElement(var element) {
- if (element.toString().contains("\"")) {
- return "$element\n";
- } else {
- return "\"$element\"\n";
- }
+ return "\"${element.toString().replaceAll("\"", "\\\"")}\"\n";
}
/**
diff --git a/sdk/lib/_internal/docgen/lib/src/dart2js_mirrors.dart b/pkg/docgen/lib/src/dart2js_mirrors.dart
similarity index 85%
rename from sdk/lib/_internal/docgen/lib/src/dart2js_mirrors.dart
rename to pkg/docgen/lib/src/dart2js_mirrors.dart
index 1885363..cee8fbe 100644
--- a/sdk/lib/_internal/docgen/lib/src/dart2js_mirrors.dart
+++ b/pkg/docgen/lib/src/dart2js_mirrors.dart
@@ -11,14 +11,14 @@
import 'dart:async' show Future;
import 'dart:io' show Path;
-import '../../../compiler/compiler.dart' as api;
-import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js
- show analyze, Dart2JsMirrorSystem;
-import '../../../compiler/implementation/mirrors/mirrors.dart'
+import '../../../../sdk/lib/_internal/compiler/compiler.dart' as api;
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart'
+ as dart2js show analyze, Dart2JsMirrorSystem;
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart'
show MirrorSystem;
-import '../../../compiler/implementation/source_file_provider.dart'
+import '../../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart'
show FormattingDiagnosticHandler, SourceFileProvider;
-import '../../../compiler/implementation/filenames.dart'
+import '../../../../sdk/lib/_internal/compiler/implementation/filenames.dart'
show appendSlash, currentDirectory;
// TODO(johnniwinther): Support client configurable providers.
diff --git a/pkg/docgen/pubspec.yaml b/pkg/docgen/pubspec.yaml
new file mode 100644
index 0000000..697f405
--- /dev/null
+++ b/pkg/docgen/pubspec.yaml
@@ -0,0 +1,4 @@
+name: docgen
+description: A documentation generator for the Dart repository.
+dependencies:
+ markdown: any
\ No newline at end of file
diff --git a/pkg/pathos/README.md b/pkg/pathos/README.md
index 66f40b1..e67fc5e 100644
--- a/pkg/pathos/README.md
+++ b/pkg/pathos/README.md
@@ -4,9 +4,9 @@
joining, splitting, normalizing, etc.
We've tried very hard to make this library do the "right" thing on whatever
-platform you run it on. When you use the top-level functions, it will assume
-the host OS's path style and work with that. If you want to specifically work
-with paths of a specific style, you can construct a `path.Builder` for that
+platform you run it on. When you use the top-level functions, it will assume the
+current platform's path style and work with that. If you want to specifically
+work with paths of a specific style, you can construct a `path.Builder` for that
style.
## Using
@@ -20,16 +20,18 @@
The most common way to use the library is through the top-level functions.
These manipulate path strings based on your current working directory and the
-path style (POSIX or Windows) of the host operating system.
+path style (POSIX, Windows, or URLs) of the host platform.
### String get current
-Gets the path to the current working directory.
+Gets the path to the current working directory. In the browser, this means the
+current URL. When using dart2js, this currently returns `.` due to technical
+constraints. In the future, it will return the current URL.
### String get separator
-Gets the path separator for the current platform. On Mac and Linux, this
-is `/`. On Windows, it's `\`.
+Gets the path separator for the current platform. On Mac, Linux, and the
+browser, this is `/`. On Windows, it's `\`.
### String absolute(String path)
@@ -100,12 +102,23 @@
path.rootPrefix(r'path\to\foo'); // -> ''
path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
+ // URL
+ path.rootPrefix('path/to/foo'); // -> ''
+ path.rootPrefix('http://dartlang.org/path/to/foo');
+ // -> 'http://dartlang.org'
+
### bool isAbsolute(String path)
-Returns `true` if [path] is an absolute path and `false` if it is a
-relative path. On POSIX systems, absolute paths start with a `/` (forward
-slash). On Windows, an absolute path starts with `\\`, or a drive letter
-followed by `:/` or `:\`.
+Returns `true` if [path] is an absolute path and `false` if it is a relative
+path. On POSIX systems, absolute paths start with a `/` (forward slash). On
+Windows, an absolute path starts with `\\`, or a drive letter followed by `:/`
+or `:\`. For URLs, absolute paths either start with a protocol and optional
+hostname (e.g. `http://dartlang.org`, `file://`) or with a `/`.
+
+URLs that start with `/` are known as "root-relative", since they're relative to
+the root of the current URL. Since root-relative paths are still absolute in
+every other sense, [isAbsolute] will return true for them. They can be detected
+using [isRootRelative].
### bool isRelative(String path)
@@ -114,6 +127,16 @@
Windows, an absolute path starts with `\\`, or a drive letter followed by
`:/` or `:\`.
+### bool isRootRelative(String path)
+
+Returns `true` if [path] is a root-relative path and `false` if it's not. URLs
+that start with `/` are known as "root-relative", since they're relative to the
+root of the current URL. Since root-relative paths are still absolute in every
+other sense, [isAbsolute] will return true for them. They can be detected using
+[isRootRelative].
+
+No POSIX and Windows paths are root-relative.
+
### String join(String part1, [String part2, String part3, ...])
Joins the given path parts into a single path using the current platform's
@@ -149,6 +172,10 @@
// Windows
path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
+ // Browser
+ path.split('http://dartlang.org/path/to/foo');
+ // -> ['http://dartlang.org', 'path', 'to', 'foo']
+
### String normalize(String path)
Normalizes [path], simplifying it by handling `..`, and `.`, and
@@ -176,8 +203,13 @@
Since there is no relative path from one drive letter to another on Windows,
this will return an absolute path in that case.
+ // Windows
path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other'
+ // URL
+ path.relative('http://dartlang.org', from: 'http://pub.dartlang.org');
+ // -> 'http://dartlang.org'
+
### String withoutExtension(String path)
Removes a trailing extension from the last part of [path].
@@ -234,6 +266,11 @@
builder.rootPrefix(r'path\to\foo'); // -> ''
builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
+ // URL
+ builder.rootPrefix('path/to/foo'); // -> ''
+ builder.rootPrefix('http://dartlang.org/path/to/foo');
+ // -> 'http://dartlang.org'
+
### String resolve(String part1, [String part2, String part3, ...])
Creates a new path by appending the given path parts to the [root].
@@ -244,9 +281,9 @@
## The path.Style class
-The path library can work with two different "flavors" of path: POSIX and
-Windows. The differences between these are encapsulated by the `path.Style`
-enum class. There are two instances of it:
+The path library can work with three different "flavors" of path: POSIX,
+Windows, and URLs. The differences between these are encapsulated by the
+`path.Style` enum class. There are three instances of it:
### path.Style.posix
@@ -259,16 +296,22 @@
a drive letter followed by a colon (example, "C:") or two backslashes
("\\") for UNC paths.
+### path.Style.url
+
+URLs aren't filesystem paths, but they're supported by Pathos to make it easier
+to manipulate URL paths in the browser.
+
+URLs use "/" (forward slash) as separators. Absolute paths either start with a
+protocol and optional hostname (e.g. `http://dartlang.org`, `file://`) or with
+"/".
+
## FAQ
### Where can I use this?
-Currently, Dart has no way of encapsulating configuration-specific code.
-Ideally, this library would be able to import dart:io when that's available or
-dart:html when that is. That would let it seamlessly work on both.
-
-Until then, this only works on the standalone VM. It's API is not coupled to
-dart:io, but it uses it internally to determine the current working directory.
+Pathos runs on the Dart VM and in the browser under both dart2js and Dartium.
+Under dart2js, it currently returns "." as the current working directory, while
+under Dartium it returns the current URL.
### Why doesn't this make paths first-class objects?
diff --git a/pkg/pathos/lib/path.dart b/pkg/pathos/lib/path.dart
index 6e7c8c2..145953f 100644
--- a/pkg/pathos/lib/path.dart
+++ b/pkg/pathos/lib/path.dart
@@ -21,7 +21,7 @@
/// [pkg]: http://pub.dartlang.org/packages/pathos
library path;
-import 'dart:io' as io;
+import 'dart:mirrors';
/// An internal builder for the current OS so we can provide a straight
/// functional interface and not require users to create one.
@@ -34,8 +34,47 @@
void _growListFront(List list, int length, fillValue) =>
list.insertAll(0, new List.filled(length, fillValue));
+/// If we're running in the server-side Dart VM, this will return a
+/// [LibraryMirror] that gives access to the `dart:io` library.
+///
+/// If `dart:io` is not available, this returns null.
+LibraryMirror get _io {
+ try {
+ return currentMirrorSystem().libraries[Uri.parse('dart:io')];
+ } catch (_) {
+ return null;
+ }
+}
+
+// TODO(nweiz): when issue 6490 or 6943 are fixed, make this work under dart2js.
+/// If we're running in Dartium, this will return a [LibraryMirror] that gives
+/// access to the `dart:html` library.
+///
+/// If `dart:html` is not available, this returns null.
+LibraryMirror get _html {
+ try {
+ return currentMirrorSystem().libraries[Uri.parse('dart:html')];
+ } catch (_) {
+ return null;
+ }
+}
+
/// Gets the path to the current working directory.
-String get current => io.Directory.current.path;
+///
+/// In the browser, this means the current URL. When using dart2js, this
+/// currently returns `.` due to technical constraints. In the future, it will
+/// return the current URL.
+String get current {
+ if (_io != null) {
+ return _io.classes[const Symbol('Directory')]
+ .getField(const Symbol('current')).reflectee.path;
+ } else if (_html != null) {
+ return _html.getField(const Symbol('window'))
+ .reflectee.location.href;
+ } else {
+ return '.';
+ }
+}
/// Gets the path separator for the current platform. On Mac and Linux, this
/// is `/`. On Windows, it's `\`.
@@ -104,6 +143,11 @@
/// // Windows
/// path.rootPrefix(r'path\to\foo'); // -> ''
/// path.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
+///
+/// // URL
+/// path.rootPrefix('path/to/foo'); // -> ''
+/// path.rootPrefix('http://dartlang.org/path/to/foo');
+/// // -> 'http://dartlang.org'
String rootPrefix(String path) => _builder.rootPrefix(path);
/// Returns `true` if [path] is an absolute path and `false` if it is a
@@ -187,6 +231,10 @@
///
/// // Windows
/// path.split(r'C:\path\to\foo'); // -> [r'C:\', 'path', 'to', 'foo']
+///
+/// // Browser
+/// path.split('http://dartlang.org/path/to/foo');
+/// // -> ['http://dartlang.org', 'path', 'to', 'foo']
List<String> split(String path) => _builder.split(path);
/// Normalizes [path], simplifying it by handling `..`, and `.`, and
@@ -210,9 +258,15 @@
/// from: '/root/path'); // -> '../other.dart'
///
/// Since there is no relative path from one drive letter to another on Windows,
-/// this will return an absolute path in that case.
+/// or from one hostname to another for URLs, this will return an absolute path
+/// in those cases.
///
+/// // Windows
/// path.relative(r'D:\other', from: r'C:\home'); // -> 'D:\other'
+///
+/// // URL
+/// path.relative('http://dartlang.org', from: 'http://pub.dartlang.org');
+/// // -> 'http://dartlang.org'
String relative(String path, {String from}) =>
_builder.relative(path, from: from);
@@ -252,9 +306,16 @@
/// If [style] is omitted, it uses the host operating system's path style. If
/// [root] is omitted, it defaults to the current working directory. If [root]
/// is relative, it is considered relative to the current working directory.
+ ///
+ /// On the browser, the path style is [Style.url]. In Dartium, [root] defaults
+ /// to the current URL. When using dart2js, it currently defaults to `.` due
+ /// to technical constraints.
factory Builder({Style style, String root}) {
if (style == null) {
- if (io.Platform.operatingSystem == 'windows') {
+ if (_io == null) {
+ style = Style.url;
+ } else if (_io.classes[const Symbol('Platform')]
+ .getField(const Symbol('operatingSystem')).reflectee == 'windows') {
style = Style.windows;
} else {
style = Style.posix;
@@ -347,6 +408,11 @@
/// // Windows
/// builder.rootPrefix(r'path\to\foo'); // -> ''
/// builder.rootPrefix(r'C:\path\to\foo'); // -> r'C:\'
+ ///
+ /// // URL
+ /// builder.rootPrefix('path/to/foo'); // -> ''
+ /// builder.rootPrefix('http://dartlang.org/path/to/foo');
+ /// // -> 'http://dartlang.org'
String rootPrefix(String path) {
var root = _parse(path).root;
return root == null ? '' : root;
@@ -550,6 +616,10 @@
var fromParsed = _parse(from)..normalize();
var pathParsed = _parse(path)..normalize();
+ if (fromParsed.parts.length > 0 && fromParsed.parts[0] == '.') {
+ return pathParsed.toString();
+ }
+
// If the root prefixes don't match (for example, different drive letters
// on Windows), then there is no relative path, so just return the absolute
// one. In Windows, drive letters are case-insenstive and we allow
diff --git a/pkg/pathos/test/pathos_dart2js_test.dart b/pkg/pathos/test/pathos_dart2js_test.dart
new file mode 100644
index 0000000..e49659d
--- /dev/null
+++ b/pkg/pathos/test/pathos_dart2js_test.dart
@@ -0,0 +1,27 @@
+// 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.
+
+import 'package:unittest/unittest.dart';
+import 'package:pathos/path.dart' as path;
+
+// In the future, the default root will be window.location.href, but right now
+// that's not possible.
+
+main() {
+ group('new Builder()', () {
+ test('uses the current working directory if root is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.root, '.');
+ });
+
+ test('uses URL if style is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.style, path.Style.url);
+ });
+ });
+
+ test('current', () {
+ expect(path.current, '.');
+ });
+}
diff --git a/pkg/pathos/test/pathos_dartium_test.dart b/pkg/pathos/test/pathos_dartium_test.dart
new file mode 100644
index 0000000..f03abc6
--- /dev/null
+++ b/pkg/pathos/test/pathos_dartium_test.dart
@@ -0,0 +1,29 @@
+// 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.
+
+import 'dart:html';
+
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:pathos/path.dart' as path;
+
+main() {
+ useHtmlConfiguration();
+
+ group('new Builder()', () {
+ test('uses the current working directory if root is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.root, window.location.href);
+ });
+
+ test('uses URL if style is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.style, path.Style.url);
+ });
+ });
+
+ test('current', () {
+ expect(path.current, window.location.href);
+ });
+}
diff --git a/pkg/pathos/test/pathos_io_test.dart b/pkg/pathos/test/pathos_io_test.dart
new file mode 100644
index 0000000..bb14bd7
--- /dev/null
+++ b/pkg/pathos/test/pathos_io_test.dart
@@ -0,0 +1,30 @@
+// 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.
+
+import 'dart:io' as io;
+
+import 'package:unittest/unittest.dart';
+import 'package:pathos/path.dart' as path;
+
+main() {
+ group('new Builder()', () {
+ test('uses the current working directory if root is omitted', () {
+ var builder = new path.Builder();
+ expect(builder.root, io.Directory.current.path);
+ });
+
+ test('uses the host OS if style is omitted', () {
+ var builder = new path.Builder();
+ if (io.Platform.operatingSystem == 'windows') {
+ expect(builder.style, path.Style.windows);
+ } else {
+ expect(builder.style, path.Style.posix);
+ }
+ });
+ });
+
+ test('current', () {
+ expect(path.current, io.Directory.current.path);
+ });
+}
diff --git a/pkg/pathos/test/pathos_posix_test.dart b/pkg/pathos/test/pathos_posix_test.dart
index d6bfb91..ecdd133 100644
--- a/pkg/pathos/test/pathos_posix_test.dart
+++ b/pkg/pathos/test/pathos_posix_test.dart
@@ -4,8 +4,6 @@
library pathos_posix_test;
-import 'dart:io' as io;
-
import 'package:unittest/unittest.dart';
import 'package:pathos/path.dart' as path;
@@ -300,6 +298,12 @@
expect(builder.relative('../a/b.txt'), '../a/b.txt');
expect(builder.relative('a/./b/../c.txt'), 'a/c.txt');
});
+
+ // Regression
+ test('from root-only path', () {
+ expect(builder.relative('/', from: '/'), '.');
+ expect(builder.relative('/root/path', from: '/'), 'root/path');
+ });
});
group('from relative root', () {
@@ -344,6 +348,12 @@
equals('/foo/bar/baz'));
expect(r.relative('..', from: 'foo/bar'), equals('../../..'));
});
+
+ test('from a . root', () {
+ var r = new path.Builder(style: path.Style.posix, root: '.');
+ expect(r.relative('/foo/bar/baz'), equals('/foo/bar/baz'));
+ expect(r.relative('foo/bar/baz'), equals('foo/bar/baz'));
+ });
});
group('resolve', () {
diff --git a/pkg/pathos/test/pathos_test.dart b/pkg/pathos/test/pathos_test.dart
index 2d56ee2..b002999 100644
--- a/pkg/pathos/test/pathos_test.dart
+++ b/pkg/pathos/test/pathos_test.dart
@@ -2,10 +2,6 @@
// 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 pathos_test;
-
-import 'dart:io' as io;
-
import 'package:unittest/unittest.dart';
import 'package:pathos/path.dart' as path;
@@ -37,23 +33,5 @@
var builder = new path.Builder(style: path.Style.windows);
expect(builder.style, path.Style.windows);
});
-
- test('uses the current working directory if root is omitted', () {
- var builder = new path.Builder();
- expect(builder.root, io.Directory.current.path);
- });
-
- test('uses the host OS if style is omitted', () {
- var builder = new path.Builder();
- if (io.Platform.operatingSystem == 'windows') {
- expect(builder.style, path.Style.windows);
- } else {
- expect(builder.style, path.Style.posix);
- }
- });
- });
-
- test('current', () {
- expect(path.current, io.Directory.current.path);
});
}
diff --git a/pkg/pathos/test/pathos_url_test.dart b/pkg/pathos/test/pathos_url_test.dart
index f419af4..b8c100f 100644
--- a/pkg/pathos/test/pathos_url_test.dart
+++ b/pkg/pathos/test/pathos_url_test.dart
@@ -2,8 +2,6 @@
// 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:io' as io;
-
import 'package:unittest/unittest.dart';
import 'package:pathos/path.dart' as path;
@@ -436,6 +434,16 @@
expect(builder.relative('../a/b.txt'), '../a/b.txt');
expect(builder.relative('a/./b/../c.txt'), 'a/c.txt');
});
+
+ // Regression
+ test('from root-only path', () {
+ expect(builder.relative('http://dartlang.org',
+ from: 'http://dartlang.org'),
+ '.');
+ expect(builder.relative('http://dartlang.org/root/path',
+ from: 'http://dartlang.org'),
+ 'root/path');
+ });
});
group('from relative root', () {
@@ -555,6 +563,15 @@
expect(r.relative('..', from: 'foo/bar'), equals('../../..'));
});
+
+ test('from a . root', () {
+ var r = new path.Builder(style: path.Style.url, root: '.');
+ expect(r.relative('http://dartlang.org/foo/bar/baz'),
+ equals('http://dartlang.org/foo/bar/baz'));
+ expect(r.relative('file:///foo/bar/baz'), equals('file:///foo/bar/baz'));
+ expect(r.relative('/foo/bar/baz'), equals('/foo/bar/baz'));
+ expect(r.relative('foo/bar/baz'), equals('foo/bar/baz'));
+ });
});
group('resolve', () {
diff --git a/pkg/pathos/test/pathos_windows_test.dart b/pkg/pathos/test/pathos_windows_test.dart
index 8419b53..6d22742 100644
--- a/pkg/pathos/test/pathos_windows_test.dart
+++ b/pkg/pathos/test/pathos_windows_test.dart
@@ -4,8 +4,6 @@
library pathos_windows_test;
-import 'dart:io' as io;
-
import 'package:unittest/unittest.dart';
import 'package:pathos/path.dart' as path;
@@ -333,6 +331,12 @@
expect(builder.relative(r'..\a\b.txt'), r'..\a\b.txt');
expect(builder.relative(r'a\.\b\..\c.txt'), r'a\c.txt');
});
+
+ // Regression
+ test('from root-only path', () {
+ expect(builder.relative(r'C:\', from: r'C:\'), '.');
+ expect(builder.relative(r'C:\root\path', from: r'C:\'), r'root\path');
+ });
});
group('from relative root', () {
@@ -385,6 +389,12 @@
expect(builder.relative(r'D:\a\b'), r'D:\a\b');
expect(builder.relative(r'\\a\b'), r'\\a\b');
});
+
+ test('from a . root', () {
+ var r = new path.Builder(style: path.Style.windows, root: '.');
+ expect(r.relative(r'C:\foo\bar\baz'), equals(r'C:\foo\bar\baz'));
+ expect(r.relative(r'foo\bar\baz'), equals(r'foo\bar\baz'));
+ });
});
group('resolve', () {
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 5b5c18f..ae61138 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -49,8 +49,10 @@
[ $runtime == safari ]
fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
-# Skip browser-specific Intl tests on VM
+# Skip browser-specific tests on VM
[ $runtime == vm ]
+pathos/test/pathos_dartium_test: Fail, OK # Uses dart:html
+pathos/test/pathos_dart2js_test: Fail, OK # Uses dart:html
intl/test/find_default_locale_browser_test: Skip
intl/test/date_time_format_http_request_test: Skip
@@ -59,11 +61,24 @@
intl/test/message_extraction/message_extraction_test: Fail # Issue 9167
[ $compiler == dart2js ]
-serialization/test/serialization_test: Fail # Issue 6490
-serialization/test/no_library_test: Fail # Issue 6490
-analyzer_experimental/test/generated/ast_test: Fail
+analyzer_experimental/test/generated/ast_test: Fail, Slow # Issue 11230
unittest/test/instance_test: Fail # http://dartbug.com/11191
+[ $compiler == dart2js && $runtime == d8 && $checked ]
+pathos/test/pathos_io_test: Fail # Issue 11258
+oauth2/*: Fail # Issue 11258
+oauth2/test/utils_test: Pass
+http/*: Fail # Issue 11258
+stack_trace/*: Fail # Issue 11258
+intl/test/date_time_format_file_odd_test: Fail # Issue 11258
+intl/test/date_time_format_file_even_test: Fail # Issue 11258
+intl/test/message_extraction/message_extraction_test: Fail # Issue 11258
+scheduled_test/*: Fail # Issue 11258
+scheduled_test/test/substitute_future_test: Pass
+scheduled_test/test/value_future_test: Pass
+analyzer_experimental/test/error_test: Fail # Issue 11258
+analyzer_experimental/test/services/formatter_test: Fail # Issue 11258
+
[ $compiler == dartc ]
unittest/test/mock_regexp_negative_test: Fail
unittest/test/mock_stepwise_negative_test: Fail
@@ -79,6 +94,9 @@
[ $compiler == dart2js && $csp ]
unittest/test/unittest_test: Pass, Crash # Issue 10935
+serialization/test/serialization_test: Fail # Issue 6490
+serialization/test/no_library_test: Fail # Issue 6490
+
[ $compiler == dart2js && $minified ]
# The unittest package relies on getting the original (non-minified) method
# names in Invocation. You can't get that when minifying.
@@ -86,6 +104,9 @@
unittest/test/mock_test: Fail
unittest/test/mock_regexp_negative_test: Fail
+serialization/test/serialization_test: Fail # Issue 6490
+serialization/test/no_library_test: Fail # Issue 6490
+
# The unminified unittest tests test that the real names of Dart types are
# printed. Minified versions of these tests exist that test the behavior when
# minified.
@@ -95,6 +116,7 @@
crypto/test/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692
[ $compiler == dart2js && $browser ]
+pathos/test/pathos_dartium_test: Fail, OK # Issue 6490
crypto/test/sha256_test: Slow, Pass
crypto/test/sha1_test: Slow, Pass
@@ -119,10 +141,7 @@
oauth2/test/client_test: Fail, OK # Uses dart:io.
oauth2/test/credentials_test: Fail, OK # Uses dart:io.
oauth2/test/handle_access_token_response_test: Fail, OK # Uses dart:io.
-pathos/test/pathos_posix_test: Fail, OK # Uses dart:io.
-pathos/test/pathos_test: Fail, OK # Uses dart:io.
-pathos/test/pathos_url_test: Fail, OK # Uses dart:io.
-pathos/test/pathos_windows_test: Fail, OK # Uses dart:io.
+pathos/test/pathos_io_test: Fail, OK # Uses dart:io.
scheduled_test/test/descriptor/async_test: Fail # http://dartbug.com/8440
scheduled_test/test/descriptor/directory_test: Fail # http://dartbug.com/8440
@@ -181,6 +200,9 @@
[ $runtime == dartium || $runtime == drt ]
serialization/test/no_library_test: Skip # Expected Failure
+[ ($runtime == dartium || $runtime == drt) && $compiler == none ]
+pathos/test/pathos_dart2js_test: Fail, OK # Issue 6490
+
# Skip mdv_observe tests on command line VM, they only run in the browser.
[ $runtime == vm ]
mdv_observe: Skip
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 0acd6c0..ba50c9f 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -336,10 +336,6 @@
bool runInShell,
Encoding stdoutEncoding,
Encoding stderrEncoding) {
- // Extract output encoding options and verify arguments.
- if (stdoutEncoding == null) stdoutEncoding = Encoding.SYSTEM;
- if (stderrEncoding == null) stderrEncoding = Encoding.SYSTEM;
-
// Start the underlying process.
return Process.start(path,
arguments,
@@ -351,30 +347,35 @@
// Make sure the process stdin is closed.
p.stdin.close();
- // Setup stdout handling.
- Future<StringBuffer> stdout = p.stdout
- .transform(new StringDecoder(stdoutEncoding))
- .fold(
- new StringBuffer(),
- (buf, data) {
- buf.write(data);
- return buf;
- });
+ // Setup stdout and stderr handling.
+ Future foldStream(Stream<List<int>> stream, Encoding encoding) {
+ if (encoding == null) {
+ return stream
+ .fold(
+ new _BufferList(),
+ (buf, data) {
+ buf.add(data);
+ return buf;
+ })
+ .then((buf) => buf.readBytes());
+ } else {
+ return stream
+ .transform(new StringDecoder(encoding))
+ .fold(
+ new StringBuffer(),
+ (buf, data) {
+ buf.write(data);
+ return buf;
+ })
+ .then((sb) => sb.toString());
+ }
+ }
- Future<StringBuffer> stderr = p.stderr
- .transform(new StringDecoder(stderrEncoding))
- .fold(
- new StringBuffer(),
- (buf, data) {
- buf.write(data);
- return buf;
- });
+ Future stdout = foldStream(p.stdout, stdoutEncoding);
+ Future stderr = foldStream(p.stderr, stderrEncoding);
return Future.wait([p.exitCode, stdout, stderr]).then((result) {
- return new _ProcessResult(pid,
- result[0],
- result[1].toString(),
- result[2].toString());
+ return new _ProcessResult(pid, result[0], result[1], result[2]);
});
});
}
@@ -383,11 +384,11 @@
class _ProcessResult implements ProcessResult {
const _ProcessResult(int this.pid,
int this.exitCode,
- String this.stdout,
- String this.stderr);
+ this.stdout,
+ this.stderr);
final int pid;
final int exitCode;
- final String stdout;
- final String stderr;
+ final stdout;
+ final stderr;
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 7d0f5da..e69dfed 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -299,7 +299,7 @@
if (isClosed) return 0;
if (bytes == 0) return 0;
_BufferAndStart bufferAndStart =
- _ensureFastAndSerializableBuffer(buffer, offset, offset + bytes);
+ _ensureFastAndSerializableByteData(buffer, offset, offset + bytes);
var result =
nativeWrite(bufferAndStart.buffer, bufferAndStart.start, bytes);
if (result is OSError) {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index afbceaa..075ce12 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2274,6 +2274,22 @@
/* TODO(turnidge): Consider renaming to NativeFunctionResolver or
* NativeResolver. */
+
+/* --- Metadata support --- */
+
+/**
+ * Get metadata associated with an object.
+ *
+ * \param obj Object for which the metadata is retrieved.
+ *
+ * \return If no error occurs, returns an array of metadata values.
+ * Returns an empty array if there is no metadata for the object.
+ * Returns an error if the evaluation of the metadata expressions fails.
+ *
+ */
+DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle obj);
+
+
/* --- Scripts and Libraries ---
* TODO(turnidge): Finish documenting this section. */
diff --git a/runtime/lib/regexp_patch.dart b/runtime/lib/regexp_patch.dart
index fc7797f..72b6f4b 100644
--- a/runtime/lib/regexp_patch.dart
+++ b/runtime/lib/regexp_patch.dart
@@ -81,6 +81,18 @@
return new _AllMatchesIterable(this, str);
}
+ Match matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ // Inefficient check that searches for a later match too.
+ // Change this when possible.
+ List<int> list = _ExecuteMatch(string, start);
+ if (list == null) return null;
+ if (list[0] != start) return null;
+ return new _JSRegExpMatch(this, string, list);
+ }
+
bool hasMatch(String str) {
List match = _ExecuteMatch(str, 0);
return (match == null) ? false : true;
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index 16c3232..80b369c 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -113,11 +113,8 @@
bool _substringMatches(int start, String other) {
if (other.isEmpty) return true;
- if ((start < 0) || (start >= this.length)) {
- return false;
- }
final int len = other.length;
- if ((start + len) > this.length) {
+ if ((start < 0) || (start + len > this.length)) {
return false;
}
for (int i = 0; i < len; i++) {
@@ -132,38 +129,57 @@
return _substringMatches(this.length - other.length, other);
}
- bool startsWith(String other) {
- return _substringMatches(0, other);
+ bool startsWith(Pattern pattern) {
+ if (pattern is String) {
+ return _substringMatches(0, pattern);
+ }
+ return pattern.matchAsPrefix(this, 0) != null;
}
- int indexOf(String other, [int start = 0]) {
- if (other.isEmpty) {
- return start < this.length ? start : this.length;
+ int indexOf(Pattern pattern, [int start = 0]) {
+ if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
}
- if ((start < 0) || (start >= this.length)) {
+ if (pattern is String) {
+ String other = pattern;
+ int maxIndex = this.length - other.length;
+ // TODO: Use an efficient string search (e.g. BMH).
+ for (int index = start; index <= maxIndex; index++) {
+ if (_substringMatches(index, other)) {
+ return index;
+ }
+ }
return -1;
}
- int len = this.length - other.length + 1;
- for (int index = start; index < len; index++) {
- if (_substringMatches(index, other)) {
- return index;
- }
+ for (int i = start; i <= this.length; i++) {
+ // TODO(11276); This has quadratic behavior because matchAsPrefix tries
+ // to find a later match too. Optimize matchAsPrefix to avoid this.
+ if (pattern.matchAsPrefix(this, i) != null) return i;
}
return -1;
}
- int lastIndexOf(String other, [int start = null]) {
- if (start == null) start = length - 1;
- if (other.isEmpty) {
- return min(this.length, start);
+ int lastIndexOf(Pattern pattern, [int start = null]) {
+ if (start == null) {
+ start = this.length;
+ } else if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
}
- if (start >= this.length) {
- start = this.length - 1;
- }
- for (int index = start; index >= 0; index--) {
- if (_substringMatches(index, other)) {
- return index;
+ if (pattern is String) {
+ String other = pattern;
+ int maxIndex = this.length - other.length;
+ if (maxIndex < start) start = maxIndex;
+ for (int index = start; index >= 0; index--) {
+ if (_substringMatches(index, other)) {
+ return index;
+ }
}
+ return -1;
+ }
+ for (int i = start; i >= 0; i--) {
+ // TODO(11276); This has quadratic behavior because matchAsPrefix tries
+ // to find a later match too. Optimize matchAsPrefix to avoid this.
+ if (pattern.matchAsPrefix(this, i) != null) return i;
}
return -1;
}
@@ -421,6 +437,19 @@
return result;
}
+ Match matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ if (start + this.length > string.length) return null;
+ for (int i = 0; i < this.length; i++) {
+ if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+ return null;
+ }
+ }
+ return new _StringMatch(start, string, this);
+ }
+
List<String> split(Pattern pattern) {
if ((pattern is String) && pattern.isEmpty) {
List<String> result = new List<String>(length);
diff --git a/runtime/lib/type_patch.dart b/runtime/lib/type_patch.dart
index 8f6c325..4f2dee7 100644
--- a/runtime/lib/type_patch.dart
+++ b/runtime/lib/type_patch.dart
@@ -16,3 +16,11 @@
// Equivalent of RawTypeParameter.
class _TypeParameter extends _AbstractType {
}
+
+// Equivalent of RawBoundedType.
+class _BoundedType extends _AbstractType {
+}
+
+// Equivalent of RawMixinAppType.
+class _MixinAppType extends _AbstractType {
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index b11812d..2319452 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -55,9 +55,9 @@
*: Skip
[ $arch == simarm || $arch == arm ]
-# Bug in optimized code generation.
-dart/byte_array_test: Fail
-dart/byte_array_optimized_test: Fail
+# Bug in optimized code generation results in timeout.
+dart/byte_array_test: Skip
+dart/byte_array_optimized_test: Skip
[ $arch == arm ]
cc/DoubleToFloatConversion: Fail # Issue: 11207
@@ -74,6 +74,10 @@
# Tests missing code generation support.
dart/byte_array_test: Skip
dart/byte_array_optimized_test: Skip
+dart/isolate_mirror_local_test: Skip
+cc/ParsePatchLibrary: Skip
+cc/CorelibCompileAll: Skip
+cc/Dart2JSCompileAll: Skip
# TODO(ajohnsen): Fix this as part of library changes.
[ $compiler == none ]
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 5cddcab..7230266 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -66,10 +66,7 @@
class CPUFeatures : public AllStatic {
public:
static void InitOnce();
- static bool double_truncate_round_supported() {
- UNIMPLEMENTED();
- return false;
- }
+ static bool double_truncate_round_supported() { return false; }
static bool integer_division_supported();
#if defined(USING_SIMULATOR)
static void set_integer_division_supported(bool supported);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index a2f37fb..a0f5306 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -406,6 +406,13 @@
flow_graph->RemoveRedefinitions();
if (FLAG_range_analysis) {
+ if (FLAG_propagate_types) {
+ // Propagate types after store-load-forwarding. Some phis may have
+ // become smi phis that can be processed by range analysis.
+ FlowGraphTypePropagator propagator(flow_graph);
+ propagator.Propagate();
+ DEBUG_ASSERT(flow_graph->VerifyUseLists());
+ }
// We have to perform range analysis after LICM because it
// optimistically moves CheckSmi through phis into loop preheaders
// making some phis smi.
@@ -420,7 +427,6 @@
DEBUG_ASSERT(flow_graph->VerifyUseLists());
}
- // The final canonicalization pass before the code generation.
if (FLAG_propagate_types) {
// Recompute types after code movement was done to ensure correct
// reaching types for hoisted values.
@@ -447,7 +453,7 @@
// Ensure that all phis inserted by optimization passes have consistent
// representations.
- optimizer.UnboxPhis();
+ optimizer.SelectRepresentations();
if (optimizer.Canonicalize()) {
// To fully remove redundant boxing (e.g. BoxDouble used only in
@@ -509,9 +515,6 @@
Code::Handle(function.unoptimized_code()).EntryPoint());
}
- // If not yet present, allocate deoptimization history array.
- function.EnsureDeoptHistory();
-
for (intptr_t i = 0; i < guarded_fields.length(); i++) {
const Field& field = *guarded_fields[i];
field.RegisterDependentCode(code);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index bf35ec2..323e4f0 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -34,6 +34,7 @@
namespace dart {
DECLARE_FLAG(bool, print_class_table);
+DECLARE_FLAG(bool, verify_handles);
ThreadLocalKey Api::api_native_key_ = Thread::kUnsetThreadLocalKey;
Dart_Handle Api::true_handle_ = NULL;
@@ -97,7 +98,8 @@
ASSERT(isolate != NULL);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- ASSERT(state->IsValidLocalHandle(object) ||
+ ASSERT(!FLAG_verify_handles ||
+ state->IsValidLocalHandle(object) ||
Dart::vm_isolate()->api_state()->IsValidLocalHandle(object));
ASSERT(FinalizablePersistentHandle::raw_offset() == 0 &&
PersistentHandle::raw_offset() == 0 &&
@@ -4348,6 +4350,28 @@
}
+// --- Metadata ----
+
+DART_EXPORT Dart_Handle Dart_GetMetadata(Dart_Handle object) {
+ Isolate* isolate = Isolate::Current();
+ CHECK_ISOLATE(isolate);
+ DARTSCOPE(isolate);
+ const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+ Class& cls = Class::Handle(isolate);
+ if (obj.IsClass()) {
+ cls ^= obj.raw();
+ } else if (obj.IsFunction()) {
+ cls = Function::Cast(obj).origin();
+ } else if (obj.IsField()) {
+ cls = Field::Cast(obj).origin();
+ } else {
+ return Api::NewHandle(isolate, Object::empty_array().raw());
+ }
+ const Library& lib = Library::Handle(cls.library());
+ return Api::NewHandle(isolate, lib.GetMetadata(obj));
+}
+
+
// --- Scripts and Libraries ---
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 89ebb10..3d77b54 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -240,7 +240,8 @@
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
- descriptor ^= descriptor.Canonicalize();
+ descriptor ^= descriptor.CheckAndCanonicalize(NULL);
+ ASSERT(!descriptor.IsNull());
return descriptor.raw();
}
@@ -275,8 +276,9 @@
// Share the immutable descriptor when possible by canonicalizing it.
descriptor.MakeImmutable();
if (canonicalize) {
- descriptor ^= descriptor.Canonicalize();
+ descriptor ^= descriptor.CheckAndCanonicalize(NULL);
}
+ ASSERT(!descriptor.IsNull());
return descriptor.raw();
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index e583545..8b82f4c 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1731,7 +1731,7 @@
return bpt->saved_bytes_.target_address_;
}
UNREACHABLE();
- return NULL;
+ return 0L;
}
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 8b37613..d194c3c 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -285,18 +285,6 @@
ic_data.set_deopt_reason(deopt_context->deopt_reason());
}
}
-
- const Array& deopt_history = Array::Handle(function.deopt_history());
- ASSERT(!deopt_history.IsNull());
- intptr_t count = function.deoptimization_counter();
- ASSERT(count > 0);
- if (count <= deopt_history.Length()) {
- deopt_history.SetAt(count - 1, Smi::Handle(Smi::New(deopt_id_)));
- if (FLAG_trace_deoptimization_verbose) {
- OS::Print(" adding id %"Pd" to history at %"Pd"\n",
- deopt_id_, count - 1);
- }
- }
}
intptr_t object_table_index() const { return object_table_index_; }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d56842f..dafa68c 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -255,8 +255,7 @@
intptr_t FlowGraphCompiler::StackSize() const {
if (is_optimizing_) {
- GraphEntryInstr* entry = flow_graph_.graph_entry();
- return entry->fixed_slot_count() + entry->spill_slot_count();
+ return flow_graph_.graph_entry()->spill_slot_count();
} else {
return parsed_function_.num_stack_locals() +
parsed_function_.num_copied_params();
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index c2379c3..911e62c 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -612,10 +612,6 @@
// Add the function to the cache.
if (!in_cache) function_cache_.Add(parsed_function);
- // Functions can be inlined before they are optimized.
- // If not yet present, allocate deoptimization history array.
- function.EnsureDeoptHistory();
-
// Build succeeded so we restore the bailout jump.
inlined_ = true;
inlined_size_ += size;
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 6087381..5094329 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -450,35 +450,6 @@
}
-void FlowGraphOptimizer::UnboxPhis() {
- GrowableArray<PhiInstr*> worklist(5);
-
- // Convervatively unbox all phis that were proven to be of Double,
- // Float32x4, or Uint32x4 type.
- for (intptr_t i = 0; i < block_order_.length(); ++i) {
- JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry();
- if (join_entry != NULL) {
- for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
- PhiInstr* phi = it.Current();
- if (UnboxPhi(phi)) {
- worklist.Add(phi);
- }
- }
- }
- }
-
- while (!worklist.is_empty()) {
- PhiInstr* phi = worklist.RemoveLast();
- InsertConversionsFor(phi);
-
- for (intptr_t i = 0; i < phi->InputCount(); i++) {
- ConvertUse(phi->InputAt(i),
- phi->InputAt(i)->definition()->representation());
- }
- }
-}
-
-
void FlowGraphOptimizer::SelectRepresentations() {
// Convervatively unbox all phis that were proven to be of Double,
// Float32x4, or Uint32x4 type.
@@ -3461,6 +3432,8 @@
void LICM::Hoist(ForwardInstructionIterator* it,
BlockEntryInstr* pre_header,
Instruction* current) {
+ // TODO(fschneider): Avoid repeated deoptimization when
+ // speculatively hoisting checks.
if (FLAG_trace_optimization) {
OS::Print("Hoisting instruction %s:%"Pd" from B%"Pd" to B%"Pd"\n",
current->DebugName(),
@@ -3516,7 +3489,7 @@
}
// Host CheckSmi instruction and make this phi smi one.
- if (MayHoist(current, pre_header)) Hoist(it, pre_header, current);
+ Hoist(it, pre_header, current);
// Replace value we are checking with phi's input.
current->value()->BindTo(phi->InputAt(non_smi_input)->definition());
@@ -3535,31 +3508,6 @@
}
-bool LICM::MayHoist(Instruction* instr, BlockEntryInstr* pre_header) {
- // TODO(fschneider): Enable hoisting of Assert-instructions
- // if it safe to do.
- if (instr->IsAssertAssignable()) return false;
- if (instr->IsAssertBoolean()) return false;
-
- if (instr->CanDeoptimize()) {
- intptr_t target_deopt_id =
- pre_header->last_instruction()->AsGoto()->GetDeoptId();
- const Function& function = flow_graph_->parsed_function().function();
- const Array& deopt_history = Array::Handle(function.deopt_history());
- if (deopt_history.IsNull()) return true;
-
- Smi& deopt_id = Smi::Handle();
- for (intptr_t i = 0; i < deopt_history.Length(); ++i) {
- deopt_id ^= deopt_history.At(i);
- if (!deopt_id.IsNull() && (deopt_id.Value() == target_deopt_id)) {
- return false;
- }
- }
- }
- return true;
-}
-
-
void LICM::Optimize() {
const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
flow_graph()->loop_headers();
@@ -3594,7 +3542,11 @@
break;
}
}
- if (inputs_loop_invariant && MayHoist(current, pre_header)) {
+ if (inputs_loop_invariant &&
+ !current->IsAssertAssignable() &&
+ !current->IsAssertBoolean()) {
+ // TODO(fschneider): Enable hoisting of Assert-instructions
+ // if it safe to do.
Hoist(&it, pre_header, current);
} else if (current->IsCheckSmi() &&
current->InputAt(0)->definition()->IsPhi()) {
@@ -4822,6 +4774,7 @@
void ConstantPropagator::OptimizeBranches(FlowGraph* graph) {
GrowableArray<BlockEntryInstr*> ignored;
ConstantPropagator cp(graph, ignored);
+ cp.Analyze();
cp.VisitBranches();
cp.Transform();
}
@@ -5160,6 +5113,15 @@
const Object& left = instr->left()->definition()->constant_value();
const Object& right = instr->right()->definition()->constant_value();
+ if (instr->left()->definition() == instr->right()->definition()) {
+ // Fold x === x, and x !== x to true/false.
+ SetValue(instr,
+ (instr->kind() == Token::kEQ_STRICT)
+ ? Bool::True()
+ : Bool::False());
+ return;
+ }
+
if (IsNonConstant(left) || IsNonConstant(right)) {
// TODO(vegorov): incorporate nullability information into the lattice.
if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
@@ -5200,6 +5162,19 @@
void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) {
const Object& left = instr->left()->definition()->constant_value();
const Object& right = instr->right()->definition()->constant_value();
+
+ if (instr->left()->definition() == instr->right()->definition()) {
+ // Fold x == x, and x != x to true/false for numbers and checked strict
+ // comparisons.
+ if (instr->is_checked_strict_equal() ||
+ RawObject::IsIntegerClassId(instr->receiver_class_id())) {
+ return SetValue(instr,
+ (instr->kind() == Token::kEQ)
+ ? Bool::True()
+ : Bool::False());
+ }
+ }
+
if (IsNonConstant(left) || IsNonConstant(right)) {
SetValue(instr, non_constant_);
} else if (IsConstant(left) && IsConstant(right)) {
@@ -5436,7 +5411,8 @@
case Token::kMOD: {
Instance& result = Integer::ZoneHandle(
left_int.ArithmeticOp(op_kind, right_int));
- result = result.Canonicalize();
+ result = result.CheckAndCanonicalize(NULL);
+ ASSERT(!result.IsNull());
SetValue(instr, result);
break;
}
@@ -5445,7 +5421,8 @@
if (left.IsSmi() && right.IsSmi()) {
Instance& result = Integer::ZoneHandle(
Smi::Cast(left_int).ShiftOp(op_kind, Smi::Cast(right_int)));
- result = result.Canonicalize();
+ result = result.CheckAndCanonicalize(NULL);
+ ASSERT(!result.IsNull());
SetValue(instr, result);
} else {
SetValue(instr, non_constant_);
@@ -5456,7 +5433,8 @@
case Token::kBIT_XOR: {
Instance& result = Integer::ZoneHandle(
left_int.BitOp(op_kind, right_int));
- result = result.Canonicalize();
+ result = result.CheckAndCanonicalize(NULL);
+ ASSERT(!result.IsNull());
SetValue(instr, result);
break;
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 4b8574a..ce18d6b 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -42,8 +42,6 @@
void SelectRepresentations();
- void UnboxPhis();
-
void InferSmiRanges();
void AnalyzeTryCatch();
@@ -204,8 +202,6 @@
private:
FlowGraph* flow_graph() const { return flow_graph_; }
- bool MayHoist(Instruction* instr, BlockEntryInstr* pre_header);
-
void Hoist(ForwardInstructionIterator* it,
BlockEntryInstr* pre_header,
Instruction* current);
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 82a9233..5b6d6b2 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -742,7 +742,6 @@
value().GetClassId(),
AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
} else {
- ASSERT(value().IsAbstractTypeArguments());
return CompileType::Dynamic();
}
}
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 72e8c7b..5dcc4b9 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -7,6 +7,7 @@
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/flags.h"
+#include "vm/heap_histogram.h"
#include "vm/heap_profiler.h"
#include "vm/isolate.h"
#include "vm/object.h"
@@ -162,6 +163,7 @@
old_space_->MarkSweep(invoke_api_callbacks);
RecordAfterGC();
PrintStats();
+ UpdateObjectHistogram();
break;
}
default:
@@ -170,6 +172,13 @@
}
+void Heap::UpdateObjectHistogram() {
+ Isolate* isolate = Isolate::Current();
+ if (isolate->object_histogram() == NULL) return;
+ isolate->object_histogram()->Collect();
+}
+
+
void Heap::CollectGarbage(Space space) {
ApiCallbacks api_callbacks;
if (space == kOld) {
@@ -190,6 +199,7 @@
old_space_->MarkSweep(kInvokeApiCallbacks);
RecordAfterGC();
PrintStats();
+ UpdateObjectHistogram();
}
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index b85d262..359efea 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -212,7 +212,7 @@
intptr_t new_capacity_;
intptr_t old_used_;
intptr_t old_capacity_;
-
+ private:
DISALLOW_COPY_AND_ASSIGN(Data);
};
@@ -225,6 +225,7 @@
int64_t times_[kDataEntries];
intptr_t data_[kDataEntries];
+ private:
DISALLOW_COPY_AND_ASSIGN(GCStats);
};
@@ -239,6 +240,7 @@
void RecordBeforeGC(Space space, GCReason reason);
void RecordAfterGC();
void PrintStats();
+ void UpdateObjectHistogram();
// The different spaces used for allocation.
Scavenger* new_space_;
diff --git a/runtime/vm/heap_histogram.cc b/runtime/vm/heap_histogram.cc
new file mode 100644
index 0000000..09fd5cd
--- /dev/null
+++ b/runtime/vm/heap_histogram.cc
@@ -0,0 +1,133 @@
+// 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.
+
+#include "vm/heap_histogram.h"
+
+#include "platform/assert.h"
+#include "vm/flags.h"
+#include "vm/object.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, print_object_histogram, false,
+ "Print average object histogram at isolate shutdown");
+
+class ObjectHistogramVisitor : public ObjectVisitor {
+ public:
+ explicit ObjectHistogramVisitor(Isolate* isolate) : ObjectVisitor(isolate) { }
+
+ virtual void VisitObject(RawObject* obj) {
+ isolate()->object_histogram()->Add(obj);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ObjectHistogramVisitor);
+};
+
+
+void ObjectHistogram::Collect() {
+ major_gc_count_++;
+ ObjectHistogramVisitor object_visitor(isolate_);
+ isolate_->heap()->IterateObjects(&object_visitor);
+}
+
+
+ObjectHistogram::ObjectHistogram(Isolate* isolate) {
+ isolate_ = isolate;
+ major_gc_count_ = 0;
+ table_length_ = 512;
+ table_ = reinterpret_cast<Element*>(
+ calloc(table_length_, sizeof(Element))); // NOLINT
+ for (int index = 0; index < table_length_; index++) {
+ table_[index].class_id_ = index;
+ }
+}
+
+
+ObjectHistogram::~ObjectHistogram() {
+ free(table_);
+}
+
+
+void ObjectHistogram::RegisterClass(const Class& cls) {
+ int class_id = cls.id();
+ if (class_id < table_length_) return;
+ // Resize the table.
+ int new_table_length = table_length_ * 2;
+ Element* new_table = reinterpret_cast<Element*>(
+ realloc(table_, new_table_length * sizeof(Element))); // NOLINT
+ for (int i = table_length_; i < new_table_length; i++) {
+ new_table[i].class_id_ = i;
+ new_table[i].count_ = 0;
+ new_table[i].size_ = 0;
+ }
+ table_ = new_table;
+ table_length_ = new_table_length;
+ ASSERT(class_id < table_length_);
+}
+
+
+void ObjectHistogram::Add(RawObject* obj) {
+ intptr_t class_id = obj->GetClassId();
+ if (class_id == kFreeListElement) return;
+ ASSERT(class_id < table_length_);
+ table_[class_id].Add(obj->Size());
+}
+
+
+int ObjectHistogram::compare(const Element** a, const Element** b) {
+ return (*b)->size_ - (*a)->size_;
+}
+
+
+void ObjectHistogram::Print() {
+ OS::Print("Printing Object Histogram\n");
+ OS::Print("____bytes___count_description____________\n");
+ // First count the number of non empty entries.
+ int length = 0;
+ for (int index = 0; index < table_length_; index++) {
+ if (table_[index].count_ > 0) length++;
+ }
+ // Then add them to a new array and sort.
+ Element** array = reinterpret_cast<Element**>(
+ calloc(length, sizeof(Element*))); // NOLINT
+ int pos = 0;
+ for (int index = 0; index < table_length_; index++) {
+ if (table_[index].count_ > 0) array[pos++] = &table_[index];
+ }
+ typedef int (*CmpFunc)(const void*, const void*);
+ qsort(array, length, sizeof(Element*), // NOLINT
+ reinterpret_cast<CmpFunc>(compare));
+
+ // Finally print the sorted array.
+ Class& cls = Class::Handle();
+ String& str = String::Handle();
+ Library& lib = Library::Handle();
+ for (pos = 0; pos < length; pos++) {
+ Element* e = array[pos];
+ if (e->count_ > 0) {
+ cls = isolate_->class_table()->At(e->class_id_);
+ str = cls.Name();
+ lib = cls.library();
+ OS::Print("%9"Pd" %7"Pd" ",
+ e->size_ / major_gc_count_,
+ e->count_ / major_gc_count_);
+ if (e->class_id_ < kInstanceCid) {
+ OS::Print("`%s`", str.ToCString()); // VM names.
+ } else {
+ OS::Print("%s", str.ToCString());
+ }
+ if (lib.IsNull()) {
+ OS::Print("\n");
+ } else {
+ str = lib.url();
+ OS::Print(", library \'%s\'\n", str.ToCString());
+ }
+ }
+ }
+ // Deallocate the array for sorting.
+ free(array);
+}
+
+} // namespace dart
diff --git a/runtime/vm/heap_histogram.h b/runtime/vm/heap_histogram.h
new file mode 100644
index 0000000..13e0a38
--- /dev/null
+++ b/runtime/vm/heap_histogram.h
@@ -0,0 +1,68 @@
+// 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.
+
+#ifndef VM_HEAP_HISTOGRAM_H_
+#define VM_HEAP_HISTOGRAM_H_
+
+#include "platform/assert.h"
+#include "vm/flags.h"
+#include "vm/globals.h"
+#include "vm/raw_object.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, print_object_histogram);
+
+// ObjectHistogram is used to compute an average object histogram over
+// the lifetime of an isolate and then print the histogram when the isolate
+// is shut down. Information is gathered at the back-edge of each major GC
+// event. When an object histogram is collected for an isolate, an extra major
+// GC is performed just prior to shutdown.
+class ObjectHistogram {
+ public:
+ explicit ObjectHistogram(Isolate* isolate);
+ ~ObjectHistogram();
+
+ // Called when a new class is registered in the isolate.
+ void RegisterClass(const Class& cls);
+
+ // Collect sample for the histogram. Called at back-edge of major GC.
+ void Collect();
+
+ // Print the histogram on stdout.
+ void Print();
+
+ private:
+ // Add obj to histogram
+ void Add(RawObject* obj);
+
+ // For each class an Element keeps track of the accounting.
+ class Element : public ValueObject {
+ public:
+ void Add(int size) {
+ count_++;
+ size_ += size;
+ }
+ intptr_t class_id_;
+ intptr_t count_;
+ intptr_t size_;
+ };
+
+ // Compare function for sorting result.
+ static int compare(const Element** a, const Element** b);
+
+ intptr_t major_gc_count_;
+ intptr_t table_length_;
+ Element* table_;
+ Isolate* isolate_;
+
+ friend class ObjectHistogramVisitor;
+
+ DISALLOW_COPY_AND_ASSIGN(ObjectHistogram);
+};
+
+} // namespace dart
+
+#endif // VM_HEAP_HISTOGRAM_H_
+
diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc
index 43f978b..03f94e9 100644
--- a/runtime/vm/instructions_arm.cc
+++ b/runtime/vm/instructions_arm.cc
@@ -93,9 +93,9 @@
offset = instr & 0xfff;
instr = Back(++end);
if ((instr & 0xffff0000) == 0xe28a0000) { // add reg, pp, shifter_op
- const int rot = (instr & 0xf00) * 2;
+ const int rot = (instr & 0xf00) >> 7;
const int imm8 = instr & 0xff;
- offset |= (imm8 >> rot) | (imm8 << (32 - rot));
+ offset += (imm8 >> rot) | (imm8 << (32 - rot));
*reg = static_cast<Register>((instr & 0xf000) >> 12);
} else {
ASSERT((instr & 0xffff0000) == 0xe08a0000); // add reg, pp, reg
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 55746ec..01edb86 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -310,8 +310,6 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (receiver_class_id() == kMintCid) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -344,7 +342,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -783,9 +781,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -826,9 +822,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
@@ -2097,7 +2091,7 @@
const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
if (value == 0) {
- // No code needed.
+ __ MoveRegister(result, left);
} else if ((value < 0) || (value >= kCountLimit)) {
// This condition may not be known earlier in some cases because
// of constant propagation, inlining, etc.
@@ -2278,7 +2272,7 @@
case Token::kTRUNCDIV: {
const intptr_t value = Smi::Cast(constant).Value();
if (value == 1) {
- // Do nothing.
+ __ MoveRegister(result, left);
break;
} else if (value == -1) {
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 500ca71..3f043e3 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -269,8 +269,6 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (receiver_class_id() == kMintCid) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -304,7 +302,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -843,9 +841,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -885,9 +881,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 5c4a45c..0245899 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -304,8 +304,6 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (receiver_class_id() == kMintCid) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -338,7 +336,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -757,9 +755,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -803,9 +799,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index f84bb4c..c93b79a3 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -435,8 +435,6 @@
LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
if (receiver_class_id() == kDoubleCid) {
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -460,7 +458,7 @@
locs->set_out(Location::RequiresRegister());
return locs;
}
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
const intptr_t kNumTemps = 1;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
@@ -888,9 +886,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
deopt_id());
return;
@@ -927,9 +923,7 @@
EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
return;
}
- const bool is_checked_strict_equal =
- HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
- if (is_checked_strict_equal) {
+ if (is_checked_strict_equal()) {
EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
deopt_id());
return;
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6c41997..87a6d81 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -14,6 +14,7 @@
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/heap.h"
+#include "vm/heap_histogram.h"
#include "vm/message_handler.h"
#include "vm/object_store.h"
#include "vm/parser.h"
@@ -34,6 +35,13 @@
"Trace isolate creation and shut down.");
DECLARE_FLAG(bool, trace_deoptimization_verbose);
+
+void Isolate::RegisterClass(const Class& cls) {
+ class_table()->Register(cls);
+ if (object_histogram() != NULL) object_histogram()->RegisterClass(cls);
+}
+
+
class IsolateMessageHandler : public MessageHandler {
public:
explicit IsolateMessageHandler(Isolate* isolate);
@@ -400,7 +408,11 @@
deferred_objects_count_(0),
deferred_objects_(NULL),
stacktrace_(NULL),
- stack_frame_index_(-1) {
+ stack_frame_index_(-1),
+ object_histogram_(NULL) {
+ if (FLAG_print_object_histogram && (Dart::vm_isolate() != NULL)) {
+ object_histogram_ = new ObjectHistogram(this);
+ }
}
@@ -418,6 +430,7 @@
mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate.
delete message_handler_;
message_handler_ = NULL; // Fail fast if we send messages to a dead isolate.
+ delete object_histogram_;
}
void Isolate::SetCurrent(Isolate* current) {
@@ -729,6 +742,13 @@
ASSERT(top_resource() == NULL);
ASSERT((heap_ == NULL) || heap_->Verify());
+ if (FLAG_print_object_histogram) {
+ StackZone stack_zone(this);
+ HandleScope handle_scope(this);
+ heap()->CollectAllGarbage();
+ object_histogram()->Print();
+ }
+
// Clean up debugger resources. Shutting down the debugger
// requires a handle zone. We must set up a temporary zone because
// Isolate::Shutdown is called without a zone.
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e0059cf..a2e37c5 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -46,6 +46,7 @@
class StubCode;
class RawFloat32x4;
class RawUint32x4;
+class ObjectHistogram;
// Used by the deoptimization infrastructure to defer allocation of unboxed
@@ -231,6 +232,9 @@
static Isolate* Init(const char* name_prefix);
void Shutdown();
+ // Register a newly introduced class.
+ void RegisterClass(const Class& cls);
+
// Visit all object pointers.
void VisitObjectPointers(ObjectPointerVisitor* visitor,
bool visit_prologue_weak_persistent_handles,
@@ -250,6 +254,8 @@
return OFFSET_OF(Isolate, class_table_);
}
+ ObjectHistogram* object_histogram() { return object_histogram_; }
+
MegamorphicCacheTable* megamorphic_cache_table() {
return &megamorphic_cache_table_;
}
@@ -635,6 +641,7 @@
// Status support.
char* stacktrace_;
intptr_t stack_frame_index_;
+ ObjectHistogram* object_histogram_;
static Dart_IsolateCreateCallback create_callback_;
static Dart_IsolateInterruptCallback interrupt_callback_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c29dd4f..e1185d5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -55,7 +55,6 @@
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
-DECLARE_FLAG(int, deoptimization_counter_threshold);
static const char* kGetterPrefix = "get:";
static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
@@ -390,7 +389,7 @@
Class::kNoTypeArguments;
cls.raw_ptr()->num_native_fields_ = 0;
cls.InitEmptyFields();
- isolate->class_table()->Register(cls);
+ isolate->RegisterClass(cls);
}
// Allocate and initialize the null class.
@@ -892,6 +891,14 @@
RegisterPrivateClass(cls, Symbols::TypeParameter(), core_lib);
pending_classes.Add(cls, Heap::kOld);
+ cls = object_store->bounded_type_class();
+ RegisterPrivateClass(cls, Symbols::BoundedType(), core_lib);
+ pending_classes.Add(cls, Heap::kOld);
+
+ cls = object_store->mixin_app_type_class();
+ RegisterPrivateClass(cls, Symbols::MixinAppType(), core_lib);
+ pending_classes.Add(cls, Heap::kOld);
+
cls = Class::New<Integer>();
object_store->set_integer_implementation_class(cls);
RegisterPrivateClass(cls, Symbols::IntegerImplementation(), core_lib);
@@ -1468,7 +1475,7 @@
result.raw_ptr()->num_native_fields_ = 0;
result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex;
result.InitEmptyFields();
- Isolate::Current()->class_table()->Register(result);
+ Isolate::Current()->RegisterClass(result);
return result.raw();
}
@@ -1619,7 +1626,7 @@
}
}
num_type_args += cls.NumTypeParameters();
- // Object is its own super class during bootstrap.
+ // Super type of Object class is null.
if (cls.super_type() == AbstractType::null() ||
cls.super_type() == isolate->object_store()->object_type()) {
break;
@@ -1879,7 +1886,7 @@
result.raw_ptr()->num_native_fields_ = 0;
result.raw_ptr()->token_pos_ = Scanner::kDummyTokenIndex;
result.InitEmptyFields();
- Isolate::Current()->class_table()->Register(result);
+ Isolate::Current()->RegisterClass(result);
return result.raw();
}
@@ -3446,20 +3453,6 @@
}
-void Function::set_deopt_history(const Array& value) const {
- StorePointer(&raw_ptr()->deopt_history_, value.raw());
-}
-
-
-void Function::EnsureDeoptHistory() const {
- Array& array = Array::Handle(deopt_history());
- if (array.IsNull()) {
- array = Array::New(FLAG_deoptimization_counter_threshold);
- set_deopt_history(array);
- }
-}
-
-
RawContextScope* Function::context_scope() const {
if (IsClosureFunction()) {
const Object& obj = Object::Handle(raw_ptr()->data_);
@@ -5992,6 +5985,123 @@
}
+static RawString* MakeClassMetaName(const Class& cls) {
+ String& cname = String::Handle(cls.Name());
+ return String::Concat(Symbols::At(), cname);
+}
+
+
+static RawString* MakeFieldMetaName(const Field& field) {
+ const String& cname =
+ String::Handle(MakeClassMetaName(Class::Handle(field.origin())));
+ String& fname = String::Handle(field.name());
+ fname = String::Concat(Symbols::At(), fname);
+ return String::Concat(cname, fname);
+}
+
+
+static RawString* MakeFunctionMetaName(const Function& func) {
+ const String& cname =
+ String::Handle(MakeClassMetaName(Class::Handle(func.origin())));
+ String& fname = String::Handle(func.name());
+ fname = String::Concat(Symbols::At(), fname);
+ return String::Concat(cname, fname);
+}
+
+
+void Library::AddMetadata(const Class& cls,
+ const String& name,
+ intptr_t token_pos) const {
+ const String& metaname = String::Handle(Symbols::New(name));
+ Field& field = Field::Handle(Field::New(metaname,
+ true, // is_static
+ false, // is_final
+ false, // is_const
+ cls,
+ token_pos));
+ field.set_type(Type::Handle(Type::DynamicType()));
+ field.set_value(Array::empty_array());
+ GrowableObjectArray& metadata =
+ GrowableObjectArray::Handle(this->metadata());
+ metadata.Add(field, Heap::kOld);
+}
+
+
+void Library::AddClassMetadata(const Class& cls, intptr_t token_pos) const {
+ AddMetadata(cls, String::Handle(MakeClassMetaName(cls)), token_pos);
+}
+
+
+void Library::AddFieldMetadata(const Field& field,
+ intptr_t token_pos) const {
+ AddMetadata(Class::Handle(field.origin()),
+ String::Handle(MakeFieldMetaName(field)),
+ token_pos);
+}
+
+
+void Library::AddFunctionMetadata(const Function& func,
+ intptr_t token_pos) const {
+ AddMetadata(Class::Handle(func.origin()),
+ String::Handle(MakeFunctionMetaName(func)),
+ token_pos);
+}
+
+
+RawString* Library::MakeMetadataName(const Object& obj) const {
+ if (obj.IsClass()) {
+ return MakeClassMetaName(Class::Cast(obj));
+ } else if (obj.IsField()) {
+ return MakeFieldMetaName(Field::Cast(obj));
+ } else if (obj.IsFunction()) {
+ return MakeFunctionMetaName(Function::Cast(obj));
+ }
+ UNIMPLEMENTED();
+ return String::null();
+}
+
+
+RawField* Library::GetMetadataField(const String& metaname) const {
+ const GrowableObjectArray& metadata =
+ GrowableObjectArray::Handle(this->metadata());
+ Field& entry = Field::Handle();
+ String& entryname = String::Handle();
+ intptr_t num_entries = metadata.Length();
+ for (intptr_t i = 0; i < num_entries; i++) {
+ entry ^= metadata.At(i);
+ entryname = entry.name();
+ if (entryname.Equals(metaname)) {
+ return entry.raw();
+ }
+ }
+ return Field::null();
+}
+
+
+RawObject* Library::GetMetadata(const Object& obj) const {
+ if (!obj.IsClass() && !obj.IsField() && !obj.IsFunction()) {
+ return Object::null();
+ }
+ const String& metaname = String::Handle(MakeMetadataName(obj));
+ Field& field = Field::Handle(GetMetadataField(metaname));
+ if (field.IsNull()) {
+ // There is no metadata for this object.
+ return Object::empty_array().raw();;
+ }
+ Object& metadata = Object::Handle();
+ metadata = field.value();
+ if (field.value() == Object::empty_array().raw()) {
+ metadata = Parser::ParseMetadata(Class::Handle(field.owner()),
+ field.token_pos());
+ if (metadata.IsArray()) {
+ ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
+ field.set_value(Array::Cast(metadata));
+ }
+ }
+ return metadata.raw();
+}
+
+
void Library::GrowDictionary(const Array& dict, intptr_t dict_size) const {
// TODO(iposva): Avoid exponential growth.
intptr_t new_dict_size = dict_size * 2;
@@ -6530,6 +6640,8 @@
result.StorePointer(&result.raw_ptr()->url_, url.raw());
result.raw_ptr()->private_key_ = Scanner::AllocatePrivateKey(result);
result.raw_ptr()->dictionary_ = Object::empty_array().raw();
+ result.StorePointer(&result.raw_ptr()->metadata_,
+ GrowableObjectArray::New(4, Heap::kOld));
result.raw_ptr()->anonymous_classes_ = Object::empty_array().raw();
result.raw_ptr()->num_anonymous_ = 0;
result.raw_ptr()->imports_ = Object::empty_array().raw();
@@ -9090,13 +9202,43 @@
}
-RawInstance* Instance::Canonicalize() const {
+RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
ASSERT(!IsNull());
if (this->IsCanonical()) {
return this->raw();
}
Instance& result = Instance::Handle();
const Class& cls = Class::Handle(this->clazz());
+ // TODO(srdjan): Check that predefined classes do not have fields that need
+ // to be checked/canonicalized as well.
+ if ((cls.id() >= kNumPredefinedCids) || cls.IsArray()) {
+ // Iterate over all fields, canonicalize numbers and strings, expect all
+ // other instances to be canonical otherwise report error (return
+ // Instance::null()).
+ Object& obj = Object::Handle();
+ const intptr_t end_field_offset = cls.instance_size() - kWordSize;
+ for (intptr_t field_offset = 0;
+ field_offset <= end_field_offset;
+ field_offset += kWordSize) {
+ obj = *this->FieldAddrAtOffset(field_offset);
+ if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
+ if (obj.IsNumber() || obj.IsString()) {
+ obj = Instance::Cast(obj).CheckAndCanonicalize(NULL);
+ ASSERT(!obj.IsNull());
+ this->SetFieldAtOffset(field_offset, obj);
+ } else {
+ ASSERT(error_str != NULL);
+ const char* kFormat = "field: %s\n";
+ const intptr_t len =
+ OS::SNPrint(NULL, 0, kFormat, obj.ToCString()) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, kFormat, obj.ToCString());
+ *error_str = chars;
+ return Instance::null();
+ }
+ }
+ }
+ }
Array& constants = Array::Handle(cls.constants());
const intptr_t constants_len = constants.Length();
// Linear search to see whether this value is already present in the
@@ -11444,7 +11586,7 @@
}
-RawInstance* String::Canonicalize() const {
+RawInstance* String::CheckAndCanonicalize(const char** error_str) const {
if (IsCanonical()) {
return this->raw();
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 35786cb..492b595 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1368,11 +1368,6 @@
static intptr_t code_offset() { return OFFSET_OF(RawFunction, code_); }
inline bool HasCode() const;
- RawArray* deopt_history() const { return raw_ptr()->deopt_history_; }
- void set_deopt_history(const Array& value) const;
- // If not yet present, allocate deoptimization history array.
- void EnsureDeoptHistory() const;
-
// Returns true if there is at least one debugger breakpoint
// set in this function.
bool HasBreakpoint() const;
@@ -2251,6 +2246,11 @@
void AddExport(const Namespace& ns) const;
+ void AddClassMetadata(const Class& cls, intptr_t token_pos) const;
+ void AddFieldMetadata(const Field& field, intptr_t token_pos) const;
+ void AddFunctionMetadata(const Function& func, intptr_t token_pos) const;
+ RawObject* GetMetadata(const Object& obj) const;
+
// Library imports.
void AddImport(const Namespace& ns) const;
intptr_t num_imports() const { return raw_ptr()->num_imports_; }
@@ -2333,6 +2333,7 @@
RawArray* exports() const { return raw_ptr()->exports_; }
bool HasExports() const;
RawArray* loaded_scripts() const { return raw_ptr()->loaded_scripts_; }
+ RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; }
RawArray* dictionary() const { return raw_ptr()->dictionary_; }
void InitClassDictionary() const;
void InitImportList() const;
@@ -2341,6 +2342,12 @@
bool import_core_lib);
RawObject* LookupEntry(const String& name, intptr_t *index) const;
+ RawString* MakeMetadataName(const Object& obj) const;
+ RawField* GetMetadataField(const String& metaname) const;
+ void AddMetadata(const Class& cls,
+ const String& name,
+ intptr_t token_pos) const;
+
FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object);
friend class Bootstrap;
@@ -3517,7 +3524,12 @@
class Instance : public Object {
public:
virtual bool Equals(const Instance& other) const;
- virtual RawInstance* Canonicalize() const;
+ // Returns Instance::null() if instance cannot be canonicalized.
+ // Any non-canonical number of string will be canonicalized here.
+ // An instance cannot be canonicalized if it still contains non-canonical
+ // instances in its fields.
+ // Returns error in error_str, pass NULL if an error cannot occur.
+ virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
RawObject* GetField(const Field& field) const {
return *FieldAddr(field);
@@ -3608,6 +3620,10 @@
const AbstractTypeArguments& instantiator_type_arguments,
Error* malformed_error) const;
+ virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
+ return Canonicalize();
+ }
+
// Return the canonical version of this type.
virtual RawAbstractType* Canonicalize() const;
@@ -4061,7 +4077,7 @@
virtual bool IsZero() const { return Value() == 0; }
virtual bool IsNegative() const { return Value() < 0; }
// Smi values are implicitly canonicalized.
- virtual RawInstance* Canonicalize() const {
+ virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
return reinterpret_cast<RawSmi*>(raw_value());
}
@@ -4391,7 +4407,7 @@
bool StartsWith(const String& other) const;
- virtual RawInstance* Canonicalize() const;
+ virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
bool IsSymbol() const { return raw()->IsCanonical(); }
@@ -5101,6 +5117,11 @@
virtual bool Equals(const Instance& other) const;
+ virtual RawInstance* CheckAndCanonicalize(const char** error_str) const {
+ UNREACHABLE();
+ return Instance::null();
+ }
+
static intptr_t type_arguments_offset() {
return OFFSET_OF(RawGrowableObjectArray, type_arguments_);
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 4a6ce55..0115294 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -6,6 +6,7 @@
#include "vm/assembler.h"
#include "vm/bigint_operations.h"
#include "vm/class_finalizer.h"
+#include "vm/dart_api_impl.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_store.h"
@@ -2770,14 +2771,14 @@
"MyException\n"
"#0 baz (dart:test-lib:2:3)\n"
"#1 _OtherClass._OtherClass._named (dart:test-lib:7:8)\n"
- "#2 globalVar= (dart:test-lib:12:3)\n"
+ "#2 globalVar= (dart:test-lib:12:7)\n"
"#3 _bar (dart:test-lib:16:3)\n"
"#4 MyClass.field (dart:test-lib:25:9)\n"
"#5 MyClass.foo.fooHelper (dart:test-lib:30:7)\n"
"#6 MyClass.foo (dart:test-lib:32:14)\n"
"#7 MyClass.MyClass.<anonymous closure> (dart:test-lib:21:15)\n"
"#8 MyClass.MyClass (dart:test-lib:21:18)\n"
- "#9 main.<anonymous closure> (dart:test-lib:37:10)\n"
+ "#9 main.<anonymous closure> (dart:test-lib:37:14)\n"
"#10 main (dart:test-lib:37:24)");
}
@@ -3171,6 +3172,112 @@
}
+static RawField* GetField(const Class& cls, const char* name) {
+ const Field& field =
+ Field::Handle(cls.LookupField(String::Handle(String::New(name))));
+ ASSERT(!field.IsNull());
+ return field.raw();
+}
+
+
+static RawClass* GetClass(const Library& lib, const char* name) {
+ const Class& cls =
+ Class::Handle(lib.LookupClass(String::Handle(Symbols::New(name))));
+ ASSERT(!cls.IsNull());
+ return cls.raw();
+}
+
+
+static void PrintMetadata(const char* name, const Object& data) {
+ if (data.IsError()) {
+ OS::Print("Error in metadata evaluation for %s: '%s'\n",
+ name,
+ Error::Cast(data).ToErrorCString());
+ }
+ ASSERT(data.IsArray());
+ const Array& metadata = Array::Cast(data);
+ OS::Print("Metadata for %s has %"Pd" values:\n", name, metadata.Length());
+ Object& elem = Object::Handle();
+ for (int i = 0; i < metadata.Length(); i++) {
+ elem = metadata.At(i);
+ OS::Print(" %d: %s\n", i, elem.ToCString());
+ }
+}
+
+
+TEST_CASE(Metadata) {
+ const char* kScriptChars =
+ "@metafoo \n"
+ "class Meta { \n"
+ " final m; \n"
+ " const Meta(this.m); \n"
+ "} \n"
+ " \n"
+ "const metafoo = 'metafoo'; \n"
+ "const metabar = 'meta' 'bar'; \n"
+ " \n"
+ "@metafoo \n"
+ "@Meta(0) String gVar; \n"
+ " \n"
+ "@metafoo \n"
+ "get tlGetter => gVar; \n"
+ " \n"
+ "@metabar \n"
+ "class A { \n"
+ " @metafoo \n"
+ " @metabar \n"
+ " @Meta('baz') \n"
+ " var aField; \n"
+ " \n"
+ " @metabar @Meta('baa') \n"
+ " int aFunc(a,b) => a + b; \n"
+ "} \n"
+ " \n"
+ "@Meta('main') \n"
+ "A main() { \n"
+ " return new A(); \n"
+ "} \n";
+
+ Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(h_lib);
+ Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ Library& lib = Library::Handle();
+ lib ^= Api::UnwrapHandle(h_lib);
+ ASSERT(!lib.IsNull());
+ const Class& class_a = Class::Handle(GetClass(lib, "A"));
+ Object& res = Object::Handle(lib.GetMetadata(class_a));
+ PrintMetadata("A", res);
+
+ const Class& class_meta = Class::Handle(GetClass(lib, "Meta"));
+ res = lib.GetMetadata(class_meta);
+ PrintMetadata("Meta", res);
+
+ Field& field = Field::Handle(GetField(class_a, "aField"));
+ res = lib.GetMetadata(field);
+ PrintMetadata("A.aField", res);
+
+ Function& func = Function::Handle(GetFunction(class_a, "aFunc"));
+ res = lib.GetMetadata(func);
+ PrintMetadata("A.aFunc", res);
+
+ func = lib.LookupLocalFunction(String::Handle(Symbols::New("main")));
+ ASSERT(!func.IsNull());
+ res = lib.GetMetadata(func);
+ PrintMetadata("main", res);
+
+ func = lib.LookupLocalFunction(String::Handle(Symbols::New("get:tlGetter")));
+ ASSERT(!func.IsNull());
+ res = lib.GetMetadata(func);
+ PrintMetadata("tlGetter", res);
+
+ field = lib.LookupLocalField(String::Handle(Symbols::New("gVar")));
+ ASSERT(!field.IsNull());
+ res = lib.GetMetadata(field);
+ PrintMetadata("gVar", res);
+}
+
+
TEST_CASE(FunctionSourceFingerprint) {
const char* kScriptChars =
"class A {\n"
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index eb3ea07..e2ade07 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -511,6 +511,7 @@
has_var = false;
has_factory = false;
has_operator = false;
+ metadata_pos = -1;
operator_token = Token::kILLEGAL;
type = NULL;
name_pos = 0;
@@ -543,6 +544,7 @@
bool has_var;
bool has_factory;
bool has_operator;
+ intptr_t metadata_pos;
Token::Kind operator_token;
const AbstractType* type;
intptr_t name_pos;
@@ -647,8 +649,8 @@
return fields_;
}
- RawClass* clazz() const {
- return clazz_.raw();
+ const Class& clazz() const {
+ return clazz_;
}
const String& class_name() const {
@@ -841,6 +843,63 @@
}
+RawObject* Parser::ParseMetadata(const Class& cls, intptr_t token_pos) {
+ Isolate* isolate = Isolate::Current();
+ StackZone zone(isolate);
+ LongJump* base = isolate->long_jump_base();
+ LongJump jump;
+ isolate->set_long_jump_base(&jump);
+ if (setjmp(*jump.Set()) == 0) {
+ const Script& script = Script::Handle(cls.script());
+ const Library& lib = Library::Handle(cls.library());
+ Parser parser(script, lib, token_pos);
+ parser.set_current_class(cls);
+ return parser.EvaluateMetadata();
+ } else {
+ Error& error = Error::Handle();
+ error = isolate->object_store()->sticky_error();
+ isolate->object_store()->clear_sticky_error();
+ isolate->set_long_jump_base(base);
+ return error.raw();
+ }
+ UNREACHABLE();
+ return Object::null();
+}
+
+
+RawArray* Parser::EvaluateMetadata() {
+ if (CurrentToken() != Token::kAT) {
+ ErrorMsg("Metadata character '@' expected");
+ }
+ GrowableObjectArray& meta_values =
+ GrowableObjectArray::Handle(GrowableObjectArray::New());
+ while (CurrentToken() == Token::kAT) {
+ ConsumeToken();
+ intptr_t expr_pos = TokenPos();
+ if (!IsIdentifier()) {
+ ExpectIdentifier("identifier expected");
+ }
+ AstNode* expr = NULL;
+ if ((LookaheadToken(1) == Token::kLPAREN) ||
+ ((LookaheadToken(1) == Token::kPERIOD) &&
+ (LookaheadToken(3) == Token::kLPAREN)) ||
+ ((LookaheadToken(1) == Token::kPERIOD) &&
+ (LookaheadToken(3) == Token::kPERIOD) &&
+ (LookaheadToken(5) == Token::kLPAREN))) {
+ expr = ParseNewOperator(Token::kCONST);
+ } else {
+ expr = ParsePrimary();
+ }
+ if (expr->EvalConstExpr() == NULL) {
+ ErrorMsg(expr_pos, "expression must be a compile-time constant");
+ }
+ const Instance& val = EvaluateConstExpr(expr);
+ meta_values.Add(val);
+ }
+ return Array::MakeArray(meta_values);
+}
+
+
// TODO(regis): Since a const variable is implicitly final,
// rename ParseStaticConstGetter to ParseStaticFinalGetter and
// rename kConstImplicitGetter to kImplicitFinalGetter.
@@ -2824,6 +2883,9 @@
method_pos));
func.set_result_type(*method->type);
func.set_end_token_pos(method_end_pos);
+ if (method->metadata_pos > 0) {
+ library_.AddFunctionMetadata(func, method->metadata_pos);
+ }
// If this method is a redirecting factory, set the redirection information.
if (!redirection_type.IsNull()) {
@@ -2911,6 +2973,9 @@
class_field.set_type(*field->type);
class_field.set_has_initializer(has_initializer);
members->AddField(class_field);
+ if (field->metadata_pos >= 0) {
+ library_.AddFieldMetadata(class_field, field->metadata_pos);
+ }
// For static const fields, set value to "uninitialized" and
// create a kConstImplicitGetter getter method.
@@ -3001,10 +3066,12 @@
}
-void Parser::ParseClassMemberDefinition(ClassDesc* members) {
+void Parser::ParseClassMemberDefinition(ClassDesc* members,
+ intptr_t metadata_pos) {
TRACE_PARSER("ParseClassMemberDefinition");
MemberDesc member;
current_member_ = &member;
+ member.metadata_pos = metadata_pos;
if ((CurrentToken() == Token::kEXTERNAL) &&
(LookaheadToken(1) != Token::kLPAREN)) {
ConsumeToken();
@@ -3217,7 +3284,8 @@
}
-void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes) {
+void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes,
+ intptr_t metadata_pos) {
TRACE_PARSER("ParseClassDeclaration");
bool is_patch = false;
bool is_abstract = false;
@@ -3359,6 +3427,9 @@
cls.set_is_patch();
}
pending_classes.Add(cls, Heap::kOld);
+ if (metadata_pos >= 0) {
+ library_.AddClassMetadata(cls, metadata_pos);
+ }
if (CurrentToken() != Token::kLBRACE) {
ErrorMsg("{ expected");
@@ -3379,8 +3450,8 @@
}
ExpectToken(Token::kLBRACE);
while (CurrentToken() != Token::kRBRACE) {
- SkipMetadata();
- ParseClassMemberDefinition(&members);
+ intptr_t metadata_pos = SkipMetadata();
+ ParseClassMemberDefinition(&members, metadata_pos);
}
ExpectToken(Token::kRBRACE);
@@ -3719,7 +3790,11 @@
}
-void Parser::SkipMetadata() {
+intptr_t Parser::SkipMetadata() {
+ if (CurrentToken() != Token::kAT) {
+ return -1;
+ }
+ intptr_t metadata_pos = TokenPos();
while (CurrentToken() == Token::kAT) {
ConsumeToken();
ExpectIdentifier("identifier expected");
@@ -3735,6 +3810,7 @@
SkipToMatchingParenthesis();
}
}
+ return metadata_pos;
}
@@ -3973,7 +4049,8 @@
}
-void Parser::ParseTopLevelVariable(TopLevel* top_level) {
+void Parser::ParseTopLevelVariable(TopLevel* top_level,
+ intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelVariable");
const bool is_const = (CurrentToken() == Token::kCONST);
// Const fields are implicitly final.
@@ -4013,6 +4090,9 @@
field.set_value(Instance::Handle(Instance::null()));
top_level->fields.Add(field);
library_.AddObject(field, var_name);
+ if (metadata_pos >= 0) {
+ library_.AddFieldMetadata(field, metadata_pos);
+ }
if (CurrentToken() == Token::kASSIGN) {
ConsumeToken();
Instance& field_value = Instance::Handle(Object::sentinel().raw());
@@ -4052,7 +4132,8 @@
}
-void Parser::ParseTopLevelFunction(TopLevel* top_level) {
+void Parser::ParseTopLevelFunction(TopLevel* top_level,
+ intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelFunction");
AbstractType& result_type = Type::Handle(Type::DynamicType());
const bool is_static = true;
@@ -4137,10 +4218,14 @@
} else {
library_.ReplaceObject(func, func_name);
}
+ if (metadata_pos >= 0) {
+ library_.AddFunctionMetadata(func, metadata_pos);
+ }
}
-void Parser::ParseTopLevelAccessor(TopLevel* top_level) {
+void Parser::ParseTopLevelAccessor(TopLevel* top_level,
+ intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelAccessor");
const bool is_static = true;
bool is_external = false;
@@ -4258,6 +4343,9 @@
} else {
library_.ReplaceObject(func, accessor_name);
}
+ if (metadata_pos >= 0) {
+ library_.AddFunctionMetadata(func, metadata_pos);
+ }
}
@@ -4528,27 +4616,27 @@
const Class& cls = Class::Handle(isolate());
while (true) {
set_current_class(cls); // No current class.
- SkipMetadata();
+ intptr_t metadata_pos = SkipMetadata();
if (CurrentToken() == Token::kCLASS) {
- ParseClassDeclaration(pending_classes);
+ ParseClassDeclaration(pending_classes, metadata_pos);
} else if ((CurrentToken() == Token::kTYPEDEF) &&
(LookaheadToken(1) != Token::kLPAREN)) {
set_current_class(toplevel_class);
ParseTypedef(pending_classes);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
- ParseClassDeclaration(pending_classes);
+ ParseClassDeclaration(pending_classes, metadata_pos);
} else if (is_patch_source() && IsLiteral("patch") &&
(LookaheadToken(1) == Token::kCLASS)) {
- ParseClassDeclaration(pending_classes);
+ ParseClassDeclaration(pending_classes, metadata_pos);
} else {
set_current_class(toplevel_class);
if (IsVariableDeclaration()) {
- ParseTopLevelVariable(&top_level);
+ ParseTopLevelVariable(&top_level, metadata_pos);
} else if (IsFunctionDeclaration()) {
- ParseTopLevelFunction(&top_level);
+ ParseTopLevelFunction(&top_level, metadata_pos);
} else if (IsTopLevelAccessor()) {
- ParseTopLevelAccessor(&top_level);
+ ParseTopLevelAccessor(&top_level, metadata_pos);
} else if (CurrentToken() == Token::kEOS) {
break;
} else {
@@ -6803,8 +6891,8 @@
arguments->Add(new LiteralNode(call_pos, Array::ZoneHandle()));
} else {
const int total_num_parameters = function.NumParameters();
- Array& array = Array::ZoneHandle(Array::New(total_num_parameters));
- array ^= array.Canonicalize();
+ Array& array =
+ Array::ZoneHandle(Array::New(total_num_parameters, Heap::kOld));
// Skip receiver.
for (int i = 0; i < total_num_parameters; i++) {
array.SetAt(i, String::Handle(function.ParameterNameAt(i)));
@@ -7437,8 +7525,23 @@
ASSERT(field.value() != Object::transition_sentinel().raw());
return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value()));
}
- // Access the field directly.
- return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw()));
+ ASSERT(field.is_static());
+ const Class& field_owner = Class::ZoneHandle(field.owner());
+ const String& field_name = String::ZoneHandle(field.name());
+ const String& getter_name = String::Handle(Field::GetterName(field_name));
+ const Function& getter =
+ Function::Handle(field_owner.LookupStaticFunction(getter_name));
+ // Never load field directly if there is a getter (deterministic AST).
+ if (getter.IsNull()) {
+ return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw()));
+ } else {
+ ASSERT(getter.kind() == RawFunction::kConstImplicitGetter);
+ return new StaticGetterNode(ident_pos,
+ NULL, // Receiver.
+ false, // is_super_getter.
+ field_owner,
+ field_name);
+ }
}
@@ -8059,11 +8162,24 @@
}
+RawInstance* Parser::TryCanonicalize(const Instance& instance,
+ intptr_t token_pos) {
+ if (instance.IsNull()) {
+ return instance.raw();
+ }
+ const char* error_str = NULL;
+ Instance& result =
+ Instance::Handle(instance.CheckAndCanonicalize(&error_str));
+ if (result.IsNull()) {
+ ErrorMsg(token_pos, "Invalid const object %s", error_str);
+ }
+ return result.raw();
+}
-// If the field is constant, initialize the field if necessary and return
-// no ast (NULL).
-// Otherwise return NULL if no implicit getter exists (either never created
-// because trivial, or not needed or field not readable).
+
+// If the field is already initialized, return no ast (NULL).
+// Otherwise, if the field is constant, initialize the field and return no ast.
+// If the field is not initialized and not const, return the ast for the getter.
AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
ASSERT(field.is_static());
const Class& field_owner = Class::ZoneHandle(field.owner());
@@ -8121,9 +8237,7 @@
ASSERT(const_value.IsNull() || const_value.IsInstance());
Instance& instance = Instance::Handle();
instance ^= const_value.raw();
- if (!instance.IsNull()) {
- instance ^= instance.Canonicalize();
- }
+ instance = TryCanonicalize(instance, TokenPos());
field.set_value(instance);
return NULL; // Constant
} else {
@@ -8188,10 +8302,7 @@
return Object::null();
}
} else {
- if (!instance.IsNull()) {
- instance ^= instance.Canonicalize();
- }
- return instance.raw();
+ return TryCanonicalize(instance, TokenPos());
}
}
@@ -8831,7 +8942,7 @@
}
const_list.SetAt(i, elem->AsLiteralNode()->literal());
}
- const_list ^= const_list.Canonicalize();
+ const_list ^= TryCanonicalize(const_list, literal_pos);
const_list.MakeImmutable();
return new LiteralNode(literal_pos, const_list);
} else {
@@ -9028,7 +9139,7 @@
}
key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
}
- key_value_array ^= key_value_array.Canonicalize();
+ key_value_array ^= TryCanonicalize(key_value_array, TokenPos());
key_value_array.MakeImmutable();
// Construct the map object.
@@ -9146,12 +9257,11 @@
}
-AstNode* Parser::ParseNewOperator() {
+AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
TRACE_PARSER("ParseNewOperator");
const intptr_t new_pos = TokenPos();
- ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST));
- bool is_const = (CurrentToken() == Token::kCONST);
- ConsumeToken();
+ ASSERT((op_kind == Token::kNEW) || (op_kind == Token::kCONST));
+ bool is_const = (op_kind == Token::kCONST);
if (!IsIdentifier()) {
ErrorMsg("type name expected");
}
@@ -9619,7 +9729,8 @@
} else if (CurrentToken() == Token::kSTRING) {
primary = ParseStringLiteral();
} else if (CurrentToken() == Token::kNEW) {
- primary = ParseNewOperator();
+ ConsumeToken();
+ primary = ParseNewOperator(Token::kNEW);
} else if (CurrentToken() == Token::kCONST) {
if ((LookaheadToken(1) == Token::kLT) ||
(LookaheadToken(1) == Token::kLBRACK) ||
@@ -9627,7 +9738,8 @@
(LookaheadToken(1) == Token::kLBRACE)) {
primary = ParseCompoundLiteral();
} else {
- primary = ParseNewOperator();
+ ConsumeToken();
+ primary = ParseNewOperator(Token::kCONST);
}
} else if (CurrentToken() == Token::kLT ||
CurrentToken() == Token::kLBRACK ||
@@ -9701,9 +9813,7 @@
ASSERT(result.IsInstance());
Instance& value = Instance::ZoneHandle();
value ^= result.raw();
- if (!value.IsNull()) {
- value ^= value.Canonicalize();
- }
+ value = TryCanonicalize(value, TokenPos());
return value;
}
}
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 42e1074..00681dc 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -141,6 +141,11 @@
static void ParseFunction(ParsedFunction* parsed_function);
+ // Parse and evaluate the metadata expressions at token_pos in the
+ // class namespace of class cls (which can be the implicit toplevel
+ // class if the metadata is at the top-level).
+ static RawObject* ParseMetadata(const Class& cls, intptr_t token_pos);
+
// Format and print a message with source location.
// A null script means no source and a negative token_pos means no position.
static void PrintMessage(const Script& script,
@@ -261,7 +266,7 @@
void SkipIf(Token::Kind);
void SkipBlock();
- void SkipMetadata();
+ intptr_t SkipMetadata();
void SkipToMatchingParenthesis();
void SkipTypeArguments();
void SkipType(bool allow_void);
@@ -325,13 +330,15 @@
// Support for parsing of scripts.
void ParseTopLevel();
- void ParseClassDeclaration(const GrowableObjectArray& pending_classes);
+ void ParseClassDeclaration(const GrowableObjectArray& pending_classes,
+ intptr_t metadata_pos);
void ParseClassDefinition(const Class& cls);
void ParseMixinTypedef(const GrowableObjectArray& pending_classes);
void ParseTypedef(const GrowableObjectArray& pending_classes);
- void ParseTopLevelVariable(TopLevel* top_level);
- void ParseTopLevelFunction(TopLevel* top_level);
- void ParseTopLevelAccessor(TopLevel* top_level);
+ void ParseTopLevelVariable(TopLevel* top_level, intptr_t metadata_pos);
+ void ParseTopLevelFunction(TopLevel* top_level, intptr_t metadata_pos);
+ void ParseTopLevelAccessor(TopLevel* top_level, intptr_t metadata_pos);
+ RawArray* EvaluateMetadata();
// Support for parsing libraries.
RawObject* CallLibraryTagHandler(Dart_LibraryTag tag,
@@ -358,7 +365,8 @@
void ParseQualIdent(QualIdent* qual_ident);
void ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method);
void ParseFieldDefinition(ClassDesc* members, MemberDesc* field);
- void ParseClassMemberDefinition(ClassDesc* members);
+ void ParseClassMemberDefinition(ClassDesc* members,
+ intptr_t metadata_pos);
void ParseFormalParameter(bool allow_explicit_default_value,
ParamList* params);
void ParseFormalParameters(bool allow_explicit_default_values,
@@ -522,7 +530,7 @@
AstNode* ParseMapLiteral(intptr_t type_pos,
bool is_const,
const AbstractTypeArguments& type_arguments);
- AstNode* ParseNewOperator();
+ AstNode* ParseNewOperator(Token::Kind op_kind);
AstNode* ParseArgumentDefinitionTest();
// An implicit argument, if non-null, is prepended to the returned list.
@@ -629,6 +637,8 @@
const Function& constructor,
ArgumentListNode* arguments);
+ RawInstance* TryCanonicalize(const Instance& instance, intptr_t token_pos);
+
Isolate* isolate() const { return isolate_; }
Isolate* isolate_; // Cached current isolate.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 1ef30f4..9794c11 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -443,6 +443,7 @@
friend class HeapProfilerRootVisitor;
friend class MarkingVisitor;
friend class Object;
+ friend class ObjectHistogram;
friend class RawExternalTypedData;
friend class RawInstructions;
friend class RawInstance;
@@ -611,7 +612,6 @@
RawArray* parameter_names_;
RawCode* code_; // Compiled code for the function.
RawCode* unoptimized_code_; // Unoptimized code, keep it after optimization.
- RawArray* deopt_history_; // Deopt Ids of past deoptimizations.
RawObject* data_; // Additional data specific to the function kind.
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->data_);
@@ -761,6 +761,7 @@
RawScript* script_;
RawString* private_key_;
RawArray* dictionary_; // Top-level names in this library.
+ RawGrowableObjectArray* metadata_; // Metadata on classes, methods etc.
RawArray* anonymous_classes_; // Classes containing top-level elements.
RawArray* imports_; // List of Namespaces imported without prefix.
RawArray* exports_; // List of re-exported Namespaces.
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index d4f39a7..7f139db 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1711,7 +1711,8 @@
if ((kind != Snapshot::kFull) && RawObject::IsCanonical(tags) &&
(RawObject::IsCreatedFromSnapshot(tags) ||
(kind == Snapshot::kMessage))) {
- obj ^= obj.Canonicalize();
+ obj ^= obj.CheckAndCanonicalize(NULL);
+ ASSERT(!obj.IsNull());
}
reader->AddBackRef(object_id, &obj, kIsDeserialized);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index ff22e03..3333f2d 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -479,7 +479,7 @@
obj->ptr()->handle_vtable_ = fake.vtable();
cls_ = obj;
cls_.set_id(kIllegalCid);
- isolate()->class_table()->Register(cls_);
+ isolate()->RegisterClass(cls_);
return cls_.raw();
}
@@ -795,7 +795,8 @@
if (kind_ == Snapshot::kFull) {
result->SetCreatedFromSnapshot();
} else if (result->IsCanonical()) {
- *result = result->Canonicalize();
+ *result = result->CheckAndCanonicalize(NULL);
+ ASSERT(!result->IsNull());
}
return result->raw();
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index a1752a0..2688745 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -70,6 +70,8 @@
V(UnresolvedClass, "UnresolvedClass") \
V(Type, "_Type") \
V(TypeParameter, "_TypeParameter") \
+ V(BoundedType, "_BoundedType") \
+ V(MixinAppType, "_MixinAppType") \
V(TypeArguments, "TypeArguments") \
V(InstantiatedTypeArguments, "InstantiatedTypeArguments") \
V(PatchClass, "PatchClass") \
@@ -347,6 +349,9 @@
static const String& Slash() {
return *(symbol_handles_[kNullCharId + '/']);
}
+ static const String& At() {
+ return *(symbol_handles_[kNullCharId + '@']);
+ }
// Access methods for symbol handles stored in the vm isolate.
#define DEFINE_SYMBOL_HANDLE_ACCESSOR(symbol, literal) \
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 6c68fba..1d6ec29 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -170,6 +170,8 @@
'hash_map_test.cc',
'heap.cc',
'heap.h',
+ 'heap_histogram.cc',
+ 'heap_histogram.h',
'heap_profiler.cc',
'heap_profiler.h',
'heap_profiler_test.cc',
diff --git a/sdk/bin/dart2analyzer b/sdk/bin/dart2analyzer
deleted file mode 100755
index 4c17671..0000000
--- a/sdk/bin/dart2analyzer
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash --posix
-# 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.
-
-set -e
-
-BIN_DIR="$(cd "${BASH_SOURCE%/*}" ; pwd -P)"
-SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
-DART="$BIN_DIR/dart"
-PKG_ANALYZER="$BIN_DIR/../packages/analyzer_experimental/bin/analyzer.dart"
-
-FOUND_BATCH=0
-FOUND_SDK=0
-for ARG in "$@"
-do
- case $ARG in
- -batch|--batch)
- FOUND_BATCH=1
- ;;
- --dart-sdk)
- FOUND_SDK=1
- ;;
- *)
- ;;
- esac
-done
-
-if [ $FOUND_SDK = 0 ] ; then
- exec "$DART" "${PKG_ANALYZER}" --dart-sdk "${SDK_DIR}" "$@"
-else
- exec "$DART" "${PKG_ANALYZER}" "$@"
-fi
diff --git a/sdk/bin/dart2analyzer_developer b/sdk/bin/dart2analyzer_developer
deleted file mode 100755
index 5583382..0000000
--- a/sdk/bin/dart2analyzer_developer
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-# 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.
-
-. ${BASH_SOURCE%_developer}
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 04191ab..b51e9f5 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -913,7 +913,13 @@
if (element.isClass()) {
ClassElement cls = element;
cls.ensureResolved(this);
- cls.forEachLocalMember(world.addToWorkList);
+ cls.forEachLocalMember((e) {
+ if (e.isSynthesized) {
+ // TODO(ahe): Work-around for http://dartbug.com/11205.
+ if (e.getLibrary().isPlatformLibrary) return;
+ }
+ world.addToWorkList(e);
+ });
world.registerInstantiatedClass(element, globalDependencies);
} else {
world.addToWorkList(element);
@@ -1308,7 +1314,9 @@
const Tracer();
- void traceCompilation(String methodName, ItemCompilationContext context) {
+ void traceCompilation(String methodName,
+ ItemCompilationContext context,
+ Compiler compiler) {
}
void traceGraph(String name, var graph) {
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 5bc30cd..609b2be 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -418,7 +418,9 @@
new EmptyStatement(new StringToken(SEMICOLON_INFO, ';', -1)),
null, Modifiers.EMPTY, null, null);
- classMembers[classElement].add(constructor);
+ if (!constructor.isSynthesized) {
+ classMembers[classElement].add(constructor);
+ }
elementAsts[constructor] =
new ElementAst(constructor.cachedNode, new TreeElementMapping(null));
}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 732e44c..66f97f4 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1959,6 +1959,8 @@
void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
addToScope(constructor, compiler);
+ // The default constructor, although synthetic, is part of a class' API.
+ localMembers = localMembers.prepend(constructor);
}
Link<DartType> computeTypeParameters(Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 1dfe675..419f521 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -69,6 +69,14 @@
Element getInterceptorMethod;
Element interceptedNames;
+ HType stringType;
+ HType indexablePrimitiveType;
+ HType readableArrayType;
+ HType mutableArrayType;
+ HType fixedArrayType;
+ HType extendableArrayType;
+
+
// TODO(9577): Make it so that these are not needed when there are no native
// classes.
Element dispatchPropertyName;
@@ -371,6 +379,19 @@
..add(jsNullClass);
validateInterceptorImplementsAllObjectMethods(jsInterceptorClass);
+
+ stringType = new HBoundedType(
+ new TypeMask.nonNullExact(jsStringClass.rawType));
+ indexablePrimitiveType = new HBoundedType(
+ new TypeMask.nonNullSubtype(jsIndexableClass.rawType));
+ readableArrayType = new HBoundedType(
+ new TypeMask.nonNullSubclass(jsArrayClass.rawType));
+ mutableArrayType = new HBoundedType(
+ new TypeMask.nonNullSubclass(jsMutableArrayClass.rawType));
+ fixedArrayType = new HBoundedType(
+ new TypeMask.nonNullExact(jsFixedArrayClass.rawType));
+ extendableArrayType = new HBoundedType(
+ new TypeMask.nonNullExact(jsExtendableArrayClass.rawType));
}
void validateInterceptorImplementsAllObjectMethods(
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index fb146ff..7721152 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -1132,14 +1132,16 @@
bool instanceFieldNeedsGetter(Element member) {
assert(member.isField());
if (fieldAccessNeverThrows(member)) return false;
- return compiler.codegenWorld.hasInvokedGetter(member, compiler);
+ return compiler.mirrorsEnabled
+ || compiler.codegenWorld.hasInvokedGetter(member, compiler);
}
bool instanceFieldNeedsSetter(Element member) {
assert(member.isField());
if (fieldAccessNeverThrows(member)) return false;
return (!member.modifiers.isFinalOrConst())
- && compiler.codegenWorld.hasInvokedSetter(member, compiler);
+ && (compiler.mirrorsEnabled
+ || compiler.codegenWorld.hasInvokedSetter(member, compiler));
}
// We never access a field in a closure (a captured variable) without knowing
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index f7adf4a..3f29f71 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -172,17 +172,6 @@
needed = true;
}
- // BUG. There is a missing proto in the picture the DOM gives of the
- // proto chain.
- // TODO(9907): Fix DOM generation. We might need an annotation.
- if (classElement.isNative()) {
- List<String> nativeTags = nativeTagsOfClass(classElement);
- if (nativeTags.contains('HTMLElement')) {
- nonleafClasses.add(classElement);
- needed = true;
- }
- }
-
if (needed || neededClasses.contains(classElement)) {
neededClasses.add(classElement);
neededClasses.add(classElement.superclass);
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 6a70a51..df00f77 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -942,7 +942,7 @@
HInstruction local = builder.localsHandler.readLocal(parameter);
Constant arityConstant =
builder.constantSystem.createInt(type.computeArity());
- HInstruction arity = builder.graph.addConstant(arityConstant);
+ HInstruction arity = builder.graph.addConstant(arityConstant, compiler);
// TODO(ngeoffray): For static methods, we could pass a method with a
// defined arity.
Element helper = builder.backend.getClosureConverter();
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index d0ffd9a..95f6edf 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -3336,10 +3336,17 @@
void doApplyMixinTo(MixinApplicationElement mixinApplication,
DartType supertype,
DartType mixinType) {
- assert(mixinApplication.supertype == null);
- mixinApplication.supertype = supertype;
-
Node node = mixinApplication.parseNode(compiler);
+
+ if (mixinApplication.supertype != null) {
+ // [supertype] is not null if there was a cycle.
+ assert(invariant(node, compiler.compilationFailed));
+ supertype = mixinApplication.supertype;
+ assert(invariant(node, supertype.element == compiler.objectClass));
+ } else {
+ mixinApplication.supertype = supertype;
+ }
+
// Named mixin application may have an 'implements' clause.
NamedMixinApplication namedMixinApplication =
node.asNamedMixinApplication();
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index b9db4c4..1396a72 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -110,7 +110,7 @@
// Primitive types that are not null are valuable. These include
// indexable arrays.
bool typeValuable(HType type) {
- return type.isPrimitive() && !type.isNull();
+ return type.isPrimitive(compiler) && !type.isNull();
}
bool get hasTypeGuards => work.guards.length != 0;
@@ -219,7 +219,8 @@
bool willThrowArgumentError(Selector selector,
HInstruction receiver,
HType speculativeType) {
- if (receiver != null && (receiver.isInteger() || receiver.isString())) {
+ if (receiver != null
+ && (receiver.isInteger() || receiver.isString(compiler))) {
return selector.isOperator()
&& selector.name != const SourceString('==')
&& (speculativeType.isNumber() && !speculativeType.isInteger());
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 9121747..1cd2255 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -73,7 +73,8 @@
} else {
name = "${element.name.slowToString()}";
}
- compiler.tracer.traceCompilation(name, work.compilationContext);
+ compiler.tracer.traceCompilation(
+ name, work.compilationContext, compiler);
compiler.tracer.traceGraph('builder', graph);
}
return graph;
@@ -829,7 +830,7 @@
assert(label != null);
HInstruction value = builder.graph.addConstantInt(
targetIndexMap[label.target],
- builder.constantSystem);
+ builder.compiler);
builder.localsHandler.updateLocal(target, value);
assert(label.target.labels.contains(label));
@@ -1017,11 +1018,11 @@
() {
HParameterValue parameter = parameters.values.first;
push(new HIdentity(
- parameter, graph.addConstantNull(constantSystem)));
+ parameter, graph.addConstantNull(compiler)));
},
() {
closeAndGotoExit(new HReturn(
- graph.addConstantBool(false, constantSystem)));
+ graph.addConstantBool(false, compiler)));
},
null);
}
@@ -1183,7 +1184,7 @@
ElementKind.VARIABLE,
function);
newLocalsHandler.updateLocal(returnElement,
- graph.addConstantNull(constantSystem));
+ graph.addConstantNull(compiler));
elements = compiler.enqueuer.resolution.getCachedElements(function);
assert(elements != null);
returnType = signature.returnType;
@@ -1343,7 +1344,7 @@
|| superclass.typeVariables == typeVariables);
while (!typeVariables.isEmpty) {
localsHandler.updateLocal(typeVariables.head.element,
- graph.addConstantNull(constantSystem));
+ graph.addConstantNull(compiler));
typeVariables = typeVariables.tail;
}
}
@@ -1490,7 +1491,7 @@
SendSet assignment = node.asSendSet();
HInstruction value;
if (assignment == null) {
- value = graph.addConstantNull(constantSystem);
+ value = graph.addConstantNull(compiler);
} else {
Node right = assignment.arguments.head;
TreeElements savedElements = elements;
@@ -1677,11 +1678,12 @@
// Fetch the original default value of [element];
Constant constant = compileVariable(element);
HConstant defaultValue = constant == null
- ? graph.addConstantNull(constantSystem)
- : graph.addConstant(constant);
+ ? graph.addConstantNull(compiler)
+ : graph.addConstant(constant, compiler);
// Emit the equality check with the sentinel.
- HConstant sentinel = graph.addConstant(SentinelConstant.SENTINEL);
+ HConstant sentinel =
+ graph.addConstant(SentinelConstant.SENTINEL, compiler);
HInstruction operand = parameters[element];
check = new HIdentity(sentinel, operand);
add(check);
@@ -1943,7 +1945,7 @@
}
visitExpressionStatement(ExpressionStatement node) {
- assert(isReachable);
+ if (!isReachable) return;
Throw throwExpression = node.expression.asThrow();
if (throwExpression != null && inliningStack.isEmpty) {
visit(throwExpression.expression);
@@ -2243,7 +2245,7 @@
}
HInstruction buildCondition() {
if (node.condition == null) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
}
visit(node.condition);
return popBoolified();
@@ -2504,7 +2506,7 @@
HConstant constant = operand;
Constant folded = operation.fold(constant.constant);
if (folded != null) {
- stack.add(graph.addConstant(folded));
+ stack.add(graph.addConstant(folded, compiler));
return;
}
}
@@ -2572,7 +2574,7 @@
value = compileVariable(element);
}
if (value != null) {
- stack.add(graph.addConstant(value));
+ stack.add(graph.addConstant(value, compiler));
} else if (element.isField() && isLazilyInitialized(element)) {
HInstruction instruction = new HLazyStatic(element);
instruction.instructionType =
@@ -2689,13 +2691,17 @@
return pop();
}
+ HLiteralList buildLiteralList(List<HInstruction> inputs) {
+ return new HLiteralList(inputs, backend.extendableArrayType);
+ }
+
// TODO(karlklose): change construction of the representations to be GVN'able
// (dartbug.com/7182).
HInstruction buildTypeArgumentRepresentations(DartType type) {
// Compute the representation of the type arguments, including access
// to the runtime type information for type variables as instructions.
if (type.kind == TypeKind.TYPE_VARIABLE) {
- return new HLiteralList(<HInstruction>[addTypeVariableReference(type)]);
+ return buildLiteralList(<HInstruction>[addTypeVariableReference(type)]);
} else {
assert(type.element.isClass());
InterfaceType interface = type;
@@ -2710,7 +2716,7 @@
}
String template = '[${templates.join(', ')}]';
HInstruction representation =
- createForeign(template, HType.READABLE_ARRAY, inputs);
+ createForeign(template, backend.readableArrayType, inputs);
return representation;
}
}
@@ -2789,7 +2795,7 @@
HInstruction isFieldName = addConstantString(node, operator);
HInstruction asFieldName = compiler.world.hasAnySubtype(element)
? addConstantString(node, backend.namer.substitutionName(element))
- : graph.addConstantNull(constantSystem);
+ : graph.addConstantNull(compiler);
List<HInstruction> inputs = <HInstruction>[expression,
isFieldName,
representations,
@@ -2848,7 +2854,7 @@
} else {
constant = compileConstant(parameter);
}
- return graph.addConstant(constant);
+ return graph.addConstant(constant, compiler);
}
/**
@@ -3131,7 +3137,7 @@
constantSystem.createString(new DartString.literal(internalName), node);
Element createInvocationMirror = backend.getCreateInvocationMirror();
- var argumentsInstruction = new HLiteralList(arguments);
+ var argumentsInstruction = buildLiteralList(arguments);
add(argumentsInstruction);
var argumentNames = new List<HInstruction>();
@@ -3139,9 +3145,9 @@
Constant argumentNameConstant =
constantSystem.createString(new DartString.literal(
argumentName.slowToString()), node);
- argumentNames.add(graph.addConstant(argumentNameConstant));
+ argumentNames.add(graph.addConstant(argumentNameConstant, compiler));
}
- var argumentNamesInstruction = new HLiteralList(argumentNames);
+ var argumentNamesInstruction = buildLiteralList(argumentNames);
add(argumentNamesInstruction);
Constant kindConstant =
@@ -3149,9 +3155,9 @@
pushInvokeStatic(null,
createInvocationMirror,
- [graph.addConstant(nameConstant),
- graph.addConstant(internalNameConstant),
- graph.addConstant(kindConstant),
+ [graph.addConstant(nameConstant, compiler),
+ graph.addConstant(internalNameConstant, compiler),
+ graph.addConstant(kindConstant, compiler),
argumentsInstruction,
argumentNamesInstruction],
HType.UNKNOWN);
@@ -3214,7 +3220,7 @@
int index = RuntimeTypes.getTypeVariableIndex(variable);
String substitutionNameString = backend.namer.substitutionName(cls);
HInstruction substitutionName = graph.addConstantString(
- new LiteralDartString(substitutionNameString), null, constantSystem);
+ new LiteralDartString(substitutionNameString), null, compiler);
HInstruction target = localsHandler.readThis();
HInstruction substitution = createForeign('#[#]', HType.UNKNOWN,
<HInstruction>[target, substitutionName]);
@@ -3223,7 +3229,7 @@
backend.getGetRuntimeTypeArgument(),
[target,
substitution,
- graph.addConstantInt(index, constantSystem)],
+ graph.addConstantInt(index, compiler)],
HType.UNKNOWN);
return pop();
}
@@ -3271,7 +3277,7 @@
message: '$argument is malformed in checked mode'));
if (argument == compiler.types.dynamicType || argument.isMalformed) {
// Represent [dynamic] as [null].
- return graph.addConstantNull(constantSystem);
+ return graph.addConstantNull(compiler);
}
List<HInstruction> inputs = <HInstruction>[];
@@ -3280,7 +3286,7 @@
inputs.add(addTypeVariableReference(variable));
});
- HInstruction result = createForeign(template, HType.STRING, inputs);
+ HInstruction result = createForeign(template, backend.stringType, inputs);
add(result);
return result;
}
@@ -3305,7 +3311,7 @@
return;
}
- HInstruction typeInfo = new HLiteralList(rtiInputs);
+ HInstruction typeInfo = buildLiteralList(rtiInputs);
add(typeInfo);
// Set the runtime type information on the object.
@@ -3334,11 +3340,11 @@
if (Elements.isFixedListConstructorCall(
originalElement, send, compiler)) {
isListConstructor = true;
- return HType.FIXED_ARRAY;
+ return backend.fixedArrayType;
} else if (Elements.isGrowableListConstructorCall(
originalElement, send, compiler)) {
isListConstructor = true;
- return HType.EXTENDABLE_ARRAY;
+ return backend.extendableArrayType;
} else if (element.isGenerativeConstructor()) {
ClassElement cls = element.getEnclosingClass();
return new HType.nonNullExact(cls.thisType, compiler);
@@ -3413,7 +3419,7 @@
// Also add null to non-provided type variables to call the
// constructor with the right number of arguments.
while (!typeVariable.isEmpty) {
- inputs.add(graph.addConstantNull(constantSystem));
+ inputs.add(graph.addConstantNull(compiler));
typeVariable = typeVariable.tail;
}
}
@@ -3458,7 +3464,7 @@
}
if (identical(element, compiler.assertMethod)
&& !compiler.enableUserAssertions) {
- stack.add(graph.addConstantNull(constantSystem));
+ stack.add(graph.addConstantNull(compiler));
return;
}
compiler.ensure(!element.isGenerativeConstructor());
@@ -3492,7 +3498,7 @@
HConstant addConstantString(Node node, String string) {
DartString dartString = new DartString.literal(string);
Constant constant = constantSystem.createString(dartString, node);
- return graph.addConstant(constant);
+ return graph.addConstant(constant, compiler);
}
visitTypeReferenceSend(Send node) {
@@ -3501,14 +3507,14 @@
// TODO(karlklose): add type representation
ConstantHandler handler = compiler.constantHandler;
Constant constant = handler.compileNodeWithDefinitions(node, elements);
- stack.add(graph.addConstant(constant));
+ stack.add(graph.addConstant(constant, compiler));
} else if (element.isTypeVariable()) {
HInstruction value =
addTypeVariableReference(element.computeType(compiler));
pushInvokeStatic(node,
backend.getRuntimeTypeToString(),
[value],
- HType.STRING);
+ backend.stringType);
pushInvokeStatic(node,
backend.getCreateRuntimeType(),
[pop()]);
@@ -3561,11 +3567,11 @@
Element helper = backend.getThrowNoSuchMethod();
Constant receiverConstant =
constantSystem.createString(new DartString.empty(), diagnosticNode);
- HInstruction receiver = graph.addConstant(receiverConstant);
+ HInstruction receiver = graph.addConstant(receiverConstant, compiler);
DartString dartString = new DartString.literal(methodName);
Constant nameConstant =
constantSystem.createString(dartString, diagnosticNode);
- HInstruction name = graph.addConstant(nameConstant);
+ HInstruction name = graph.addConstant(nameConstant, compiler);
if (argumentValues == null) {
argumentValues = <HInstruction>[];
argumentNodes.forEach((argumentNode) {
@@ -3574,7 +3580,7 @@
argumentValues.add(value);
});
}
- HInstruction arguments = new HLiteralList(argumentValues);
+ HInstruction arguments = buildLiteralList(argumentValues);
add(arguments);
HInstruction existingNamesList;
if (existingArguments != null) {
@@ -3582,13 +3588,13 @@
for (String name in existingArguments) {
HInstruction nameConstant =
graph.addConstantString(new DartString.literal(name),
- diagnosticNode, constantSystem);
+ diagnosticNode, compiler);
existingNames.add(nameConstant);
}
- existingNamesList = new HLiteralList(existingNames);
+ existingNamesList = buildLiteralList(existingNames);
add(existingNamesList);
} else {
- existingNamesList = graph.addConstantNull(constantSystem);
+ existingNamesList = graph.addConstantNull(compiler);
}
pushInvokeStatic(diagnosticNode,
helper,
@@ -3643,7 +3649,7 @@
// TODO(karlklose): add type representation
ConstantHandler handler = compiler.constantHandler;
Constant constant = handler.compileNodeWithDefinitions(node, elements);
- stack.add(graph.addConstant(constant));
+ stack.add(graph.addConstant(constant, compiler));
if (isSymbolConstructor) {
ConstructedConstant symbol = constant;
StringConstant stringConstant = symbol.fields.single;
@@ -3794,7 +3800,7 @@
Link<Node> arguments) {
HInstruction rhs;
if (node.isPrefix || node.isPostfix) {
- rhs = graph.addConstantInt(1, constantSystem);
+ rhs = graph.addConstantInt(1, compiler);
} else {
visit(arguments.head);
assert(arguments.tail.isEmpty);
@@ -3945,25 +3951,25 @@
}
void visitLiteralInt(LiteralInt node) {
- stack.add(graph.addConstantInt(node.value, constantSystem));
+ stack.add(graph.addConstantInt(node.value, compiler));
}
void visitLiteralDouble(LiteralDouble node) {
- stack.add(graph.addConstantDouble(node.value, constantSystem));
+ stack.add(graph.addConstantDouble(node.value, compiler));
}
void visitLiteralBool(LiteralBool node) {
- stack.add(graph.addConstantBool(node.value, constantSystem));
+ stack.add(graph.addConstantBool(node.value, compiler));
}
void visitLiteralString(LiteralString node) {
- stack.add(graph.addConstantString(node.dartString, node, constantSystem));
+ stack.add(graph.addConstantString(node.dartString, node, compiler));
}
void visitStringJuxtaposition(StringJuxtaposition node) {
if (!node.isInterpolation) {
// This is a simple string with no interpolations.
- stack.add(graph.addConstantString(node.dartString, node, constantSystem));
+ stack.add(graph.addConstantString(node.dartString, node, compiler));
return;
}
StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node);
@@ -3972,7 +3978,7 @@
}
void visitLiteralNull(LiteralNull node) {
- stack.add(graph.addConstantNull(constantSystem));
+ stack.add(graph.addConstantNull(compiler));
}
visitNodeList(NodeList node) {
@@ -4016,7 +4022,7 @@
visitRethrow(Rethrow node) {
HInstruction exception = rethrowableException;
if (exception == null) {
- exception = graph.addConstantNull(constantSystem);
+ exception = graph.addConstantNull(compiler);
compiler.internalError(
'rethrowableException should not be null', node: node);
}
@@ -4032,9 +4038,9 @@
HInstruction value;
if (node.isRedirectingFactoryBody) {
// TODO(ahe): This is only for reflection, and it is not correct yet.
- value = graph.addConstantNull(constantSystem);
+ value = graph.addConstantNull(compiler);
} else if (node.expression == null) {
- value = graph.addConstantNull(constantSystem);
+ value = graph.addConstantNull(compiler);
} else {
visit(node.expression);
value = pop();
@@ -4071,7 +4077,7 @@
link = link.tail) {
Node definition = link.head;
if (definition is Identifier) {
- HInstruction initialValue = graph.addConstantNull(constantSystem);
+ HInstruction initialValue = graph.addConstantNull(compiler);
localsHandler.updateLocal(elements[definition], initialValue);
} else {
assert(definition is SendSet);
@@ -4085,7 +4091,7 @@
if (node.isConst()) {
ConstantHandler handler = compiler.constantHandler;
Constant constant = handler.compileNodeWithDefinitions(node, elements);
- stack.add(graph.addConstant(constant));
+ stack.add(graph.addConstant(constant, compiler));
return;
}
@@ -4096,7 +4102,7 @@
visit(link.head);
inputs.add(pop());
}
- push(new HLiteralList(inputs));
+ push(buildLiteralList(inputs));
}
visitConditional(Conditional node) {
@@ -4280,7 +4286,7 @@
if (node.isConst()) {
ConstantHandler handler = compiler.constantHandler;
Constant constant = handler.compileNodeWithDefinitions(node, elements);
- stack.add(graph.addConstant(constant));
+ stack.add(graph.addConstant(constant, compiler));
return;
}
List<HInstruction> inputs = <HInstruction>[];
@@ -4291,7 +4297,7 @@
inputs.add(pop());
inputs.add(pop());
}
- HLiteralList keyValuePairs = new HLiteralList(inputs);
+ HLiteralList keyValuePairs = buildLiteralList(inputs);
add(keyValuePairs);
HType mapType = new HType.nonNullSubtype(
backend.mapLiteralClass.computeType(compiler), compiler);
@@ -4452,7 +4458,7 @@
// }
TargetElement switchTarget = elements[node];
- HInstruction initialValue = graph.addConstantNull(constantSystem);
+ HInstruction initialValue = graph.addConstantNull(compiler);
localsHandler.updateLocal(switchTarget, initialValue);
JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false);
@@ -4485,11 +4491,11 @@
if (switchCase != null) {
// Generate 'target = i; break;' for switch case i.
int index = caseIndex[switchCase];
- HInstruction value = graph.addConstantInt(index, constantSystem);
+ HInstruction value = graph.addConstantInt(index, compiler);
localsHandler.updateLocal(switchTarget, value);
} else {
// Generate synthetic default case 'target = null; break;'.
- HInstruction value = graph.addConstantNull(constantSystem);
+ HInstruction value = graph.addConstantNull(compiler);
localsHandler.updateLocal(switchTarget, value);
}
jumpTargets[switchTarget].generateBreak();
@@ -4504,7 +4510,7 @@
jumpHandler.close();
HInstruction buildCondition() =>
- graph.addConstantBool(true, constantSystem);
+ graph.addConstantBool(true, compiler);
void buildSwitch() {
HInstruction buildExpression() {
@@ -4599,7 +4605,7 @@
HBasicBlock block = graph.addNewBlock();
for (Constant constant in getConstants(switchCase)) {
caseConstants.add(constant);
- HConstant hConstant = graph.addConstant(constant);
+ HConstant hConstant = graph.addConstant(constant, compiler);
switchInstruction.inputs.add(hConstant);
hConstant.usedBy.add(switchInstruction);
expressionBlock.addSuccessor(block);
@@ -4786,7 +4792,7 @@
if (type.isMalformed) {
// TODO(johnniwinther): Handle malformed types in [HIs] instead.
HInstruction condition =
- graph.addConstantBool(true, constantSystem);
+ graph.addConstantBool(true, compiler);
stack.add(condition);
} else {
// TODO(karlkose): support type arguments here.
@@ -4799,7 +4805,7 @@
VariableDefinitions declaration = catchBlock.formals.nodes.head;
HInstruction condition = null;
if (declaration.type == null) {
- condition = graph.addConstantBool(true, constantSystem);
+ condition = graph.addConstantBool(true, compiler);
stack.add(condition);
} else {
// TODO(aprelev@gmail.com): Once old catch syntax is removed
@@ -4992,7 +4998,7 @@
node.accept(builder);
HInstruction expression = builder.pop();
if (!expression.isConstantString()) {
- expression = new HStringify(expression, node);
+ expression = new HStringify(expression, node, builder.backend.stringType);
builder.add(expression);
}
result = (result == null) ? expression : concat(result, expression);
@@ -5016,7 +5022,8 @@
}
HInstruction concat(HInstruction left, HInstruction right) {
- HInstruction instruction = new HStringConcat(left, right, diagnosticNode);
+ HInstruction instruction = new HStringConcat(
+ left, right, diagnosticNode, builder.backend.stringType);
builder.add(instruction);
return instruction;
}
@@ -5290,7 +5297,7 @@
handleIf(visitCondition, visitThen, null);
HConstant notIsAnd =
- builder.graph.addConstantBool(!isAnd, builder.constantSystem);
+ builder.graph.addConstantBool(!isAnd, builder.compiler);
HPhi result = new HPhi.manyInputs(null,
<HInstruction>[boolifiedRight, notIsAnd]);
builder.current.addPhi(result);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 2287d54..01ad49e 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -289,7 +289,7 @@
endLabeledBlock(HLabeledBlockInformation labeledBlockInfo);
void preGenerateMethod(HGraph graph) {
- new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
+ new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph);
new SsaConditionMerger(
generateAtUseSite, controlFlowOperators).visitGraph(graph);
SsaLiveIntervalBuilder intervalBuilder =
@@ -620,6 +620,7 @@
HCheck check = argument;
use(check.checkedInput);
} else {
+ assert(variableNames.hasName(argument));
push(new js.VariableUse(variableNames.getName(argument)));
}
}
@@ -1221,7 +1222,7 @@
void emitIdentityComparison(HInstruction left,
HInstruction right,
bool inverse) {
- String op = singleIdentityComparison(left, right);
+ String op = singleIdentityComparison(left, right, compiler);
if (op != null) {
use(left);
js.Expression jsLeft = pop();
@@ -1806,8 +1807,8 @@
HInstruction left = relational.left;
HInstruction right = relational.right;
- if (left.instructionType.isUseful() && left.isString() &&
- right.instructionType.isUseful() && right.isString()) {
+ if (left.instructionType.isUseful() && left.isString(compiler) &&
+ right.instructionType.isUseful() && right.isString(compiler)) {
return true;
}
@@ -2037,7 +2038,7 @@
void visitStringify(HStringify node) {
HInstruction input = node.inputs.first;
- if (input.isString()) {
+ if (input.isString(compiler)) {
use(input);
} else if (input.isInteger() || input.isBoolean()) {
// JavaScript's + operator with a string for the left operand will convert
@@ -2433,7 +2434,7 @@
// input is !bool
checkBool(input, '!==');
test = pop();
- } else if (node.isString()) {
+ } else if (node.isString(compiler)) {
// input is !string
checkString(input, '!==');
test = pop();
@@ -3002,7 +3003,9 @@
}
}
-String singleIdentityComparison(HInstruction left, HInstruction right) {
+String singleIdentityComparison(HInstruction left,
+ HInstruction right,
+ Compiler compiler) {
// Returns the single identity comparison (== or ===) or null if a more
// complex expression is required.
if ((left.isConstant() && left.isConstantSentinel()) ||
@@ -3011,7 +3014,7 @@
HType rightType = right.instructionType;
if (leftType.canBeNull() && rightType.canBeNull()) {
if (left.isConstantNull() || right.isConstantNull() ||
- (leftType.isPrimitive() && leftType == rightType)) {
+ (leftType.isPrimitive(compiler) && leftType == rightType)) {
return '==';
}
return null;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
index c29f3e8..b501668 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
@@ -15,6 +15,7 @@
* t2 = add(4, 3);
*/
class SsaInstructionMerger extends HBaseVisitor {
+ final Compiler compiler;
/**
* List of [HInstruction] that the instruction merger expects in
* order when visiting the inputs of an instruction.
@@ -33,7 +34,7 @@
generateAtUseSite.add(instruction);
}
- SsaInstructionMerger(this.generateAtUseSite);
+ SsaInstructionMerger(this.generateAtUseSite, this.compiler);
void visitGraph(HGraph graph) {
visitDominatorTree(graph);
@@ -104,7 +105,7 @@
void visitIdentity(HIdentity instruction) {
HInstruction left = instruction.left;
HInstruction right = instruction.right;
- if (singleIdentityComparison(left, right) != null) {
+ if (singleIdentityComparison(left, right, compiler) != null) {
super.visitIdentity(instruction);
}
// Do nothing.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
index 9c7de35..d36e593e 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
@@ -91,18 +91,20 @@
HType type = input.instructionType;
ClassElement constantInterceptor;
JavaScriptBackend backend = compiler.backend;
- if (type.isInteger()) {
+ if (type.canBeNull()) {
+ if (type.isNull()) {
+ constantInterceptor = backend.jsNullClass;
+ }
+ } else if (type.isInteger()) {
constantInterceptor = backend.jsIntClass;
} else if (type.isDouble()) {
constantInterceptor = backend.jsDoubleClass;
} else if (type.isBoolean()) {
constantInterceptor = backend.jsBoolClass;
- } else if (type.isString()) {
+ } else if (type.isString(compiler)) {
constantInterceptor = backend.jsStringClass;
} else if (type.isArray(compiler)) {
constantInterceptor = backend.jsArrayClass;
- } else if (type.isNull()) {
- constantInterceptor = backend.jsNullClass;
} else if (type.isNumber()
&& !interceptedClasses.contains(backend.jsIntClass)
&& !interceptedClasses.contains(backend.jsDoubleClass)) {
@@ -122,12 +124,9 @@
// for a subclass or call methods defined on a subclass. Provided the
// code is completely insensitive to the specific instance subclasses, we
// can use the non-leaf class directly.
-
- if (!type.canBeNull()) {
- ClassElement element = type.computeMask(compiler).singleClass(compiler);
- if (element != null && element.isNative()) {
- constantInterceptor = element;
- }
+ ClassElement element = type.computeMask(compiler).singleClass(compiler);
+ if (element != null && element.isNative()) {
+ constantInterceptor = element;
}
}
@@ -138,7 +137,7 @@
Constant constant = new InterceptorConstant(
constantInterceptor.computeType(compiler));
- return graph.addConstant(constant);
+ return graph.addConstant(constant, compiler);
}
HInstruction findDominator(Iterable<HInstruction> instructions) {
@@ -229,7 +228,7 @@
if (!user.hasSameLoopHeaderAs(node)) return false;
// Replace the user with a [HOneShotInterceptor].
- HConstant nullConstant = graph.addConstantNull(constantSystem);
+ HConstant nullConstant = graph.addConstantNull(compiler);
List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
inputs[0] = nullConstant;
HOneShotInterceptor interceptor = new HOneShotInterceptor(
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index 5ea9e29..f86ac3c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -99,7 +99,8 @@
HInstruction index = instruction.inputs[2];
if (input == instruction.inputs[1] &&
index.instructionType.canBePrimitiveNumber(compiler)) {
- return HType.MUTABLE_ARRAY;
+ JavaScriptBackend backend = compiler.backend;
+ return backend.mutableArrayType;
}
// The index should be an int when the receiver is a string or array.
// However it turns out that inserting an integer check in the optimized
@@ -133,7 +134,8 @@
HInstruction index = instruction.inputs[2];
if (input == instruction.inputs[1] &&
index.instructionType.canBePrimitiveNumber(compiler)) {
- return HType.INDEXABLE_PRIMITIVE;
+ JavaScriptBackend backend = compiler.backend;
+ return backend.indexablePrimitiveType;
}
// The index should be an int when the receiver is a string or array.
// However it turns out that inserting an integer check in the optimized
@@ -182,7 +184,7 @@
Compiler compiler) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
- if (instruction.inputs[1].isPrimitiveOrNull()) return HType.INTEGER;
+ if (instruction.inputs[1].isPrimitiveOrNull(compiler)) return HType.INTEGER;
return super.computeTypeFromInputTypes(instruction, compiler);
}
@@ -399,7 +401,7 @@
// All bitwise operations on primitive types either produce an
// integer or throw an error.
HInstruction left = instruction.inputs[1];
- if (left.isPrimitiveOrNull()) return HType.INTEGER;
+ if (left.isPrimitiveOrNull(compiler)) return HType.INTEGER;
return super.computeTypeFromInputTypes(instruction, compiler);
}
@@ -502,7 +504,7 @@
HType computeTypeFromInputTypes(HInvokeDynamic instruction,
Compiler compiler) {
- if (instruction.inputs[1].instructionType.isPrimitiveOrNull()) {
+ if (instruction.inputs[1].instructionType.isPrimitiveOrNull(compiler)) {
return HType.BOOLEAN;
}
return super.computeTypeFromInputTypes(instruction, compiler);
@@ -557,12 +559,13 @@
return right.instructionType;
}
// String equality testing is much more common than array equality testing.
+ JavaScriptBackend backend = compiler.backend;
if (input == left && left.isIndexablePrimitive(compiler)) {
- return HType.READABLE_ARRAY;
+ return backend.readableArrayType;
}
// String equality testing is much more common than array equality testing.
if (input == right && right.isIndexablePrimitive(compiler)) {
- return HType.STRING;
+ return backend.stringType;
}
return HType.UNKNOWN;
}
@@ -572,7 +575,7 @@
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
HType instructionType = left.instructionType;
- if (right.isConstantNull() || instructionType.isPrimitiveOrNull()) {
+ if (right.isConstantNull() || instructionType.isPrimitiveOrNull(compiler)) {
return newBuiltinVariant(instruction);
}
Selector selector = instructionType.refine(instruction.selector, compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 915908f..3f47849 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -162,29 +162,26 @@
return result;
}
- static HType mapConstantTypeToSsaType(Constant constant) {
+ static HType mapConstantTypeToSsaType(Constant constant, Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
if (constant.isNull()) return HType.NULL;
if (constant.isBool()) return HType.BOOLEAN;
if (constant.isInt()) return HType.INTEGER;
if (constant.isDouble()) return HType.DOUBLE;
- if (constant.isString()) return HType.STRING;
- if (constant.isList()) return HType.READABLE_ARRAY;
+ if (constant.isString()) return backend.stringType;
+ if (constant.isList()) return backend.readableArrayType;
if (constant.isFunction()) return HType.UNKNOWN;
if (constant.isSentinel()) return HType.UNKNOWN;
// TODO(sra): What is the type of the prototype of an interceptor?
if (constant.isInterceptor()) return HType.UNKNOWN;
- // TODO(kasperl): This seems a bit fishy, but we do not have the
- // compiler at hand so we cannot use the usual HType factory
- // methods. At some point this should go away.
ObjectConstant objectConstant = constant;
- TypeMask mask = new TypeMask.nonNullExact(objectConstant.type);
- return new HBoundedType(mask);
+ return new HBoundedType(new TypeMask.nonNullExact(objectConstant.type));
}
- HConstant addConstant(Constant constant) {
+ HConstant addConstant(Constant constant, Compiler compiler) {
HConstant result = constants[constant];
if (result == null) {
- HType type = mapConstantTypeToSsaType(constant);
+ HType type = mapConstantTypeToSsaType(constant, compiler);
result = new HConstant.internal(constant, type);
entry.addAtExit(result);
constants[constant] = result;
@@ -195,26 +192,30 @@
return result;
}
- HConstant addConstantInt(int i, ConstantSystem constantSystem) {
- return addConstant(constantSystem.createInt(i));
+ HConstant addConstantInt(int i, Compiler compiler) {
+ return addConstant(compiler.backend.constantSystem.createInt(i), compiler);
}
- HConstant addConstantDouble(double d, ConstantSystem constantSystem) {
- return addConstant(constantSystem.createDouble(d));
+ HConstant addConstantDouble(double d, Compiler compiler) {
+ return addConstant(
+ compiler.backend.constantSystem.createDouble(d), compiler);
}
HConstant addConstantString(DartString str,
Node diagnosticNode,
- ConstantSystem constantSystem) {
- return addConstant(constantSystem.createString(str, diagnosticNode));
+ Compiler compiler) {
+ return addConstant(
+ compiler.backend.constantSystem.createString(str, diagnosticNode),
+ compiler);
}
- HConstant addConstantBool(bool value, ConstantSystem constantSystem) {
- return addConstant(constantSystem.createBool(value));
+ HConstant addConstantBool(bool value, Compiler compiler) {
+ return addConstant(
+ compiler.backend.constantSystem.createBool(value), compiler);
}
- HConstant addConstantNull(ConstantSystem constantSystem) {
- return addConstant(constantSystem.createNull());
+ HConstant addConstantNull(Compiler compiler) {
+ return addConstant(compiler.backend.constantSystem.createNull(), compiler);
}
void finalize() {
@@ -621,7 +622,9 @@
void rewriteWithBetterUser(HInstruction from, HInstruction to) {
Link<HCheck> better = const Link<HCheck>();
for (HInstruction user in to.usedBy) {
- if (user is HCheck && identical((user as HCheck).checkedInput, to)) {
+ if (user == from || user is! HCheck) continue;
+ HCheck check = user;
+ if (check.checkedInput == to) {
better = better.prepend(user);
}
}
@@ -819,6 +822,10 @@
&& !canThrow();
}
+ // Overridden by [HCheck] to return the actual non-[HCheck]
+ // instruction it checks against.
+ HInstruction nonCheck() => this;
+
// Can this node throw an exception?
bool canThrow() => false;
@@ -836,6 +843,12 @@
instructionType.isExtendableArray(compiler);
bool isFixedArray(Compiler compiler) =>
instructionType.isFixedArray(compiler);
+ bool isString(Compiler compiler) =>
+ instructionType.isString(compiler);
+ bool isPrimitive(Compiler compiler) =>
+ instructionType.isPrimitive(compiler);
+ bool isPrimitiveOrNull(Compiler compiler) =>
+ instructionType.isPrimitiveOrNull(compiler);
bool isBoolean() => instructionType.isBoolean();
bool isInteger() => instructionType.isInteger();
bool isIntegerOrNull() => instructionType.isIntegerOrNull();
@@ -843,9 +856,6 @@
bool isDoubleOrNull() => instructionType.isDoubleOrNull();
bool isNumber() => instructionType.isNumber();
bool isNumberOrNull() => instructionType.isNumberOrNull();
- bool isString() => instructionType.isString();
- bool isPrimitive() => instructionType.isPrimitive();
- bool isPrimitiveOrNull() => instructionType.isPrimitiveOrNull();
bool isNull() => instructionType.isNull();
bool canBeNull() => instructionType.canBeNull();
bool canBePrimitive(Compiler compiler) =>
@@ -901,7 +911,9 @@
final List<HInstruction> otherInputs = other.inputs;
if (inputsLength != otherInputs.length) return false;
for (int i = 0; i < inputsLength; i++) {
- if (!identical(inputs[i], otherInputs[i])) return false;
+ if (!identical(inputs[i].nonCheck(), otherInputs[i].nonCheck())) {
+ return false;
+ }
}
// Check that the data in the instruction matches.
return dataEquals(other);
@@ -911,7 +923,7 @@
int result = typeCode();
int length = inputs.length;
for (int i = 0; i < length; i++) {
- result = (result * 19) + (inputs[i].id) + (result >> 7);
+ result = (result * 19) + (inputs[i].nonCheck().id) + (result >> 7);
}
return result;
}
@@ -1158,11 +1170,7 @@
bool isJsStatement() => true;
bool canThrow() => true;
- HInstruction unwrap() {
- var checked = checkedInput;
- while (checked is HCheck) checked = checked.checkedInput;
- return checked;
- }
+ HInstruction nonCheck() => checkedInput.nonCheck();
}
class HBailoutTarget extends HInstruction {
@@ -1320,7 +1328,11 @@
int typeCode() => HInstruction.INVOKE_DYNAMIC_TYPECODE;
bool typeEquals(other) => other is HInvokeDynamic;
bool dataEquals(HInvokeDynamic other) {
- return selector == other.selector && element == other.element;
+ // Use the name and the kind instead of [Selector.operator==]
+ // because we don't need to check the arity (already checked in
+ // [gvnEquals]), and the receiver types may not be in sync.
+ return selector.name == other.selector.name
+ && selector.kind == other.selector.kind;
}
}
@@ -2137,8 +2149,8 @@
}
class HLiteralList extends HInstruction {
- HLiteralList(inputs) : super(inputs) {
- instructionType = HType.EXTENDABLE_ARRAY;
+ HLiteralList(List<HInstruction> inputs, HType type) : super(inputs) {
+ instructionType = type;
}
toString() => 'literal list';
accept(HVisitor visitor) => visitor.visitLiteralList(this);
@@ -2291,6 +2303,7 @@
int typeCode() => HInstruction.TYPE_CONVERSION_TYPECODE;
bool typeEquals(HInstruction other) => other is HTypeConversion;
+ bool isCodeMotionInvariant() => kind == NO_CHECK;
bool dataEquals(HTypeConversion other) {
return kind == other.kind
@@ -2310,13 +2323,13 @@
class HStringConcat extends HInstruction {
final Node node;
- HStringConcat(HInstruction left, HInstruction right, this.node)
+ HStringConcat(HInstruction left, HInstruction right, this.node, HType type)
: super(<HInstruction>[left, right]) {
// TODO(sra): Until Issue 9293 is fixed, this false dependency keeps the
// concats bunched with stringified inputs for much better looking code with
// fewer temps.
sideEffects.setDependsOnSomething();
- instructionType = HType.STRING;
+ instructionType = type;
}
HInstruction get left => inputs[0];
@@ -2332,10 +2345,11 @@
*/
class HStringify extends HInstruction {
final Node node;
- HStringify(HInstruction input, this.node) : super(<HInstruction>[input]) {
+ HStringify(HInstruction input, this.node, HType type)
+ : super(<HInstruction>[input]) {
sideEffects.setAllSideEffects();
sideEffects.setDependsOnSomething();
- instructionType = HType.STRING;
+ instructionType = type;
}
accept(HVisitor visitor) => visitor.visitStringify(this);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 68d1455..c61ff48 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -195,7 +195,7 @@
// TODO(kasperl): Get rid of the null check here once all HTypes
// have a proper mask.
if (mask != null && !mask.contains(booleanType, compiler)) {
- return graph.addConstantBool(false, constantSystem);
+ return graph.addConstantBool(false, compiler);
}
return node;
}
@@ -207,7 +207,7 @@
if (input is HConstant) {
HConstant constant = input;
bool isTrue = constant.constant.isTrue();
- return graph.addConstantBool(!isTrue, constantSystem);
+ return graph.addConstantBool(!isTrue, compiler);
} else if (input is HNot) {
return input.inputs[0];
}
@@ -224,7 +224,7 @@
if (operand is HConstant) {
HConstant receiver = operand;
Constant folded = operation.fold(receiver.constant);
- if (folded != null) return graph.addConstant(folded);
+ if (folded != null) return graph.addConstant(folded, compiler);
}
return null;
}
@@ -235,15 +235,15 @@
if (actualReceiver.isConstantString()) {
HConstant constantInput = actualReceiver;
StringConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
+ return graph.addConstantInt(constant.length, compiler);
} else if (actualReceiver.isConstantList()) {
HConstant constantInput = actualReceiver;
ListConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
+ return graph.addConstantInt(constant.length, compiler);
}
Element element = backend.jsIndexableLength;
bool isAssignable = !actualReceiver.isFixedArray(compiler) &&
- !actualReceiver.isString();
+ !actualReceiver.isString(compiler);
HFieldGet result = new HFieldGet(
element, actualReceiver, isAssignable: isAssignable);
result.instructionType = HType.INTEGER;
@@ -251,7 +251,7 @@
} else if (actualReceiver.isConstantMap()) {
HConstant constantInput = actualReceiver;
MapConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
+ return graph.addConstantInt(constant.length, compiler);
}
return null;
}
@@ -286,13 +286,13 @@
target = backend.jsArrayAdd;
}
}
- } else if (input.isString()) {
+ } else if (input.isString(compiler)) {
if (selector.applies(backend.jsStringSplit, compiler)) {
- if (node.inputs[2].isString()) {
+ if (node.inputs[2].isString(compiler)) {
target = backend.jsStringSplit;
}
} else if (selector.applies(backend.jsStringConcat, compiler)) {
- if (node.inputs[2].isString()) {
+ if (node.inputs[2].isString(compiler)) {
target = backend.jsStringConcat;
}
} else if (selector.applies(backend.jsStringToString, compiler)) {
@@ -439,7 +439,7 @@
HConstant op1 = left;
HConstant op2 = right;
Constant folded = operation.fold(op1.constant, op2.constant);
- if (folded != null) return graph.addConstant(folded);
+ if (folded != null) return graph.addConstant(folded, compiler);
}
return null;
}
@@ -482,11 +482,11 @@
// we don't optimize on numbers to preserve the runtime semantics.
if (!(left.isNumberOrNull() && right.isNumberOrNull()) &&
leftType.intersection(rightType, compiler).isConflicting()) {
- return graph.addConstantBool(false, constantSystem);
+ return graph.addConstantBool(false, compiler);
}
if (left.isNull() && right.isNull()) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
}
if (left.isConstantBoolean() && right.isBoolean()) {
@@ -538,7 +538,7 @@
}
if (element == compiler.objectClass || element == compiler.dynamicClass) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
}
HType expressionType = node.expression.instructionType;
@@ -546,40 +546,33 @@
if (identical(element, compiler.intClass)
|| identical(element, compiler.numClass)
|| Elements.isNumberOrStringSupertype(element, compiler)) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
} else if (identical(element, compiler.doubleClass)) {
// We let the JS semantics decide for that check. Currently
// the code we emit will always return true.
return node;
} else {
- return graph.addConstantBool(false, constantSystem);
+ return graph.addConstantBool(false, compiler);
}
} else if (expressionType.isDouble()) {
if (identical(element, compiler.doubleClass)
|| identical(element, compiler.numClass)
|| Elements.isNumberOrStringSupertype(element, compiler)) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
} else if (identical(element, compiler.intClass)) {
// We let the JS semantics decide for that check. Currently
// the code we emit will return true for a double that can be
// represented as a 31-bit integer and for -0.0.
return node;
} else {
- return graph.addConstantBool(false, constantSystem);
+ return graph.addConstantBool(false, compiler);
}
} else if (expressionType.isNumber()) {
if (identical(element, compiler.numClass)) {
- return graph.addConstantBool(true, constantSystem);
- }
- // We cannot just return false, because the expression may be of
- // type int or double.
- } else if (expressionType.isString()) {
- if (identical(element, compiler.stringClass)
- || Elements.isStringOnlySupertype(element, compiler)
- || Elements.isNumberOrStringSupertype(element, compiler)) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
} else {
- return graph.addConstantBool(false, constantSystem);
+ // We cannot just return false, because the expression may be of
+ // type int or double.
}
// We need the [:hasTypeArguments:] check because we don't have
// the notion of generics in the backend. For example, [:this:] in
@@ -589,9 +582,9 @@
TypeMask expressionMask = expressionType.computeMask(compiler);
TypeMask typeMask = new TypeMask.nonNullSubtype(type);
if (expressionMask.union(typeMask, compiler) == typeMask) {
- return graph.addConstantBool(true, constantSystem);
+ return graph.addConstantBool(true, compiler);
} else if (expressionMask.intersection(typeMask, compiler).isEmpty) {
- return graph.addConstantBool(false, constantSystem);
+ return graph.addConstantBool(false, compiler);
}
}
return node;
@@ -637,7 +630,7 @@
node.receiver.isConstantString()) {
var instruction = node.receiver;
return graph.addConstantInt(
- instruction.constant.length, backend.constantSystem);
+ instruction.constant.length, compiler);
}
}
return node;
@@ -650,7 +643,7 @@
instruction = node.index;
int index = instruction.constant.value;
if (index >= 0 && index < entries.length) {
- return graph.addConstant(entries[index]);
+ return graph.addConstant(entries[index], compiler);
}
}
return node;
@@ -760,23 +753,24 @@
if (leftString == null) return node;
}
- HInstruction folded =
- graph.addConstant(constantSystem.createString(
+ HInstruction folded = graph.addConstant(
+ constantSystem.createString(
new DartString.concat(leftString.value, rightString.value),
- node.node));
+ node.node),
+ compiler);
if (prefix == null) return folded;
- return new HStringConcat(prefix, folded, node.node);
+ return new HStringConcat(prefix, folded, node.node, backend.stringType);
}
HInstruction visitStringify(HStringify node) {
HInstruction input = node.inputs[0];
- if (input.isString()) return input;
+ if (input.isString(compiler) && !input.canBeNull()) return input;
if (input.isConstant()) {
HConstant constant = input;
if (!constant.constant.isPrimitive()) return node;
PrimitiveConstant primitive = constant.constant;
return graph.addConstant(constantSystem.createString(
- primitive.toDartString(), node.node));
+ primitive.toDartString(), node.node), compiler);
}
return node;
}
@@ -814,8 +808,9 @@
HBoundsCheck insertBoundsCheck(HInstruction indexNode,
HInstruction array,
HInstruction indexArgument) {
+ Compiler compiler = backend.compiler;
bool isAssignable =
- !array.isFixedArray(backend.compiler) && !array.isString();
+ !array.isFixedArray(compiler) && !array.isString(compiler);
HFieldGet length = new HFieldGet(
backend.jsIndexableLength, array, isAssignable: isAssignable);
length.instructionType = HType.INTEGER;
@@ -855,7 +850,7 @@
if (element != backend.jsArrayRemoveLast) return;
if (boundsChecked.contains(node)) return;
insertBoundsCheck(
- node, node.receiver, graph.addConstantInt(0, backend.constantSystem));
+ node, node.receiver, graph.addConstantInt(0, backend.compiler));
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index c603386..f408df4 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -14,6 +14,7 @@
const String SSA_TRACE_FILTER = null;
class HTracer extends HGraphVisitor implements Tracer {
+ Compiler compiler;
JavaScriptItemCompilationContext context;
int indent = 0;
final EventSink<String> output;
@@ -27,9 +28,11 @@
}
void traceCompilation(String methodName,
- JavaScriptItemCompilationContext compilationContext) {
+ JavaScriptItemCompilationContext compilationContext,
+ Compiler compiler) {
if (!enabled) return;
this.context = compilationContext;
+ this.compiler = compiler;
traceActive =
SSA_TRACE_FILTER == null || methodName.contains(SSA_TRACE_FILTER);
if (!traceActive) return;
@@ -92,7 +95,7 @@
void visitBasicBlock(HBasicBlock block) {
HInstructionStringifier stringifier =
- new HInstructionStringifier(context, block);
+ new HInstructionStringifier(context, block, compiler);
assert(block.id != null);
tag("block", () {
printProperty("name", "B${block.id}");
@@ -165,21 +168,22 @@
}
class HInstructionStringifier implements HVisitor<String> {
- JavaScriptItemCompilationContext context;
- HBasicBlock currentBlock;
+ final Compiler compiler;
+ final JavaScriptItemCompilationContext context;
+ final HBasicBlock currentBlock;
- HInstructionStringifier(this.context, this.currentBlock);
+ HInstructionStringifier(this.context, this.currentBlock, this.compiler);
visit(HInstruction node) => node.accept(this);
String temporaryId(HInstruction instruction) {
String prefix;
HType type = instruction.instructionType;
- if (type == HType.MUTABLE_ARRAY) {
+ if (type.isMutableArray(compiler)) {
prefix = 'm';
- } else if (type == HType.READABLE_ARRAY) {
+ } else if (type.isReadableArray(compiler)) {
prefix = 'a';
- } else if (type == HType.EXTENDABLE_ARRAY) {
+ } else if (type.isExtendableArray(compiler)) {
prefix = 'e';
} else if (type == HType.BOOLEAN) {
prefix = 'b';
@@ -189,13 +193,13 @@
prefix = 'd';
} else if (type == HType.NUMBER) {
prefix = 'n';
- } else if (type == HType.STRING) {
+ } else if (type.isString(compiler)) {
prefix = 's';
} else if (type == HType.UNKNOWN) {
prefix = 'v';
} else if (type == HType.CONFLICTING) {
prefix = 'c';
- } else if (type == HType.INDEXABLE_PRIMITIVE) {
+ } else if (type.isIndexable(compiler)) {
prefix = 'r';
} else if (type == HType.NULL) {
prefix = 'u';
@@ -505,12 +509,12 @@
String visitTypeGuard(HTypeGuard node) {
String type;
HType guardedType = node.guardedType;
- if (guardedType == HType.MUTABLE_ARRAY) {
- type = "mutable_array";
- } else if (guardedType == HType.READABLE_ARRAY) {
- type = "readable_array";
- } else if (guardedType == HType.EXTENDABLE_ARRAY) {
+ if (guardedType.isExtendableArray(compiler)) {
type = "extendable_array";
+ } else if (guardedType.isMutableArray(compiler)) {
+ type = "mutable_array";
+ } else if (guardedType.isReadableArray(compiler)) {
+ type = "readable_array";
} else if (guardedType == HType.BOOLEAN) {
type = "bool";
} else if (guardedType == HType.INTEGER) {
@@ -519,9 +523,9 @@
type = "double";
} else if (guardedType == HType.NUMBER) {
type = "number";
- } else if (guardedType == HType.STRING) {
+ } else if (guardedType.isString(compiler)) {
type = "string";
- } else if (guardedType == HType.INDEXABLE_PRIMITIVE) {
+ } else if (guardedType.isIndexable(compiler)) {
type = "string_or_array";
} else if (guardedType == HType.UNKNOWN) {
type = 'unknown';
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 06fa93d..ff49492 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -27,7 +27,12 @@
|| mask.satisfies(backend.jsNumberClass, compiler)) {
return isNullable ? HType.NUMBER_OR_NULL : HType.NUMBER;
} else if (mask.containsOnlyString(compiler)) {
- return isNullable ? HType.STRING_OR_NULL : HType.STRING;
+ // TODO(ngeoffray): Avoid creating [TypeMask]s with the string
+ // class as base.
+ return isNullable
+ ? new HBoundedType(
+ new TypeMask.exact(backend.jsStringClass.rawType))
+ : backend.stringType;
} else if (mask.containsOnlyBool(compiler)) {
return isNullable ? HType.BOOLEAN_OR_NULL : HType.BOOLEAN;
} else if (mask.containsOnlyNull(compiler)) {
@@ -40,19 +45,6 @@
return isNullable ? HType.UNKNOWN : HType.NON_NULL;
}
- if (!isNullable) {
- if (mask.containsOnly(backend.jsFixedArrayClass)) {
- return HType.FIXED_ARRAY;
- } else if (mask.containsOnly(backend.jsExtendableArrayClass)) {
- return HType.EXTENDABLE_ARRAY;
- } else if (mask.satisfies(backend.jsMutableArrayClass, compiler)) {
- return HType.MUTABLE_ARRAY;
- } else if (mask.satisfies(backend.jsArrayClass, compiler)) {
- return HType.READABLE_ARRAY;
- } else if (mask.satisfies(backend.jsIndexableClass, compiler)) {
- return HType.INDEXABLE_PRIMITIVE;
- }
- }
return new HBoundedType(mask);
}
@@ -134,7 +126,8 @@
return new HType.nonNullExact(
compiler.objectClass.computeType(compiler), compiler);
} else if (type == native.SpecialType.JsArray) {
- return HType.READABLE_ARRAY;
+ JavaScriptBackend backend = compiler.backend;
+ return backend.readableArrayType;
} else if (type.isVoid) {
return HType.NULL;
} else if (type.element == compiler.nullClass) {
@@ -157,19 +150,12 @@
static const HType NUMBER = const HNumberType();
static const HType INTEGER = const HIntegerType();
static const HType DOUBLE = const HDoubleType();
- static const HType INDEXABLE_PRIMITIVE = const HIndexablePrimitiveType();
- static const HType STRING = const HStringType();
- static const HType READABLE_ARRAY = const HReadableArrayType();
- static const HType MUTABLE_ARRAY = const HMutableArrayType();
- static const HType FIXED_ARRAY = const HFixedArrayType();
- static const HType EXTENDABLE_ARRAY = const HExtendableArrayType();
static const HType NULL = const HNullType();
static const HType BOOLEAN_OR_NULL = const HBooleanOrNullType();
static const HType NUMBER_OR_NULL = const HNumberOrNullType();
static const HType INTEGER_OR_NULL = const HIntegerOrNullType();
static const HType DOUBLE_OR_NULL = const HDoubleOrNullType();
- static const HType STRING_OR_NULL = const HStringOrNullType();
bool isConflicting() => identical(this, CONFLICTING);
bool isUnknown() => identical(this, UNKNOWN);
@@ -179,20 +165,19 @@
bool isNumber() => false;
bool isInteger() => false;
bool isDouble() => false;
- bool isString() => false;
+ bool isString(Compiler compiler) => false;
bool isFixedArray(Compiler compiler) => false;
bool isReadableArray(Compiler compiler) => false;
bool isMutableArray(Compiler compiler) => false;
bool isExtendableArray(Compiler compiler) => false;
+ bool isPrimitive(Compiler compiler) => false;
+ bool isPrimitiveOrNull(Compiler compiler) => false;
- bool isPrimitive() => false;
bool isBooleanOrNull() => false;
bool isNumberOrNull() => false;
bool isIntegerOrNull() => false;
bool isDoubleOrNull() => false;
- bool isStringOrNull() => false;
- bool isPrimitiveOrNull() => false;
// TODO(kasperl): Get rid of this one.
bool isIndexablePrimitive(Compiler compiler) => false;
@@ -326,9 +311,9 @@
abstract class HPrimitiveType extends HType {
const HPrimitiveType();
- bool isPrimitive() => true;
+ bool isPrimitive(Compiler compiler) => true;
bool canBePrimitive(Compiler compiler) => true;
- bool isPrimitiveOrNull() => true;
+ bool isPrimitiveOrNull(Compiler compiler) => true;
}
class HNullType extends HPrimitiveType {
@@ -347,7 +332,7 @@
const HPrimitiveOrNullType();
bool canBePrimitive(Compiler compiler) => true;
bool canBeNull() => true;
- bool isPrimitiveOrNull() => true;
+ bool isPrimitiveOrNull(Compiler compiler) => true;
}
class HBooleanOrNullType extends HPrimitiveOrNullType {
@@ -457,97 +442,6 @@
}
}
-class HIndexablePrimitiveType extends HPrimitiveType {
- const HIndexablePrimitiveType();
- bool isIndexablePrimitive(Compiler compiler) => true;
- String toString() => "indexable";
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsIndexableClass.computeType(compiler);
- return new TypeMask.nonNullSubtype(base);
- }
-}
-
-class HStringOrNullType extends HPrimitiveOrNullType {
- const HStringOrNullType();
- bool isStringOrNull() => true;
- String toString() => "String or null";
- bool canBePrimitiveString(Compiler compiler) => true;
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsStringClass.computeType(compiler);
- return new TypeMask.exact(base);
- }
-}
-
-class HStringType extends HIndexablePrimitiveType {
- const HStringType();
- bool isString() => true;
- bool isStringOrNull() => true;
- String toString() => "String";
- bool isExact() => true;
- bool canBePrimitiveString(Compiler compiler) => true;
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsStringClass.computeType(compiler);
- return new TypeMask.nonNullExact(base);
- }
-}
-
-class HReadableArrayType extends HIndexablePrimitiveType {
- const HReadableArrayType();
- bool isReadableArray(Compiler compiler) => true;
- String toString() => "readable array";
- bool canBePrimitiveArray(Compiler compiler) => true;
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsArrayClass.computeType(compiler);
- return new TypeMask.nonNullSubclass(base);
- }
-}
-
-class HMutableArrayType extends HReadableArrayType {
- const HMutableArrayType();
- bool isMutableArray(Compiler compiler) => true;
- String toString() => "mutable array";
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsMutableArrayClass.computeType(compiler);
- return new TypeMask.nonNullSubclass(base);
- }
-}
-
-class HFixedArrayType extends HMutableArrayType {
- const HFixedArrayType();
- bool isFixedArray(Compiler compiler) => true;
- String toString() => "fixed array";
- bool isExact() => true;
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsFixedArrayClass.computeType(compiler);
- return new TypeMask.nonNullExact(base);
- }
-}
-
-class HExtendableArrayType extends HMutableArrayType {
- const HExtendableArrayType();
- bool isExtendableArray(Compiler compiler) => true;
- String toString() => "extendable array";
- bool isExact() => true;
-
- TypeMask computeMask(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- DartType base = backend.jsExtendableArrayClass.computeType(compiler);
- return new TypeMask.nonNullExact(base);
- }
-}
-
class HBoundedType extends HType {
final TypeMask mask;
const HBoundedType(this.mask);
@@ -591,8 +485,7 @@
bool isIndexablePrimitive(Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
- return mask.containsOnlyString(compiler)
- || mask.satisfies(backend.jsIndexableClass, compiler);
+ return mask.satisfies(backend.jsIndexableClass, compiler);
}
bool isFixedArray(Compiler compiler) {
@@ -627,6 +520,18 @@
return new HType.fromMask(mask.simplify(compiler), compiler);
}
+ bool isString(Compiler compiler) {
+ return mask.containsOnlyString(compiler);
+ }
+
+ bool isPrimitive(Compiler compiler) {
+ return isIndexablePrimitive(compiler) && !mask.isNullable;
+ }
+
+ bool isPrimitiveOrNull(Compiler compiler) {
+ return isIndexablePrimitive(compiler);
+ }
+
bool operator ==(HType other) {
if (other is !HBoundedType) return false;
HBoundedType bounded = other;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index 6eed301..d2ef66c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -355,7 +355,7 @@
}
// TODO(ngeoffray): Allow speculative optimizations on
// non-primitive types?
- if (!desiredType.isPrimitive()) return newType;
+ if (!desiredType.isPrimitive(compiler)) return newType;
desiredType = newType.intersection(desiredType, compiler);
if (desiredType != newType && !hasBeenSpeculativelyOptimized(instruction)) {
savedTypes[instruction] = oldType;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index 092a99c..e067089 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -714,11 +714,11 @@
handleEqualityCheck(relational);
} else if (operation.apply(leftRange, rightRange)) {
relational.block.rewrite(
- relational, graph.addConstantBool(true, constantSystem));
+ relational, graph.addConstantBool(true, compiler));
relational.block.remove(relational);
} else if (reverseOperation(operation).apply(leftRange, rightRange)) {
relational.block.rewrite(
- relational, graph.addConstantBool(false, constantSystem));
+ relational, graph.addConstantBool(false, compiler));
relational.block.remove(relational);
}
return info.newUnboundRange();
@@ -729,7 +729,7 @@
Range left = ranges[node.left];
if (left.isSingleValue && right.isSingleValue && left == right) {
node.block.rewrite(
- node, graph.addConstantBool(true, constantSystem));
+ node, graph.addConstantBool(true, compiler));
node.block.remove(node);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart b/sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart
index aef770f..3df538d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/variable_allocator.dart
@@ -233,7 +233,7 @@
// [HCheck] will share the same live ranges.
if (instruction is HCheck) {
HCheck check = instruction;
- HInstruction checked = check.unwrap();
+ HInstruction checked = check.nonCheck();
if (!generateAtUseSite.contains(checked)) {
environment.add(checked, instructionId);
}
@@ -248,7 +248,7 @@
// interval as the instruction it is checking.
if (instruction is HCheck) {
HCheck check = instruction;
- HInstruction checked = check.unwrap();
+ HInstruction checked = check.nonCheck();
if (!generateAtUseSite.contains(checked)) {
liveIntervals.putIfAbsent(checked, () => new LiveInterval());
// Unconditionally force the live ranges of the HCheck to
@@ -625,12 +625,7 @@
if (instruction is HParameterValue) return true;
if (instruction.usedBy.isEmpty) return false;
if (generateAtUseSite.contains(instruction)) return false;
- // A [HCheck] instruction needs a name only if its
- // checked input does not have a fixed name or value.
- if (instruction is HCheck) {
- return !instruction.unwrap().isCodeMotionInvariant();
- }
- return true;
+ return !instruction.nonCheck().isCodeMotionInvariant();
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 59f6874..a318d0e 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -130,18 +130,9 @@
}
bool satisfies(ClassElement cls, Compiler compiler) {
- if (isEmpty) {
- return false;
- } else if (base.element == cls) {
- return true;
- } else if (isExact) {
- return false;
- } else if (isSubclass) {
- return isSubclassOf(base, cls.computeType(compiler).asRaw(), compiler);
- } else {
- assert(isSubtype);
- return isSubtypeOf(base, cls.computeType(compiler).asRaw(), compiler);
- }
+ if (isEmpty) return false;
+ return base.element == cls
+ || isSubtypeOf(base, cls.computeType(compiler).asRaw(), compiler);
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
new file mode 100644
index 0000000..68aa7ce
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -0,0 +1,728 @@
+// 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.
+
+part of simple_types_inferrer;
+
+TypeMask narrowType(TypeMask type,
+ DartType annotation,
+ Compiler compiler,
+ {bool isNullable: true}) {
+ if (annotation.isDynamic) return type;
+ if (annotation.isMalformed) return type;
+ if (annotation.isVoid) return compiler.typesTask.typesInferrer.nullType;
+ if (annotation.element == compiler.objectClass) return type;
+ TypeMask otherType;
+ if (annotation.kind == TypeKind.TYPEDEF
+ || annotation.kind == TypeKind.FUNCTION) {
+ otherType = compiler.typesTask.typesInferrer.functionType;
+ } else if (annotation.kind == TypeKind.TYPE_VARIABLE) {
+ return type;
+ } else {
+ assert(annotation.kind == TypeKind.INTERFACE);
+ otherType = new TypeMask.nonNullSubtype(annotation);
+ }
+ if (isNullable) otherType = otherType.nullable();
+ if (type == null) return otherType;
+ return type.intersection(otherType, compiler);
+}
+
+/**
+ * Returns the least upper bound between [firstType] and
+ * [secondType].
+ */
+ TypeMask computeLUB(TypeMask firstType,
+ TypeMask secondType,
+ Compiler compiler) {
+ TypesInferrer inferrer = compiler.typesTask.typesInferrer;
+ TypeMask dynamicType = inferrer.dynamicType;
+ if (firstType == null) {
+ return secondType;
+ } else if (secondType == dynamicType) {
+ return secondType;
+ } else if (firstType == dynamicType) {
+ return firstType;
+ } else {
+ TypeMask union = firstType.union(secondType, compiler);
+ // TODO(kasperl): If the union isn't nullable it seems wasteful
+ // to use dynamic. Fix that.
+ return union.containsAll(compiler) ? dynamicType : union;
+ }
+}
+
+/**
+ * Placeholder for inferred types of local variables.
+ */
+class LocalsHandler {
+ final InternalSimpleTypesInferrer inferrer;
+ final Map<Element, TypeMask> locals;
+ final Map<Element, Element> capturedAndBoxed;
+ final Map<Element, TypeMask> fieldsInitializedInConstructor;
+ final bool inTryBlock;
+ bool isThisExposed;
+ bool seenReturn = false;
+ bool seenBreakOrContinue = false;
+
+ bool get aborts {
+ return seenReturn || seenBreakOrContinue;
+ }
+
+ LocalsHandler(this.inferrer)
+ : locals = new Map<Element, TypeMask>(),
+ capturedAndBoxed = new Map<Element, Element>(),
+ fieldsInitializedInConstructor = new Map<Element, TypeMask>(),
+ inTryBlock = false,
+ isThisExposed = true;
+ LocalsHandler.from(LocalsHandler other, {bool inTryBlock: false})
+ : locals = new Map<Element, TypeMask>.from(other.locals),
+ capturedAndBoxed = new Map<Element, Element>.from(
+ other.capturedAndBoxed),
+ fieldsInitializedInConstructor = new Map<Element, TypeMask>.from(
+ other.fieldsInitializedInConstructor),
+ inTryBlock = other.inTryBlock || inTryBlock,
+ inferrer = other.inferrer,
+ isThisExposed = other.isThisExposed;
+
+ TypeMask use(Element local) {
+ if (capturedAndBoxed.containsKey(local)) {
+ return inferrer.getTypeOfElement(capturedAndBoxed[local]);
+ }
+ return locals[local];
+ }
+
+ void update(Element local, TypeMask type) {
+ assert(type != null);
+ Compiler compiler = inferrer.compiler;
+ if (compiler.trustTypeAnnotations || compiler.enableTypeAssertions) {
+ type = narrowType(type, local.computeType(compiler), compiler);
+ }
+ if (capturedAndBoxed.containsKey(local) || inTryBlock) {
+ // If a local is captured and boxed, or is set in a try block,
+ // we compute the LUB of its assignments.
+ //
+ // We don't know if an assignment in a try block
+ // will be executed, so all assigments in that block are
+ // potential types after we have left it.
+ type = computeLUB(locals[local], type, compiler);
+ }
+ locals[local] = type;
+ }
+
+ void setCapturedAndBoxed(Element local, Element field) {
+ capturedAndBoxed[local] = field;
+ }
+
+ /**
+ * Merge handlers [first] and [second] into [:this:] and returns
+ * whether the merge changed one of the variables types in [first].
+ */
+ bool merge(LocalsHandler other, {bool discardIfAborts: true}) {
+ bool changed = false;
+ List<Element> toRemove = <Element>[];
+ // Iterating over a map and just updating its entries is OK.
+ locals.forEach((Element local, TypeMask oldType) {
+ TypeMask otherType = other.locals[local];
+ bool isCaptured = capturedAndBoxed.containsKey(local);
+ if (otherType == null) {
+ if (!isCaptured) {
+ // If [local] is not in the other map and is not captured
+ // and boxed, we know it is not a
+ // local we want to keep. For example, in an if/else, we don't
+ // want to keep variables declared in the if or in the else
+ // branch at the merge point.
+ toRemove.add(local);
+ }
+ return;
+ }
+ if (!isCaptured && aborts && discardIfAborts) {
+ locals[local] = otherType;
+ } else if (!isCaptured && other.aborts && discardIfAborts) {
+ // Don't do anything.
+ } else {
+ TypeMask type = computeLUB(oldType, otherType, inferrer.compiler);
+ if (type != oldType) changed = true;
+ locals[local] = type;
+ }
+ });
+
+ // Remove locals that will not be used anymore.
+ toRemove.forEach((Element element) {
+ locals.remove(element);
+ });
+
+ // Update the locals that are captured and boxed. We
+ // unconditionally add them to [this] because we register the type
+ // of boxed variables after analyzing all closures.
+ other.capturedAndBoxed.forEach((Element local, Element field) {
+ capturedAndBoxed[local] = field;
+ // If [element] is not in our [locals], we need to update it.
+ // Otherwise, we have already computed the LUB of it.
+ if (locals[local] == null) {
+ locals[local] = other.locals[local];
+ }
+ });
+
+ // Merge instance fields initialized in both handlers. This is
+ // only relevant for generative constructors.
+ toRemove = <Element>[];
+ // Iterate over the map in [:this:]. The map in [other] may
+ // contain different fields, but if this map does not contain it,
+ // then we know the field can be null and we don't need to track
+ // it.
+ fieldsInitializedInConstructor.forEach((Element element, TypeMask type) {
+ TypeMask otherType = other.fieldsInitializedInConstructor[element];
+ if (otherType == null) {
+ toRemove.add(element);
+ } else {
+ fieldsInitializedInConstructor[element] =
+ computeLUB(type, otherType, inferrer.compiler);
+ }
+ });
+ // Remove fields that were not initialized in [other].
+ toRemove.forEach((Element element) {
+ fieldsInitializedInConstructor.remove(element);
+ });
+ isThisExposed = isThisExposed || other.isThisExposed;
+ seenReturn = seenReturn && other.seenReturn;
+ seenBreakOrContinue = seenBreakOrContinue && other.seenBreakOrContinue;
+
+ return changed;
+ }
+
+ void updateField(Element element, TypeMask type) {
+ if (isThisExposed) return;
+ fieldsInitializedInConstructor[element] = type;
+ }
+}
+
+abstract class InferrerVisitor extends ResolvedVisitor<TypeMask> {
+ final Element analyzedElement;
+ final InternalSimpleTypesInferrer inferrer;
+ final Compiler compiler;
+ final Map<TargetElement, List<LocalsHandler>> breaksFor =
+ new Map<TargetElement, List<LocalsHandler>>();
+ final Map<TargetElement, List<LocalsHandler>> continuesFor =
+ new Map<TargetElement, List<LocalsHandler>>();
+ LocalsHandler locals;
+
+ bool accumulateIsChecks = false;
+ bool conditionIsSimple = false;
+ List<Send> isChecks;
+ int loopLevel = 0;
+
+ bool get inLoop => loopLevel > 0;
+ bool get isThisExposed => locals.isThisExposed;
+ void set isThisExposed(value) { locals.isThisExposed = value; }
+
+ InferrerVisitor(Element analyzedElement,
+ this.inferrer,
+ Compiler compiler,
+ this.locals)
+ : this.compiler = compiler,
+ this.analyzedElement = analyzedElement,
+ super(compiler.enqueuer.resolution.getCachedElements(analyzedElement));
+
+ TypeMask visitSendSet(SendSet node);
+
+ TypeMask visitSuperSend(Send node);
+
+ TypeMask visitStaticSend(Send node);
+
+ TypeMask visitGetterSend(Send node);
+
+ TypeMask visitClosureSend(Send node);
+
+ TypeMask visitDynamicSend(Send node);
+
+ TypeMask visitForIn(ForIn node);
+
+ TypeMask visitReturn(Return node);
+
+ TypeMask visitNode(Node node) {
+ node.visitChildren(this);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitNewExpression(NewExpression node) {
+ return node.send.accept(this);
+ }
+
+ TypeMask visit(Node node) {
+ return node == null ? inferrer.dynamicType : node.accept(this);
+ }
+
+ TypeMask visitFunctionExpression(FunctionExpression node) {
+ return inferrer.functionType;
+ }
+
+ TypeMask visitFunctionDeclaration(FunctionDeclaration node) {
+ locals.update(elements[node], inferrer.functionType);
+ return visit(node.function);
+ }
+
+ TypeMask visitLiteralString(LiteralString node) {
+ return inferrer.stringType;
+ }
+
+ TypeMask visitStringInterpolation(StringInterpolation node) {
+ node.visitChildren(this);
+ return inferrer.stringType;
+ }
+
+ TypeMask visitStringJuxtaposition(StringJuxtaposition node) {
+ node.visitChildren(this);
+ return inferrer.stringType;
+ }
+
+ TypeMask visitLiteralBool(LiteralBool node) {
+ return inferrer.boolType;
+ }
+
+ TypeMask visitLiteralDouble(LiteralDouble node) {
+ return inferrer.doubleType;
+ }
+
+ TypeMask visitLiteralInt(LiteralInt node) {
+ return inferrer.intType;
+ }
+
+ TypeMask visitLiteralList(LiteralList node) {
+ node.visitChildren(this);
+ return node.isConst()
+ ? inferrer.constListType
+ : inferrer.growableListType;
+ }
+
+ TypeMask visitLiteralMap(LiteralMap node) {
+ node.visitChildren(this);
+ return node.isConst()
+ ? inferrer.constMapType
+ : inferrer.mapType;
+ }
+
+ TypeMask visitLiteralNull(LiteralNull node) {
+ return inferrer.nullType;
+ }
+
+ TypeMask visitTypeReferenceSend(Send node) {
+ return inferrer.typeType;
+ }
+
+ bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
+
+ Element get outermostElement {
+ return
+ analyzedElement.getOutermostEnclosingMemberOrTopLevel().implementation;
+ }
+
+ TypeMask _thisType;
+ TypeMask get thisType {
+ if (_thisType != null) return _thisType;
+ ClassElement cls = outermostElement.getEnclosingClass();
+ if (compiler.world.isUsedAsMixin(cls)) {
+ return _thisType = new TypeMask.nonNullSubtype(inferrer.rawTypeOf(cls));
+ } else if (compiler.world.hasAnySubclass(cls)) {
+ return _thisType = new TypeMask.nonNullSubclass(inferrer.rawTypeOf(cls));
+ } else {
+ return _thisType = new TypeMask.nonNullExact(inferrer.rawTypeOf(cls));
+ }
+ }
+
+ TypeMask _superType;
+ TypeMask get superType {
+ if (_superType != null) return _superType;
+ return _superType = new TypeMask.nonNullExact(
+ inferrer.rawTypeOf(outermostElement.getEnclosingClass().superclass));
+ }
+
+ TypeMask visitIdentifier(Identifier node) {
+ if (node.isThis()) {
+ return thisType;
+ } else if (node.isSuper()) {
+ return superType;
+ }
+ return inferrer.dynamicType;
+ }
+
+ void potentiallyAddIsCheck(Send node) {
+ if (!accumulateIsChecks) return;
+ if (!Elements.isLocal(elements[node.receiver])) return;
+ isChecks.add(node);
+ }
+
+ void updateIsChecks(List<Node> tests, {bool usePositive}) {
+ if (tests == null) return;
+ for (Send node in tests) {
+ if (node.isIsNotCheck) {
+ if (usePositive) continue;
+ } else {
+ if (!usePositive) continue;
+ }
+ DartType type = elements.getType(node.typeAnnotationFromIsCheck);
+ Element element = elements[node.receiver];
+ TypeMask existing = locals.use(element);
+ TypeMask newType = narrowType(
+ existing, type, inferrer.compiler, isNullable: false);
+ locals.update(element, newType);
+ }
+ }
+
+ TypeMask visitOperatorSend(Send node) {
+ Operator op = node.selector;
+ if (const SourceString("[]") == op.source) {
+ return visitDynamicSend(node);
+ } else if (const SourceString("&&") == op.source) {
+ conditionIsSimple = false;
+ bool oldAccumulateIsChecks = accumulateIsChecks;
+ accumulateIsChecks = true;
+ if (isChecks == null) isChecks = <Send>[];
+ visit(node.receiver);
+ accumulateIsChecks = oldAccumulateIsChecks;
+ if (!accumulateIsChecks) isChecks = null;
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ updateIsChecks(isChecks, usePositive: true);
+ visit(node.arguments.head);
+ locals.merge(saved);
+ return inferrer.boolType;
+ } else if (const SourceString("||") == op.source) {
+ conditionIsSimple = false;
+ visit(node.receiver);
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ updateIsChecks(isChecks, usePositive: false);
+ bool oldAccumulateIsChecks = accumulateIsChecks;
+ accumulateIsChecks = false;
+ visit(node.arguments.head);
+ accumulateIsChecks = oldAccumulateIsChecks;
+ locals.merge(saved);
+ return inferrer.boolType;
+ } else if (const SourceString("!") == op.source) {
+ bool oldAccumulateIsChecks = accumulateIsChecks;
+ accumulateIsChecks = false;
+ node.visitChildren(this);
+ accumulateIsChecks = oldAccumulateIsChecks;
+ return inferrer.boolType;
+ } else if (const SourceString("is") == op.source) {
+ potentiallyAddIsCheck(node);
+ node.visitChildren(this);
+ return inferrer.boolType;
+ } else if (const SourceString("as") == op.source) {
+ TypeMask receiverType = visit(node.receiver);
+ DartType type = elements.getType(node.arguments.head);
+ return narrowType(receiverType, type, inferrer.compiler);
+ } else if (node.isParameterCheck) {
+ node.visitChildren(this);
+ return inferrer.boolType;
+ } else if (node.argumentsNode is Prefix) {
+ // Unary operator.
+ return visitDynamicSend(node);
+ } else if (const SourceString('===') == op.source
+ || const SourceString('!==') == op.source) {
+ node.visitChildren(this);
+ return inferrer.boolType;
+ } else {
+ // Binary operator.
+ return visitDynamicSend(node);
+ }
+ }
+
+ // Because some nodes just visit their children, we may end up
+ // visiting a type annotation, that may contain a send in case of a
+ // prefixed type. Therefore we explicitly visit the type annotation
+ // to avoid confusing the [ResolvedVisitor].
+ visitTypeAnnotation(TypeAnnotation node) {}
+
+ TypeMask visitConditional(Conditional node) {
+ List<Send> tests = <Send>[];
+ bool simpleCondition = handleCondition(node.condition, tests);
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ updateIsChecks(tests, usePositive: true);
+ TypeMask firstType = visit(node.thenExpression);
+ LocalsHandler thenLocals = locals;
+ locals = saved;
+ if (simpleCondition) updateIsChecks(tests, usePositive: false);
+ TypeMask secondType = visit(node.elseExpression);
+ locals.merge(thenLocals);
+ TypeMask type = computeLUB(firstType, secondType, compiler);
+ return type;
+ }
+
+ TypeMask visitVariableDefinitions(VariableDefinitions node) {
+ for (Link<Node> link = node.definitions.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ Node definition = link.head;
+ if (definition is Identifier) {
+ locals.update(elements[definition], inferrer.nullType);
+ } else {
+ assert(definition.asSendSet() != null);
+ visit(definition);
+ }
+ }
+ return inferrer.dynamicType;
+ }
+
+ bool handleCondition(Node node, List<Send> tests) {
+ bool oldConditionIsSimple = conditionIsSimple;
+ bool oldAccumulateIsChecks = accumulateIsChecks;
+ List<Send> oldIsChecks = isChecks;
+ accumulateIsChecks = true;
+ conditionIsSimple = true;
+ isChecks = tests;
+ visit(node);
+ bool simpleCondition = conditionIsSimple;
+ accumulateIsChecks = oldAccumulateIsChecks;
+ isChecks = oldIsChecks;
+ conditionIsSimple = oldConditionIsSimple;
+ return simpleCondition;
+ }
+
+ TypeMask visitIf(If node) {
+ List<Send> tests = <Send>[];
+ bool simpleCondition = handleCondition(node.condition, tests);
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ updateIsChecks(tests, usePositive: true);
+ visit(node.thenPart);
+ LocalsHandler thenLocals = locals;
+ locals = saved;
+ if (simpleCondition) updateIsChecks(tests, usePositive: false);
+ visit(node.elsePart);
+ locals.merge(thenLocals);
+ return inferrer.dynamicType;
+ }
+
+ void setupBreaksAndContinues(TargetElement element) {
+ if (element == null) return;
+ if (element.isContinueTarget) continuesFor[element] = <LocalsHandler>[];
+ if (element.isBreakTarget) breaksFor[element] = <LocalsHandler>[];
+ }
+
+ void clearBreaksAndContinues(TargetElement element) {
+ continuesFor.remove(element);
+ breaksFor.remove(element);
+ }
+
+ void mergeBreaks(TargetElement element) {
+ if (element == null) return;
+ if (!element.isBreakTarget) return;
+ for (LocalsHandler handler in breaksFor[element]) {
+ locals.merge(handler, discardIfAborts: false);
+ }
+ }
+
+ bool mergeContinues(TargetElement element) {
+ if (element == null) return false;
+ if (!element.isContinueTarget) return false;
+ bool changed = false;
+ for (LocalsHandler handler in continuesFor[element]) {
+ changed = locals.merge(handler, discardIfAborts: false) || changed;
+ }
+ return changed;
+ }
+
+ TypeMask handleLoop(Node node, void logic()) {
+ loopLevel++;
+ bool changed = false;
+ TargetElement target = elements[node];
+ setupBreaksAndContinues(target);
+ do {
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ logic();
+ changed = saved.merge(locals);
+ locals = saved;
+ changed = mergeContinues(target) || changed;
+ } while (changed);
+ loopLevel--;
+ mergeBreaks(target);
+ clearBreaksAndContinues(target);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitWhile(While node) {
+ return handleLoop(node, () {
+ List<Send> tests = <Send>[];
+ handleCondition(node.condition, tests);
+ updateIsChecks(tests, usePositive: true);
+ visit(node.body);
+ });
+ }
+
+ TypeMask visitDoWhile(DoWhile node) {
+ return handleLoop(node, () {
+ visit(node.body);
+ List<Send> tests = <Send>[];
+ handleCondition(node.condition, tests);
+ updateIsChecks(tests, usePositive: true);
+ });
+ }
+
+ TypeMask visitFor(For node) {
+ visit(node.initializer);
+ return handleLoop(node, () {
+ List<Send> tests = <Send>[];
+ handleCondition(node.condition, tests);
+ updateIsChecks(tests, usePositive: true);
+ visit(node.body);
+ visit(node.update);
+ });
+ }
+
+ TypeMask visitTryStatement(TryStatement node) {
+ LocalsHandler saved = locals;
+ locals = new LocalsHandler.from(locals, inTryBlock: true);
+ visit(node.tryBlock);
+ saved.merge(locals);
+ locals = saved;
+ for (Node catchBlock in node.catchBlocks) {
+ saved = new LocalsHandler.from(locals);
+ visit(catchBlock);
+ saved.merge(locals);
+ locals = saved;
+ }
+ visit(node.finallyBlock);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitThrow(Throw node) {
+ node.visitChildren(this);
+ locals.seenReturn = true;
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitCatchBlock(CatchBlock node) {
+ Node exception = node.exception;
+ if (exception != null) {
+ DartType type = elements.getType(node.type);
+ TypeMask mask = type == null
+ ? inferrer.dynamicType
+ : new TypeMask.nonNullSubtype(type.asRaw());
+ locals.update(elements[exception], mask);
+ }
+ Node trace = node.trace;
+ if (trace != null) {
+ locals.update(elements[trace], inferrer.dynamicType);
+ }
+ visit(node.block);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitParenthesizedExpression(ParenthesizedExpression node) {
+ return visit(node.expression);
+ }
+
+ TypeMask visitBlock(Block node) {
+ if (node.statements != null) {
+ for (Node statement in node.statements) {
+ visit(statement);
+ if (locals.aborts) break;
+ }
+ }
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitLabeledStatement(LabeledStatement node) {
+ Statement body = node.statement;
+ if (body is Loop
+ || body is SwitchStatement
+ || Elements.isUnusedLabel(node, elements)) {
+ // Loops and switches handle their own labels.
+ visit(body);
+ return inferrer.dynamicType;
+ }
+
+ TargetElement targetElement = elements[body];
+ setupBreaksAndContinues(targetElement);
+ visit(body);
+ mergeBreaks(targetElement);
+ clearBreaksAndContinues(targetElement);
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitBreakStatement(BreakStatement node) {
+ TargetElement target = elements[node];
+ breaksFor[target].add(locals);
+ locals.seenBreakOrContinue = true;
+ return inferrer.dynamicType;
+ }
+
+ TypeMask visitContinueStatement(ContinueStatement node) {
+ TargetElement target = elements[node];
+ continuesFor[target].add(locals);
+ locals.seenBreakOrContinue = true;
+ return inferrer.dynamicType;
+ }
+
+ void internalError(String reason, {Node node}) {
+ compiler.internalError(reason, node: node);
+ }
+
+ TypeMask visitSwitchStatement(SwitchStatement node) {
+ visit(node.parenthesizedExpression);
+
+ setupBreaksAndContinues(elements[node]);
+ if (Elements.switchStatementHasContinue(node, elements)) {
+ void forEachLabeledCase(void action(TargetElement target)) {
+ for (SwitchCase switchCase in node.cases) {
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ if (labelOrCase.asLabel() == null) continue;
+ LabelElement labelElement = elements[labelOrCase];
+ if (labelElement != null) {
+ action(labelElement.target);
+ }
+ }
+ }
+ }
+
+ forEachLabeledCase((TargetElement target) {
+ setupBreaksAndContinues(target);
+ });
+
+ // If the switch statement has a continue, we conservatively
+ // visit all cases and update [locals] until we have reached a
+ // fixed point.
+ bool changed;
+ do {
+ changed = false;
+ for (Node switchCase in node.cases) {
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ visit(switchCase);
+ changed = saved.merge(locals, discardIfAborts: false) || changed;
+ locals = saved;
+ }
+ } while (changed);
+
+ forEachLabeledCase((TargetElement target) {
+ clearBreaksAndContinues(target);
+ });
+ } else {
+ LocalsHandler saved = new LocalsHandler.from(locals);
+ // If there is a default case, the current values of the local
+ // variable might be overwritten, so we don't need the current
+ // [locals] for the join block.
+ LocalsHandler result = Elements.switchStatementHasDefault(node)
+ ? null
+ : new LocalsHandler.from(locals);
+
+ for (Node switchCase in node.cases) {
+ locals = new LocalsHandler.from(saved);
+ visit(switchCase);
+ if (result == null) {
+ result = locals;
+ } else {
+ result.merge(locals, discardIfAborts: false);
+ }
+ }
+ locals = result;
+ }
+ clearBreaksAndContinues(elements[node]);
+ // In case there is a default in the switch we discard the
+ // incoming localsHandler, because the types it holds do not need
+ // to be merged after the switch statement. This means that, if all
+ // cases, including the default, break or continue, the [result]
+ // handler may think it just aborts the current block. Therefore
+ // we set the current locals to not have any break or continue, so
+ // that the [visitBlock] method does not assume the code after the
+ // switch is dead code.
+ locals.seenBreakOrContinue = false;
+ return inferrer.dynamicType;
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index a75f930..4a9b948 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -21,6 +21,8 @@
import '../dart2jslib.dart' hide Selector, TypedSelector;
import '../universe/universe.dart' show Selector, SideEffects, TypedSelector;
+part 'inferrer_visitor.dart';
+
/**
* A work queue that ensures there are no duplicates, and adds and
* removes in FIFO.
@@ -97,32 +99,6 @@
bool get isDone => constructorsToVisitCount == 0;
}
-/**
- * A sentinel type mask class used by the inferrer for the give up
- * type, and the dynamic type.
- */
-class SentinelTypeMask extends FlatTypeMask {
- final String name;
-
- SentinelTypeMask(this.name) : super(null, 0, false);
-
- bool operator==(other) {
- return identical(this, other);
- }
-
- TypeMask nullable() {
- throw 'Unsupported operation';
- }
-
- TypeMask intersection(TypeMask other, Compiler compiler) {
- return other;
- }
-
- bool get isNullable => true;
-
- String toString() => '$name sentinel type mask';
-}
-
final OPTIMISTIC = 0;
final RETRY = 1;
final PESSIMISTIC = 2;
@@ -180,8 +156,6 @@
}
}
-
-
class InternalSimpleTypesInferrer extends TypesInferrer {
/**
* Maps an element to its callers.
@@ -267,10 +241,6 @@
int optimismState;
- /**
- * Sentinel used by the inferrer to notify that it does not know
- * the type of a specific element.
- */
TypeMask dynamicType;
bool isDynamicType(TypeMask type) => identical(type, dynamicType);
@@ -383,23 +353,23 @@
* Query method after the analysis to know the type of [element].
*/
TypeMask getReturnTypeOfElement(Element element) {
- return getTypeIfValuable(returnTypeOf[element]);
+ return getNonNullType(returnTypeOf[element]);
}
TypeMask getTypeOfElement(Element element) {
- return getTypeIfValuable(typeOf[element]);
+ return getNonNullType(typeOf[element]);
}
TypeMask getTypeOfSelector(Selector selector) {
- return getTypeIfValuable(typeOfSelector(selector));
+ return getNonNullType(typeOfSelector(selector));
}
bool isTypeValuable(TypeMask returnType) {
return !isDynamicType(returnType);
}
- TypeMask getTypeIfValuable(TypeMask returnType) {
- return isTypeValuable(returnType) ? returnType : null;
+ TypeMask getNonNullType(TypeMask returnType) {
+ return returnType != null ? returnType : dynamicType;
}
/**
@@ -417,7 +387,7 @@
if (selector == null || selector.isSetter() || selector.isIndexSet()) {
return null;
}
- return getTypeIfValuable(typeOfSelector(selector));
+ return getNonNullType(typeOfSelector(selector));
}
void checkAnalyzedAll() {
@@ -678,7 +648,7 @@
assert(annotation is FunctionType);
annotation = annotation.returnType;
}
- newType = narrowType(newType, annotation);
+ newType = narrowType(newType, annotation, compiler);
}
// Fields and native methods of native classes are handled
@@ -721,7 +691,7 @@
|| element.isGetter()
|| element.isFactoryConstructor())) {
FunctionType functionType = element.computeType(compiler);
- returnType = narrowType(dynamicType, functionType.returnType);
+ returnType = narrowType(dynamicType, functionType.returnType, compiler);
} else {
returnType = dynamicType;
}
@@ -763,7 +733,7 @@
} else {
mappedType = new TypeMask.nonNullExact(rawTypeOf(type.element));
}
- returnType = computeLUB(returnType, mappedType);
+ returnType = computeLUB(returnType, mappedType, compiler);
if (!isTypeValuable(returnType)) {
returnType = dynamicType;
break;
@@ -797,7 +767,7 @@
// therefore only trust their type after the checks.
|| (compiler.enableTypeAssertions
&& (element.isField() || element.isVariable()))) {
- type = narrowType(dynamicType, element.computeType(compiler));
+ type = narrowType(dynamicType, element.computeType(compiler), compiler);
} else {
type = dynamicType;
}
@@ -818,7 +788,7 @@
iterateOverElements(selector, (Element element) {
assert(element.isImplementation);
TypeMask type = typeOfElementWithSelector(element, selector);
- result = computeLUB(result, type);
+ result = computeLUB(result, type, compiler);
return isTypeValuable(result);
});
if (result == null) {
@@ -1023,7 +993,8 @@
TypeMask type;
typeOfArguments[element].forEach((_, ArgumentsTypes arguments) {
if (!visitingOptionalParameter) {
- type = computeLUB(type, arguments.positional[parameterIndex]);
+ type = computeLUB(
+ type, arguments.positional[parameterIndex], compiler);
} else {
TypeMask argumentType = signature.optionalParametersAreNamed
? arguments.named[parameter.name]
@@ -1034,7 +1005,7 @@
argumentType = defaultTypeOfParameter[parameter];
}
assert(argumentType != null);
- type = computeLUB(type, argumentType);
+ type = computeLUB(type, argumentType, compiler);
}
});
if (recordType(parameter, type)) {
@@ -1100,7 +1071,7 @@
if (!selector.isSetter()) {
TypeMask type = handleIntrisifiedSelector(selector, arguments);
if (type == null) type = typeOfElementWithSelector(element, selector);
- result = computeLUB(result, type);
+ result = computeLUB(result, type, compiler);
}
}
}
@@ -1155,7 +1126,7 @@
// use its type.
constraints.add(constraint);
} else {
- fieldType = computeLUB(fieldType, mask);
+ fieldType = computeLUB(fieldType, mask, compiler);
}
});
@@ -1178,7 +1149,7 @@
// Otherwise the constraint is on the form [: field = other.field :].
assert(constraint.isGetter());
}
- fieldType = computeLUB(fieldType, typeOfSelector(constraint));
+ fieldType = computeLUB(fieldType, typeOfSelector(constraint), compiler);
}
if (existing == null) {
typeOf.remove(element);
@@ -1262,47 +1233,6 @@
}
});
}
-
- /**
- * Returns the least upper bound between [firstType] and
- * [secondType].
- */
- TypeMask computeLUB(TypeMask firstType, TypeMask secondType) {
- if (firstType == null) {
- return secondType;
- } else if (isDynamicType(secondType)) {
- return secondType;
- } else if (isDynamicType(firstType)) {
- return firstType;
- } else {
- TypeMask union = firstType.union(secondType, compiler);
- // TODO(kasperl): If the union isn't nullable it seems wasteful
- // to use dynamic. Fix that.
- return union.containsAll(compiler) ? dynamicType : union;
- }
- }
-
- TypeMask narrowType(TypeMask type,
- DartType annotation,
- {bool isNullable: true}) {
- if (annotation.isDynamic) return type;
- if (annotation.isMalformed) return type;
- if (annotation.isVoid) return nullType;
- if (annotation.element == compiler.objectClass) return type;
- TypeMask otherType;
- if (annotation.kind == TypeKind.TYPEDEF
- || annotation.kind == TypeKind.FUNCTION) {
- otherType = functionType;
- } else if (annotation.kind == TypeKind.TYPE_VARIABLE) {
- return type;
- } else {
- assert(annotation.kind == TypeKind.INTERFACE);
- otherType = new TypeMask.nonNullSubtype(annotation);
- }
- if (isNullable) otherType = otherType.nullable();
- if (type == null) return otherType;
- return type.intersection(otherType, compiler);
- }
}
/**
@@ -1337,183 +1267,19 @@
}
}
-/**
- * Placeholder for inferred types of local variables.
- */
-class LocalsHandler {
- final InternalSimpleTypesInferrer inferrer;
- final Map<Element, TypeMask> locals;
- final Map<Element, Element> capturedAndBoxed;
- final Map<Element, TypeMask> fieldsInitializedInConstructor;
- final bool inTryBlock;
- bool isThisExposed;
- bool seenReturn = false;
- bool seenBreakOrContinue = false;
-
- bool get aborts {
- return seenReturn || seenBreakOrContinue;
- }
-
- LocalsHandler(this.inferrer)
- : locals = new Map<Element, TypeMask>(),
- capturedAndBoxed = new Map<Element, Element>(),
- fieldsInitializedInConstructor = new Map<Element, TypeMask>(),
- inTryBlock = false,
- isThisExposed = true;
- LocalsHandler.from(LocalsHandler other, {bool inTryBlock: false})
- : locals = new Map<Element, TypeMask>.from(other.locals),
- capturedAndBoxed = new Map<Element, Element>.from(
- other.capturedAndBoxed),
- fieldsInitializedInConstructor = new Map<Element, TypeMask>.from(
- other.fieldsInitializedInConstructor),
- inTryBlock = other.inTryBlock || inTryBlock,
- inferrer = other.inferrer,
- isThisExposed = other.isThisExposed;
-
- TypeMask use(Element local) {
- if (capturedAndBoxed.containsKey(local)) {
- return inferrer.typeOfElement(capturedAndBoxed[local]);
- }
- return locals[local];
- }
-
- void update(Element local, TypeMask type) {
- assert(type != null);
- if (inferrer.compiler.trustTypeAnnotations
- || inferrer.compiler.enableTypeAssertions) {
- type = inferrer.narrowType(type, local.computeType(inferrer.compiler));
- }
- if (capturedAndBoxed.containsKey(local) || inTryBlock) {
- // If a local is captured and boxed, or is set in a try block,
- // we compute the LUB of its assignments.
- //
- // We don't know if an assignment in a try block
- // will be executed, so all assigments in that block are
- // potential types after we have left it.
- type = inferrer.computeLUB(locals[local], type);
- }
- locals[local] = type;
- }
-
- void setCapturedAndBoxed(Element local, Element field) {
- capturedAndBoxed[local] = field;
- }
-
- /**
- * Merge handlers [first] and [second] into [:this:] and returns
- * whether the merge changed one of the variables types in [first].
- */
- bool merge(LocalsHandler other, {bool discardIfAborts: true}) {
- bool changed = false;
- List<Element> toRemove = <Element>[];
- // Iterating over a map and just updating its entries is OK.
- locals.forEach((Element local, TypeMask oldType) {
- TypeMask otherType = other.locals[local];
- bool isCaptured = capturedAndBoxed.containsKey(local);
- if (otherType == null) {
- if (!isCaptured) {
- // If [local] is not in the other map and is not captured
- // and boxed, we know it is not a
- // local we want to keep. For example, in an if/else, we don't
- // want to keep variables declared in the if or in the else
- // branch at the merge point.
- toRemove.add(local);
- }
- return;
- }
- if (!isCaptured && aborts && discardIfAborts) {
- locals[local] = otherType;
- } else if (!isCaptured && other.aborts && discardIfAborts) {
- // Don't do anything.
- } else {
- TypeMask type = inferrer.computeLUB(oldType, otherType);
- if (type != oldType) changed = true;
- locals[local] = type;
- }
- });
-
- // Remove locals that will not be used anymore.
- toRemove.forEach((Element element) {
- locals.remove(element);
- });
-
- // Update the locals that are captured and boxed. We
- // unconditionally add them to [this] because we register the type
- // of boxed variables after analyzing all closures.
- other.capturedAndBoxed.forEach((Element local, Element field) {
- capturedAndBoxed[local] = field;
- // If [element] is not in our [locals], we need to update it.
- // Otherwise, we have already computed the LUB of it.
- if (locals[local] == null) {
- locals[local] = other.locals[local];
- }
- });
-
- // Merge instance fields initialized in both handlers. This is
- // only relevant for generative constructors.
- toRemove = <Element>[];
- // Iterate over the map in [:this:]. The map in [other] may
- // contain different fields, but if this map does not contain it,
- // then we know the field can be null and we don't need to track
- // it.
- fieldsInitializedInConstructor.forEach((Element element, TypeMask type) {
- TypeMask otherType = other.fieldsInitializedInConstructor[element];
- if (otherType == null) {
- toRemove.add(element);
- } else {
- fieldsInitializedInConstructor[element] =
- inferrer.computeLUB(type, otherType);
- }
- });
- // Remove fields that were not initialized in [other].
- toRemove.forEach((Element element) {
- fieldsInitializedInConstructor.remove(element);
- });
- isThisExposed = isThisExposed || other.isThisExposed;
- seenReturn = seenReturn && other.seenReturn;
- seenBreakOrContinue = seenBreakOrContinue && other.seenBreakOrContinue;
-
- return changed;
- }
-
- void updateField(Element element, TypeMask type) {
- if (isThisExposed) return;
- fieldsInitializedInConstructor[element] = type;
- }
-}
-
-class SimpleTypeInferrerVisitor extends ResolvedVisitor<TypeMask> {
- final Element analyzedElement;
- final Element outermostElement;
- final InternalSimpleTypesInferrer inferrer;
- final Compiler compiler;
- final Map<TargetElement, List<LocalsHandler>> breaksFor =
- new Map<TargetElement, List<LocalsHandler>>();
- final Map<TargetElement, List<LocalsHandler>> continuesFor =
- new Map<TargetElement, List<LocalsHandler>>();
- LocalsHandler locals;
+class SimpleTypeInferrerVisitor extends InferrerVisitor {
TypeMask returnType;
-
bool visitingInitializers = false;
bool isConstructorRedirect = false;
- bool accumulateIsChecks = false;
- bool conditionIsSimple = false;
-
- List<Send> isChecks;
- int loopLevel = 0;
SideEffects sideEffects = new SideEffects.empty();
+ final Element outermostElement;
- bool get inLoop => loopLevel > 0;
- bool get isThisExposed => locals.isThisExposed;
- void set isThisExposed(value) { locals.isThisExposed = value; }
-
- SimpleTypeInferrerVisitor.internal(TreeElements mapping,
- this.analyzedElement,
+ SimpleTypeInferrerVisitor.internal(analyzedElement,
this.outermostElement,
- this.inferrer,
- this.compiler,
- this.locals)
- : super(mapping);
+ inferrer,
+ compiler,
+ locals)
+ : super(analyzedElement, inferrer, compiler, locals);
factory SimpleTypeInferrerVisitor(Element element,
Compiler compiler,
@@ -1521,13 +1287,10 @@
[LocalsHandler handler]) {
Element outermostElement =
element.getOutermostEnclosingMemberOrTopLevel().implementation;
- TreeElements elements = compiler.enqueuer.resolution.resolvedElements[
- outermostElement.declaration];
- assert(elements != null);
assert(outermostElement != null);
handler = handler != null ? handler : new LocalsHandler(inferrer);
return new SimpleTypeInferrerVisitor.internal(
- elements, element, outermostElement, inferrer, compiler, handler);
+ element, outermostElement, inferrer, compiler, handler);
}
TypeMask run() {
@@ -1637,7 +1400,7 @@
// bool.
signature.forEachParameter((Element parameter) {
if (inferrer.typeOfElement(parameter).isNullable){
- returnType = inferrer.computeLUB(returnType, inferrer.boolType);
+ returnType = computeLUB(returnType, inferrer.boolType, compiler);
}
});
}
@@ -1658,43 +1421,6 @@
return returnType;
}
- TypeMask _thisType;
- TypeMask get thisType {
- if (_thisType != null) return _thisType;
- ClassElement cls = outermostElement.getEnclosingClass();
- if (compiler.world.isUsedAsMixin(cls)) {
- return _thisType = new TypeMask.nonNullSubtype(inferrer.rawTypeOf(cls));
- } else if (compiler.world.hasAnySubclass(cls)) {
- return _thisType = new TypeMask.nonNullSubclass(inferrer.rawTypeOf(cls));
- } else {
- return _thisType = new TypeMask.nonNullExact(inferrer.rawTypeOf(cls));
- }
- }
-
- TypeMask _superType;
- TypeMask get superType {
- if (_superType != null) return _superType;
- return _superType = new TypeMask.nonNullExact(
- inferrer.rawTypeOf(outermostElement.getEnclosingClass().superclass));
- }
-
- void recordReturnType(TypeMask type) {
- returnType = inferrer.computeLUB(returnType, type);
- }
-
- TypeMask visitNode(Node node) {
- node.visitChildren(this);
- return inferrer.dynamicType;
- }
-
- TypeMask visitNewExpression(NewExpression node) {
- return node.send.accept(this);
- }
-
- TypeMask visit(Node node) {
- return node == null ? inferrer.dynamicType : node.accept(this);
- }
-
TypeMask visitFunctionExpression(FunctionExpression node) {
Element element = elements[node];
// We don't put the closure in the work queue of the
@@ -1725,59 +1451,6 @@
return inferrer.functionType;
}
- TypeMask visitFunctionDeclaration(FunctionDeclaration node) {
- locals.update(elements[node], inferrer.functionType);
- return visit(node.function);
- }
-
- TypeMask visitLiteralString(LiteralString node) {
- return inferrer.stringType;
- }
-
- TypeMask visitStringInterpolation(StringInterpolation node) {
- node.visitChildren(this);
- return inferrer.stringType;
- }
-
- TypeMask visitStringJuxtaposition(StringJuxtaposition node) {
- node.visitChildren(this);
- return inferrer.stringType;
- }
-
- TypeMask visitLiteralBool(LiteralBool node) {
- return inferrer.boolType;
- }
-
- TypeMask visitLiteralDouble(LiteralDouble node) {
- return inferrer.doubleType;
- }
-
- TypeMask visitLiteralInt(LiteralInt node) {
- return inferrer.intType;
- }
-
- TypeMask visitLiteralList(LiteralList node) {
- node.visitChildren(this);
- return node.isConst()
- ? inferrer.constListType
- : inferrer.growableListType;
- }
-
- TypeMask visitLiteralMap(LiteralMap node) {
- node.visitChildren(this);
- return node.isConst()
- ? inferrer.constMapType
- : inferrer.mapType;
- }
-
- TypeMask visitLiteralNull(LiteralNull node) {
- return inferrer.nullType;
- }
-
- TypeMask visitTypeReferenceSend(Send node) {
- return inferrer.typeType;
- }
-
bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
void checkIfExposesThis(Selector selector) {
@@ -1995,15 +1668,6 @@
return rhsType;
}
- TypeMask visitIdentifier(Identifier node) {
- if (node.isThis()) {
- return thisType;
- } else if (node.isSuper()) {
- return superType;
- }
- return inferrer.dynamicType;
- }
-
TypeMask visitSuperSend(Send node) {
Element element = elements[node];
if (Elements.isUnresolved(element)) {
@@ -2092,92 +1756,6 @@
return new ArgumentsTypes(positional, named);
}
- void potentiallyAddIsCheck(Send node) {
- if (!accumulateIsChecks) return;
- if (!Elements.isLocal(elements[node.receiver])) return;
- isChecks.add(node);
- }
-
- void updateIsChecks(List<Node> tests, {bool usePositive}) {
- if (tests == null) return;
- for (Send node in tests) {
- if (node.isIsNotCheck) {
- if (usePositive) continue;
- } else {
- if (!usePositive) continue;
- }
- DartType type = elements.getType(node.typeAnnotationFromIsCheck);
- Element element = elements[node.receiver];
- TypeMask existing = locals.use(element);
- TypeMask newType = inferrer.narrowType(existing, type, isNullable: false);
- locals.update(element, newType);
- }
- }
-
- TypeMask visitOperatorSend(Send node) {
- Operator op = node.selector;
- if (const SourceString("[]") == op.source) {
- return visitDynamicSend(node);
- } else if (const SourceString("&&") == op.source) {
- conditionIsSimple = false;
- bool oldAccumulateIsChecks = accumulateIsChecks;
- accumulateIsChecks = true;
- if (isChecks == null) isChecks = <Send>[];
- visit(node.receiver);
- accumulateIsChecks = oldAccumulateIsChecks;
- if (!accumulateIsChecks) isChecks = null;
- LocalsHandler saved = new LocalsHandler.from(locals);
- updateIsChecks(isChecks, usePositive: true);
- visit(node.arguments.head);
- locals.merge(saved);
- return inferrer.boolType;
- } else if (const SourceString("||") == op.source) {
- conditionIsSimple = false;
- visit(node.receiver);
- LocalsHandler saved = new LocalsHandler.from(locals);
- updateIsChecks(isChecks, usePositive: false);
- bool oldAccumulateIsChecks = accumulateIsChecks;
- accumulateIsChecks = false;
- visit(node.arguments.head);
- accumulateIsChecks = oldAccumulateIsChecks;
- locals.merge(saved);
- return inferrer.boolType;
- } else if (const SourceString("!") == op.source) {
- bool oldAccumulateIsChecks = accumulateIsChecks;
- accumulateIsChecks = false;
- node.visitChildren(this);
- accumulateIsChecks = oldAccumulateIsChecks;
- return inferrer.boolType;
- } else if (const SourceString("is") == op.source) {
- potentiallyAddIsCheck(node);
- node.visitChildren(this);
- return inferrer.boolType;
- } else if (const SourceString("as") == op.source) {
- TypeMask receiverType = visit(node.receiver);
- DartType type = elements.getType(node.arguments.head);
- return inferrer.narrowType(receiverType, type);
- } else if (node.isParameterCheck) {
- node.visitChildren(this);
- return inferrer.boolType;
- } else if (node.argumentsNode is Prefix) {
- // Unary operator.
- return visitDynamicSend(node);
- } else if (const SourceString('===') == op.source
- || const SourceString('!==') == op.source) {
- node.visitChildren(this);
- return inferrer.boolType;
- } else {
- // Binary operator.
- return visitDynamicSend(node);
- }
- }
-
- // Because some nodes just visit their children, we may end up
- // visiting a type annotation, that may contain a send in case of a
- // prefixed type. Therefore we explicitly visit the type annotation
- // to avoid confusing the [ResolvedVisitor].
- visitTypeAnnotation(TypeAnnotation node) {}
-
TypeMask visitGetterSend(Send node) {
Element element = elements[node];
Selector selector = elements.getSelector(node);
@@ -2292,6 +1870,10 @@
return handleDynamicSend(node, selector, receiverType, arguments);
}
+ void recordReturnType(TypeMask type) {
+ returnType = computeLUB(returnType, type, compiler);
+ }
+
TypeMask visitReturn(Return node) {
if (node.isRedirectingFactoryBody) {
Element element = elements[node.expression];
@@ -2332,143 +1914,7 @@
return inferrer.dynamicType;
}
- TypeMask visitConditional(Conditional node) {
- List<Send> tests = <Send>[];
- bool simpleCondition = handleCondition(node.condition, tests);
- LocalsHandler saved = new LocalsHandler.from(locals);
- updateIsChecks(tests, usePositive: true);
- TypeMask firstType = visit(node.thenExpression);
- LocalsHandler thenLocals = locals;
- locals = saved;
- if (simpleCondition) updateIsChecks(tests, usePositive: false);
- TypeMask secondType = visit(node.elseExpression);
- locals.merge(thenLocals);
- TypeMask type = inferrer.computeLUB(firstType, secondType);
- return type;
- }
-
- TypeMask visitVariableDefinitions(VariableDefinitions node) {
- for (Link<Node> link = node.definitions.nodes;
- !link.isEmpty;
- link = link.tail) {
- Node definition = link.head;
- if (definition is Identifier) {
- locals.update(elements[definition], inferrer.nullType);
- } else {
- assert(definition.asSendSet() != null);
- visit(definition);
- }
- }
- return inferrer.dynamicType;
- }
-
- bool handleCondition(Node node, List<Send> tests) {
- bool oldConditionIsSimple = conditionIsSimple;
- bool oldAccumulateIsChecks = accumulateIsChecks;
- List<Send> oldIsChecks = isChecks;
- accumulateIsChecks = true;
- conditionIsSimple = true;
- isChecks = tests;
- visit(node);
- bool simpleCondition = conditionIsSimple;
- accumulateIsChecks = oldAccumulateIsChecks;
- isChecks = oldIsChecks;
- conditionIsSimple = oldConditionIsSimple;
- return simpleCondition;
- }
-
- TypeMask visitIf(If node) {
- List<Send> tests = <Send>[];
- bool simpleCondition = handleCondition(node.condition, tests);
- LocalsHandler saved = new LocalsHandler.from(locals);
- updateIsChecks(tests, usePositive: true);
- visit(node.thenPart);
- LocalsHandler thenLocals = locals;
- locals = saved;
- if (simpleCondition) updateIsChecks(tests, usePositive: false);
- visit(node.elsePart);
- locals.merge(thenLocals);
- return inferrer.dynamicType;
- }
-
- void setupBreaksAndContinues(TargetElement element) {
- if (element == null) return;
- if (element.isContinueTarget) continuesFor[element] = <LocalsHandler>[];
- if (element.isBreakTarget) breaksFor[element] = <LocalsHandler>[];
- }
-
- void clearBreaksAndContinues(TargetElement element) {
- continuesFor.remove(element);
- breaksFor.remove(element);
- }
-
- void mergeBreaks(TargetElement element) {
- if (element == null) return;
- if (!element.isBreakTarget) return;
- for (LocalsHandler handler in breaksFor[element]) {
- locals.merge(handler, discardIfAborts: false);
- }
- }
-
- bool mergeContinues(TargetElement element) {
- if (element == null) return false;
- if (!element.isContinueTarget) return false;
- bool changed = false;
- for (LocalsHandler handler in continuesFor[element]) {
- changed = locals.merge(handler, discardIfAborts: false) || changed;
- }
- return changed;
- }
-
- TypeMask handleLoop(Node node, void logic()) {
- loopLevel++;
- bool changed = false;
- TargetElement target = elements[node];
- setupBreaksAndContinues(target);
- do {
- LocalsHandler saved = new LocalsHandler.from(locals);
- logic();
- changed = saved.merge(locals);
- locals = saved;
- changed = mergeContinues(target) || changed;
- } while (changed);
- loopLevel--;
- mergeBreaks(target);
- clearBreaksAndContinues(target);
- return inferrer.dynamicType;
- }
-
- TypeMask visitWhile(While node) {
- return handleLoop(node, () {
- List<Send> tests = <Send>[];
- handleCondition(node.condition, tests);
- updateIsChecks(tests, usePositive: true);
- visit(node.body);
- });
- }
-
- TypeMask visitDoWhile(DoWhile node) {
- return handleLoop(node, () {
- visit(node.body);
- List<Send> tests = <Send>[];
- handleCondition(node.condition, tests);
- updateIsChecks(tests, usePositive: true);
- });
- }
-
- TypeMask visitFor(For node) {
- visit(node.initializer);
- return handleLoop(node, () {
- List<Send> tests = <Send>[];
- handleCondition(node.condition, tests);
- updateIsChecks(tests, usePositive: true);
- visit(node.body);
- visit(node.update);
- });
- }
-
TypeMask visitForIn(ForIn node) {
- bool changed = false;
TypeMask expressionType = visit(node.expression);
Selector iteratorSelector = elements.getIteratorSelector(node);
Selector currentSelector = elements.getCurrentSelector(node);
@@ -2509,164 +1955,4 @@
visit(node.body);
});
}
-
- TypeMask visitTryStatement(TryStatement node) {
- LocalsHandler saved = locals;
- locals = new LocalsHandler.from(locals, inTryBlock: true);
- visit(node.tryBlock);
- saved.merge(locals);
- locals = saved;
- for (Node catchBlock in node.catchBlocks) {
- saved = new LocalsHandler.from(locals);
- visit(catchBlock);
- saved.merge(locals);
- locals = saved;
- }
- visit(node.finallyBlock);
- return inferrer.dynamicType;
- }
-
- TypeMask visitThrow(Throw node) {
- node.visitChildren(this);
- locals.seenReturn = true;
- return inferrer.dynamicType;
- }
-
- TypeMask visitCatchBlock(CatchBlock node) {
- Node exception = node.exception;
- if (exception != null) {
- DartType type = elements.getType(node.type);
- TypeMask mask = type == null
- ? inferrer.dynamicType
- : new TypeMask.nonNullSubtype(type.asRaw());
- locals.update(elements[exception], mask);
- }
- Node trace = node.trace;
- if (trace != null) {
- locals.update(elements[trace], inferrer.dynamicType);
- }
- visit(node.block);
- return inferrer.dynamicType;
- }
-
- TypeMask visitParenthesizedExpression(ParenthesizedExpression node) {
- return visit(node.expression);
- }
-
- TypeMask visitBlock(Block node) {
- if (node.statements != null) {
- for (Node statement in node.statements) {
- visit(statement);
- if (locals.aborts) break;
- }
- }
- return inferrer.dynamicType;
- }
-
- TypeMask visitLabeledStatement(LabeledStatement node) {
- Statement body = node.statement;
- if (body is Loop
- || body is SwitchStatement
- || Elements.isUnusedLabel(node, elements)) {
- // Loops and switches handle their own labels.
- visit(body);
- return inferrer.dynamicType;
- }
-
- TargetElement targetElement = elements[body];
- setupBreaksAndContinues(targetElement);
- visit(body);
- mergeBreaks(targetElement);
- clearBreaksAndContinues(targetElement);
- return inferrer.dynamicType;
- }
-
- TypeMask visitBreakStatement(BreakStatement node) {
- TargetElement target = elements[node];
- breaksFor[target].add(locals);
- locals.seenBreakOrContinue = true;
- return inferrer.dynamicType;
- }
-
- TypeMask visitContinueStatement(ContinueStatement node) {
- TargetElement target = elements[node];
- continuesFor[target].add(locals);
- locals.seenBreakOrContinue = true;
- return inferrer.dynamicType;
- }
-
- void internalError(String reason, {Node node}) {
- compiler.internalError(reason, node: node);
- }
-
- TypeMask visitSwitchStatement(SwitchStatement node) {
- visit(node.parenthesizedExpression);
-
- setupBreaksAndContinues(elements[node]);
- if (Elements.switchStatementHasContinue(node, elements)) {
- void forEachLabeledCase(void action(TargetElement target)) {
- for (SwitchCase switchCase in node.cases) {
- for (Node labelOrCase in switchCase.labelsAndCases) {
- if (labelOrCase.asLabel() == null) continue;
- LabelElement labelElement = elements[labelOrCase];
- if (labelElement != null) {
- action(labelElement.target);
- }
- }
- }
- }
-
- forEachLabeledCase((TargetElement target) {
- setupBreaksAndContinues(target);
- });
-
- // If the switch statement has a continue, we conservatively
- // visit all cases and update [locals] until we have reached a
- // fixed point.
- bool changed;
- do {
- changed = false;
- for (Node switchCase in node.cases) {
- LocalsHandler saved = new LocalsHandler.from(locals);
- visit(switchCase);
- changed = saved.merge(locals, discardIfAborts: false) || changed;
- locals = saved;
- }
- } while (changed);
-
- forEachLabeledCase((TargetElement target) {
- clearBreaksAndContinues(target);
- });
- } else {
- LocalsHandler saved = new LocalsHandler.from(locals);
- // If there is a default case, the current values of the local
- // variable might be overwritten, so we don't need the current
- // [locals] for the join block.
- LocalsHandler result = Elements.switchStatementHasDefault(node)
- ? null
- : new LocalsHandler.from(locals);
-
- for (Node switchCase in node.cases) {
- locals = new LocalsHandler.from(saved);
- visit(switchCase);
- if (result == null) {
- result = locals;
- } else {
- result.merge(locals, discardIfAborts: false);
- }
- }
- locals = result;
- }
- clearBreaksAndContinues(elements[node]);
- // In case there is a default in the switch we discard the
- // incoming localsHandler, because the types it holds do not need
- // to be merged after the switch statement. This means that, if all
- // cases, including the default, break or continue, the [result]
- // handler may think it just aborts the current block. Therefore
- // we set the current locals to not have any break or continue, so
- // that the [visitBlock] method does not assume the code after the
- // switch is dead code.
- locals.seenBreakOrContinue = false;
- return inferrer.dynamicType;
- }
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index 5813cfe..60f3641 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -30,6 +30,22 @@
TypeMask getTypeOfElement(Element element);
TypeMask getTypeOfNode(Element owner, Node node);
TypeMask getTypeOfSelector(Selector selector);
+
+ TypeMask get dynamicType;
+ TypeMask get nullType;
+ TypeMask get intType;
+ TypeMask get doubleType;
+ TypeMask get numType;
+ TypeMask get boolType;
+ TypeMask get functionType;
+ TypeMask get listType;
+ TypeMask get constListType;
+ TypeMask get fixedListType;
+ TypeMask get growableListType;
+ TypeMask get mapType;
+ TypeMask get constMapType;
+ TypeMask get stringType;
+ TypeMask get typeType;
}
/**
diff --git a/sdk/lib/_internal/docgen/docgen.dart b/sdk/lib/_internal/docgen/docgen.dart
deleted file mode 100644
index b245bf5..0000000
--- a/sdk/lib/_internal/docgen/docgen.dart
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * The docgen tool takes in a library as input and produces documentation
- * for the library as well as all libraries it imports and uses. The tool can
- * be run by passing in the path to a .dart file like this:
- *
- * ./dart docgen.dart path/to/file.dart
- *
- * This outputs information about all classes, variables, functions, and
- * methods defined in the library and its imported libraries.
- */
-library docgen;
-
-import 'dart:io';
-import 'dart:async';
-import 'lib/src/dart2js_mirrors.dart';
-import 'lib/dart2yaml.dart';
-import '../../../../pkg/args/lib/args.dart';
-import '../compiler/implementation/mirrors/mirrors.dart';
-import '../compiler/implementation/mirrors/mirrors_util.dart';
-
-/**
- * Entry function to create YAML documentation from Dart files.
- */
-void main() {
- // TODO(tmandel): Use args library once flags are clear.
- Options opts = new Options();
-
- if (opts.arguments.length > 0) {
- List<Path> libraries = [new Path(opts.arguments[0])];
- Path sdkDirectory = new Path("../../../");
- var workingMirrors = analyze(libraries, sdkDirectory,
- options: ['--preserve-comments', '--categories=Client,Server']);
- workingMirrors.then( (MirrorSystem mirrorSystem) {
- var mirrors = mirrorSystem.libraries;
- if (mirrors.isEmpty) {
- print("no LibraryMirrors");
- } else {
- mirrors.values.forEach( (library) {
- // TODO(tmandel): Use flags to filter libraries.
- if (library.uri.scheme != "dart") {
- String result = _getDocumentation(library);
- if (result != null) {
- _writeToFile(result, "${library.qualifiedName}.yaml");
- }
- }
- });
- }
- });
- }
-}
-
-/**
- * Creates YAML output from relevant libraries.
- */
-//TODO(tmandel): Also allow for output to JSON based on flags
-String _getDocumentation(LibraryMirror library) {
- Map libMap = new Map();
- String libraryName = library.qualifiedName;
-
- // Get library top-level information.
- libMap[libraryName] = new Map();
-
- libMap[libraryName]["variables"] = new Map();
- _getVariables(libMap[libraryName]["variables"], library.variables);
-
- libMap[libraryName]["functions"] = new Map();
- _getMethods(libMap[libraryName]["functions"], library.functions);
-
- String comment = _getComment(library);
- libMap[libraryName]["comment"] = comment != null ? comment.trim() : null;
-
- // Get specific information about each class.
- Map classes = new Map();
- library.classes.forEach( (String cName, ClassMirror mir) {
-
- classes[cName] = new Map();
- _getMethods(classes[cName], mir.methods);
-
- classes[cName]["variables"] = new Map();
- _getVariables(classes[cName]["variables"], mir.variables);
-
- classes[cName]["superclass"] = mir.superclass;
- classes[cName]["interfaces"] = mir.superinterfaces;
- classes[cName]["abstract"] = mir.isAbstract;
-
- String comment = _getComment(mir);
- classes[cName]["comment"] = comment != null ? comment.trim() : null;
-
- });
- libMap[libraryName]["classes"] = classes;
- return getYamlString(libMap);
-}
-
-/**
- * Returns any documentation comments associated with a mirror.
- */
-// TODO(tmandel): Handle reference links in comments.
-String _getComment(DeclarationMirror mirror) {
- String commentText;
- mirror.metadata.forEach( (metadata) {
- if (metadata is CommentInstanceMirror) {
- CommentInstanceMirror comment = metadata;
- if (comment.isDocComment) {
- if (commentText == null) {
- commentText = comment.trimmedText;
- } else {
- commentText = "$commentText ${comment.trimmedText}";
- }
- }
- }
- });
- return commentText;
-}
-
-/**
- * Populates an input Map with characteristics of variables.
- */
-void _getVariables(Map data, Map<String, VariableMirror> mirrorMap) {
- mirrorMap.forEach( (String name, VariableMirror mirror) {
- data[name] = new Map();
- data[name]["final"] = mirror.isFinal.toString();
- data[name]["static"] = mirror.isStatic.toString();
- data[name]["type"] = mirror.type.toString();
-
- String comment = _getComment(mirror);
- data[name]["comment"] = comment != null ? comment.trim() : null;
- });
-}
-
-/**
- * Populates an input Map with characteristics of methods.
- */
-void _getMethods(Map data, Map<String, MethodMirror> mirrorMap) {
- mirrorMap.forEach( (String mirrorName, MethodMirror mirror) {
- String category = mirror.isSetter ? "setters" :
- mirror.isGetter ? "getters" :
- mirror.isConstructor ? "constructors" :
- mirror.isTopLevel ? "functions" : "methods";
-
- if (data[category] == null) {
- data[category] = new Map();
- }
- data[category][mirrorName] = new Map();
- data[category][mirrorName]["operator"] = mirror.isOperator;
- data[category][mirrorName]["static"] = mirror.isStatic;
- data[category][mirrorName]["rtype"] = mirror.returnType;
- data[category][mirrorName]["parameters"] = new Map();
- List parameters = mirror.parameters;
- parameters.forEach( (ParameterMirror param) {
- String pName = param.simpleName;
- data[category][mirrorName]
- ["parameters"][pName] = new Map();
- data[category][mirrorName]
- ["parameters"][pName]["optional"] = param.isOptional;
- data[category][mirrorName]
- ["parameters"][pName]["default"] = param.defaultValue;
- data[category][mirrorName]
- ["parameters"][pName]["type"] = param.type.toString();
- });
- String comment = _getComment(mirror);
- data[category][mirrorName]["comment"] =
- comment != null ? comment.trim() : null;
- });
-}
-
-/**
- * Writes documentation for a library to a file.
- */
-//TODO(tmandel): Use flags to put files in specific directory if supported.
-void _writeToFile(String text, String filename) {
- File file = new File(filename);
- if (!file.exists()) {
- file.createSync();
- }
- file.openSync();
- file.writeAsString(text);
-}
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/implementation/lib/async_patch.dart b/sdk/lib/_internal/lib/async_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/async_patch.dart
rename to sdk/lib/_internal/lib/async_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/collection_dev_patch.dart b/sdk/lib/_internal/lib/collection_dev_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/collection_dev_patch.dart
rename to sdk/lib/_internal/lib/collection_dev_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart b/sdk/lib/_internal/lib/collection_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart
rename to sdk/lib/_internal/lib/collection_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/constant_map.dart
rename to sdk/lib/_internal/lib/constant_map.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/lib/core_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
rename to sdk/lib/_internal/lib/core_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/lib/foreign_helper.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
rename to sdk/lib/_internal/lib/foreign_helper.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/lib/interceptors.dart
similarity index 98%
rename from sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
rename to sdk/lib/_internal/lib/interceptors.dart
index b144a30..bcfef43 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
+++ b/sdk/lib/_internal/lib/interceptors.dart
@@ -22,7 +22,9 @@
stringReplaceAllFuncUnchecked,
stringReplaceAllUnchecked,
stringReplaceFirstUnchecked,
- lookupDispatchRecord;
+ lookupDispatchRecord,
+ StringMatch,
+ firstMatchAfter;
import 'dart:_foreign_helper' show JS;
part 'js_array.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
rename to sdk/lib/_internal/lib/io_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
rename to sdk/lib/_internal/lib/isolate_helper.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart b/sdk/lib/_internal/lib/isolate_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/isolate_patch.dart
rename to sdk/lib/_internal/lib/isolate_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/lib/js_array.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/js_array.dart
rename to sdk/lib/_internal/lib/js_array.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
rename to sdk/lib/_internal/lib/js_helper.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
similarity index 76%
rename from sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart
rename to sdk/lib/_internal/lib/js_mirrors.dart
index db8d87f..a4254b8 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -21,6 +21,11 @@
String getName(Symbol symbol) => n(symbol);
+final Map<String, String> mangledNames = JsMirrorSystem.computeMangledNames();
+
+final Map<String, String> reflectiveNames =
+ JsMirrorSystem.computeReflectiveNames();
+
class JsMirrorSystem implements MirrorSystem {
TypeMirror get dynamicType => _dynamicType;
TypeMirror get voidType => _voidType;
@@ -32,10 +37,6 @@
static final Map<String, List<LibraryMirror>> librariesByName =
computeLibrariesByName();
- static final Map<String, String> mangledNames = computeMangledNames();
-
- static final Map<String, String> reflectiveNames = computeReflectiveNames();
-
Iterable<LibraryMirror> findLibrary(Symbol libraryName) {
return new List<LibraryMirror>.from(librariesByName[n(libraryName)]);
}
@@ -61,14 +62,7 @@
static Map<String, String> computeMangledNames() {
var mangledNames = JS('', 'init.mangledNames');
- var keys = JS('List', '''
-(function(mangled, hasOwnProperty) {
- var result = [];
- for (var key in mangled) {
- if (hasOwnProperty.call(mangled, key)) result.push(key);
- }
- return result;
-})(#, Object.prototype.hasOwnProperty)''', mangledNames);
+ var keys = extractKeys(mangledNames);
var result = <String, String>{};
for (String key in keys) {
result[key] = JS('String', '#[#]', mangledNames, key);
@@ -133,12 +127,15 @@
String name = _functions[i];
Symbol symbol = s(name);
int parameterCount = null; // TODO(ahe): Compute this.
+ bool isStatic = true; // Top-level functions are static.
+ bool isSetter = false; // TODO(ahe): Compute this.
+ bool isGetter = false; // TODO(ahe): Compute this.
JsMethodMirror mirror =
// TODO(ahe): Create accessor for accessing $. It is also
// used in js_helper.
new JsMethodMirror(
symbol, JS('', '#[#]', JS_CURRENT_ISOLATE(), name),
- parameterCount);
+ parameterCount, isGetter, isSetter, isStatic);
// TODO(ahe): Cache mirrors.
result[symbol] = mirror;
mirror._owner = this;
@@ -276,7 +273,7 @@
// JavaScript.
var jsList = new List.from(positionalArguments);
String reflectiveName = '${n(memberName)}:${positionalArguments.length}:0';
- String mangledName = JsMirrorSystem.reflectiveNames[reflectiveName];
+ String mangledName = reflectiveNames[reflectiveName];
return _invoke(memberName, JSInvocationMirror.METHOD, mangledName, jsList);
}
@@ -294,14 +291,14 @@
InstanceMirror setField(Symbol fieldName, Object arg) {
String reflectiveName = '${n(fieldName)}=';
- String mangledName = JsMirrorSystem.reflectiveNames[reflectiveName];
+ String mangledName = reflectiveNames[reflectiveName];
_invoke(s(reflectiveName), JSInvocationMirror.SETTER, mangledName, [arg]);
return reflect(arg);
}
InstanceMirror getField(Symbol fieldName) {
String reflectiveName = n(fieldName);
- String mangledName = JsMirrorSystem.reflectiveNames[reflectiveName];
+ String mangledName = reflectiveNames[reflectiveName];
return _invoke(fieldName, JSInvocationMirror.GETTER, mangledName, []);
}
@@ -319,6 +316,7 @@
final List _fieldsMetadata;
List _metadata;
JsClassMirror _superclass;
+ List<JsMethodMirror> _cachedMethods;
// Set as side-effect of accessing JsLibraryMirror.classes.
JsLibraryMirror _owner;
@@ -330,21 +328,57 @@
Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
- Map<Symbol, MethodMirror> get functions {
+ List<JsMethodMirror> get _methods {
+ if (_cachedMethods != null) return _cachedMethods;
+ var prototype = JS('', '#.prototype', _jsConstructor);
+ List<String> keys = extractKeys(prototype);
+ var result = <JsMethodMirror>[];
+ int i = 0;
+ for (String key in keys) {
+ if (key == '') continue;
+ String simpleName = mangledNames[key];
+ // [simpleName] can be null if [key] represents an implementation
+ // detail, for example, a bailout method, or runtime type support.
+ // It might also be null if the user has limited what is reified for
+ // reflection with metadata.
+ if (simpleName == null) continue;
+ var function = JS('', '#[#]', prototype, key);
+ var mirror = new JsMethodMirror.fromUnmangledName(simpleName, function);
+ result.add(mirror);
+ mirror._owner = this;
+ }
+ return _cachedMethods = result;
+ }
+
+ Map<Symbol, MethodMirror> get methods {
var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
+ for (JsMethodMirror method in _methods) {
+ if (!method.isGetter && !method.isSetter) {
+ result[method.simpleName] = method;
+ }
+ }
return result;
}
Map<Symbol, MethodMirror> get getters {
+ // TODO(ahe): Should this include getters for fields?
var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
+ for (JsMethodMirror method in _methods) {
+ if (method.isGetter) {
+ result[method.simpleName] = method;
+ }
+ }
return result;
}
Map<Symbol, MethodMirror> get setters {
+ // TODO(ahe): Should this include setters for fields?
var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
+ for (JsMethodMirror method in _methods) {
+ if (method.isSetter) {
+ result[method.simpleName] = method;
+ }
+ }
return result;
}
@@ -359,20 +393,26 @@
metadata = _fieldsMetadata[fieldNumber++];
}
JsVariableMirror mirror = new JsVariableMirror.from(field, metadata);
- result[mirror.simpleName] = mirror;
- mirror._owner = this;
+ if (mirror != null) {
+ result[mirror.simpleName] = mirror;
+ mirror._owner = this;
+ }
}
return result;
}
Map<Symbol, Mirror> get members {
- Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(functions);
- addToResult(Symbol key, Mirror value) {
- result[key] = value;
+ Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(variables);
+ for (JsMethodMirror method in _methods) {
+ if (method.isSetter) {
+ String name = n(method.simpleName);
+ name = name.substring(0, name.length - 1);
+ // Filter-out setters corresponding to variables.
+ if (result[s(name)] is VariableMirror) continue;
+ }
+ // Use putIfAbsent to filter-out getters corresponding to variables.
+ result.putIfAbsent(method.simpleName, () => method);
}
- getters.forEach(addToResult);
- setters.forEach(addToResult);
- variables.forEach(addToResult);
return result;
}
@@ -392,15 +432,24 @@
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
- [Map<Symbol,dynamic> namedArguments]) {
+ [Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
throw new UnsupportedError('Named arguments are not implemented');
}
- String constructorName = '${n(simpleName)}\$${n(constructorName)}';
- return reflect(JS('', r'#[#].apply(#, #)', JS_CURRENT_ISOLATE(),
- constructorName,
- JS_CURRENT_ISOLATE(),
- new List.from(positionalArguments)));
+ String mangledName = '${n(simpleName)}\$${n(constructorName)}';
+ var factory = JS('', '#[#]', JS_CURRENT_ISOLATE(), mangledName);
+ if (factory == null) {
+ // TODO(ahe): Pass namedArguments when NoSuchMethodError has
+ // been fixed to use Symbol.
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(
+ this, "constructor ${n(constructorName)}", positionalArguments,
+ null);
+ }
+ return reflect(JS('', r'#.apply(#, #)',
+ factory,
+ JS_CURRENT_ISOLATE(),
+ new List.from(positionalArguments)));
}
Future<InstanceMirror> newInstanceAsync(
@@ -476,15 +525,11 @@
int length = descriptor.length;
var code = fieldCode(descriptor.codeUnitAt(length - 1));
bool isFinal = false;
- // code might be 0 if the accessors aren't needed, or if they are
- // inherited.
- // TODO(ahe): Ensure code is only 0 for inherited fields.
- if (code != 0) {
- bool hasGetter = (code & 3) != 0;
- bool hasSetter = (code >> 2) != 0;
- isFinal = !hasSetter;
- length--;
- }
+ if (code == 0) return null; // Inherited field.
+ bool hasGetter = (code & 3) != 0;
+ bool hasSetter = (code >> 2) != 0;
+ isFinal = !hasSetter;
+ length--;
String jsName;
String accessorName = jsName = descriptor.substring(0, length);
int divider = descriptor.indexOf(':');
@@ -512,6 +557,8 @@
bool get isPrivate => n(simpleName).startsWith('_');
+ bool get isTopLevel => owner != null && owner is LibraryMirror;
+
String toString() => 'VariableMirror(${n(qualifiedName)})';
static int fieldCode(int code) {
@@ -540,14 +587,17 @@
throw new RuntimeError('Cannot find callName on "$reflectee"');
}
int parameterCount = int.parse(callName.split(r'$')[1]);
+ bool isStatic = true; // TODO(ahe): Compute isStatic correctly.
if (reflectee is BoundClosure) {
var target = BoundClosure.targetOf(reflectee);
var self = BoundClosure.selfOf(reflectee);
return new JsMethodMirror(
- s(target), JS('', '#[#]', self, target), parameterCount);
+ s(target), JS('', '#[#]', self, target), parameterCount,
+ false, false, isStatic);
} else {
var jsFunction = JS('', '#[#]', reflectee, callName);
- return new JsMethodMirror(s(callName), jsFunction, parameterCount);
+ return new JsMethodMirror(
+ s(callName), jsFunction, parameterCount, false, false, isStatic);
}
}
@@ -568,10 +618,41 @@
final Symbol simpleName;
final _jsFunction;
final int _parameterCount;
+ final bool isGetter;
+ final bool isSetter;
+ final bool isStatic;
DeclarationMirror _owner;
List _metadata;
- JsMethodMirror(this.simpleName, this._jsFunction, this._parameterCount);
+ JsMethodMirror(this.simpleName,
+ this._jsFunction,
+ this._parameterCount,
+ this.isGetter,
+ this.isSetter,
+ this.isStatic);
+
+ factory JsMethodMirror.fromUnmangledName(String name, jsFunction) {
+ List<String> info = name.split(':');
+ name = info[0];
+ bool isSetter = name.endsWith('=');
+ int requiredParameterCount = 0;
+ int optionalParameterCount = 0;
+ bool isGetter = false;
+ if (info.length == 1) {
+ if (isSetter) {
+ requiredParameterCount = 2;
+ } else {
+ isGetter = true;
+ requiredParameterCount = 1;
+ }
+ } else {
+ requiredParameterCount = int.parse(info[1]);
+ optionalParameterCount = int.parse(info[2]);
+ }
+ return new JsMethodMirror(
+ s(name), jsFunction, requiredParameterCount + optionalParameterCount,
+ isGetter, isSetter, false);
+ }
List<ParameterMirror> get parameters {
// TODO(ahe): Fill the list with parameter mirrors.
@@ -588,6 +669,18 @@
}
return _metadata.map(reflect).toList();
}
+
+ // TODO(ahe): Share with VariableMirror.
+ bool get isPrivate => n(simpleName).startsWith('_');
+
+ // TODO(ahe): Share with VariableMirror.
+ bool get isTopLevel => owner != null && owner is LibraryMirror;
+
+ String toString() {
+ return
+ 'MethodMirror(${n(simpleName)}'
+ '${isSetter ? ", setter" : (isGetter ? ", getter" : "")})';
+ }
}
Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
@@ -602,3 +695,14 @@
return (metadataFunction == null)
? const [] : JS('', '#()', metadataFunction);
}
+
+List extractKeys(victim) {
+ return JS('List', '''
+(function(victim, hasOwnProperty) {
+ var result = [];
+ for (var key in victim) {
+ if (hasOwnProperty.call(victim, key)) result.push(key);
+ }
+ return result;
+})(#, Object.prototype.hasOwnProperty)''', victim);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/lib/js_number.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/js_number.dart
rename to sdk/lib/_internal/lib/js_number.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/lib/js_rti.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
rename to sdk/lib/_internal/lib/js_rti.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart b/sdk/lib/_internal/lib/js_string.dart
similarity index 78%
rename from sdk/lib/_internal/compiler/implementation/lib/js_string.dart
rename to sdk/lib/_internal/lib/js_string.dart
index 92d7c67..2da5ed4 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
+++ b/sdk/lib/_internal/lib/js_string.dart
@@ -25,6 +25,20 @@
return allMatchesInStringUnchecked(this, str);
}
+ Match matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ if (start + this.length > string.length) return null;
+ // TODO(lrn): See if this can be optimized.
+ for (int i = 0; i < this.length; i++) {
+ if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
+ return null;
+ }
+ }
+ return new StringMatch(start, string, this);
+ }
+
String operator +(String other) {
if (other is !String) throw new ArgumentError(other);
return JS('String', r'# + #', this, other);
@@ -71,12 +85,15 @@
}
}
- bool startsWith(String other) {
- checkString(other);
- int otherLength = other.length;
- if (otherLength > length) return false;
- return JS('bool', r'# == #', other,
- JS('String', r'#.substring(0, #)', this, otherLength));
+ bool startsWith(Pattern pattern) {
+ if (pattern is String) {
+ String other = pattern;
+ int otherLength = other.length;
+ if (otherLength > length) return false;
+ return JS('bool', r'# == #', other,
+ JS('String', r'#.substring(0, #)', this, otherLength));
+ }
+ return pattern.matchAsPrefix(this, 0) != null;
}
String substring(int startIndex, [int endIndex]) {
@@ -196,28 +213,46 @@
Runes get runes => new Runes(this);
- int indexOf(String other, [int start = 0]) {
- checkNull(other);
- if (start is !int) throw new ArgumentError(start);
- if (other is !String) throw new ArgumentError(other);
- if (start < 0) return -1;
- return JS('int', r'#.indexOf(#, #)', this, other, start);
+ int indexOf(Pattern pattern, [int start = 0]) {
+ checkNull(pattern);
+ if (start is! int) throw new ArgumentError(start);
+ if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
+ }
+ if (pattern is String) {
+ return JS('int', r'#.indexOf(#, #)', this, pattern, start);
+ }
+ if (pattern is JSSyntaxRegExp) {
+ JSSyntaxRegExp re = pattern;
+ Match match = firstMatchAfter(re, this, start);
+ return (match == null) ? -1 : match.start;
+ }
+ for (int i = start; i <= this.length; i++) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
}
- int lastIndexOf(String other, [int start]) {
- checkNull(other);
- if (other is !String) throw new ArgumentError(other);
- if (start != null) {
- if (start is !num) throw new ArgumentError(start);
- if (start < 0) return -1;
- if (start >= length) {
- if (other == "") return length;
- start = length - 1;
- }
- } else {
- start = length - 1;
+ int lastIndexOf(Pattern pattern, [int start]) {
+ checkNull(pattern);
+ if (start == null) {
+ start = length;
+ } else if (start is! int) {
+ throw new ArgumentError(start);
+ } else if (start < 0 || start > this.length) {
+ throw new RangeError.range(start, 0, this.length);
}
- return stringLastIndexOfUnchecked(this, other, start);
+ if (pattern is String) {
+ String other = pattern;
+ if (start + other.length > this.length) {
+ start = this.length - other.length;
+ }
+ return stringLastIndexOfUnchecked(this, other, start);
+ }
+ for (int i = start; i >= 0; i--) {
+ if (pattern.matchAsPrefix(this, i) != null) return i;
+ }
+ return -1;
}
bool contains(Pattern other, [int startIndex = 0]) {
diff --git a/sdk/lib/_internal/compiler/implementation/lib/json_patch.dart b/sdk/lib/_internal/lib/json_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/json_patch.dart
rename to sdk/lib/_internal/lib/json_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/math_patch.dart
rename to sdk/lib/_internal/lib/math_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart b/sdk/lib/_internal/lib/mirrors_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
rename to sdk/lib/_internal/lib/mirrors_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/lib/native_helper.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
rename to sdk/lib/_internal/lib/native_helper.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart b/sdk/lib/_internal/lib/regexp_helper.dart
similarity index 63%
rename from sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart
rename to sdk/lib/_internal/lib/regexp_helper.dart
index 45ab03c..0e923a3 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/lib/regexp_helper.dart
@@ -33,6 +33,12 @@
other.isCaseSensitive,
true);
+ JSSyntaxRegExp._anchoredVersionOf(JSSyntaxRegExp other)
+ : this._internal(other.pattern + "|()",
+ other.isMultiLine,
+ other.isCaseSensitive,
+ true);
+
static makeNative(
String pattern, bool multiLine, bool caseSensitive, bool global) {
checkString(pattern);
@@ -82,21 +88,41 @@
return new _AllMatchesIterable(this, str);
}
+ Match matchAsPrefix(String string, [int start = 0]) {
+ if (start < 0 || start > string.length) {
+ throw new RangeError.range(start, 0, string.length);
+ }
+ // An "anchored version" of a regexp is created by adding "|()" to the
+ // source. This means that the regexp always matches at the first position
+ // that it tries, and you can see if the original regexp matched, or it
+ // was the added zero-width match that matched, by looking at the last
+ // capture. If it is a String, the match participated, otherwise it didn't.
+ JSSyntaxRegExp regexp = new JSSyntaxRegExp._anchoredVersionOf(this);
+ if (start > 0) {
+ JS("void", "#.lastIndex = #", regExpGetNative(regexp), start);
+ }
+ _MatchImplementation match = regexp.firstMatch(string);
+ if (match == null) return null;
+ if (match._groups[match._groups.length - 1] != null) return null;
+ match._groups.length -= 1;
+ return match;
+ }
+
String get pattern => _pattern;
bool get isMultiLine => _isMultiLine;
bool get isCaseSensitive => _isCaseSensitive;
}
class _MatchImplementation implements Match {
- final String pattern;
+ final Pattern pattern;
final String str;
final int start;
final int end;
final List<String> _groups;
const _MatchImplementation(
- String this.pattern,
- String this.str,
+ this.pattern,
+ this.str,
int this.start,
int this.end,
List<String> this._groups);
@@ -124,23 +150,46 @@
}
class _AllMatchesIterator implements Iterator<Match> {
- final RegExp _re;
- final String _str;
+ final RegExp _regExp;
+ final RegExp _globalRegExp;
+ String _str;
Match _current;
_AllMatchesIterator(JSSyntaxRegExp re, String this._str)
- : _re = new JSSyntaxRegExp._globalVersionOf(re);
+ : _regExp = re,
+ _globalRegExp = new JSSyntaxRegExp._globalVersionOf(re);
Match get current => _current;
bool moveNext() {
+ if (_str == null) return false;
// firstMatch actually acts as nextMatch because of
// hidden global flag.
if (_current != null && _current.start == _current.end) {
// Advance implicit start-position if last match was empty.
- JS("void", "#.lastIndex++", regExpGetNative(_re));
+ JS("void", "#.lastIndex++", regExpGetNative(_globalRegExp));
}
- _current = _re.firstMatch(_str);
- return _current != null;
+ List<String> m =
+ JS('=List|Null', r'#.exec(#)', regExpGetNative(_globalRegExp), _str);
+ if (m == null) {
+ _current = null;
+ _str = null; // Marks iteration as ended.
+ return false;
+ }
+ var matchStart = JS('int', r'#.index', m);
+ var matchEnd = matchStart + m[0].length;
+ _current = new _MatchImplementation(_regExp, _str, matchStart, matchEnd, m);
+ return true;
}
}
+
+Match firstMatchAfter(JSSyntaxRegExp re, String str, int start) {
+ JSSyntaxRegExp global = new JSSyntaxRegExp._globalVersionOf(re);
+ JS("void", "#.lastIndex = #", regExpGetNative(global), start);
+ List<String> m =
+ JS('=List|Null', r'#.exec(#)', regExpGetNative(global), checkString(str));
+ if (m == null) return null;
+ var matchStart = JS('int', r'#.index', m);
+ var matchEnd = matchStart + m[0].length;
+ return new _MatchImplementation(re, str, matchStart, matchEnd, m);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/scalarlist_patch.dart b/sdk/lib/_internal/lib/scalarlist_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/scalarlist_patch.dart
rename to sdk/lib/_internal/lib/scalarlist_patch.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/string_helper.dart b/sdk/lib/_internal/lib/string_helper.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/string_helper.dart
rename to sdk/lib/_internal/lib/string_helper.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/typed_data_patch.dart b/sdk/lib/_internal/lib/typed_data_patch.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/implementation/lib/typed_data_patch.dart
rename to sdk/lib/_internal/lib/typed_data_patch.dart
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 5c20d17..d56bdc3 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -24,7 +24,7 @@
"async": const LibraryInfo(
"async/async.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/async_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/async_patch.dart"),
"chrome": const LibraryInfo(
"chrome/dart2js/chrome_dart2js.dart",
@@ -32,11 +32,11 @@
"collection": const LibraryInfo(
"collection/collection.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/collection_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/collection_patch.dart"),
"core": const LibraryInfo(
"core/core.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/core_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/core_patch.dart"),
"html": const LibraryInfo(
"html/dartium/html_dartium.dart",
@@ -58,23 +58,23 @@
"io": const LibraryInfo(
"io/io.dart",
category: "Server",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/io_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/io_patch.dart"),
"isolate": const LibraryInfo(
"isolate/isolate.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/isolate_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/isolate_patch.dart"),
"json": const LibraryInfo(
"json/json.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/json_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/json_patch.dart"),
"math": const LibraryInfo(
"math/math.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/math_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/math_patch.dart"),
"mirrors": const LibraryInfo(
"mirrors/mirrors.dart",
- dart2jsPatchPath: "_internal/compiler/implementation/lib/mirrors_patch.dart"),
+ dart2jsPatchPath: "_internal/lib/mirrors_patch.dart"),
"nativewrappers": const LibraryInfo(
"html/dartium/nativewrappers.dart",
@@ -121,34 +121,34 @@
category: "Internal",
documented: false,
dart2jsPatchPath:
- "_internal/compiler/implementation/lib/collection_dev_patch.dart"),
+ "_internal/lib/collection_dev_patch.dart"),
"_js_helper": const LibraryInfo(
- "_internal/compiler/implementation/lib/js_helper.dart",
+ "_internal/lib/js_helper.dart",
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
"_interceptors": const LibraryInfo(
- "_internal/compiler/implementation/lib/interceptors.dart",
+ "_internal/lib/interceptors.dart",
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
"_foreign_helper": const LibraryInfo(
- "_internal/compiler/implementation/lib/foreign_helper.dart",
+ "_internal/lib/foreign_helper.dart",
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
"_isolate_helper": const LibraryInfo(
- "_internal/compiler/implementation/lib/isolate_helper.dart",
+ "_internal/lib/isolate_helper.dart",
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
"_js_mirrors": const LibraryInfo(
- "_internal/compiler/implementation/lib/js_mirrors.dart",
+ "_internal/lib/js_mirrors.dart",
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
diff --git a/sdk/lib/_internal/pub/test/error_group_test.dart b/sdk/lib/_internal/pub/test/error_group_test.dart
index 7cad9be..8fbd032 100644
--- a/sdk/lib/_internal/pub/test/error_group_test.dart
+++ b/sdk/lib/_internal/pub/test/error_group_test.dart
@@ -64,13 +64,13 @@
"been called", () {
completer.complete('value');
- completer.future.then(expectAsync1((_) {
- expect(() => errorGroup.registerFuture(new Future.value()),
+ expect(completer.future
+ .then((_) => errorGroup.registerFuture(new Future.value())),
+ throwsStateError);
+ expect(completer.future
+ .then((_) => errorGroup.registerStream(
+ new StreamController(sync: true).stream)),
throwsStateError);
- expect(() => errorGroup.registerStream(
- new StreamController(sync: true).stream),
- throwsStateError);
- }));
});
test('should pass through an exception from the future if it has a '
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index 03287d7..f77fc23 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.dart
@@ -12,6 +12,7 @@
part 'maps.dart';
part 'queue.dart';
part 'splay_tree.dart';
+part 'linked_list.dart';
part 'hash_set.dart';
part 'hash_map.dart';
part 'list.dart';
diff --git a/sdk/lib/collection/collection_sources.gypi b/sdk/lib/collection/collection_sources.gypi
index 7fe56d8..5f2ab98 100644
--- a/sdk/lib/collection/collection_sources.gypi
+++ b/sdk/lib/collection/collection_sources.gypi
@@ -14,6 +14,7 @@
'iterator.dart',
'linked_hash_map.dart',
'linked_hash_set.dart',
+ 'linked_list.dart',
'list.dart',
'maps.dart',
'queue.dart',
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
new file mode 100644
index 0000000..a9c8989
--- /dev/null
+++ b/sdk/lib/collection/linked_list.dart
@@ -0,0 +1,232 @@
+// 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.
+
+part of dart.collection;
+
+
+/**
+ * A linked list implementation, providing O(1) removal(unlink) of elements and
+ * manual traversal through [next] and [previous].
+ *
+ * The list elements must extend [LinkedListEntry].
+ */
+class LinkedList<E extends LinkedListEntry<E>>
+ extends IterableBase<E>
+ implements _LinkedListLink {
+ int _modificationCount = 0;
+ int _length = 0;
+ _LinkedListLink _next;
+ _LinkedListLink _previous;
+
+ /**
+ * Construct a new empty linked list.
+ */
+ LinkedList() {
+ _next = _previous = this;
+ }
+
+ /**
+ * Add [entry] to the beginning of the list.
+ */
+ void addFirst(E entry) {
+ _insertAfter(this, entry);
+ }
+
+ /**
+ * Add [entry] to the end of the list.
+ */
+ void add(E entry) {
+ _insertAfter(_previous, entry);
+ }
+
+ /**
+ * Add [entries] to the end of the list.
+ */
+ void addAll(Iterable<E> entries) {
+ entries.forEach((entry) => _insertAfter(_previous, entry));
+ }
+
+ /**
+ * Remove [entry] from the list. This is the same as calling `entry.unlink()`.
+ *
+ * If [entry] is not in the list, `false` is returned.
+ */
+ bool remove(E entry) {
+ if (entry._list != this) return false;
+ _unlink(entry); // Unlink will decrement length.
+ return true;
+ }
+
+ Iterator<E> get iterator => new _LinkedListIterator<E>(this);
+
+ String toString() => ToString.iterableToString(this);
+
+ int get length => _length;
+
+ void clear() {
+ _modificationCount++;
+ _LinkedListLink next = _next;
+ while (!identical(next, this)) {
+ E entry = next;
+ next = entry._next;
+ entry._next = entry._previous = entry._list = null;
+ }
+ _next = _previous = this;
+ _length = 0;
+ }
+
+ E get first {
+ if (identical(_next, this)) {
+ throw new StateError('No such element');
+ }
+ return _next;
+ }
+
+ E get last {
+ if (identical(_previous, this)) {
+ throw new StateError('No such element');
+ }
+ return _previous;
+ }
+
+ E get single {
+ if (identical(_previous, this)) {
+ throw new StateError('No such element');
+ }
+ if (!identical(_previous, _next)) {
+ throw new StateError('Too many elements');
+ }
+ return _next;
+ }
+
+ /**
+ * Call [action] with each entry in the list.
+ *
+ * It's an error if [action] modify the list.
+ */
+ void forEach(void action(E entry)) {
+ int modificationCount = _modificationCount;
+ _LinkedListLink current = _next;
+ while (!identical(current, this)) {
+ action(current);
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
+ current = current._next;
+ }
+ }
+
+ bool get isEmpty => _length == 0;
+
+ void _insertAfter(_LinkedListLink entry, E newEntry) {
+ if (newEntry.list != null) {
+ throw new StateError(
+ 'LinkedListEntry is already in a LinkedList');
+ }
+ _modificationCount++;
+ newEntry._list = this;
+ var predecessor = entry;
+ var successor = entry._next;
+ successor._previous = newEntry;
+ newEntry._previous = predecessor;
+ newEntry._next = successor;
+ predecessor._next = newEntry;
+ _length++;
+ }
+
+ void _unlink(LinkedListEntry<E> entry) {
+ _modificationCount++;
+ entry._next._previous = entry._previous;
+ entry._previous._next = entry._next;
+ _length--;
+ entry._list = entry._next = entry._previous = null;
+ }
+}
+
+
+class _LinkedListIterator<E extends LinkedListEntry>
+ implements Iterator<E> {
+ final LinkedList<E> _list;
+ final int _modificationCount;
+ E _current;
+ _LinkedListLink _next;
+
+ _LinkedListIterator(LinkedList<E> list)
+ : _list = list,
+ _modificationCount = list._modificationCount,
+ _next = list._next;
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (identical(_next, _list)) {
+ _current = null;
+ return false;
+ }
+ if (_modificationCount != _list._modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
+ _current = _next;
+ _next = _next._next;
+ return true;
+ }
+}
+
+
+class _LinkedListLink {
+ _LinkedListLink _next;
+ _LinkedListLink _previous;
+}
+
+
+/**
+ * Entry element for a [LinkedList]. Any entry must extend this class.
+ */
+abstract class LinkedListEntry<E> implements _LinkedListLink {
+ LinkedList<E> _list;
+ _LinkedListLink _next;
+ _LinkedListLink _previous;
+
+ /**
+ * Get the list containing this element.
+ */
+ LinkedList<E> get list => _list;
+
+ /**
+ * Unlink the element from the list.
+ */
+ void unlink() {
+ _list._unlink(this);
+ }
+
+ /**
+ * Return the succeeding element in the list.
+ */
+ E get next {
+ if (identical(_next, _list)) return null;
+ return _next as E;
+ }
+
+ /**
+ * Return the preceeding element in the list.
+ */
+ E get previous {
+ if (identical(_previous, _list)) return null;
+ return _previous as E;
+ }
+
+ /**
+ * insert an element after this.
+ */
+ void insertAfter(E entry) {
+ _list._insertAfter(this, entry);
+ }
+
+ /**
+ * Insert an element before this.
+ */
+ void insertBefore(E entry) {
+ _list._insertAfter(_previous, entry);
+ }
+}
diff --git a/sdk/lib/core/pattern.dart b/sdk/lib/core/pattern.dart
index ac7815d..d85c8ac 100644
--- a/sdk/lib/core/pattern.dart
+++ b/sdk/lib/core/pattern.dart
@@ -5,5 +5,28 @@
part of dart.core;
abstract class Pattern {
+ /**
+ * Match this pattern against the string repeatedly.
+ *
+ * The iterable will contain all the non-overlapping matches of the
+ * pattern on the string, ordered by start index.
+ *
+ * The matches are found by repeatedly finding the first match
+ * of the pattern on the string, starting from the end of the previous
+ * match, and initially starting from index zero.
+ *
+ * If the pattern matches the empty string at some point, the next
+ * match is found by starting at the previous match's end plus one.
+ */
Iterable<Match> allMatches(String str);
+
+ /**
+ * Match this pattern against the start of string.
+ *
+ * If [start] is provided, it must be an integer in the range `0` ..
+ * `string.length`. In that case, this patten is tested against the
+ * string at the [start] position. That is, a match is returned if the
+ * pattern can match a part of the string starting from position [start].
+ */
+ Match matchAsPrefix(String string, [int start = 0]);
}
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 0b4fbd4..0d2503a 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -105,23 +105,29 @@
bool endsWith(String other);
/**
- * Returns whether this string starts with [other].
+ * Returns whether this string starts with a match of [pattern].
*/
- bool startsWith(String other);
+ bool startsWith(Pattern pattern);
/**
- * Returns the first location of [other] in this string starting at
- * [start] (inclusive).
- * Returns -1 if [other] could not be found.
+ * Returns the first position of a match of [pattern] in this string,
+ * starting at [start] (inclusive).
+ *
+ * Returns -1 if a match could not be found.
+ *
+ * It is an error if start is negative or greater than [length].
*/
- int indexOf(String other, [int start]);
+ int indexOf(Pattern pattern, [int start]);
/**
- * Returns the last location of [other] in this string, searching
+ * Returns the last position of a match [pattern] in this string, searching
* backward starting at [start] (inclusive).
+ *
* Returns -1 if [other] could not be found.
+ *
+ * It is an error if start is negative or greater than [length].
*/
- int lastIndexOf(String other, [int start]);
+ int lastIndexOf(Pattern pattern, [int start]);
/**
* Returns whether this string is empty.
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 75bd214..c0a7fdf 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -107,7 +107,7 @@
query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
- /*
+ /**
* Create a new URI from its components.
*
* Each component is set through a named argument. Any number of
@@ -177,7 +177,7 @@
_path = _makePath(path, pathSegments);
}
- /*
+ /**
* Returns the URI path split into its segments. Each of the
* segments in the returned list have been decoded. If the path is
* empty the empty list will be returned. A leading slash `/` does
@@ -200,30 +200,22 @@
return _pathSegments;
}
- /*
+ /**
* Returns the URI query split into a map according to the rules
- * specified for FORM post in the HTML 4.01 specification. Each key
- * and value in the returned map have been decoded. If there is no
- * query the empty map will be returned.
+ * specified for FORM post in the [HTML 4.01 specification section 17.13.4]
+ * (http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
+ * "HTML 4.01 section 17.13.4"). Each key and value in the returned map
+ * has been decoded. If there is no query the empty map is returned.
+ *
+ * Keys in the query string that have no value are mapped to the
+ * empty string.
*
* The returned map is unmodifiable and will throw [UnsupportedError] on any
* calls that would mutate it.
*/
Map<String, String> get queryParameters {
if (_queryParameters == null) {
- var map;
- map = query.split("&").fold({}, (map, element) {
- int index = element.indexOf("=");
- if (index == -1) {
- if (!element.isEmpty) map[decodeQueryComponent(element)] = "";
- } else if (index != 0) {
- var key = element.substring(0, index);
- var value = element.substring(index + 1);
- map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value);
- }
- return map;
- });
- _queryParameters = new _UnmodifiableMap(map);
+ _queryParameters = new _UnmodifiableMap(splitQueryString(query));
}
return _queryParameters;
}
@@ -549,6 +541,9 @@
fragment: reference.fragment);
}
+ /**
+ * Returns whether the URI has an [authority] component.
+ */
bool get hasAuthority => host != "";
/**
@@ -647,7 +642,7 @@
return _uriEncode(_unreserved2396Table, component);
}
- /*
+ /**
* Encode the string [component] according to the HTML 4.01 rules
* for encoding the posting of a HTML form as a query string
* component.
@@ -718,6 +713,32 @@
return _uriDecode(uri);
}
+ /**
+ * Returns the [query] split into a map according to the rules
+ * specified for FORM post in the
+ * [HTML 4.01 specification section 17.13.4]
+ * (http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
+ * "HTML 4.01 section 17.13.4"). Each key and value in the returned
+ * map has been decoded. If the [query]
+ * is the empty string an empty map is returned.
+ *
+ * Keys in the query string that have no value are mapped to the
+ * empty string.
+ */
+ static Map<String, String> splitQueryString(String query) {
+ return query.split("&").fold({}, (map, element) {
+ int index = element.indexOf("=");
+ if (index == -1) {
+ if (element != "") map[decodeQueryComponent(element)] = "";
+ } else if (index != 0) {
+ var key = element.substring(0, index);
+ var value = element.substring(index + 1);
+ map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value);
+ }
+ return map;
+ });
+ }
+
// Frequently used character codes.
static const int _PERCENT = 0x25;
static const int _PLUS = 0x2B;
@@ -1004,6 +1025,9 @@
V putIfAbsent(K key, V ifAbsent()) {
throw new UnsupportedError("Cannot modify an unmodifiable map");
}
+ addAll(Map other) {
+ throw new UnsupportedError("Cannot modify an unmodifiable map");
+ }
V remove(K key) {
throw new UnsupportedError("Cannot modify an unmodifiable map");
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 1022653..abafc22 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -105,7 +105,7 @@
@DocsEditable
@DomName('HTMLAnchorElement')
-class AnchorElement extends Element native "HTMLAnchorElement" {
+class AnchorElement extends _HTMLElement native "HTMLAnchorElement" {
@DomName('HTMLAnchorElement.HTMLAnchorElement')
@DocsEditable
@@ -362,7 +362,7 @@
* on MDN.
*/
@DomName('HTMLAreaElement')
-class AreaElement extends Element native "HTMLAreaElement" {
+class AreaElement extends _HTMLElement native "HTMLAreaElement" {
@DomName('HTMLAreaElement.HTMLAreaElement')
@DocsEditable
@@ -464,7 +464,7 @@
@DocsEditable
@DomName('HTMLBRElement')
-class BRElement extends Element native "HTMLBRElement" {
+class BRElement extends _HTMLElement native "HTMLBRElement" {
@DomName('HTMLBRElement.HTMLBRElement')
@DocsEditable
@@ -492,7 +492,7 @@
@DocsEditable
@DomName('HTMLBaseElement')
-class BaseElement extends Element native "HTMLBaseElement" {
+class BaseElement extends _HTMLElement native "HTMLBaseElement" {
@DomName('HTMLBaseElement.HTMLBaseElement')
@DocsEditable
@@ -567,7 +567,7 @@
@DocsEditable
@DomName('HTMLBodyElement')
-class BodyElement extends Element native "HTMLBodyElement" {
+class BodyElement extends _HTMLElement native "HTMLBodyElement" {
@DomName('HTMLBodyElement.blurEvent')
@DocsEditable
@@ -676,7 +676,7 @@
@DocsEditable
@DomName('HTMLButtonElement')
-class ButtonElement extends Element native "HTMLButtonElement" {
+class ButtonElement extends _HTMLElement native "HTMLButtonElement" {
@DomName('HTMLButtonElement.HTMLButtonElement')
@DocsEditable
@@ -785,7 +785,15 @@
@DomName('HTMLCanvasElement')
-class CanvasElement extends Element implements CanvasImageSource native "HTMLCanvasElement" {
+class CanvasElement extends _HTMLElement implements CanvasImageSource native "HTMLCanvasElement" {
+
+ @DomName('HTMLCanvasElement.webglcontextlostEvent')
+ @DocsEditable
+ static const EventStreamProvider<gl.ContextEvent> webGlContextLostEvent = const EventStreamProvider<gl.ContextEvent>('webglcontextlost');
+
+ @DomName('HTMLCanvasElement.webglcontextrestoredEvent')
+ @DocsEditable
+ static const EventStreamProvider<gl.ContextEvent> webGlContextRestoredEvent = const EventStreamProvider<gl.ContextEvent>('webglcontextrestored');
@DomName('HTMLCanvasElement.HTMLCanvasElement')
@DocsEditable
@@ -869,6 +877,14 @@
@DocsEditable
String toDataUrl(String type, [num quality]) native;
+ @DomName('HTMLCanvasElement.onwebglcontextlost')
+ @DocsEditable
+ Stream<gl.ContextEvent> get onWebGlContextLost => webGlContextLostEvent.forTarget(this);
+
+ @DomName('HTMLCanvasElement.onwebglcontextrestored')
+ @DocsEditable
+ Stream<gl.ContextEvent> get onWebGlContextRestored => webGlContextRestoredEvent.forTarget(this);
+
/** An API for drawing on this canvas. */
CanvasRenderingContext2D get context2D =>
JS('Null|CanvasRenderingContext2D', '#.getContext(#)', this, '2d');
@@ -1807,7 +1823,7 @@
@SupportedBrowser(SupportedBrowser.CHROME, '26')
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#content-element
-class ContentElement extends Element native "HTMLContentElement" {
+class ContentElement extends _HTMLElement native "HTMLContentElement" {
@DomName('HTMLContentElement.HTMLContentElement')
@DocsEditable
@@ -2096,7 +2112,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
// http://www.w3.org/TR/css3-animations/#CSSKeyframeRule-interface
-class CssKeyframeRule extends CssRule native "WebKitCSSKeyframeRule" {
+class CssKeyframeRule extends CssRule native "CSSKeyframeRule,MozCSSKeyframeRule,WebKitCSSKeyframeRule" {
@DomName('WebKitCSSKeyframeRule.keyText')
@DocsEditable
@@ -2117,7 +2133,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
// http://www.w3.org/TR/css3-animations/#csskeyframesrule
-class CssKeyframesRule extends CssRule native "WebKitCSSKeyframesRule" {
+class CssKeyframesRule extends CssRule native "CSSKeyframesRule,MozCSSKeyframesRule,WebKitCSSKeyframesRule" {
@DomName('WebKitCSSKeyframesRule.cssRules')
@DocsEditable
@@ -2141,9 +2157,14 @@
@DocsEditable
CssKeyframeRule findRule(String key) native;
- @DomName('WebKitCSSKeyframesRule.insertRule')
- @DocsEditable
- void insertRule(String rule) native;
+
+ void appendRule(String rule) {
+ if (JS('bool', '("appendRule" in #)', this)) {
+ JS('', '#.appendRule(#)', this, rule);
+ } else {
+ JS('', '#.insertRule(#)', this, rule);
+ }
+ }
}
// 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
@@ -5959,7 +5980,7 @@
@DocsEditable
@DomName('HTMLDListElement')
-class DListElement extends Element native "HTMLDListElement" {
+class DListElement extends _HTMLElement native "HTMLDListElement" {
@DomName('HTMLDListElement.HTMLDListElement')
@DocsEditable
@@ -5976,7 +5997,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
-class DataListElement extends Element native "HTMLDataListElement" {
+class DataListElement extends _HTMLElement native "HTMLDataListElement" {
@DomName('HTMLDataListElement.HTMLDataListElement')
@DocsEditable
@@ -6146,7 +6167,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
-class DetailsElement extends Element native "HTMLDetailsElement" {
+class DetailsElement extends _HTMLElement native "HTMLDetailsElement" {
@DomName('HTMLDetailsElement.HTMLDetailsElement')
@DocsEditable
@@ -6282,7 +6303,7 @@
@DocsEditable
@DomName('HTMLDialogElement')
@Unstable
-class DialogElement extends Element native "HTMLDialogElement" {
+class DialogElement extends _HTMLElement native "HTMLDialogElement" {
@DomName('HTMLDialogElement.open')
@DocsEditable
@@ -6522,7 +6543,7 @@
* * [Inline-level element](http://www.w3.org/TR/CSS2/visuren.html#inline-boxes) from W3C.
*/
@DomName('HTMLDivElement')
-class DivElement extends Element native "HTMLDivElement" {
+class DivElement extends _HTMLElement native "HTMLDivElement" {
@DomName('HTMLDivElement.HTMLDivElement')
@DocsEditable
@@ -9483,7 +9504,7 @@
@SupportedBrowser(SupportedBrowser.IE)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class EmbedElement extends Element native "HTMLEmbedElement" {
+class EmbedElement extends _HTMLElement native "HTMLEmbedElement" {
@DomName('HTMLEmbedElement.HTMLEmbedElement')
@DocsEditable
@@ -10149,7 +10170,7 @@
@DocsEditable
@DomName('HTMLFieldSetElement')
@Unstable
-class FieldSetElement extends Element native "HTMLFieldSetElement" {
+class FieldSetElement extends _HTMLElement native "HTMLFieldSetElement" {
@DomName('HTMLFieldSetElement.HTMLFieldSetElement')
@DocsEditable
@@ -10908,7 +10929,7 @@
@DocsEditable
@DomName('HTMLFormElement')
-class FormElement extends Element native "HTMLFormElement" {
+class FormElement extends _HTMLElement native "HTMLFormElement" {
@DomName('HTMLFormElement.autocompleteEvent')
@DocsEditable
@@ -11178,7 +11199,7 @@
* An `<hr>` tag.
*/
@DomName('HTMLHRElement')
-class HRElement extends Element native "HTMLHRElement" {
+class HRElement extends _HTMLElement native "HTMLHRElement" {
@DomName('HTMLHRElement.HTMLHRElement')
@DocsEditable
@@ -11231,7 +11252,7 @@
@DocsEditable
@DomName('HTMLHeadElement')
-class HeadElement extends Element native "HTMLHeadElement" {
+class HeadElement extends _HTMLElement native "HTMLHeadElement" {
@DomName('HTMLHeadElement.HTMLHeadElement')
@DocsEditable
@@ -11244,7 +11265,7 @@
@DocsEditable
@DomName('HTMLHeadingElement')
-class HeadingElement extends Element native "HTMLHeadingElement" {
+class HeadingElement extends _HTMLElement native "HTMLHeadingElement" {
@DomName('HTMLHeadingElement.HTMLHeadingElement')
@DocsEditable
@@ -11645,7 +11666,7 @@
@DocsEditable
@DomName('HTMLHtmlElement')
-class HtmlElement extends Element native "HTMLHtmlElement" {
+class HtmlElement extends _HTMLElement native "HTMLHtmlElement" {
@DomName('HTMLHtmlElement.HTMLHtmlElement')
@DocsEditable
@@ -12307,7 +12328,7 @@
@DocsEditable
@DomName('HTMLIFrameElement')
-class IFrameElement extends Element native "HTMLIFrameElement" {
+class IFrameElement extends _HTMLElement native "HTMLIFrameElement" {
@DomName('HTMLIFrameElement.HTMLIFrameElement')
@DocsEditable
@@ -12377,7 +12398,7 @@
@DomName('HTMLImageElement')
-class ImageElement extends Element implements CanvasImageSource native "HTMLImageElement" {
+class ImageElement extends _HTMLElement implements CanvasImageSource native "HTMLImageElement" {
@DomName('HTMLImageElement.HTMLImageElement')
@DocsEditable
@@ -12456,7 +12477,7 @@
@DomName('HTMLInputElement')
-class InputElement extends Element implements
+class InputElement extends _HTMLElement implements
HiddenInputElement,
SearchInputElement,
TextInputElement,
@@ -13515,7 +13536,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-keygen-element
-class KeygenElement extends Element native "HTMLKeygenElement" {
+class KeygenElement extends _HTMLElement native "HTMLKeygenElement" {
@DomName('HTMLKeygenElement.HTMLKeygenElement')
@DocsEditable
@@ -13586,7 +13607,7 @@
@DocsEditable
@DomName('HTMLLIElement')
-class LIElement extends Element native "HTMLLIElement" {
+class LIElement extends _HTMLElement native "HTMLLIElement" {
@DomName('HTMLLIElement.HTMLLIElement')
@DocsEditable
@@ -13609,7 +13630,7 @@
@DocsEditable
@DomName('HTMLLabelElement')
-class LabelElement extends Element native "HTMLLabelElement" {
+class LabelElement extends _HTMLElement native "HTMLLabelElement" {
@DomName('HTMLLabelElement.HTMLLabelElement')
@DocsEditable
@@ -13634,7 +13655,7 @@
@DocsEditable
@DomName('HTMLLegendElement')
-class LegendElement extends Element native "HTMLLegendElement" {
+class LegendElement extends _HTMLElement native "HTMLLegendElement" {
@DomName('HTMLLegendElement.HTMLLegendElement')
@DocsEditable
@@ -13651,7 +13672,7 @@
@DocsEditable
@DomName('HTMLLinkElement')
-class LinkElement extends Element native "HTMLLinkElement" {
+class LinkElement extends _HTMLElement native "HTMLLinkElement" {
@DomName('HTMLLinkElement.HTMLLinkElement')
@DocsEditable
@@ -13786,7 +13807,7 @@
@DocsEditable
@DomName('HTMLMapElement')
-class MapElement extends Element native "HTMLMapElement" {
+class MapElement extends _HTMLElement native "HTMLMapElement" {
@DomName('HTMLMapElement.HTMLMapElement')
@DocsEditable
@@ -13896,7 +13917,7 @@
@DocsEditable
@DomName('HTMLMediaElement')
@Unstable
-class MediaElement extends Element native "HTMLMediaElement" {
+class MediaElement extends _HTMLElement native "HTMLMediaElement" {
@DomName('HTMLMediaElement.canplayEvent')
@DocsEditable
@@ -14224,6 +14245,7 @@
@DomName('HTMLMediaElement.canPlayType')
@DocsEditable
+ @Unstable
String canPlayType(String type, String keySystem) native;
@DomName('HTMLMediaElement.load')
@@ -15034,7 +15056,7 @@
* * [Menu Element](http://www.w3.org/TR/html5/the-menu-element.html#the-menu-element) from the W3C.
*/
@DomName('HTMLMenuElement')
-class MenuElement extends Element native "HTMLMenuElement" {
+class MenuElement extends _HTMLElement native "HTMLMenuElement" {
@DomName('HTMLMenuElement.HTMLMenuElement')
@DocsEditable
@@ -15192,7 +15214,7 @@
@DocsEditable
@DomName('HTMLMetaElement')
-class MetaElement extends Element native "HTMLMetaElement" {
+class MetaElement extends _HTMLElement native "HTMLMetaElement" {
@DomName('HTMLMetaElement.HTMLMetaElement')
@DocsEditable
@@ -15254,7 +15276,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class MeterElement extends Element native "HTMLMeterElement" {
+class MeterElement extends _HTMLElement native "HTMLMeterElement" {
@DomName('HTMLMeterElement.HTMLMeterElement')
@DocsEditable
@@ -15568,7 +15590,7 @@
@DocsEditable
@DomName('HTMLModElement')
@Unstable
-class ModElement extends Element native "HTMLModElement" {
+class ModElement extends _HTMLElement native "HTMLModElement" {
@DomName('HTMLModElement.cite')
@DocsEditable
@@ -17132,7 +17154,7 @@
@DocsEditable
@DomName('HTMLOListElement')
-class OListElement extends Element native "HTMLOListElement" {
+class OListElement extends _HTMLElement native "HTMLOListElement" {
@DomName('HTMLOListElement.HTMLOListElement')
@DocsEditable
@@ -17161,7 +17183,7 @@
@SupportedBrowser(SupportedBrowser.IE)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class ObjectElement extends Element native "HTMLObjectElement" {
+class ObjectElement extends _HTMLElement native "HTMLObjectElement" {
@DomName('HTMLObjectElement.HTMLObjectElement')
@DocsEditable
@@ -17239,7 +17261,7 @@
@DocsEditable
@DomName('HTMLOptGroupElement')
-class OptGroupElement extends Element native "HTMLOptGroupElement" {
+class OptGroupElement extends _HTMLElement native "HTMLOptGroupElement" {
@DomName('HTMLOptGroupElement.HTMLOptGroupElement')
@DocsEditable
@@ -17260,7 +17282,7 @@
@DocsEditable
@DomName('HTMLOptionElement')
-class OptionElement extends Element native "HTMLOptionElement" {
+class OptionElement extends _HTMLElement native "HTMLOptionElement" {
@DomName('HTMLOptionElement.HTMLOptionElement')
@DocsEditable
@@ -17323,7 +17345,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.SAFARI)
-class OutputElement extends Element native "HTMLOutputElement" {
+class OutputElement extends _HTMLElement native "HTMLOutputElement" {
@DomName('HTMLOutputElement.HTMLOutputElement')
@DocsEditable
@@ -17439,7 +17461,7 @@
@DocsEditable
@DomName('HTMLParagraphElement')
-class ParagraphElement extends Element native "HTMLParagraphElement" {
+class ParagraphElement extends _HTMLElement native "HTMLParagraphElement" {
@DomName('HTMLParagraphElement.HTMLParagraphElement')
@DocsEditable
@@ -17453,7 +17475,7 @@
@DocsEditable
@DomName('HTMLParamElement')
@Unstable
-class ParamElement extends Element native "HTMLParamElement" {
+class ParamElement extends _HTMLElement native "HTMLParamElement" {
@DomName('HTMLParamElement.HTMLParamElement')
@DocsEditable
@@ -18063,7 +18085,7 @@
@DocsEditable
@DomName('HTMLPreElement')
-class PreElement extends Element native "HTMLPreElement" {
+class PreElement extends _HTMLElement native "HTMLPreElement" {
@DomName('HTMLPreElement.HTMLPreElement')
@DocsEditable
@@ -18109,7 +18131,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
-class ProgressElement extends Element native "HTMLProgressElement" {
+class ProgressElement extends _HTMLElement native "HTMLProgressElement" {
@DomName('HTMLProgressElement.HTMLProgressElement')
@DocsEditable
@@ -18165,7 +18187,7 @@
@DocsEditable
@DomName('HTMLQuoteElement')
-class QuoteElement extends Element native "HTMLQuoteElement" {
+class QuoteElement extends _HTMLElement native "HTMLQuoteElement" {
@DomName('HTMLQuoteElement.HTMLQuoteElement')
@DocsEditable
@@ -18220,6 +18242,9 @@
class Range native "Range" {
factory Range() => document.$dom_createRange();
+ factory Range.fromPoint(Point point) =>
+ document.$dom_caretRangeFromPoint(point.x, point.y);
+
@DomName('Range.END_TO_END')
@DocsEditable
static const int END_TO_END = 2;
@@ -18429,7 +18454,7 @@
@DomName('RTCDataChannel')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannel
@Experimental
-class RtcDataChannel extends EventTarget native "RTCDataChannel" {
+class RtcDataChannel extends EventTarget native "RTCDataChannel,DataChannel" {
@DomName('RTCDataChannel.closeEvent')
@DocsEditable
@@ -19119,7 +19144,7 @@
@DocsEditable
@DomName('HTMLScriptElement')
-class ScriptElement extends Element native "HTMLScriptElement" {
+class ScriptElement extends _HTMLElement native "HTMLScriptElement" {
@DomName('HTMLScriptElement.HTMLScriptElement')
@DocsEditable
@@ -19297,7 +19322,7 @@
@DomName('HTMLSelectElement')
-class SelectElement extends Element native "HTMLSelectElement" {
+class SelectElement extends _HTMLElement native "HTMLSelectElement" {
@DomName('HTMLSelectElement.HTMLSelectElement')
@DocsEditable
@@ -19538,7 +19563,7 @@
@SupportedBrowser(SupportedBrowser.CHROME, '26')
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#shadow-element
-class ShadowElement extends Element native "HTMLShadowElement" {
+class ShadowElement extends _HTMLElement native "HTMLShadowElement" {
@DomName('HTMLShadowElement.HTMLShadowElement')
@DocsEditable
@@ -19733,7 +19758,7 @@
@DocsEditable
@DomName('HTMLSourceElement')
-class SourceElement extends Element native "HTMLSourceElement" {
+class SourceElement extends _HTMLElement native "HTMLSourceElement" {
@DomName('HTMLSourceElement.HTMLSourceElement')
@DocsEditable
@@ -19758,7 +19783,7 @@
@DocsEditable
@DomName('HTMLSpanElement')
-class SpanElement extends Element native "HTMLSpanElement" {
+class SpanElement extends _HTMLElement native "HTMLSpanElement" {
@DomName('HTMLSpanElement.HTMLSpanElement')
@DocsEditable
@@ -20655,7 +20680,7 @@
@DocsEditable
@DomName('HTMLStyleElement')
-class StyleElement extends Element native "HTMLStyleElement" {
+class StyleElement extends _HTMLElement native "HTMLStyleElement" {
@DomName('HTMLStyleElement.HTMLStyleElement')
@DocsEditable
@@ -20744,7 +20769,7 @@
@DocsEditable
@DomName('HTMLTableCaptionElement')
-class TableCaptionElement extends Element native "HTMLTableCaptionElement" {
+class TableCaptionElement extends _HTMLElement native "HTMLTableCaptionElement" {
@DomName('HTMLTableCaptionElement.HTMLTableCaptionElement')
@DocsEditable
@@ -20757,7 +20782,7 @@
@DocsEditable
@DomName('HTMLTableCellElement')
-class TableCellElement extends Element native "HTMLTableCellElement" {
+class TableCellElement extends _HTMLElement native "HTMLTableCellElement" {
@DomName('HTMLTableCellElement.HTMLTableCellElement')
@DocsEditable
@@ -20786,7 +20811,7 @@
@DocsEditable
@DomName('HTMLTableColElement')
-class TableColElement extends Element native "HTMLTableColElement" {
+class TableColElement extends _HTMLElement native "HTMLTableColElement" {
@DomName('HTMLTableColElement.HTMLTableColElement')
@DocsEditable
@@ -20803,7 +20828,7 @@
@DocsEditable
@DomName('HTMLTableElement')
-class TableElement extends Element native "HTMLTableElement" {
+class TableElement extends _HTMLElement native "HTMLTableElement" {
@DomName('HTMLTableElement.tBodies')
List<TableSectionElement> get tBodies =>
@@ -20911,7 +20936,7 @@
@DocsEditable
@DomName('HTMLTableRowElement')
-class TableRowElement extends Element native "HTMLTableRowElement" {
+class TableRowElement extends _HTMLElement native "HTMLTableRowElement" {
@DomName('HTMLTableRowElement.cells')
List<TableCellElement> get cells =>
@@ -20957,7 +20982,7 @@
@DocsEditable
@DomName('HTMLTableSectionElement')
-class TableSectionElement extends Element native "HTMLTableSectionElement" {
+class TableSectionElement extends _HTMLElement native "HTMLTableSectionElement" {
@DomName('HTMLTableSectionElement.rows')
List<TableRowElement> get rows =>
@@ -20996,7 +21021,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#template-element
-class TemplateElement extends Element native "HTMLTemplateElement" {
+class TemplateElement extends _HTMLElement native "HTMLTemplateElement" {
@DomName('HTMLTemplateElement.HTMLTemplateElement')
@DocsEditable
@@ -21203,7 +21228,7 @@
@DocsEditable
@DomName('HTMLTextAreaElement')
-class TextAreaElement extends Element native "HTMLTextAreaElement" {
+class TextAreaElement extends _HTMLElement native "HTMLTextAreaElement" {
@DomName('HTMLTextAreaElement.HTMLTextAreaElement')
@DocsEditable
@@ -21735,7 +21760,7 @@
@DocsEditable
@DomName('HTMLTitleElement')
-class TitleElement extends Element native "HTMLTitleElement" {
+class TitleElement extends _HTMLElement native "HTMLTitleElement" {
@DomName('HTMLTitleElement.HTMLTitleElement')
@DocsEditable
@@ -21995,7 +22020,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#the-track-element
@Experimental
-class TrackElement extends Element native "HTMLTrackElement" {
+class TrackElement extends _HTMLElement native "HTMLTrackElement" {
@DomName('HTMLTrackElement.HTMLTrackElement')
@DocsEditable
@@ -22262,7 +22287,7 @@
@DocsEditable
@DomName('HTMLUListElement')
-class UListElement extends Element native "HTMLUListElement" {
+class UListElement extends _HTMLElement native "HTMLUListElement" {
@DomName('HTMLUListElement.HTMLUListElement')
@DocsEditable
@@ -22275,7 +22300,7 @@
@DocsEditable
@DomName('HTMLUnknownElement')
-class UnknownElement extends Element native "HTMLUnknownElement" {
+class UnknownElement extends _HTMLElement native "HTMLUnknownElement" {
}
// 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
@@ -22916,12 +22941,17 @@
}
/**
- * Returns a Future that completes just before the window is about to repaint
- * so the user can draw an animation frame
+ * Returns a Future that completes just before the window is about to
+ * repaint so the user can draw an animation frame.
*
* If you need to later cancel this animation, use [requestAnimationFrame]
* instead.
*
+ * The [Future] completes to a timestamp that represents a floating
+ * point value of the number of milliseconds that have elapsed since the page
+ * started to load (which is also the timestamp at this call to
+ * animationFrame).
+ *
* Note: The code that runs when the future completes should call
* [animationFrame] again for the animation to continue.
*/
@@ -25012,7 +25042,7 @@
@DomName('HTMLAppletElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-applet-element
@deprecated // deprecated
-abstract class _HTMLAppletElement extends Element native "HTMLAppletElement" {
+abstract class _HTMLAppletElement extends _HTMLElement native "HTMLAppletElement" {
}
// 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
@@ -25023,7 +25053,7 @@
@DomName('HTMLBaseFontElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#basefont
@deprecated // deprecated
-abstract class _HTMLBaseFontElement extends Element native "HTMLBaseFontElement" {
+abstract class _HTMLBaseFontElement extends _HTMLElement native "HTMLBaseFontElement" {
}
// 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
@@ -25034,7 +25064,7 @@
@DomName('HTMLDirectoryElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dir
@deprecated // deprecated
-abstract class _HTMLDirectoryElement extends Element native "HTMLDirectoryElement" {
+abstract class _HTMLDirectoryElement extends _HTMLElement native "HTMLDirectoryElement" {
}
// 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
@@ -25045,7 +25075,7 @@
@DomName('HTMLFontElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlfontelement
@deprecated // deprecated
-abstract class _HTMLFontElement extends Element native "HTMLFontElement" {
+abstract class _HTMLFontElement extends _HTMLElement native "HTMLFontElement" {
}
// 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
@@ -25056,7 +25086,7 @@
@DomName('HTMLFrameElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlframeelement
@deprecated // deprecated
-abstract class _HTMLFrameElement extends Element native "HTMLFrameElement" {
+abstract class _HTMLFrameElement extends _HTMLElement native "HTMLFrameElement" {
}
// 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
@@ -25067,7 +25097,7 @@
@DomName('HTMLFrameSetElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#frameset
@deprecated // deprecated
-abstract class _HTMLFrameSetElement extends Element native "HTMLFrameSetElement" {
+abstract class _HTMLFrameSetElement extends _HTMLElement native "HTMLFrameSetElement" {
}
// 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
@@ -25078,7 +25108,7 @@
@DomName('HTMLMarqueeElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-marquee-element
@deprecated // deprecated
-abstract class _HTMLMarqueeElement extends Element native "HTMLMarqueeElement" {
+abstract class _HTMLMarqueeElement extends _HTMLElement native "HTMLMarqueeElement" {
}
// 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
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 8409fee..a97473f 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -114,7 +114,7 @@
@DocsEditable
@DomName('HTMLAnchorElement')
-class AnchorElement extends _Element_Merged {
+class AnchorElement extends _HTMLElement {
AnchorElement.internal() : super.internal();
@DomName('HTMLAnchorElement.HTMLAnchorElement')
@@ -445,7 +445,7 @@
* on MDN.
*/
@DomName('HTMLAreaElement')
-class AreaElement extends _Element_Merged {
+class AreaElement extends _HTMLElement {
AreaElement.internal() : super.internal();
@DomName('HTMLAreaElement.HTMLAreaElement')
@@ -583,7 +583,7 @@
@DocsEditable
@DomName('HTMLBRElement')
-class BRElement extends _Element_Merged {
+class BRElement extends _HTMLElement {
BRElement.internal() : super.internal();
@DomName('HTMLBRElement.HTMLBRElement')
@@ -619,7 +619,7 @@
@DocsEditable
@DomName('HTMLBaseElement')
-class BaseElement extends _Element_Merged {
+class BaseElement extends _HTMLElement {
BaseElement.internal() : super.internal();
@DomName('HTMLBaseElement.HTMLBaseElement')
@@ -717,7 +717,7 @@
@DocsEditable
@DomName('HTMLBodyElement')
-class BodyElement extends _Element_Merged {
+class BodyElement extends _HTMLElement {
BodyElement.internal() : super.internal();
@DomName('HTMLBodyElement.blurEvent')
@@ -830,7 +830,7 @@
@DocsEditable
@DomName('HTMLButtonElement')
-class ButtonElement extends _Element_Merged {
+class ButtonElement extends _HTMLElement {
ButtonElement.internal() : super.internal();
@DomName('HTMLButtonElement.HTMLButtonElement')
@@ -991,9 +991,17 @@
@DomName('HTMLCanvasElement')
-class CanvasElement extends _Element_Merged implements CanvasImageSource {
+class CanvasElement extends _HTMLElement implements CanvasImageSource {
CanvasElement.internal() : super.internal();
+ @DomName('HTMLCanvasElement.webglcontextlostEvent')
+ @DocsEditable
+ static const EventStreamProvider<gl.ContextEvent> webGlContextLostEvent = const EventStreamProvider<gl.ContextEvent>('webglcontextlost');
+
+ @DomName('HTMLCanvasElement.webglcontextrestoredEvent')
+ @DocsEditable
+ static const EventStreamProvider<gl.ContextEvent> webGlContextRestoredEvent = const EventStreamProvider<gl.ContextEvent>('webglcontextrestored');
+
@DomName('HTMLCanvasElement.HTMLCanvasElement')
@DocsEditable
factory CanvasElement({int width, int height}) {
@@ -1071,6 +1079,14 @@
@DocsEditable
String toDataUrl(String type, [num quality]) native "HTMLCanvasElement_toDataURL_Callback";
+ @DomName('HTMLCanvasElement.onwebglcontextlost')
+ @DocsEditable
+ Stream<gl.ContextEvent> get onWebGlContextLost => webGlContextLostEvent.forTarget(this);
+
+ @DomName('HTMLCanvasElement.onwebglcontextrestored')
+ @DocsEditable
+ Stream<gl.ContextEvent> get onWebGlContextRestored => webGlContextRestoredEvent.forTarget(this);
+
/** An API for drawing on this canvas. */
CanvasRenderingContext2D get context2D => getContext('2d');
@@ -2172,7 +2188,7 @@
@SupportedBrowser(SupportedBrowser.CHROME, '26')
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#content-element
-class ContentElement extends _Element_Merged {
+class ContentElement extends _HTMLElement {
ContentElement.internal() : super.internal();
@DomName('HTMLContentElement.HTMLContentElement')
@@ -2541,8 +2557,6 @@
// 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.
-// WARNING: Do not edit - generated code.
-
@DocsEditable
@DomName('WebKitCSSKeyframesRule')
@@ -2579,7 +2593,8 @@
@DomName('WebKitCSSKeyframesRule.insertRule')
@DocsEditable
- void insertRule(String rule) native "CSSKeyframesRule_insertRule_Callback";
+ void appendRule(String rule) native "CSSKeyframesRule_insertRule_Callback";
+
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -6534,7 +6549,7 @@
@DocsEditable
@DomName('HTMLDListElement')
-class DListElement extends _Element_Merged {
+class DListElement extends _HTMLElement {
DListElement.internal() : super.internal();
@DomName('HTMLDListElement.HTMLDListElement')
@@ -6555,7 +6570,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
-class DataListElement extends _Element_Merged {
+class DataListElement extends _HTMLElement {
DataListElement.internal() : super.internal();
@DomName('HTMLDataListElement.HTMLDataListElement')
@@ -6754,7 +6769,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
-class DetailsElement extends _Element_Merged {
+class DetailsElement extends _HTMLElement {
DetailsElement.internal() : super.internal();
@DomName('HTMLDetailsElement.HTMLDetailsElement')
@@ -6910,7 +6925,7 @@
@DocsEditable
@DomName('HTMLDialogElement')
@Unstable
-class DialogElement extends _Element_Merged {
+class DialogElement extends _HTMLElement {
DialogElement.internal() : super.internal();
@DomName('HTMLDialogElement.open')
@@ -7081,7 +7096,7 @@
* * [Inline-level element](http://www.w3.org/TR/CSS2/visuren.html#inline-boxes) from W3C.
*/
@DomName('HTMLDivElement')
-class DivElement extends _Element_Merged {
+class DivElement extends _HTMLElement {
DivElement.internal() : super.internal();
@DomName('HTMLDivElement.HTMLDivElement')
@@ -9906,7 +9921,7 @@
@SupportedBrowser(SupportedBrowser.IE)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class EmbedElement extends _Element_Merged {
+class EmbedElement extends _HTMLElement {
EmbedElement.internal() : super.internal();
@DomName('HTMLEmbedElement.HTMLEmbedElement')
@@ -10603,7 +10618,7 @@
@DocsEditable
@DomName('HTMLFieldSetElement')
@Unstable
-class FieldSetElement extends _Element_Merged {
+class FieldSetElement extends _HTMLElement {
FieldSetElement.internal() : super.internal();
@DomName('HTMLFieldSetElement.HTMLFieldSetElement')
@@ -11395,7 +11410,7 @@
@DocsEditable
@DomName('HTMLFormElement')
-class FormElement extends _Element_Merged {
+class FormElement extends _HTMLElement {
FormElement.internal() : super.internal();
@DomName('HTMLFormElement.autocompleteEvent')
@@ -11695,7 +11710,7 @@
* An `<hr>` tag.
*/
@DomName('HTMLHRElement')
-class HRElement extends _Element_Merged {
+class HRElement extends _HTMLElement {
HRElement.internal() : super.internal();
@DomName('HTMLHRElement.HTMLHRElement')
@@ -11750,7 +11765,7 @@
@DocsEditable
@DomName('HTMLHeadElement')
-class HeadElement extends _Element_Merged {
+class HeadElement extends _HTMLElement {
HeadElement.internal() : super.internal();
@DomName('HTMLHeadElement.HTMLHeadElement')
@@ -11767,7 +11782,7 @@
@DocsEditable
@DomName('HTMLHeadingElement')
-class HeadingElement extends _Element_Merged {
+class HeadingElement extends _HTMLElement {
HeadingElement.internal() : super.internal();
@DomName('HTMLHeadingElement.HTMLHeadingElement')
@@ -12181,7 +12196,7 @@
@DocsEditable
@DomName('HTMLHtmlElement')
-class HtmlElement extends _Element_Merged {
+class HtmlElement extends _HTMLElement {
HtmlElement.internal() : super.internal();
@DomName('HTMLHtmlElement.HTMLHtmlElement')
@@ -12878,7 +12893,7 @@
@DocsEditable
@DomName('HTMLIFrameElement')
-class IFrameElement extends _Element_Merged {
+class IFrameElement extends _HTMLElement {
IFrameElement.internal() : super.internal();
@DomName('HTMLIFrameElement.HTMLIFrameElement')
@@ -12983,7 +12998,7 @@
@DomName('HTMLImageElement')
-class ImageElement extends _Element_Merged implements CanvasImageSource {
+class ImageElement extends _HTMLElement implements CanvasImageSource {
ImageElement.internal() : super.internal();
@DomName('HTMLImageElement.HTMLImageElement')
@@ -13101,7 +13116,7 @@
@DomName('HTMLInputElement')
-class InputElement extends _Element_Merged implements
+class InputElement extends _HTMLElement implements
HiddenInputElement,
SearchInputElement,
TextInputElement,
@@ -14354,7 +14369,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
@Experimental
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-keygen-element
-class KeygenElement extends _Element_Merged {
+class KeygenElement extends _HTMLElement {
KeygenElement.internal() : super.internal();
@DomName('HTMLKeygenElement.HTMLKeygenElement')
@@ -14447,7 +14462,7 @@
@DocsEditable
@DomName('HTMLLIElement')
-class LIElement extends _Element_Merged {
+class LIElement extends _HTMLElement {
LIElement.internal() : super.internal();
@DomName('HTMLLIElement.HTMLLIElement')
@@ -14484,7 +14499,7 @@
@DocsEditable
@DomName('HTMLLabelElement')
-class LabelElement extends _Element_Merged {
+class LabelElement extends _HTMLElement {
LabelElement.internal() : super.internal();
@DomName('HTMLLabelElement.HTMLLabelElement')
@@ -14517,7 +14532,7 @@
@DocsEditable
@DomName('HTMLLegendElement')
-class LegendElement extends _Element_Merged {
+class LegendElement extends _HTMLElement {
LegendElement.internal() : super.internal();
@DomName('HTMLLegendElement.HTMLLegendElement')
@@ -14538,7 +14553,7 @@
@DocsEditable
@DomName('HTMLLinkElement')
-class LinkElement extends _Element_Merged {
+class LinkElement extends _HTMLElement {
LinkElement.internal() : super.internal();
@DomName('HTMLLinkElement.HTMLLinkElement')
@@ -14735,7 +14750,7 @@
@DocsEditable
@DomName('HTMLMapElement')
-class MapElement extends _Element_Merged {
+class MapElement extends _HTMLElement {
MapElement.internal() : super.internal();
@DomName('HTMLMapElement.HTMLMapElement')
@@ -14877,7 +14892,7 @@
@DocsEditable
@DomName('HTMLMediaElement')
@Unstable
-class MediaElement extends _Element_Merged {
+class MediaElement extends _HTMLElement {
MediaElement.internal() : super.internal();
@DomName('HTMLMediaElement.canplayEvent')
@@ -15285,6 +15300,7 @@
@DomName('HTMLMediaElement.canPlayType')
@DocsEditable
+ @Unstable
String canPlayType(String type, String keySystem) native "HTMLMediaElement_canPlayType_Callback";
@DomName('HTMLMediaElement.load')
@@ -16175,7 +16191,7 @@
* * [Menu Element](http://www.w3.org/TR/html5/the-menu-element.html#the-menu-element) from the W3C.
*/
@DomName('HTMLMenuElement')
-class MenuElement extends _Element_Merged {
+class MenuElement extends _HTMLElement {
MenuElement.internal() : super.internal();
@DomName('HTMLMenuElement.HTMLMenuElement')
@@ -16317,7 +16333,7 @@
@DocsEditable
@DomName('HTMLMetaElement')
-class MetaElement extends _Element_Merged {
+class MetaElement extends _HTMLElement {
MetaElement.internal() : super.internal();
@DomName('HTMLMetaElement.HTMLMetaElement')
@@ -16396,7 +16412,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class MeterElement extends _Element_Merged {
+class MeterElement extends _HTMLElement {
MeterElement.internal() : super.internal();
@DomName('HTMLMeterElement.HTMLMeterElement')
@@ -16774,7 +16790,7 @@
@DocsEditable
@DomName('HTMLModElement')
@Unstable
-class ModElement extends _Element_Merged {
+class ModElement extends _HTMLElement {
ModElement.internal() : super.internal();
@DomName('HTMLModElement.cite')
@@ -18322,7 +18338,7 @@
@DocsEditable
@DomName('HTMLOListElement')
-class OListElement extends _Element_Merged {
+class OListElement extends _HTMLElement {
OListElement.internal() : super.internal();
@DomName('HTMLOListElement.HTMLOListElement')
@@ -18367,7 +18383,7 @@
@SupportedBrowser(SupportedBrowser.IE)
@SupportedBrowser(SupportedBrowser.SAFARI)
@Unstable
-class ObjectElement extends _Element_Merged {
+class ObjectElement extends _HTMLElement {
ObjectElement.internal() : super.internal();
@DomName('HTMLObjectElement.HTMLObjectElement')
@@ -18479,7 +18495,7 @@
@DocsEditable
@DomName('HTMLOptGroupElement')
-class OptGroupElement extends _Element_Merged {
+class OptGroupElement extends _HTMLElement {
OptGroupElement.internal() : super.internal();
@DomName('HTMLOptGroupElement.HTMLOptGroupElement')
@@ -18512,7 +18528,7 @@
@DocsEditable
@DomName('HTMLOptionElement')
-class OptionElement extends _Element_Merged {
+class OptionElement extends _HTMLElement {
OptionElement.internal() : super.internal();
@DomName('HTMLOptionElement.HTMLOptionElement')
@@ -18585,7 +18601,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.SAFARI)
-class OutputElement extends _Element_Merged {
+class OutputElement extends _HTMLElement {
OutputElement.internal() : super.internal();
@DomName('HTMLOutputElement.HTMLOutputElement')
@@ -18723,7 +18739,7 @@
@DocsEditable
@DomName('HTMLParagraphElement')
-class ParagraphElement extends _Element_Merged {
+class ParagraphElement extends _HTMLElement {
ParagraphElement.internal() : super.internal();
@DomName('HTMLParagraphElement.HTMLParagraphElement')
@@ -18741,7 +18757,7 @@
@DocsEditable
@DomName('HTMLParamElement')
@Unstable
-class ParamElement extends _Element_Merged {
+class ParamElement extends _HTMLElement {
ParamElement.internal() : super.internal();
@DomName('HTMLParamElement.HTMLParamElement')
@@ -19412,7 +19428,7 @@
@DocsEditable
@DomName('HTMLPreElement')
-class PreElement extends _Element_Merged {
+class PreElement extends _HTMLElement {
PreElement.internal() : super.internal();
@DomName('HTMLPreElement.HTMLPreElement')
@@ -19476,7 +19492,7 @@
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
-class ProgressElement extends _Element_Merged {
+class ProgressElement extends _HTMLElement {
ProgressElement.internal() : super.internal();
@DomName('HTMLProgressElement.HTMLProgressElement')
@@ -19546,7 +19562,7 @@
@DocsEditable
@DomName('HTMLQuoteElement')
-class QuoteElement extends _Element_Merged {
+class QuoteElement extends _HTMLElement {
QuoteElement.internal() : super.internal();
@DomName('HTMLQuoteElement.HTMLQuoteElement')
@@ -19606,6 +19622,9 @@
@Unstable
class Range extends NativeFieldWrapperClass1 {
factory Range() => document.$dom_createRange();
+
+ factory Range.fromPoint(Point point) =>
+ document.$dom_caretRangeFromPoint(point.x, point.y);
Range.internal();
@DomName('Range.END_TO_END')
@@ -20470,7 +20489,7 @@
@DocsEditable
@DomName('HTMLScriptElement')
-class ScriptElement extends _Element_Merged {
+class ScriptElement extends _HTMLElement {
ScriptElement.internal() : super.internal();
@DomName('HTMLScriptElement.HTMLScriptElement')
@@ -20698,7 +20717,7 @@
@DomName('HTMLSelectElement')
-class SelectElement extends _Element_Merged {
+class SelectElement extends _HTMLElement {
SelectElement.internal() : super.internal();
@DomName('HTMLSelectElement.HTMLSelectElement')
@@ -20980,7 +20999,7 @@
@SupportedBrowser(SupportedBrowser.CHROME, '26')
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#shadow-element
-class ShadowElement extends _Element_Merged {
+class ShadowElement extends _HTMLElement {
ShadowElement.internal() : super.internal();
@DomName('HTMLShadowElement.HTMLShadowElement')
@@ -21200,7 +21219,7 @@
@DocsEditable
@DomName('HTMLSourceElement')
-class SourceElement extends _Element_Merged {
+class SourceElement extends _HTMLElement {
SourceElement.internal() : super.internal();
@DomName('HTMLSourceElement.HTMLSourceElement')
@@ -21241,7 +21260,7 @@
@DocsEditable
@DomName('HTMLSpanElement')
-class SpanElement extends _Element_Merged {
+class SpanElement extends _HTMLElement {
SpanElement.internal() : super.internal();
@DomName('HTMLSpanElement.HTMLSpanElement')
@@ -22291,7 +22310,7 @@
@DocsEditable
@DomName('HTMLStyleElement')
-class StyleElement extends _Element_Merged {
+class StyleElement extends _HTMLElement {
StyleElement.internal() : super.internal();
@DomName('HTMLStyleElement.HTMLStyleElement')
@@ -22412,7 +22431,7 @@
@DocsEditable
@DomName('HTMLTableCaptionElement')
-class TableCaptionElement extends _Element_Merged {
+class TableCaptionElement extends _HTMLElement {
TableCaptionElement.internal() : super.internal();
@DomName('HTMLTableCaptionElement.HTMLTableCaptionElement')
@@ -22429,7 +22448,7 @@
@DocsEditable
@DomName('HTMLTableCellElement')
-class TableCellElement extends _Element_Merged {
+class TableCellElement extends _HTMLElement {
TableCellElement.internal() : super.internal();
@DomName('HTMLTableCellElement.HTMLTableCellElement')
@@ -22474,7 +22493,7 @@
@DocsEditable
@DomName('HTMLTableColElement')
-class TableColElement extends _Element_Merged {
+class TableColElement extends _HTMLElement {
TableColElement.internal() : super.internal();
@DomName('HTMLTableColElement.HTMLTableColElement')
@@ -22497,7 +22516,7 @@
@DocsEditable
@DomName('HTMLTableElement')
-class TableElement extends _Element_Merged {
+class TableElement extends _HTMLElement {
@DomName('HTMLTableElement.tBodies')
List<TableSectionElement> get tBodies =>
@@ -22611,7 +22630,7 @@
@DocsEditable
@DomName('HTMLTableRowElement')
-class TableRowElement extends _Element_Merged {
+class TableRowElement extends _HTMLElement {
@DomName('HTMLTableRowElement.cells')
List<TableCellElement> get cells =>
@@ -22656,7 +22675,7 @@
@DocsEditable
@DomName('HTMLTableSectionElement')
-class TableSectionElement extends _Element_Merged {
+class TableSectionElement extends _HTMLElement {
@DomName('HTMLTableSectionElement.rows')
List<TableRowElement> get rows =>
@@ -22694,7 +22713,7 @@
@SupportedBrowser(SupportedBrowser.CHROME)
@Experimental
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#template-element
-class TemplateElement extends _Element_Merged {
+class TemplateElement extends _HTMLElement {
TemplateElement.internal() : super.internal();
@DomName('HTMLTemplateElement.HTMLTemplateElement')
@@ -22903,7 +22922,7 @@
@DocsEditable
@DomName('HTMLTextAreaElement')
-class TextAreaElement extends _Element_Merged {
+class TextAreaElement extends _HTMLElement {
TextAreaElement.internal() : super.internal();
@DomName('HTMLTextAreaElement.HTMLTextAreaElement')
@@ -23598,7 +23617,7 @@
@DocsEditable
@DomName('HTMLTitleElement')
-class TitleElement extends _Element_Merged {
+class TitleElement extends _HTMLElement {
TitleElement.internal() : super.internal();
@DomName('HTMLTitleElement.HTMLTitleElement')
@@ -23851,7 +23870,7 @@
@SupportedBrowser(SupportedBrowser.SAFARI)
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#the-track-element
@Experimental
-class TrackElement extends _Element_Merged {
+class TrackElement extends _HTMLElement {
TrackElement.internal() : super.internal();
@DomName('HTMLTrackElement.HTMLTrackElement')
@@ -24143,7 +24162,7 @@
@DocsEditable
@DomName('HTMLUListElement')
-class UListElement extends _Element_Merged {
+class UListElement extends _HTMLElement {
UListElement.internal() : super.internal();
@DomName('HTMLUListElement.HTMLUListElement')
@@ -24160,7 +24179,7 @@
@DocsEditable
@DomName('HTMLUnknownElement')
-class UnknownElement extends _Element_Merged {
+class UnknownElement extends _HTMLElement {
UnknownElement.internal() : super.internal();
}
@@ -24719,12 +24738,17 @@
}
/**
- * Returns a Future that completes just before the window is about to repaint
- * so the user can draw an animation frame
+ * Returns a Future that completes just before the window is about to
+ * repaint so the user can draw an animation frame.
*
* If you need to later cancel this animation, use [requestAnimationFrame]
* instead.
*
+ * The [Future] completes to a timestamp that represents a floating
+ * point value of the number of milliseconds that have elapsed since the page
+ * started to load (which is also the timestamp at this call to
+ * animationFrame).
+ *
* Note: The code that runs when the future completes should call
* [animationFrame] again for the animation to continue.
*/
@@ -26482,159 +26506,6 @@
@DocsEditable
-@DomName('HTMLElement')
-class _Element_Merged extends Element {
- _Element_Merged.internal() : super.internal();
-
- @DomName('HTMLElement.contentEditable')
- @DocsEditable
- String get contentEditable native "HTMLElement_contentEditable_Getter";
-
- @DomName('HTMLElement.contentEditable')
- @DocsEditable
- void set contentEditable(String value) native "HTMLElement_contentEditable_Setter";
-
- @DomName('HTMLElement.dir')
- @DocsEditable
- String get dir native "HTMLElement_dir_Getter";
-
- @DomName('HTMLElement.dir')
- @DocsEditable
- void set dir(String value) native "HTMLElement_dir_Setter";
-
- @DomName('HTMLElement.draggable')
- @DocsEditable
- bool get draggable native "HTMLElement_draggable_Getter";
-
- @DomName('HTMLElement.draggable')
- @DocsEditable
- void set draggable(bool value) native "HTMLElement_draggable_Setter";
-
- @DomName('HTMLElement.hidden')
- @DocsEditable
- bool get hidden native "HTMLElement_hidden_Getter";
-
- @DomName('HTMLElement.hidden')
- @DocsEditable
- void set hidden(bool value) native "HTMLElement_hidden_Setter";
-
- @DomName('HTMLElement.id')
- @DocsEditable
- String get id native "HTMLElement_id_Getter";
-
- @DomName('HTMLElement.id')
- @DocsEditable
- void set id(String value) native "HTMLElement_id_Setter";
-
- @DomName('HTMLElement.innerHTML')
- @DocsEditable
- String get innerHtml native "HTMLElement_innerHTML_Getter";
-
- @DomName('HTMLElement.innerHTML')
- @DocsEditable
- void set innerHtml(String value) native "HTMLElement_innerHTML_Setter";
-
- @DomName('HTMLElement.isContentEditable')
- @DocsEditable
- bool get isContentEditable native "HTMLElement_isContentEditable_Getter";
-
- @DomName('HTMLElement.lang')
- @DocsEditable
- String get lang native "HTMLElement_lang_Getter";
-
- @DomName('HTMLElement.lang')
- @DocsEditable
- void set lang(String value) native "HTMLElement_lang_Setter";
-
- @DomName('HTMLElement.outerHTML')
- @DocsEditable
- String get outerHtml native "HTMLElement_outerHTML_Getter";
-
- @DomName('HTMLElement.spellcheck')
- @DocsEditable
- // http://blog.whatwg.org/the-road-to-html-5-spellchecking
- @Experimental // nonstandard
- bool get spellcheck native "HTMLElement_spellcheck_Getter";
-
- @DomName('HTMLElement.spellcheck')
- @DocsEditable
- // http://blog.whatwg.org/the-road-to-html-5-spellchecking
- @Experimental // nonstandard
- void set spellcheck(bool value) native "HTMLElement_spellcheck_Setter";
-
- @DomName('HTMLElement.tabIndex')
- @DocsEditable
- int get tabIndex native "HTMLElement_tabIndex_Getter";
-
- @DomName('HTMLElement.tabIndex')
- @DocsEditable
- void set tabIndex(int value) native "HTMLElement_tabIndex_Setter";
-
- @DomName('HTMLElement.title')
- @DocsEditable
- String get title native "HTMLElement_title_Getter";
-
- @DomName('HTMLElement.title')
- @DocsEditable
- void set title(String value) native "HTMLElement_title_Setter";
-
- @DomName('HTMLElement.translate')
- @DocsEditable
- bool get translate native "HTMLElement_translate_Getter";
-
- @DomName('HTMLElement.translate')
- @DocsEditable
- void set translate(bool value) native "HTMLElement_translate_Setter";
-
- @DomName('HTMLElement.webkitdropzone')
- @DocsEditable
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#the-dropzone-attribute
- String get dropzone native "HTMLElement_webkitdropzone_Getter";
-
- @DomName('HTMLElement.webkitdropzone')
- @DocsEditable
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#the-dropzone-attribute
- void set dropzone(String value) native "HTMLElement_webkitdropzone_Setter";
-
- @DomName('HTMLElement.click')
- @DocsEditable
- void click() native "HTMLElement_click_Callback";
-
- @DomName('HTMLElement.getInputContext')
- @DocsEditable
- // http://www.w3.org/TR/ime-api/#the-getinputcontext-method
- @Experimental
- InputMethodContext getInputContext() native "HTMLElement_getInputContext_Callback";
-
- @DomName('HTMLElement.insertAdjacentElement')
- @DocsEditable
- @Experimental // non-standard
- Element insertAdjacentElement(String where, Element element) native "HTMLElement_insertAdjacentElement_Callback";
-
- @DomName('HTMLElement.insertAdjacentHTML')
- @DocsEditable
- void insertAdjacentHtml(String where, String html) native "HTMLElement_insertAdjacentHTML_Callback";
-
- @DomName('HTMLElement.insertAdjacentText')
- @DocsEditable
- @Experimental // non-standard
- void insertAdjacentText(String where, String text) native "HTMLElement_insertAdjacentText_Callback";
-
-}
-// 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.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
@DomName('Entity')
@deprecated // deprecated
class _Entity extends Node {
@@ -26937,7 +26808,7 @@
@DomName('HTMLAppletElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-applet-element
@deprecated // deprecated
-abstract class _HTMLAppletElement extends _Element_Merged {
+abstract class _HTMLAppletElement extends _HTMLElement {
_HTMLAppletElement.internal() : super.internal();
}
@@ -26952,7 +26823,7 @@
@DomName('HTMLBaseFontElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#basefont
@deprecated // deprecated
-abstract class _HTMLBaseFontElement extends _Element_Merged {
+abstract class _HTMLBaseFontElement extends _HTMLElement {
_HTMLBaseFontElement.internal() : super.internal();
}
@@ -26967,7 +26838,7 @@
@DomName('HTMLDirectoryElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dir
@deprecated // deprecated
-abstract class _HTMLDirectoryElement extends _Element_Merged {
+abstract class _HTMLDirectoryElement extends _HTMLElement {
_HTMLDirectoryElement.internal() : super.internal();
}
@@ -26979,10 +26850,163 @@
@DocsEditable
+@DomName('HTMLElement')
+class _HTMLElement extends Element {
+ _HTMLElement.internal() : super.internal();
+
+ @DomName('HTMLElement.contentEditable')
+ @DocsEditable
+ String get contentEditable native "HTMLElement_contentEditable_Getter";
+
+ @DomName('HTMLElement.contentEditable')
+ @DocsEditable
+ void set contentEditable(String value) native "HTMLElement_contentEditable_Setter";
+
+ @DomName('HTMLElement.dir')
+ @DocsEditable
+ String get dir native "HTMLElement_dir_Getter";
+
+ @DomName('HTMLElement.dir')
+ @DocsEditable
+ void set dir(String value) native "HTMLElement_dir_Setter";
+
+ @DomName('HTMLElement.draggable')
+ @DocsEditable
+ bool get draggable native "HTMLElement_draggable_Getter";
+
+ @DomName('HTMLElement.draggable')
+ @DocsEditable
+ void set draggable(bool value) native "HTMLElement_draggable_Setter";
+
+ @DomName('HTMLElement.hidden')
+ @DocsEditable
+ bool get hidden native "HTMLElement_hidden_Getter";
+
+ @DomName('HTMLElement.hidden')
+ @DocsEditable
+ void set hidden(bool value) native "HTMLElement_hidden_Setter";
+
+ @DomName('HTMLElement.id')
+ @DocsEditable
+ String get id native "HTMLElement_id_Getter";
+
+ @DomName('HTMLElement.id')
+ @DocsEditable
+ void set id(String value) native "HTMLElement_id_Setter";
+
+ @DomName('HTMLElement.innerHTML')
+ @DocsEditable
+ String get innerHtml native "HTMLElement_innerHTML_Getter";
+
+ @DomName('HTMLElement.innerHTML')
+ @DocsEditable
+ void set innerHtml(String value) native "HTMLElement_innerHTML_Setter";
+
+ @DomName('HTMLElement.isContentEditable')
+ @DocsEditable
+ bool get isContentEditable native "HTMLElement_isContentEditable_Getter";
+
+ @DomName('HTMLElement.lang')
+ @DocsEditable
+ String get lang native "HTMLElement_lang_Getter";
+
+ @DomName('HTMLElement.lang')
+ @DocsEditable
+ void set lang(String value) native "HTMLElement_lang_Setter";
+
+ @DomName('HTMLElement.outerHTML')
+ @DocsEditable
+ String get outerHtml native "HTMLElement_outerHTML_Getter";
+
+ @DomName('HTMLElement.spellcheck')
+ @DocsEditable
+ // http://blog.whatwg.org/the-road-to-html-5-spellchecking
+ @Experimental // nonstandard
+ bool get spellcheck native "HTMLElement_spellcheck_Getter";
+
+ @DomName('HTMLElement.spellcheck')
+ @DocsEditable
+ // http://blog.whatwg.org/the-road-to-html-5-spellchecking
+ @Experimental // nonstandard
+ void set spellcheck(bool value) native "HTMLElement_spellcheck_Setter";
+
+ @DomName('HTMLElement.tabIndex')
+ @DocsEditable
+ int get tabIndex native "HTMLElement_tabIndex_Getter";
+
+ @DomName('HTMLElement.tabIndex')
+ @DocsEditable
+ void set tabIndex(int value) native "HTMLElement_tabIndex_Setter";
+
+ @DomName('HTMLElement.title')
+ @DocsEditable
+ String get title native "HTMLElement_title_Getter";
+
+ @DomName('HTMLElement.title')
+ @DocsEditable
+ void set title(String value) native "HTMLElement_title_Setter";
+
+ @DomName('HTMLElement.translate')
+ @DocsEditable
+ bool get translate native "HTMLElement_translate_Getter";
+
+ @DomName('HTMLElement.translate')
+ @DocsEditable
+ void set translate(bool value) native "HTMLElement_translate_Setter";
+
+ @DomName('HTMLElement.webkitdropzone')
+ @DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#the-dropzone-attribute
+ String get dropzone native "HTMLElement_webkitdropzone_Getter";
+
+ @DomName('HTMLElement.webkitdropzone')
+ @DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#the-dropzone-attribute
+ void set dropzone(String value) native "HTMLElement_webkitdropzone_Setter";
+
+ @DomName('HTMLElement.click')
+ @DocsEditable
+ void click() native "HTMLElement_click_Callback";
+
+ @DomName('HTMLElement.getInputContext')
+ @DocsEditable
+ // http://www.w3.org/TR/ime-api/#the-getinputcontext-method
+ @Experimental
+ InputMethodContext getInputContext() native "HTMLElement_getInputContext_Callback";
+
+ @DomName('HTMLElement.insertAdjacentElement')
+ @DocsEditable
+ @Experimental // non-standard
+ Element insertAdjacentElement(String where, Element element) native "HTMLElement_insertAdjacentElement_Callback";
+
+ @DomName('HTMLElement.insertAdjacentHTML')
+ @DocsEditable
+ void insertAdjacentHtml(String where, String html) native "HTMLElement_insertAdjacentHTML_Callback";
+
+ @DomName('HTMLElement.insertAdjacentText')
+ @DocsEditable
+ @Experimental // non-standard
+ void insertAdjacentText(String where, String text) native "HTMLElement_insertAdjacentText_Callback";
+
+}
+// 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.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
@DomName('HTMLFontElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlfontelement
@deprecated // deprecated
-abstract class _HTMLFontElement extends _Element_Merged {
+abstract class _HTMLFontElement extends _HTMLElement {
_HTMLFontElement.internal() : super.internal();
}
@@ -26997,7 +27021,7 @@
@DomName('HTMLFrameElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#htmlframeelement
@deprecated // deprecated
-abstract class _HTMLFrameElement extends _Element_Merged {
+abstract class _HTMLFrameElement extends _HTMLElement {
_HTMLFrameElement.internal() : super.internal();
}
@@ -27012,7 +27036,7 @@
@DomName('HTMLFrameSetElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#frameset
@deprecated // deprecated
-abstract class _HTMLFrameSetElement extends _Element_Merged {
+abstract class _HTMLFrameSetElement extends _HTMLElement {
_HTMLFrameSetElement.internal() : super.internal();
}
@@ -27027,7 +27051,7 @@
@DomName('HTMLMarqueeElement')
// http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#the-marquee-element
@deprecated // deprecated
-abstract class _HTMLMarqueeElement extends _Element_Merged {
+abstract class _HTMLMarqueeElement extends _HTMLElement {
_HTMLMarqueeElement.internal() : super.internal();
}
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index 063c7e9..12591d5 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -173,38 +173,10 @@
int i = 0;
- if (isJavaScriptArray(e) &&
- // We have to copy immutable lists, otherwise the structured clone
- // algorithm will copy the .immutable$list marker property, making the
- // list immutable when received!
- !isImmutableJavaScriptArray(e)) {
- writeSlot(slot, true); // Deferred copy.
- for ( ; i < length; i++) {
- var element = e[i];
- var elementCopy = walk(element);
- if (!identical(elementCopy, element)) {
- copy = readSlot(slot); // Cyclic reference may have created it.
- if (true == copy) {
- copy = JS('=List', 'new Array(#)', length);
- writeSlot(slot, copy);
- }
- for (int j = 0; j < i; j++) {
- copy[j] = e[j];
- }
- copy[i] = elementCopy;
- i++;
- break;
- }
- }
- if (copy == null) {
- copy = e;
- writeSlot(slot, copy);
- }
- } else {
- // Not a JavaScript Array. We are forced to make a copy.
- copy = JS('=List', 'new Array(#)', length);
- writeSlot(slot, copy);
- }
+ // Always clone the list, as it may have non-native properties or methods
+ // from interceptors and such.
+ copy = JS('=List', 'new Array(#)', length);
+ writeSlot(slot, copy);
for ( ; i < length; i++) {
copy[i] = walk(e[i]);
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index 31ce72b..ba5f07d 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.dart
@@ -100,7 +100,7 @@
// Only builtin Lists can be serialized through. If user-defined Lists
// get here, the contents is copied to a Uint8List. This has the added
// benefit that it is faster to access from the C code as well.
-_BufferAndStart _ensureFastAndSerializableBuffer(
+_BufferAndStart _ensureFastAndSerializableData(
List buffer, int start, int end) {
if (buffer is Uint8List ||
buffer is Int8List ||
@@ -131,6 +131,28 @@
}
+_BufferAndStart _ensureFastAndSerializableByteData(
+ List buffer, int start, int end) {
+ if (buffer is Uint8List) {
+ return new _BufferAndStart(buffer, start);
+ }
+ int length = end - start;
+ var newBuffer = new Uint8List(length);
+ int j = start;
+ for (int i = 0; i < length; i++) {
+ int value = buffer[j];
+ if (value is! int ||
+ value < 0 || 255 < value) {
+ throw new ArgumentError(
+ "List element is not a byte value (value $value at index $j)");
+ }
+ newBuffer[i] = value;
+ j++;
+ }
+ return new _BufferAndStart(newBuffer, 0);
+}
+
+
// TODO(ager): The only reason for the class here is that
// we cannot patch a top-level function.
class _BufferUtils {
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 34808d8..59695a2 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -770,7 +770,7 @@
_BufferAndStart result;
try {
- result = _ensureFastAndSerializableBuffer(buffer, start, end);
+ result = _ensureFastAndSerializableData(buffer, start, end);
} catch (e) {
return new Future.error(e);
}
@@ -805,7 +805,7 @@
if (end == start) return;
_checkReadWriteListArguments(buffer.length, start, end);
_BufferAndStart bufferAndStart =
- _ensureFastAndSerializableBuffer(buffer, start, end);
+ _ensureFastAndSerializableData(buffer, start, end);
var result = _writeFrom(_id,
bufferAndStart.buffer,
bufferAndStart.start,
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 223b246..41ab104 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -140,7 +140,7 @@
List<String> values = _headers[HttpHeaders.IF_MODIFIED_SINCE];
if (values != null) {
try {
- return _HttpUtils.parseDate(values[0]);
+ return HttpDate.parse(values[0]);
} on Exception catch (e) {
return null;
}
@@ -151,7 +151,7 @@
void set ifModifiedSince(DateTime ifModifiedSince) {
_checkMutable();
// Format "ifModifiedSince" header with date in Greenwich Mean Time (GMT).
- String formatted = _HttpUtils.formatDate(ifModifiedSince.toUtc());
+ String formatted = HttpDate.format(ifModifiedSince.toUtc());
_set(HttpHeaders.IF_MODIFIED_SINCE, formatted);
}
@@ -159,7 +159,7 @@
List<String> values = _headers[HttpHeaders.DATE];
if (values != null) {
try {
- return _HttpUtils.parseDate(values[0]);
+ return HttpDate.parse(values[0]);
} on Exception catch (e) {
return null;
}
@@ -170,7 +170,7 @@
void set date(DateTime date) {
_checkMutable();
// Format "DateTime" header with date in Greenwich Mean Time (GMT).
- String formatted = _HttpUtils.formatDate(date.toUtc());
+ String formatted = HttpDate.format(date.toUtc());
_set("date", formatted);
}
@@ -178,7 +178,7 @@
List<String> values = _headers[HttpHeaders.EXPIRES];
if (values != null) {
try {
- return _HttpUtils.parseDate(values[0]);
+ return HttpDate.parse(values[0]);
} on Exception catch (e) {
return null;
}
@@ -189,7 +189,7 @@
void set expires(DateTime expires) {
_checkMutable();
// Format "Expires" header with date in Greenwich Mean Time (GMT).
- String formatted = _HttpUtils.formatDate(expires.toUtc());
+ String formatted = HttpDate.format(expires.toUtc());
_set(HttpHeaders.EXPIRES, formatted);
}
@@ -288,7 +288,7 @@
_headers[name] = values;
}
if (value is DateTime) {
- values.add(_HttpUtils.formatDate(value));
+ values.add(HttpDate.format(value));
} else {
values.add(value.toString());
}
@@ -750,7 +750,7 @@
sb.write(value);
if (expires != null) {
sb.write("; Expires=");
- sb.write(_HttpUtils.formatDate(expires));
+ sb.write(HttpDate.format(expires));
}
if (maxAge != null) {
sb.write("; Max-Age=");
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index b272976..e82d329 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -1705,7 +1705,7 @@
}
// Default to using the process current environment.
- if (environment == null) environment = Platform.environment;
+ if (environment == null) environment = _platformEnvironmentCache;
String proxyCfg;
@@ -1730,10 +1730,12 @@
}
return "DIRECT";
}
+
+ static Map<String, String> _platformEnvironmentCache = Platform.environment;
}
-class _HttpConnection {
+class _HttpConnection extends LinkedListEntry<_HttpConnection> {
static const _ACTIVE = 0;
static const _IDLE = 1;
static const _CLOSING = 2;
@@ -1952,9 +1954,9 @@
final bool _closeServer;
// Set of currently connected clients.
- final Set<_HttpConnection> _connections = new Set<_HttpConnection>();
+ final LinkedList<_HttpConnection> _connections
+ = new LinkedList<_HttpConnection>();
StreamController<HttpRequest> _controller;
-
// TODO(ajohnsen): Use close queue?
}
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index bcd27e0..f863e4fc 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -99,13 +99,13 @@
StreamController<List<int>> controller;
final StreamSubscription subscription;
- List<int> carryOverData;
+ List<int> bufferedData;
bool paused;
Completer resumeCompleter;
_HttpDetachedIncoming(StreamSubscription this.subscription,
- List<int> this.carryOverData) {
+ List<int> this.bufferedData) {
controller = new StreamController<List<int>>(
sync: true,
onListen: resume,
@@ -114,7 +114,7 @@
onCancel: () => subscription.cancel());
if (subscription == null) {
// Socket was already closed.
- if (carryOverData != null) controller.add(carryOverData);
+ if (bufferedData != null) controller.add(bufferedData);
controller.close();
} else {
pause();
@@ -138,9 +138,9 @@
void resume() {
paused = false;
- if (carryOverData != null) {
- var data = carryOverData;
- carryOverData = null;
+ if (bufferedData != null) {
+ var data = bufferedData;
+ bufferedData = null;
controller.add(data);
// If the consumer pauses again after the carry-over data, we'll not
// continue our subscriber until the next resume.
diff --git a/sdk/lib/io/http_session.dart b/sdk/lib/io/http_session.dart
index deeebd0..85c9b3c 100644
--- a/sdk/lib/io/http_session.dart
+++ b/sdk/lib/io/http_session.dart
@@ -53,6 +53,7 @@
operator [](key) => _data[key];
void operator []=(key, value) { _data[key] = value; }
putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
+ addAll(Map other) => _data.addAll(other);
remove(key) => _data.remove(key);
void clear() => _data.clear();
void forEach(void f(key, value)) => _data.forEach(f);
diff --git a/sdk/lib/io/http_utils.dart b/sdk/lib/io/http_utils.dart
index 82db7de..487096c 100644
--- a/sdk/lib/io/http_utils.dart
+++ b/sdk/lib/io/http_utils.dart
@@ -4,112 +4,14 @@
part of dart.io;
-class _HttpUtils {
- static String decodeUrlEncodedString(
- String urlEncoded,
- {Encoding encoding: Encoding.UTF_8}) {
- // First check the string for any encoding.
- int index = 0;
- bool encoded = false;
- while (!encoded && index < urlEncoded.length) {
- encoded = urlEncoded[index] == "+" || urlEncoded[index] == "%";
- index++;
- }
- if (!encoded) return urlEncoded;
- index--;
-
- // Start decoding from the first encoded character.
- List<int> bytes = new List<int>();
- for (int i = 0; i < index; i++) bytes.add(urlEncoded.codeUnitAt(i));
- for (int i = index; i < urlEncoded.length; i++) {
- if (urlEncoded[i] == "+") {
- bytes.add(32);
- } else if (urlEncoded[i] == "%") {
- if (urlEncoded.length - i < 2) {
- throw new HttpException("Invalid URL encoding");
- }
- int byte = 0;
- for (int j = 0; j < 2; j++) {
- var charCode = urlEncoded.codeUnitAt(i + j + 1);
- if (0x30 <= charCode && charCode <= 0x39) {
- byte = byte * 16 + charCode - 0x30;
- } else {
- // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
- charCode |= 0x20;
- if (0x61 <= charCode && charCode <= 0x66) {
- byte = byte * 16 + charCode - 0x57;
- } else {
- throw new ArgumentError("Invalid URL encoding");
- }
- }
- }
- bytes.add(byte);
- i += 2;
- } else {
- bytes.add(urlEncoded.codeUnitAt(i));
- }
- }
- return _decodeString(bytes, encoding);
- }
-
- static Map<String, String> splitQueryString(
- String queryString,
- {Encoding encoding: Encoding.UTF_8}) {
- Map<String, String> result = new Map<String, String>();
- int currentPosition = 0;
- int length = queryString.length;
-
- while (currentPosition < length) {
-
- // Find the first equals character between current position and
- // the provided end.
- int indexOfEquals(int end) {
- int index = currentPosition;
- while (index < end) {
- if (queryString.codeUnitAt(index) == _CharCode.EQUAL) return index;
- index++;
- }
- return -1;
- }
-
- // Find the next separator (either & or ;), see
- // http://www.w3.org/TR/REC-html40/appendix/notes.html#ampersands-in-uris
- // relating the ; separator. If no separator is found returns
- // the length of the query string.
- int indexOfSeparator() {
- int end = length;
- int index = currentPosition;
- while (index < end) {
- int codeUnit = queryString.codeUnitAt(index);
- if (codeUnit == _CharCode.AMPERSAND ||
- codeUnit == _CharCode.SEMI_COLON) {
- return index;
- }
- index++;
- }
- return end;
- }
-
- int seppos = indexOfSeparator();
- int equalspos = indexOfEquals(seppos);
- String name;
- String value;
- if (equalspos == -1) {
- name = queryString.substring(currentPosition, seppos);
- value = '';
- } else {
- name = queryString.substring(currentPosition, equalspos);
- value = queryString.substring(equalspos + 1, seppos);
- }
- currentPosition = seppos + 1; // This also works when seppos == length.
- if (name == '') continue;
- result[_HttpUtils.decodeUrlEncodedString(name, encoding: encoding)] =
- _HttpUtils.decodeUrlEncodedString(value, encoding: encoding);
- }
- return result;
- }
-
- // From RFC 2616 section "3.3.1 Full Date"
+/**
+ * Utility functions for working with dates with HTTP specific date
+ * formats.
+ */
+class HttpDate {
+ // From RFC-2616 section "3.3.1 Full Date",
+ // http://tools.ietf.org/html/rfc2616#section-3.3.1
+ //
// HTTP-date = rfc1123-date | rfc850-date | asctime-date
// rfc1123-date = wkday "," SP date1 SP time SP "GMT"
// rfc850-date = weekday "," SP date2 SP time SP "GMT"
@@ -130,8 +32,12 @@
// | "May" | "Jun" | "Jul" | "Aug"
// | "Sep" | "Oct" | "Nov" | "Dec"
- // Format as RFC 1123 date.
- static String formatDate(DateTime date) {
+ /**
+ * Format a date according to
+ * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+ * e.g. `Thu, 1 Jan 1970 00:00:00 GMT`.
+ */
+ static String format(DateTime date) {
const List wkday = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const List month = const ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
@@ -155,7 +61,21 @@
return sb.toString();
}
- static DateTime parseDate(String date) {
+ /**
+ * Parse a date string in either of the formats
+ * [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
+ * [RFC-850](http://tools.ietf.org/html/rfc850 "RFC-850") or
+ * ANSI C's asctime() format. These formats are listed here.
+ *
+ * Thu, 1 Jan 1970 00:00:00 GMT
+ * Thursday, 1-Jan-1970 00:00:00 GMT
+ * Thu Jan 1 00:00:00 1970
+ *
+ * For more information see [RFC-2616 section 3.1.1]
+ * (http://tools.ietf.org/html/rfc2616#section-3.3.1
+ * "RFC-2616 section 3.1.1").
+ */
+ static DateTime parse(String date) {
final int SP = 32;
const List wkdays = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const List weekdays = const ["Monday", "Tuesday", "Wednesday", "Thursday",
@@ -282,6 +202,112 @@
expectEnd();
return new DateTime.utc(year, month + 1, day, hours, minutes, seconds, 0);
}
+}
+
+class _HttpUtils {
+ static String decodeUrlEncodedString(
+ String urlEncoded,
+ {Encoding encoding: Encoding.UTF_8}) {
+ // First check the string for any encoding.
+ int index = 0;
+ bool encoded = false;
+ while (!encoded && index < urlEncoded.length) {
+ encoded = urlEncoded[index] == "+" || urlEncoded[index] == "%";
+ index++;
+ }
+ if (!encoded) return urlEncoded;
+ index--;
+
+ // Start decoding from the first encoded character.
+ List<int> bytes = new List<int>();
+ for (int i = 0; i < index; i++) bytes.add(urlEncoded.codeUnitAt(i));
+ for (int i = index; i < urlEncoded.length; i++) {
+ if (urlEncoded[i] == "+") {
+ bytes.add(32);
+ } else if (urlEncoded[i] == "%") {
+ if (urlEncoded.length - i < 2) {
+ throw new HttpException("Invalid URL encoding");
+ }
+ int byte = 0;
+ for (int j = 0; j < 2; j++) {
+ var charCode = urlEncoded.codeUnitAt(i + j + 1);
+ if (0x30 <= charCode && charCode <= 0x39) {
+ byte = byte * 16 + charCode - 0x30;
+ } else {
+ // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
+ charCode |= 0x20;
+ if (0x61 <= charCode && charCode <= 0x66) {
+ byte = byte * 16 + charCode - 0x57;
+ } else {
+ throw new ArgumentError("Invalid URL encoding");
+ }
+ }
+ }
+ bytes.add(byte);
+ i += 2;
+ } else {
+ bytes.add(urlEncoded.codeUnitAt(i));
+ }
+ }
+ return _decodeString(bytes, encoding);
+ }
+
+ static Map<String, String> splitQueryString(
+ String queryString,
+ {Encoding encoding: Encoding.UTF_8}) {
+ Map<String, String> result = new Map<String, String>();
+ int currentPosition = 0;
+ int length = queryString.length;
+
+ while (currentPosition < length) {
+
+ // Find the first equals character between current position and
+ // the provided end.
+ int indexOfEquals(int end) {
+ int index = currentPosition;
+ while (index < end) {
+ if (queryString.codeUnitAt(index) == _CharCode.EQUAL) return index;
+ index++;
+ }
+ return -1;
+ }
+
+ // Find the next separator (either & or ;), see
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#ampersands-in-uris
+ // relating the ; separator. If no separator is found returns
+ // the length of the query string.
+ int indexOfSeparator() {
+ int end = length;
+ int index = currentPosition;
+ while (index < end) {
+ int codeUnit = queryString.codeUnitAt(index);
+ if (codeUnit == _CharCode.AMPERSAND ||
+ codeUnit == _CharCode.SEMI_COLON) {
+ return index;
+ }
+ index++;
+ }
+ return end;
+ }
+
+ int seppos = indexOfSeparator();
+ int equalspos = indexOfEquals(seppos);
+ String name;
+ String value;
+ if (equalspos == -1) {
+ name = queryString.substring(currentPosition, seppos);
+ value = '';
+ } else {
+ name = queryString.substring(currentPosition, equalspos);
+ value = queryString.substring(equalspos + 1, seppos);
+ }
+ currentPosition = seppos + 1; // This also works when seppos == length.
+ if (name == '') continue;
+ result[_HttpUtils.decodeUrlEncodedString(name, encoding: encoding)] =
+ _HttpUtils.decodeUrlEncodedString(value, encoding: encoding);
+ }
+ return result;
+ }
static DateTime parseCookieDate(String date) {
const List monthsLowerCase = const ["jan", "feb", "mar", "apr", "may",
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 6c1d699..3e69849 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -13,10 +13,9 @@
library dart.io;
import 'dart:async';
-import 'dart:collection' show Queue,
- LinkedHashSet,
- DoubleLinkedQueue,
- DoubleLinkedQueueEntry;
+import 'dart:collection' show LinkedHashSet,
+ LinkedList,
+ LinkedListEntry;
import 'dart:isolate';
import 'dart:json' as JSON;
import 'dart:math';
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index cee4e38..89fc2a0 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -80,6 +80,9 @@
V putIfAbsent(String key, V ifAbsent()) {
_map.putIfAbsent(key.toUpperCase(), ifAbsent);
}
+ addAll(Map other) {
+ other.forEach((key, value) => this[key.toUpperCase()] = value);
+ }
V remove(String key) => _map.remove(key.toUpperCase());
void clear() => _map.clear();
void forEach(void f(String key, V value)) => _map.forEach(f);
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 808bce5..6c79c12 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -115,13 +115,16 @@
* passed in.
*
* If [runInShell] is true, the process will be spawned through a system
- * shell. On Linux and Mac OS, [:/bin/sh:] is used, while
- * [:%WINDIR%\system32\cmd.exe:] is used on Windows.
+ * shell. On Linux and Mac OS, `/bin/sh` is used, while
+ * `%WINDIR%\system32\cmd.exe` is used on Windows.
*
- * The encoding used for text on stdout and stderr can be set by changing
- * [stdoutEncoding] and [stderrEncoding]. The default encoding is SYSTEM.
+ * The encoding used for decoding `stdout` and `stderr` into text is
+ * controlled through [stdoutEncoding] and [stderrEncoding]. The
+ * default encoding is `Encoding.SYSTEM`. If `null` is used no
+ * decoding will happen and the [ProcessResult] will hold binary
+ * data.
*
- * Returns a [:Future<ProcessResult>:] that completes with the
+ * Returns a `Future<ProcessResult>` that completes with the
* result of running the process, i.e., exit code, standard out and
* standard in.
*/
@@ -200,14 +203,20 @@
int get exitCode;
/**
- * Standard output from the process as a string.
+ * Standard output from the process. The value used for the
+ * `stdoutEncoding` argument to `Process.run` determins the type. If
+ * `null` was used this value is of type `List<int> otherwise it is
+ * of type `String`.
*/
- String get stdout;
+ get stdout;
/**
- * Standard error from the process as a string.
+ * Standard error from the process. The value used for the
+ * `stderrEncoding` argument to `Process.run` determins the type. If
+ * `null` was used this value is of type `List<int>
+ * otherwise it is of type `String`.
*/
- String get stderr;
+ get stderr;
/**
* Process id from the process.
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 05ec18c..d6f5734 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -103,7 +103,7 @@
* the right thing to do.
*
* If some of the data of the TLS handshake has already been read
- * from the socket this data can be passed in the [carryOverData]
+ * from the socket this data can be passed in the [bufferedData]
* parameter. This data will be processed before any other data
* available on the socket.
*
@@ -114,7 +114,7 @@
static Future<SecureSocket> secureServer(
Socket socket,
String certificateName,
- {List<int> carryOverData,
+ {List<int> bufferedData,
bool requestClientCertificate: false,
bool requireClientCertificate: false}) {
var completer = new Completer();
@@ -124,7 +124,7 @@
detachedRaw[0],
certificateName,
subscription: detachedRaw[1],
- carryOverData: carryOverData,
+ bufferedData: bufferedData,
requestClientCertificate: requestClientCertificate,
requireClientCertificate: requireClientCertificate);
})
@@ -284,7 +284,7 @@
* events.
*
* If some of the data of the TLS handshake has already been read
- * from the socket this data can be passed in the [carryOverData]
+ * from the socket this data can be passed in the [bufferedData]
* parameter. This data will be processed before any other data
* available on the socket.
*
@@ -296,7 +296,7 @@
RawSocket socket,
String certificateName,
{StreamSubscription subscription,
- List<int> carryOverData,
+ List<int> bufferedData,
bool requestClientCertificate: false,
bool requireClientCertificate: false}) {
socket.readEventsEnabled = false;
@@ -308,7 +308,7 @@
is_server: true,
socket: socket,
subscription: subscription,
- carryOverData: carryOverData,
+ bufferedData: bufferedData,
requestClientCertificate: requestClientCertificate,
requireClientCertificate: requireClientCertificate);
}
@@ -362,8 +362,8 @@
StreamController<RawSocketEvent> _controller;
Stream<RawSocketEvent> _stream;
StreamSubscription<RawSocketEvent> _socketSubscription;
- List<int> _carryOverData;
- int _carryOverDataIndex = 0;
+ List<int> _bufferedData;
+ int _bufferedDataIndex = 0;
final InternetAddress address;
final bool is_server;
final String certificateName;
@@ -391,7 +391,7 @@
{bool is_server,
RawSocket socket,
StreamSubscription subscription,
- List<int> carryOverData,
+ List<int> bufferedData,
bool requestClientCertificate: false,
bool requireClientCertificate: false,
bool sendClientCertificate: false,
@@ -409,7 +409,7 @@
is_server,
socket,
subscription,
- carryOverData,
+ bufferedData,
requestClientCertificate,
requireClientCertificate,
sendClientCertificate,
@@ -425,7 +425,7 @@
bool this.is_server,
RawSocket socket,
StreamSubscription this._socketSubscription,
- List<int> this._carryOverData,
+ List<int> this._bufferedData,
bool this.requestClientCertificate,
bool this.requireClientCertificate,
bool this.sendClientCertificate,
@@ -441,7 +441,7 @@
// errors will be reported through the future or the stream.
_verifyFields();
_secureFilter.init();
- if (_carryOverData != null) _readFromCarryOver();
+ if (_bufferedData != null) _readFromBuffered();
_secureFilter.registerHandshakeCompleteCallback(
_secureHandshakeCompleteHandler);
if (onBadCertificate != null) {
@@ -723,19 +723,19 @@
}
}
- void _readFromCarryOver() {
- assert(_carryOverData != null);
+ void _readFromBuffered() {
+ assert(_bufferedData != null);
var encrypted = _secureFilter.buffers[READ_ENCRYPTED];
- var bytes = _carryOverData.length - _carryOverDataIndex;
+ var bytes = _bufferedData.length - _bufferedDataIndex;
int startIndex = encrypted.start + encrypted.length;
encrypted.data.setRange(startIndex,
startIndex + bytes,
- _carryOverData,
- _carryOverDataIndex);
+ _bufferedData,
+ _bufferedDataIndex);
encrypted.length += bytes;
- _carryOverDataIndex += bytes;
- if (_carryOverData.length == _carryOverDataIndex) {
- _carryOverData = null;
+ _bufferedDataIndex += bytes;
+ if (_bufferedData.length == _bufferedDataIndex) {
+ _bufferedData = null;
}
}
@@ -873,8 +873,8 @@
}
}
if (!_socketClosedRead && encrypted.free > 0) {
- if (_carryOverData != null) {
- _readFromCarryOver();
+ if (_bufferedData != null) {
+ _readFromBuffered();
progress = true;
} else {
List<int> data = _socket.read(encrypted.free);
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 3072f5c..5a7981e 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -4,25 +4,29 @@
part of dart.io;
-class _Timer implements Timer {
- // Set jitter to wake up timer events that would happen in _TIMER_JITTER ms.
- static const int _TIMER_JITTER = 0;
-
+class _Timer extends LinkedListEntry<_Timer> implements Timer {
// Disables the timer.
static const int _NO_TIMER = -1;
+ // Timers are ordered by wakeup time.
+ static LinkedList<_Timer> _timers = new LinkedList<_Timer>();
+
+ static ReceivePort _receivePort;
+ static bool _handling_callbacks = false;
+
+ Function _callback;
+ int _milliSeconds;
+ int _wakeupTime;
+
static Timer _createTimer(void callback(Timer timer),
- int milliSeconds,
- bool repeating) {
+ int milliSeconds,
+ bool repeating) {
_EventHandler._start();
- if (_timers == null) {
- _timers = new DoubleLinkedQueue<_Timer>();
- }
_Timer timer = new _Timer._internal();
timer._callback = callback;
- timer._milliSeconds = milliSeconds;
- timer._wakeupTime = (new DateTime.now()).millisecondsSinceEpoch + milliSeconds;
- timer._repeating = repeating;
+ timer._wakeupTime =
+ new DateTime.now().millisecondsSinceEpoch + milliSeconds;
+ timer._milliSeconds = repeating ? milliSeconds : -1;
timer._addTimerToList();
timer._notifyEventHandler();
return timer;
@@ -42,50 +46,43 @@
_callback = null;
_milliSeconds = 0;
_wakeupTime = 0;
- _repeating = false;
}
+ bool get _repeating => _milliSeconds >= 0;
+
// Cancels a set timer. The timer is removed from the timer list and if
// the given timer is the earliest timer the native timer is reset.
void cancel() {
_clear();
- DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
- DoubleLinkedQueueEntry<_Timer> first = _timers.firstEntry();
-
- while (entry != null) {
- if (identical(entry.element, this)) {
- entry.remove();
- if (first.element == this) {
- entry = _timers.firstEntry();
- _notifyEventHandler();
- }
- return;
- }
- entry = entry.nextEntry();
+ // Return if already canceled.
+ if (list == null) return;
+ assert(!_timers.isEmpty);
+ _Timer first = _timers.first;
+ unlink();
+ if (identical(first, this)) {
+ _notifyEventHandler();
}
}
void _advanceWakeupTime() {
+ assert(_milliSeconds >= 0);
_wakeupTime += _milliSeconds;
}
// Adds a timer to the timer list and resets the native timer if it is the
- // earliest timer in the list. Timers with the same wakeup time are enqueued
+ // earliest timer in the list. Timers with the same wakeup time are enqueued
// in order and notified in FIFO order.
void _addTimerToList() {
- if (_callback != null) {
-
- DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
- while (entry != null) {
- if (_wakeupTime < entry.element._wakeupTime) {
- entry.prepend(this);
- return;
- }
- entry = entry.nextEntry();
+ _Timer entry = _timers.isEmpty ? null : _timers.first;
+ while (entry != null) {
+ if (_wakeupTime < entry._wakeupTime) {
+ entry.insertBefore(this);
+ return;
}
- _timers.add(this);
+ entry = entry.next;
}
+ _timers.add(this);
}
@@ -97,7 +94,7 @@
return;
}
- if (_timers.firstEntry() == null) {
+ if (_timers.isEmpty) {
// No pending timers: Close the receive port and let the event handler
// know.
if (_receivePort != null) {
@@ -112,7 +109,7 @@
}
_EventHandler._sendData(null,
_receivePort,
- _timers.firstEntry().element._wakeupTime);
+ _timers.first._wakeupTime);
}
}
@@ -122,18 +119,15 @@
void _createTimerHandler() {
void _handleTimeout() {
- int currentTime =
- (new DateTime.now()).millisecondsSinceEpoch + _TIMER_JITTER;
+ int currentTime = new DateTime.now().millisecondsSinceEpoch;
// Collect all pending timers.
- DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
var pending_timers = new List();
- while (entry != null) {
- _Timer timer = entry.element;
- if (timer._wakeupTime <= currentTime) {
- entry.remove();
- pending_timers.add(timer);
- entry = _timers.firstEntry();
+ while (!_timers.isEmpty) {
+ _Timer entry = _timers.first;
+ if (entry._wakeupTime <= currentTime) {
+ entry.unlink();
+ pending_timers.add(entry);
} else {
break;
}
@@ -174,18 +168,6 @@
_receivePort.close();
_receivePort = null;
}
-
-
- // Timers are ordered by wakeup time.
- static DoubleLinkedQueue<_Timer> _timers;
-
- static ReceivePort _receivePort;
- static bool _handling_callbacks = false;
-
- var _callback;
- int _milliSeconds;
- int _wakeupTime;
- bool _repeating;
}
// Provide a closure which will allocate a Timer object to be able to hook
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 8108084..d903061 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -531,9 +531,27 @@
header.setRange(index, index + 4, maskBytes);
index += 4;
if (data != null) {
- var list = new Uint8List(data.length);
- for (int i = 0; i < data.length; i++) {
- list[i] = data[i] ^ maskBytes[i % 4];
+ var list;
+ // If this is a text message just do the masking inside the
+ // encoded data.
+ if (opcode == _WebSocketOpcode.TEXT) {
+ list = data;
+ } else {
+ list = new Uint8List(data.length);
+ }
+ if (data is Uint8List) {
+ for (int i = 0; i < data.length; i++) {
+ list[i] = data[i] ^ maskBytes[i % 4];
+ }
+ } else {
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] < 0 || 255 < data[i]) {
+ throw new ArgumentError(
+ "List element is not a byte value "
+ "(value ${data[i]} at index $i)");
+ }
+ list[i] = data[i] ^ maskBytes[i % 4];
+ }
}
data = list;
}
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 7a856a4..8e13499 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -404,6 +404,8 @@
Language/11_Expressions/18_Assignment_A05_t05: Fail, OK # co19 issue 409
Language/11_Expressions/18_Assignment_A08_t04: Fail, OK # co19 issue 409
+LibTest/core/String/indexOf_A01_t02: Fail # Issue 427
+LibTest/core/String/lastIndexOf_A01_t02: Fail # Issue 427
[ $compiler == dart2dart && $minified ]
Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 396
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index b2f3f82..fb5aa0d 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -257,9 +257,7 @@
LibTest/core/AssertionError/failedAssertion_A01_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/AssertionError/line_A01_t02: Fail # TODO(ahe): Please triage this failure.
LibTest/core/AssertionError/url_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/Match/pattern_A01_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/Match/str_A01_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/RegExp/allMatches_A01_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/Set/intersection_A03_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/TypeError/column_A01_t01: Fail # TODO(ahe): Please triage this failure.
LibTest/core/TypeError/dstName_A01_t01: Fail # TODO(ahe): Please triage this failure.
@@ -537,6 +535,11 @@
Language/14_Types/5_Function_Types_A01_t10: Fail # co19 issue 410
Language/14_Types/5_Function_Types_A02_t06: Fail # co19 issue 410
+LibTest/core/Match/pattern_A01_t01: Fail # co19 Issue 400, 422
+LibTest/core/RegExp/allMatches_A01_t01: Fail # co19 Issue 400, 422
+
+LibTest/core/String/indexOf_A01_t02: Fail # Issue 427
+LibTest/core/String/lastIndexOf_A01_t02: Fail # Issue 427
[ $compiler == dart2js && $unchecked ]
LibTest/core/List/setRange_A05_t01: Fail # setRange throws StateError if there aren't enough elements in the iterable. Issue 402
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 960a6cb..b38e62f 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -6,17 +6,6 @@
Language/11_Expressions/33_Argument_Definition_Test_A02_t02: Crash, Pass # http://dartbug.com/9597
Language/07_Classes/6_Constructors_A02_t01: Skip # co19 issue 415.
-[ $compiler == none && $runtime == vm && $unchecked ]
-Language/11_Expressions/11_Instance_Creation_A05_t02: Fail # TODO(vm-team): Please triage this failure.
-
-
-[ $compiler == none && $runtime == vm && $checked ]
-LibTest/core/AssertionError/line_A01_t02: Fail # TODO(vm-team): Please triage this failure.
-LibTest/core/Set/intersection_A03_t01: Fail # TODO(vm-team): Please triage this failure.
-LibTest/core/TypeError/line_A01_t01: Fail # TODO(vm-team): Please triage this failure.
-
-
-
[ $compiler == none && $runtime == vm ]
Language/05_Variables/05_Variables_A07_t01: Fail # TODO(vm-team): Please triage this failure.
Language/05_Variables/05_Variables_A07_t02: Fail # TODO(vm-team): Please triage this failure.
@@ -70,29 +59,6 @@
LibTest/core/Match/pattern_A01_t01: Fail # Issue 422
LibTest/core/RegExp/allMatches_A01_t01: Fail # Issue 422
-[ $compiler == none && $runtime == vm && $checked ]
-LibTest/core/Strings/concatAll_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. co19 issue 366
-LibTest/core/Strings/join_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. co19 issue 366
-
-LibTest/core/int/operator_division_A01_t01: Fail # ~/ returns ints, issue 361
-
-Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t01: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t03: Fail, OK # co19 issue 405
-Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t04: Fail, OK # co19 issue 405
-Language/11_Expressions/17_Getter_Invocation_A02_t01: Fail, OK # co19 issue 405
-Language/11_Expressions/17_Getter_Invocation_A02_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/18_Assignment_A05_t02: Fail, OK # co19 issue 405
-Language/11_Expressions/18_Assignment_A05_t04: Fail, OK # co19 issue 405
-Language/11_Expressions/18_Assignment_A05_t05: Fail, OK # co19 issue 405
-Language/11_Expressions/18_Assignment_A08_t04: Fail, OK # co19 issue 405
-
-
-[ $compiler == none && $runtime == vm ]
Language/13_Libraries_and_Scripts/1_Imports_A02_t21: Crash # Dart issue 6060
Language/13_Libraries_and_Scripts/1_Imports_A02_t22: Crash # Dart issue 6060
@@ -107,11 +73,8 @@
Language/07_Classes/4_Abstract_Instance_Members_A04_t05: Fail # Dart issue 978
Language/07_Classes/4_Abstract_Instance_Members_A04_t06: Fail # Dart issue 978
Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: Fail # Dart issue 6954
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t01: Fail # Dart issue 811
Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t02: Fail # Dart issue 811
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A04_t03: Fail # Dart issue 811
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: Fail # Dart issue 811
-Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: Fail # Dart issue 811
+Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t01: Fail # co19 issue 426
Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t04: Fail # Dart issue 7246
Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t05: Fail # Dart issue 7246
Language/11_Expressions/05_Strings/1_String_Interpolation_A01_t06: Fail # Dart issue 7246
@@ -233,12 +196,6 @@
Language/11_Expressions/18_Assignment_A05_t05: Fail, OK # co19 issue 409
Language/11_Expressions/18_Assignment_A08_t04: Fail, OK # co19 issue 409
-
-[ $compiler == none && $runtime == vm && $checked ]
-Language/12_Statements/09_Switch_A05_t01: Fail # TODO(vm-team): Please triage this failure.
-
-
-[ $compiler == none && $runtime == vm ]
Language/11_Expressions/01_Constants_A16_t01: Fail # Not properly reporting exception in initializer expressions
Language/11_Expressions/01_Constants_A16_t02: Fail # Not properly reporting exception in initializer expressions
@@ -282,8 +239,6 @@
LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterEscape_A06_t02: Fail
-
-[ $compiler == none && $runtime == vm ]
LibTest/core/Date/Date.fromString_A03_t01: Pass # Issue co19 - 121 (currently passing due to co19 issues 373 and 374)
LibTest/core/Match/operator_subscript_A01_t01: Fail
LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t05: Fail
@@ -292,33 +247,8 @@
LibTest/core/double/toRadixString_A01_t01: Fail # Issue 463
LibTest/core/int/toRadixString_A01_t01: Fail # Issue 461
-
-[ $compiler == none && $runtime == vm ]
LibTest/math/sin_A01_t01: Fail, OK # Issue co19 - 44
-
-[ $compiler == none && $runtime == vm && $system == macos ]
-LibTest/math/exp_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/acos_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/asin_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/atan_A01_t01: Fail, OK # Issue co19 - 44
-LibTest/math/tan_A01_t01: Fail, OK # Issue co19 - 44
-
-
-[ $compiler == none && $runtime == vm && $system == linux ]
-LibTest/math/exp_A01_t01: Fail
-
-
-[ $compiler == none && $runtime == vm && $system == linux && $arch == ia32 ]
-LibTest/math/sin_A01_t01: Fail
-LibTest/math/tan_A01_t01: Fail
-
-
-[ $compiler == none && $runtime == vm && $arch == x64 && $mode == debug ]
-LibTest/core/Map/Map_class_A01_t04: Skip # Timeout
-
-
-[ $compiler == none && $runtime == vm ]
LibTest/core/Date/toString_A02_t01: Fail # Argument error. Year 999999 is out of range. Needs to be specified (and then potentially reported to co19): issue 1878.
LibTest/core/Date/year_A01_t01: Fail # Year out of range. Needs to be specified: issue 8808. Possibly a co19 bug.
@@ -333,18 +263,10 @@
Language/11_Expressions/07_Maps_A07_t03: Fail, OK # co19 issue 287
Language/11_Expressions/07_Maps_A04_t02: Fail, OK # co19 issue 287
-
-[ $compiler == none && $runtime == vm ]
LibTest/core/String/contains_A01_t03: Skip # Times out.
LibTest/core/String/contains_A01_t02: Fail
-
-[ $compiler == none && $runtime == vm && $arch == ia32 ]
-LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
-
-
-[ $compiler == none && $runtime == vm ]
Language/07_Classes/07_Classes_A02_t29: Fail
Language/07_Classes/07_Classes_A02_t31: Fail
Language/11_Expressions/05_Strings_A20_t01: Fail
@@ -358,16 +280,6 @@
# parameter name or type expected
Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t07: Fail
-
-[ $compiler == none && $runtime == vm && $checked ]
-Language/03_Overview/1_Scoping_A02_t30: Fail
-
-
-[ $compiler == none && $runtime == vm && $mode == debug ]
-LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
-
-
-[ $compiler == none && $runtime == vm ]
LibTest/core/Strings/join_A01_t01: Fail # Strings class has been removed. co19 issue 380
LibTest/core/Strings/join_A04_t01: Fail # Strings class has been removed. co19 issue 380
LibTest/core/Strings/concatAll_A01_t01: Fail # Strings class has been removed. co19 issue 380
@@ -491,7 +403,47 @@
LibTest/async/Future/then_A01_t01: Fail # Completer is now asynchronous. Issue 419
LibTest/async/Future/then_A01_t04: Fail # Completer is now asynchronous. Issue 419
+LibTest/core/String/indexOf_A01_t02: Fail # Issue 427
+LibTest/core/String/lastIndexOf_A01_t02: Fail # Issue 427
+
+# end [ $compiler == none && $runtime == vm ]
+
+
+[ $compiler == none && $runtime == vm && $unchecked ]
+Language/11_Expressions/11_Instance_Creation_A05_t02: Fail # TODO(vm-team): Please triage this failure.
+
+LibTest/core/List/setRange_A05_t01: Fail # setRange now takes end-argument. Issue 402
+
+
[ $compiler == none && $runtime == vm && $checked ]
+LibTest/core/AssertionError/line_A01_t02: Fail # TODO(vm-team): Please triage this failure.
+LibTest/core/Set/intersection_A03_t01: Fail # TODO(vm-team): Please triage this failure.
+LibTest/core/TypeError/line_A01_t01: Fail # TODO(vm-team): Please triage this failure.
+
+LibTest/core/Strings/concatAll_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. co19 issue 366
+LibTest/core/Strings/join_A04_t01: Fail, OK # checks for ArgumentError. TypeError is ok too. co19 issue 366
+
+LibTest/core/int/operator_division_A01_t01: Fail # ~/ returns ints, issue 361
+
+Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t02: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t03: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t06: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t01: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t02: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t03: Fail, OK # co19 issue 405
+Language/11_Expressions/15_Method_Invocation/4_Super_Invocation_A04_t04: Fail, OK # co19 issue 405
+Language/11_Expressions/17_Getter_Invocation_A02_t01: Fail, OK # co19 issue 405
+Language/11_Expressions/17_Getter_Invocation_A02_t02: Fail, OK # co19 issue 405
+Language/11_Expressions/18_Assignment_A05_t02: Fail, OK # co19 issue 405
+Language/11_Expressions/18_Assignment_A05_t04: Fail, OK # co19 issue 405
+Language/11_Expressions/18_Assignment_A05_t05: Fail, OK # co19 issue 405
+Language/11_Expressions/18_Assignment_A08_t04: Fail, OK # co19 issue 405
+
+Language/12_Statements/09_Switch_A05_t01: Fail # TODO(vm-team): Please triage this failure.
+
+Language/03_Overview/1_Scoping_A02_t30: Fail
+
LibTest/core/Set/intersection_A01_t01: Fail # issue 390
LibTest/core/Set/intersection_A01_t02: Fail # issue 390
LibTest/core/Set/intersection_A01_t03: Fail # issue 390
@@ -506,50 +458,76 @@
LibTest/async/Future/catchError_A01_t01: Fail # No AsyncError anymore. Issue 407
LibTest/async/Future/catchError_A01_t02: Fail # No AsyncError anymore. Issue 407
-[ $compiler == none && $runtime == vm && $unchecked ]
-LibTest/core/List/setRange_A05_t01: Fail # setRange now takes end-argument. Issue 402
+#end [ $compiler == none && $runtime == vm && $checked ]
+
+
+[ $compiler == none && $runtime == vm && $mode == debug ]
+LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
+
+
+[ $compiler == none && $runtime == vm && $system == macos ]
+LibTest/math/exp_A01_t01: Fail, OK # Issue co19 - 44
+LibTest/math/acos_A01_t01: Fail, OK # Issue co19 - 44
+LibTest/math/asin_A01_t01: Fail, OK # Issue co19 - 44
+LibTest/math/atan_A01_t01: Fail, OK # Issue co19 - 44
+LibTest/math/tan_A01_t01: Fail, OK # Issue co19 - 44
+
+
+[ $compiler == none && $runtime == vm && $system == linux ]
+LibTest/math/exp_A01_t01: Fail
+
+
+[ $compiler == none && $runtime == vm && $system == linux && $arch == ia32 ]
+LibTest/math/sin_A01_t01: Fail
+LibTest/math/tan_A01_t01: Fail
+
+
+[ $compiler == none && $runtime == vm && $arch == x64 && $mode == debug ]
+LibTest/core/Map/Map_class_A01_t04: Skip # Timeout
+
+
+[ $compiler == none && $runtime == vm && $arch == ia32 ]
+LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
+
[ $compiler == none && $runtime == vm && $arch == arm ]
LibTest/math/tan_A01_t01: Pass, Fail
-LibTest/math/cos_A01_t01: Pass, Fail
LibTest/math/sin_A01_t01: Pass, Fail
-LibTest/math/Random/nextDouble_A01_t01: Pass, Crash, Fail
-LibTest/core/int/operator_left_shift_A01_t02: Fail
-LibTest/core/int/operator_unary_minus_A01_t01: Fail, Pass
+LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
+LibTest/core/int/operator_unary_minus_A01_t01: Pass, Fail
+LibTest/math/Random/nextDouble_A01_t01: Pass, Fail
+
[ $compiler == none && $runtime == vm && $arch == arm && $mode == debug ]
LibTest/core/Expect/throws_A01_t04: Crash
-LibTest/core/List/sort_A01_t04: Crash
LibTest/core/List/sort_A01_t05: Crash
LibTest/core/List/sort_A01_t06: Crash
-LibTest/core/double/ceil_A01_t02: Fail, Pass
-LibTest/core/double/floor_A01_t02: Fail, Pass
-LibTest/core/double/truncate_A01_t01: Fail, Pass
-LibTest/core/int/operator_left_shift_A01_t02: Fail
-LibTest/core/int/operator_unary_minus_A01_t01: Fail, Pass
+LibTest/core/double/ceil_A01_t02: Fail
+LibTest/core/double/floor_A01_t02: Fail
+LibTest/core/double/truncate_A01_t01: Fail
+
[ $compiler == none && $runtime == vm && $arch == simarm ]
LibTest/math/tan_A01_t01: Pass, Fail
-LibTest/math/cos_A01_t01: Pass, Fail
-LibTest/math/sin_A01_t01: Pass, Fail
-LibTest/math/Random/nextDouble_A01_t01: Pass, Crash, Fail
-LibTest/core/int/operator_left_shift_A01_t02: Fail
-LibTest/core/int/operator_unary_minus_A01_t01: Fail, Pass
+LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
+LibTest/core/int/operator_unary_minus_A01_t01: Fail, Pass # Pass on Mac
+LibTest/math/cos_A01_t01: Pass, Fail # Fail on Mac
+LibTest/math/Random/nextDouble_A01_t01: Pass, Crash
+
[ $compiler == none && $runtime == vm && $arch == simarm && $mode == debug ]
LibTest/core/Expect/throws_A01_t04: Crash
-LibTest/core/List/sort_A01_t04: Crash
LibTest/core/List/sort_A01_t05: Crash
LibTest/core/List/sort_A01_t06: Crash
-LibTest/core/double/ceil_A01_t02: Fail, Pass
-LibTest/core/double/floor_A01_t02: Fail, Pass
-LibTest/core/double/truncate_A01_t01: Fail, Pass
-LibTest/core/int/operator_left_shift_A01_t02: Fail
-LibTest/core/int/operator_unary_minus_A01_t01: Fail, Pass
+LibTest/core/double/ceil_A01_t02: Fail, Pass # Pass on Mac
+LibTest/core/double/floor_A01_t02: Fail, Pass # Pass on Mac
+LibTest/core/double/truncate_A01_t01: Fail, Pass # Pass on Mac
+
[ $compiler == none && $runtime == vm && $arch == mips ]
*: Skip
+
[ $compiler == none && $runtime == vm && $arch == simmips ]
*: Skip
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index c801442..581b26b 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -33,7 +33,8 @@
var parameter =
printElement.computeSignature(compiler).requiredParameters.head;
var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
- Expect.isNull(type);
+ var inferrer = compiler.typesTask.typesInferrer;
+ Expect.identical(inferrer.dynamicType, type);
});
compileAndFind(
diff --git a/tests/compiler/dart2js/generate_at_use_site_test.dart b/tests/compiler/dart2js/generate_at_use_site_test.dart
index 8204f6a..573b302 100644
--- a/tests/compiler/dart2js/generate_at_use_site_test.dart
+++ b/tests/compiler/dart2js/generate_at_use_site_test.dart
@@ -2,6 +2,7 @@
// 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:expect/expect.dart";
import 'compiler_helper.dart';
const String FIB = r"""
@@ -34,6 +35,19 @@
}
""";
+// Test that a synthesized [HTypeConversion] node added due to the is
+// check is code motion invariant. No 'else' should be generated in
+// this code snippet (the new [HTypeConversion] is put in the else
+// branch, but the else branch dominates the rest of the code in this
+// snippet).
+const String TEST = r"""
+foo(a) {
+ if (a is !int) throw a;
+ if (a < 0) throw a;
+ return a + a;
+}
+""";
+
main() {
// Make sure we don't introduce a new variable.
RegExp regexp = new RegExp("var $anyIdentifier =");
@@ -41,4 +55,10 @@
regexp = new RegExp("isLeaf");
compileAndDoNotMatch(BAR, 'bar', regexp);
+
+ String generated = compile(TEST, entry: 'foo');
+ Expect.isFalse(generated.contains('else'));
+ // Regression check to ensure that there is no floating variable
+ // expression.
+ Expect.isFalse(new RegExp('^[ ]*a;').hasMatch(generated));
}
diff --git a/tests/compiler/dart2js/gvn_test.dart b/tests/compiler/dart2js/gvn_test.dart
index b580aca..b648bca 100644
--- a/tests/compiler/dart2js/gvn_test.dart
+++ b/tests/compiler/dart2js/gvn_test.dart
@@ -41,6 +41,25 @@
}
""";
+// Check that [HCheck] instructions do not prevent GVN.
+const String TEST_FIVE = r"""
+class A {
+ var foo = 21;
+}
+
+class B {}
+
+main() {
+ var a = [new B(), new A()][0];
+ var b = a.foo;
+ var c = a.foo;
+ if (a is B) {
+ c = a.foo;
+ }
+ return b + c;
+}
+""";
+
main() {
String generated = compile(TEST_ONE, entry: 'foo');
RegExp regexp = new RegExp(r"1 \+ [a-z]+");
@@ -54,4 +73,8 @@
generated = compile(TEST_FOUR, entry: 'foo');
checkNumberOfMatches(new RegExp("shr").allMatches(generated).iterator, 1);
+
+ generated = compileAll(TEST_FIVE);
+ checkNumberOfMatches(
+ new RegExp("get\\\$foo").allMatches(generated).iterator, 1);
}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 7102f8b..08a8630 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -1139,7 +1139,9 @@
ClassElement classElement = element;
classElement.ensureResolved(compiler);
// Analyze last class member.
- classElement.forEachLocalMember((Element e) => element = e);
+ classElement.forEachLocalMember((Element e) {
+ if (!e.isSynthesized) element = e;
+ });
}
Node node = element.parseNode(compiler);
TreeElements mapping = compiler.resolver.resolve(element);
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index 3fea40e..f1a1366 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -14,17 +14,10 @@
const NUMBER = HType.NUMBER;
const INTEGER = HType.INTEGER;
const DOUBLE = HType.DOUBLE;
-const INDEXABLE_PRIMITIVE = HType.INDEXABLE_PRIMITIVE;
-const STRING = HType.STRING;
-const READABLE_ARRAY = HType.READABLE_ARRAY;
-const MUTABLE_ARRAY = HType.MUTABLE_ARRAY;
-const FIXED_ARRAY = HType.FIXED_ARRAY;
-const EXTENDABLE_ARRAY = HType.EXTENDABLE_ARRAY;
const BOOLEAN_OR_NULL = HType.BOOLEAN_OR_NULL;
const NUMBER_OR_NULL = HType.NUMBER_OR_NULL;
const INTEGER_OR_NULL = HType.INTEGER_OR_NULL;
const DOUBLE_OR_NULL = HType.DOUBLE_OR_NULL;
-const STRING_OR_NULL = HType.STRING_OR_NULL;
const NULL = HType.NULL;
const NON_NULL = HType.NON_NULL;
@@ -35,6 +28,13 @@
HType potentialString;
HType jsInterceptor;
+HType jsIndexable;
+HType jsReadableArray;
+HType jsMutableArray;
+HType jsFixedArray;
+HType jsExtendableArray;
+HType jsString;
+HType jsStringOrNull;
HType jsArrayOrNull;
HType jsMutableArrayOrNull;
HType jsFixedArrayOrNull;
@@ -107,11 +107,11 @@
rule(CONFLICTING, NUMBER, NUMBER);
rule(CONFLICTING, INTEGER, INTEGER);
rule(CONFLICTING, DOUBLE, DOUBLE);
- rule(CONFLICTING, INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE);
- rule(CONFLICTING, STRING, STRING);
- rule(CONFLICTING, READABLE_ARRAY, READABLE_ARRAY);
- rule(CONFLICTING, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(CONFLICTING, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
+ rule(CONFLICTING, jsIndexable, jsIndexable);
+ rule(CONFLICTING, jsString, jsString);
+ rule(CONFLICTING, jsReadableArray, jsReadableArray);
+ rule(CONFLICTING, jsMutableArray, jsMutableArray);
+ rule(CONFLICTING, jsExtendableArray, jsExtendableArray);
rule(CONFLICTING, nonPrimitive1, nonPrimitive1);
rule(CONFLICTING, nonPrimitive2, nonPrimitive2);
rule(CONFLICTING, potentialArray, potentialArray);
@@ -120,20 +120,20 @@
rule(CONFLICTING, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(CONFLICTING, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(CONFLICTING, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(CONFLICTING, STRING_OR_NULL, STRING_OR_NULL);
+ rule(CONFLICTING, jsStringOrNull, jsStringOrNull);
rule(CONFLICTING, NULL, NULL);
- rule(CONFLICTING, FIXED_ARRAY, FIXED_ARRAY);
+ rule(CONFLICTING, jsFixedArray, jsFixedArray);
rule(UNKNOWN, UNKNOWN, UNKNOWN);
rule(UNKNOWN, BOOLEAN, UNKNOWN);
rule(UNKNOWN, NUMBER, UNKNOWN);
rule(UNKNOWN, INTEGER, UNKNOWN);
rule(UNKNOWN, DOUBLE, UNKNOWN);
- rule(UNKNOWN, INDEXABLE_PRIMITIVE, UNKNOWN);
- rule(UNKNOWN, STRING, UNKNOWN);
- rule(UNKNOWN, READABLE_ARRAY, UNKNOWN);
- rule(UNKNOWN, MUTABLE_ARRAY, UNKNOWN);
- rule(UNKNOWN, EXTENDABLE_ARRAY, UNKNOWN);
+ rule(UNKNOWN, jsIndexable, UNKNOWN);
+ rule(UNKNOWN, jsString, UNKNOWN);
+ rule(UNKNOWN, jsReadableArray, UNKNOWN);
+ rule(UNKNOWN, jsMutableArray, UNKNOWN);
+ rule(UNKNOWN, jsExtendableArray, UNKNOWN);
rule(UNKNOWN, nonPrimitive1, UNKNOWN);
rule(UNKNOWN, nonPrimitive2, UNKNOWN);
rule(UNKNOWN, potentialArray, UNKNOWN);
@@ -142,19 +142,19 @@
rule(UNKNOWN, NUMBER_OR_NULL, UNKNOWN);
rule(UNKNOWN, INTEGER_OR_NULL, UNKNOWN);
rule(UNKNOWN, DOUBLE_OR_NULL, UNKNOWN);
- rule(UNKNOWN, STRING_OR_NULL, UNKNOWN);
+ rule(UNKNOWN, jsStringOrNull, UNKNOWN);
rule(UNKNOWN, NULL, UNKNOWN);
- rule(UNKNOWN, FIXED_ARRAY, UNKNOWN);
+ rule(UNKNOWN, jsFixedArray, UNKNOWN);
rule(BOOLEAN, BOOLEAN, BOOLEAN);
rule(BOOLEAN, NUMBER, jsInterceptor);
rule(BOOLEAN, INTEGER, jsInterceptor);
rule(BOOLEAN, DOUBLE, jsInterceptor);
- rule(BOOLEAN, INDEXABLE_PRIMITIVE, NON_NULL);
- rule(BOOLEAN, STRING, jsInterceptor);
- rule(BOOLEAN, READABLE_ARRAY, jsInterceptor);
- rule(BOOLEAN, MUTABLE_ARRAY, jsInterceptor);
- rule(BOOLEAN, EXTENDABLE_ARRAY, jsInterceptor);
+ rule(BOOLEAN, jsIndexable, NON_NULL);
+ rule(BOOLEAN, jsString, jsInterceptor);
+ rule(BOOLEAN, jsReadableArray, jsInterceptor);
+ rule(BOOLEAN, jsMutableArray, jsInterceptor);
+ rule(BOOLEAN, jsExtendableArray, jsInterceptor);
rule(BOOLEAN, nonPrimitive1, NON_NULL);
rule(BOOLEAN, nonPrimitive2, NON_NULL);
rule(BOOLEAN, potentialArray, UNKNOWN);
@@ -163,18 +163,18 @@
rule(BOOLEAN, NUMBER_OR_NULL, jsInterceptorOrNull);
rule(BOOLEAN, INTEGER_OR_NULL, jsInterceptorOrNull);
rule(BOOLEAN, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(BOOLEAN, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(BOOLEAN, jsStringOrNull, jsInterceptorOrNull);
rule(BOOLEAN, NULL, BOOLEAN_OR_NULL);
- rule(BOOLEAN, FIXED_ARRAY, jsInterceptor);
+ rule(BOOLEAN, jsFixedArray, jsInterceptor);
rule(NUMBER, NUMBER, NUMBER);
rule(NUMBER, INTEGER, NUMBER);
rule(NUMBER, DOUBLE, NUMBER);
- rule(NUMBER, INDEXABLE_PRIMITIVE, NON_NULL);
- rule(NUMBER, STRING, jsInterceptor);
- rule(NUMBER, READABLE_ARRAY, jsInterceptor);
- rule(NUMBER, MUTABLE_ARRAY, jsInterceptor);
- rule(NUMBER, EXTENDABLE_ARRAY, jsInterceptor);
+ rule(NUMBER, jsIndexable, NON_NULL);
+ rule(NUMBER, jsString, jsInterceptor);
+ rule(NUMBER, jsReadableArray, jsInterceptor);
+ rule(NUMBER, jsMutableArray, jsInterceptor);
+ rule(NUMBER, jsExtendableArray, jsInterceptor);
rule(NUMBER, nonPrimitive1, NON_NULL);
rule(NUMBER, nonPrimitive2, NON_NULL);
rule(NUMBER, potentialArray, UNKNOWN);
@@ -183,17 +183,17 @@
rule(NUMBER, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(NUMBER, INTEGER_OR_NULL, NUMBER_OR_NULL);
rule(NUMBER, DOUBLE_OR_NULL, NUMBER_OR_NULL);
- rule(NUMBER, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(NUMBER, jsStringOrNull, jsInterceptorOrNull);
rule(NUMBER, NULL, NUMBER_OR_NULL);
- rule(NUMBER, FIXED_ARRAY, jsInterceptor);
+ rule(NUMBER, jsFixedArray, jsInterceptor);
rule(INTEGER, INTEGER, INTEGER);
rule(INTEGER, DOUBLE, NUMBER);
- rule(INTEGER, INDEXABLE_PRIMITIVE, NON_NULL);
- rule(INTEGER, STRING, jsInterceptor);
- rule(INTEGER, READABLE_ARRAY, jsInterceptor);
- rule(INTEGER, MUTABLE_ARRAY, jsInterceptor);
- rule(INTEGER, EXTENDABLE_ARRAY, jsInterceptor);
+ rule(INTEGER, jsIndexable, NON_NULL);
+ rule(INTEGER, jsString, jsInterceptor);
+ rule(INTEGER, jsReadableArray, jsInterceptor);
+ rule(INTEGER, jsMutableArray, jsInterceptor);
+ rule(INTEGER, jsExtendableArray, jsInterceptor);
rule(INTEGER, nonPrimitive1, NON_NULL);
rule(INTEGER, nonPrimitive2, NON_NULL);
rule(INTEGER, potentialArray, UNKNOWN);
@@ -202,16 +202,16 @@
rule(INTEGER, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(INTEGER, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(INTEGER, DOUBLE_OR_NULL, NUMBER_OR_NULL);
- rule(INTEGER, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(INTEGER, jsStringOrNull, jsInterceptorOrNull);
rule(INTEGER, NULL, INTEGER_OR_NULL);
- rule(INTEGER, FIXED_ARRAY, jsInterceptor);
+ rule(INTEGER, jsFixedArray, jsInterceptor);
rule(DOUBLE, DOUBLE, DOUBLE);
- rule(DOUBLE, INDEXABLE_PRIMITIVE, NON_NULL);
- rule(DOUBLE, STRING, jsInterceptor);
- rule(DOUBLE, READABLE_ARRAY, jsInterceptor);
- rule(DOUBLE, MUTABLE_ARRAY, jsInterceptor);
- rule(DOUBLE, EXTENDABLE_ARRAY, jsInterceptor);
+ rule(DOUBLE, jsIndexable, NON_NULL);
+ rule(DOUBLE, jsString, jsInterceptor);
+ rule(DOUBLE, jsReadableArray, jsInterceptor);
+ rule(DOUBLE, jsMutableArray, jsInterceptor);
+ rule(DOUBLE, jsExtendableArray, jsInterceptor);
rule(DOUBLE, nonPrimitive1, NON_NULL);
rule(DOUBLE, nonPrimitive2, NON_NULL);
rule(DOUBLE, potentialArray, UNKNOWN);
@@ -220,84 +220,84 @@
rule(DOUBLE, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(DOUBLE, INTEGER_OR_NULL, NUMBER_OR_NULL);
rule(DOUBLE, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(DOUBLE, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(DOUBLE, jsStringOrNull, jsInterceptorOrNull);
rule(DOUBLE, NULL, DOUBLE_OR_NULL);
- rule(DOUBLE, FIXED_ARRAY, jsInterceptor);
+ rule(DOUBLE, jsFixedArray, jsInterceptor);
- rule(INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, STRING, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, READABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, MUTABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, EXTENDABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, nonPrimitive1, NON_NULL);
- rule(INDEXABLE_PRIMITIVE, nonPrimitive2, NON_NULL);
- rule(INDEXABLE_PRIMITIVE, potentialArray, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, potentialString, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, BOOLEAN_OR_NULL, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, NUMBER_OR_NULL, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, INTEGER_OR_NULL, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, DOUBLE_OR_NULL, UNKNOWN);
- rule(INDEXABLE_PRIMITIVE, STRING_OR_NULL, jsIndexableOrNull);
- rule(INDEXABLE_PRIMITIVE, NULL, jsIndexableOrNull);
- rule(INDEXABLE_PRIMITIVE, FIXED_ARRAY, INDEXABLE_PRIMITIVE);
+ rule(jsIndexable, jsIndexable, jsIndexable);
+ rule(jsIndexable, jsString, jsIndexable);
+ rule(jsIndexable, jsReadableArray, jsIndexable);
+ rule(jsIndexable, jsMutableArray, jsIndexable);
+ rule(jsIndexable, jsExtendableArray, jsIndexable);
+ rule(jsIndexable, nonPrimitive1, NON_NULL);
+ rule(jsIndexable, nonPrimitive2, NON_NULL);
+ rule(jsIndexable, potentialArray, UNKNOWN);
+ rule(jsIndexable, potentialString, UNKNOWN);
+ rule(jsIndexable, BOOLEAN_OR_NULL, UNKNOWN);
+ rule(jsIndexable, NUMBER_OR_NULL, UNKNOWN);
+ rule(jsIndexable, INTEGER_OR_NULL, UNKNOWN);
+ rule(jsIndexable, DOUBLE_OR_NULL, UNKNOWN);
+ rule(jsIndexable, jsStringOrNull, jsIndexableOrNull);
+ rule(jsIndexable, NULL, jsIndexableOrNull);
+ rule(jsIndexable, jsFixedArray, jsIndexable);
- rule(STRING, STRING, STRING);
- rule(STRING, READABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(STRING, MUTABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(STRING, EXTENDABLE_ARRAY, INDEXABLE_PRIMITIVE);
- rule(STRING, nonPrimitive1, NON_NULL);
- rule(STRING, nonPrimitive2, NON_NULL);
- rule(STRING, potentialArray, UNKNOWN);
- rule(STRING, potentialString, potentialString);
- rule(STRING, BOOLEAN_OR_NULL, jsInterceptorOrNull);
- rule(STRING, NUMBER_OR_NULL, jsInterceptorOrNull);
- rule(STRING, INTEGER_OR_NULL, jsInterceptorOrNull);
- rule(STRING, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(STRING, STRING_OR_NULL, STRING_OR_NULL);
- rule(STRING, NULL, STRING_OR_NULL);
- rule(STRING, FIXED_ARRAY, INDEXABLE_PRIMITIVE);
+ rule(jsString, jsString, jsString);
+ rule(jsString, jsReadableArray, jsIndexable);
+ rule(jsString, jsMutableArray, jsIndexable);
+ rule(jsString, jsExtendableArray, jsIndexable);
+ rule(jsString, nonPrimitive1, NON_NULL);
+ rule(jsString, nonPrimitive2, NON_NULL);
+ rule(jsString, potentialArray, UNKNOWN);
+ rule(jsString, potentialString, potentialString);
+ rule(jsString, BOOLEAN_OR_NULL, jsInterceptorOrNull);
+ rule(jsString, NUMBER_OR_NULL, jsInterceptorOrNull);
+ rule(jsString, INTEGER_OR_NULL, jsInterceptorOrNull);
+ rule(jsString, DOUBLE_OR_NULL, jsInterceptorOrNull);
+ rule(jsString, jsStringOrNull, jsStringOrNull);
+ rule(jsString, NULL, jsStringOrNull);
+ rule(jsString, jsFixedArray, jsIndexable);
- rule(READABLE_ARRAY, READABLE_ARRAY, READABLE_ARRAY);
- rule(READABLE_ARRAY, MUTABLE_ARRAY, READABLE_ARRAY);
- rule(READABLE_ARRAY, EXTENDABLE_ARRAY, READABLE_ARRAY);
- rule(READABLE_ARRAY, nonPrimitive1, NON_NULL);
- rule(READABLE_ARRAY, nonPrimitive2, NON_NULL);
- rule(READABLE_ARRAY, potentialArray, potentialArray);
- rule(READABLE_ARRAY, potentialString, UNKNOWN);
- rule(READABLE_ARRAY, BOOLEAN_OR_NULL, jsInterceptorOrNull);
- rule(READABLE_ARRAY, NUMBER_OR_NULL, jsInterceptorOrNull);
- rule(READABLE_ARRAY, INTEGER_OR_NULL, jsInterceptorOrNull);
- rule(READABLE_ARRAY, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(READABLE_ARRAY, STRING_OR_NULL, jsIndexableOrNull);
- rule(READABLE_ARRAY, NULL, jsArrayOrNull);
- rule(READABLE_ARRAY, FIXED_ARRAY, READABLE_ARRAY);
+ rule(jsReadableArray, jsReadableArray, jsReadableArray);
+ rule(jsReadableArray, jsMutableArray, jsReadableArray);
+ rule(jsReadableArray, jsExtendableArray, jsReadableArray);
+ rule(jsReadableArray, nonPrimitive1, NON_NULL);
+ rule(jsReadableArray, nonPrimitive2, NON_NULL);
+ rule(jsReadableArray, potentialArray, potentialArray);
+ rule(jsReadableArray, potentialString, UNKNOWN);
+ rule(jsReadableArray, BOOLEAN_OR_NULL, jsInterceptorOrNull);
+ rule(jsReadableArray, NUMBER_OR_NULL, jsInterceptorOrNull);
+ rule(jsReadableArray, INTEGER_OR_NULL, jsInterceptorOrNull);
+ rule(jsReadableArray, DOUBLE_OR_NULL, jsInterceptorOrNull);
+ rule(jsReadableArray, jsStringOrNull, jsIndexableOrNull);
+ rule(jsReadableArray, NULL, jsArrayOrNull);
+ rule(jsReadableArray, jsFixedArray, jsReadableArray);
- rule(MUTABLE_ARRAY, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(MUTABLE_ARRAY, EXTENDABLE_ARRAY, MUTABLE_ARRAY);
- rule(MUTABLE_ARRAY, nonPrimitive1, NON_NULL);
- rule(MUTABLE_ARRAY, nonPrimitive2, NON_NULL);
- rule(MUTABLE_ARRAY, potentialArray, potentialArray);
- rule(MUTABLE_ARRAY, potentialString, UNKNOWN);
- rule(MUTABLE_ARRAY, BOOLEAN_OR_NULL, jsInterceptorOrNull);
- rule(MUTABLE_ARRAY, NUMBER_OR_NULL, jsInterceptorOrNull);
- rule(MUTABLE_ARRAY, INTEGER_OR_NULL, jsInterceptorOrNull);
- rule(MUTABLE_ARRAY, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(MUTABLE_ARRAY, STRING_OR_NULL, jsIndexableOrNull);
- rule(MUTABLE_ARRAY, NULL, jsMutableArrayOrNull);
- rule(MUTABLE_ARRAY, FIXED_ARRAY, MUTABLE_ARRAY);
+ rule(jsMutableArray, jsMutableArray, jsMutableArray);
+ rule(jsMutableArray, jsExtendableArray, jsMutableArray);
+ rule(jsMutableArray, nonPrimitive1, NON_NULL);
+ rule(jsMutableArray, nonPrimitive2, NON_NULL);
+ rule(jsMutableArray, potentialArray, potentialArray);
+ rule(jsMutableArray, potentialString, UNKNOWN);
+ rule(jsMutableArray, BOOLEAN_OR_NULL, jsInterceptorOrNull);
+ rule(jsMutableArray, NUMBER_OR_NULL, jsInterceptorOrNull);
+ rule(jsMutableArray, INTEGER_OR_NULL, jsInterceptorOrNull);
+ rule(jsMutableArray, DOUBLE_OR_NULL, jsInterceptorOrNull);
+ rule(jsMutableArray, jsStringOrNull, jsIndexableOrNull);
+ rule(jsMutableArray, NULL, jsMutableArrayOrNull);
+ rule(jsMutableArray, jsFixedArray, jsMutableArray);
- rule(EXTENDABLE_ARRAY, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
- rule(EXTENDABLE_ARRAY, nonPrimitive1, NON_NULL);
- rule(EXTENDABLE_ARRAY, nonPrimitive2, NON_NULL);
- rule(EXTENDABLE_ARRAY, potentialArray, potentialArray);
- rule(EXTENDABLE_ARRAY, potentialString, UNKNOWN);
- rule(EXTENDABLE_ARRAY, BOOLEAN_OR_NULL, jsInterceptorOrNull);
- rule(EXTENDABLE_ARRAY, NUMBER_OR_NULL, jsInterceptorOrNull);
- rule(EXTENDABLE_ARRAY, INTEGER_OR_NULL, jsInterceptorOrNull);
- rule(EXTENDABLE_ARRAY, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(EXTENDABLE_ARRAY, STRING_OR_NULL, jsIndexableOrNull);
- rule(EXTENDABLE_ARRAY, NULL, jsExtendableArrayOrNull);
- rule(EXTENDABLE_ARRAY, FIXED_ARRAY, MUTABLE_ARRAY);
+ rule(jsExtendableArray, jsExtendableArray, jsExtendableArray);
+ rule(jsExtendableArray, nonPrimitive1, NON_NULL);
+ rule(jsExtendableArray, nonPrimitive2, NON_NULL);
+ rule(jsExtendableArray, potentialArray, potentialArray);
+ rule(jsExtendableArray, potentialString, UNKNOWN);
+ rule(jsExtendableArray, BOOLEAN_OR_NULL, jsInterceptorOrNull);
+ rule(jsExtendableArray, NUMBER_OR_NULL, jsInterceptorOrNull);
+ rule(jsExtendableArray, INTEGER_OR_NULL, jsInterceptorOrNull);
+ rule(jsExtendableArray, DOUBLE_OR_NULL, jsInterceptorOrNull);
+ rule(jsExtendableArray, jsStringOrNull, jsIndexableOrNull);
+ rule(jsExtendableArray, NULL, jsExtendableArrayOrNull);
+ rule(jsExtendableArray, jsFixedArray, jsMutableArray);
rule(nonPrimitive1, nonPrimitive1, nonPrimitive1);
rule(nonPrimitive1, nonPrimitive2, NON_NULL);
@@ -307,8 +307,8 @@
rule(nonPrimitive1, NUMBER_OR_NULL, UNKNOWN);
rule(nonPrimitive1, INTEGER_OR_NULL, UNKNOWN);
rule(nonPrimitive1, DOUBLE_OR_NULL, UNKNOWN);
- rule(nonPrimitive1, STRING_OR_NULL, UNKNOWN);
- rule(nonPrimitive1, FIXED_ARRAY, NON_NULL);
+ rule(nonPrimitive1, jsStringOrNull, UNKNOWN);
+ rule(nonPrimitive1, jsFixedArray, NON_NULL);
rule(nonPrimitive2, nonPrimitive2, nonPrimitive2);
rule(nonPrimitive2, potentialArray, UNKNOWN);
@@ -317,8 +317,8 @@
rule(nonPrimitive2, NUMBER_OR_NULL, UNKNOWN);
rule(nonPrimitive2, INTEGER_OR_NULL, UNKNOWN);
rule(nonPrimitive2, DOUBLE_OR_NULL, UNKNOWN);
- rule(nonPrimitive2, STRING_OR_NULL, UNKNOWN);
- rule(nonPrimitive2, FIXED_ARRAY, NON_NULL);
+ rule(nonPrimitive2, jsStringOrNull, UNKNOWN);
+ rule(nonPrimitive2, jsFixedArray, NON_NULL);
rule(potentialArray, potentialArray, potentialArray);
rule(potentialArray, potentialString, UNKNOWN);
@@ -326,53 +326,53 @@
rule(potentialArray, NUMBER_OR_NULL, UNKNOWN);
rule(potentialArray, INTEGER_OR_NULL, UNKNOWN);
rule(potentialArray, DOUBLE_OR_NULL, UNKNOWN);
- rule(potentialArray, STRING_OR_NULL, UNKNOWN);
+ rule(potentialArray, jsStringOrNull, UNKNOWN);
rule(potentialArray, NULL, potentialArray);
- rule(potentialArray, FIXED_ARRAY, potentialArray);
+ rule(potentialArray, jsFixedArray, potentialArray);
rule(potentialString, potentialString, potentialString);
rule(potentialString, BOOLEAN_OR_NULL, UNKNOWN);
rule(potentialString, NUMBER_OR_NULL, UNKNOWN);
rule(potentialString, INTEGER_OR_NULL, UNKNOWN);
rule(potentialString, DOUBLE_OR_NULL, UNKNOWN);
- rule(potentialString, STRING_OR_NULL, potentialString);
+ rule(potentialString, jsStringOrNull, potentialString);
rule(potentialString, NULL, potentialString);
- rule(potentialString, FIXED_ARRAY, UNKNOWN);
+ rule(potentialString, jsFixedArray, UNKNOWN);
rule(BOOLEAN_OR_NULL, BOOLEAN_OR_NULL, BOOLEAN_OR_NULL);
rule(BOOLEAN_OR_NULL, NUMBER_OR_NULL, jsInterceptorOrNull);
rule(BOOLEAN_OR_NULL, INTEGER_OR_NULL, jsInterceptorOrNull);
rule(BOOLEAN_OR_NULL, DOUBLE_OR_NULL, jsInterceptorOrNull);
- rule(BOOLEAN_OR_NULL, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(BOOLEAN_OR_NULL, jsStringOrNull, jsInterceptorOrNull);
rule(BOOLEAN_OR_NULL, NULL, BOOLEAN_OR_NULL);
- rule(BOOLEAN_OR_NULL, FIXED_ARRAY, jsInterceptorOrNull);
+ rule(BOOLEAN_OR_NULL, jsFixedArray, jsInterceptorOrNull);
rule(NUMBER_OR_NULL, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(NUMBER_OR_NULL, INTEGER_OR_NULL, NUMBER_OR_NULL);
rule(NUMBER_OR_NULL, DOUBLE_OR_NULL, NUMBER_OR_NULL);
- rule(NUMBER_OR_NULL, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(NUMBER_OR_NULL, jsStringOrNull, jsInterceptorOrNull);
rule(NUMBER_OR_NULL, NULL, NUMBER_OR_NULL);
- rule(NUMBER_OR_NULL, FIXED_ARRAY, jsInterceptorOrNull);
+ rule(NUMBER_OR_NULL, jsFixedArray, jsInterceptorOrNull);
rule(INTEGER_OR_NULL, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(INTEGER_OR_NULL, DOUBLE_OR_NULL, NUMBER_OR_NULL);
- rule(INTEGER_OR_NULL, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(INTEGER_OR_NULL, jsStringOrNull, jsInterceptorOrNull);
rule(INTEGER_OR_NULL, NULL, INTEGER_OR_NULL);
- rule(INTEGER_OR_NULL, FIXED_ARRAY, jsInterceptorOrNull);
+ rule(INTEGER_OR_NULL, jsFixedArray, jsInterceptorOrNull);
rule(DOUBLE_OR_NULL, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(DOUBLE_OR_NULL, STRING_OR_NULL, jsInterceptorOrNull);
+ rule(DOUBLE_OR_NULL, jsStringOrNull, jsInterceptorOrNull);
rule(DOUBLE_OR_NULL, NULL, DOUBLE_OR_NULL);
- rule(DOUBLE_OR_NULL, FIXED_ARRAY, jsInterceptorOrNull);
+ rule(DOUBLE_OR_NULL, jsFixedArray, jsInterceptorOrNull);
- rule(STRING_OR_NULL, STRING_OR_NULL, STRING_OR_NULL);
- rule(STRING_OR_NULL, NULL, STRING_OR_NULL);
- rule(STRING_OR_NULL, FIXED_ARRAY, jsIndexableOrNull);
+ rule(jsStringOrNull, jsStringOrNull, jsStringOrNull);
+ rule(jsStringOrNull, NULL, jsStringOrNull);
+ rule(jsStringOrNull, jsFixedArray, jsIndexableOrNull);
rule(NULL, NULL, NULL);
- rule(NULL, FIXED_ARRAY, jsFixedArrayOrNull);
+ rule(NULL, jsFixedArray, jsFixedArrayOrNull);
- rule(FIXED_ARRAY, FIXED_ARRAY, FIXED_ARRAY);
+ rule(jsFixedArray, jsFixedArray, jsFixedArray);
check(nonPrimitive1, NULL, (type) => type is HBoundedType);
check(nonPrimitive2, NULL, (type) => type is HBoundedType);
@@ -393,11 +393,11 @@
rule(CONFLICTING, NUMBER, CONFLICTING);
rule(CONFLICTING, INTEGER, CONFLICTING);
rule(CONFLICTING, DOUBLE, CONFLICTING);
- rule(CONFLICTING, INDEXABLE_PRIMITIVE, CONFLICTING);
- rule(CONFLICTING, STRING, CONFLICTING);
- rule(CONFLICTING, READABLE_ARRAY, CONFLICTING);
- rule(CONFLICTING, MUTABLE_ARRAY, CONFLICTING);
- rule(CONFLICTING, EXTENDABLE_ARRAY, CONFLICTING);
+ rule(CONFLICTING, jsIndexable, CONFLICTING);
+ rule(CONFLICTING, jsString, CONFLICTING);
+ rule(CONFLICTING, jsReadableArray, CONFLICTING);
+ rule(CONFLICTING, jsMutableArray, CONFLICTING);
+ rule(CONFLICTING, jsExtendableArray, CONFLICTING);
rule(CONFLICTING, nonPrimitive1, CONFLICTING);
rule(CONFLICTING, nonPrimitive2, CONFLICTING);
rule(CONFLICTING, potentialArray, CONFLICTING);
@@ -406,20 +406,20 @@
rule(CONFLICTING, NUMBER_OR_NULL, CONFLICTING);
rule(CONFLICTING, INTEGER_OR_NULL, CONFLICTING);
rule(CONFLICTING, DOUBLE_OR_NULL, CONFLICTING);
- rule(CONFLICTING, STRING_OR_NULL, CONFLICTING);
+ rule(CONFLICTING, jsStringOrNull, CONFLICTING);
rule(CONFLICTING, NULL, CONFLICTING);
- rule(CONFLICTING, FIXED_ARRAY, CONFLICTING);
+ rule(CONFLICTING, jsFixedArray, CONFLICTING);
rule(UNKNOWN, UNKNOWN, UNKNOWN);
rule(UNKNOWN, BOOLEAN, BOOLEAN);
rule(UNKNOWN, NUMBER, NUMBER);
rule(UNKNOWN, INTEGER, INTEGER);
rule(UNKNOWN, DOUBLE, DOUBLE);
- rule(UNKNOWN, INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE);
- rule(UNKNOWN, STRING, STRING);
- rule(UNKNOWN, READABLE_ARRAY, READABLE_ARRAY);
- rule(UNKNOWN, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(UNKNOWN, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
+ rule(UNKNOWN, jsIndexable, jsIndexable);
+ rule(UNKNOWN, jsString, jsString);
+ rule(UNKNOWN, jsReadableArray, jsReadableArray);
+ rule(UNKNOWN, jsMutableArray, jsMutableArray);
+ rule(UNKNOWN, jsExtendableArray, jsExtendableArray);
rule(UNKNOWN, nonPrimitive1, nonPrimitive1);
rule(UNKNOWN, nonPrimitive2, nonPrimitive2);
rule(UNKNOWN, potentialArray, potentialArray);
@@ -428,19 +428,19 @@
rule(UNKNOWN, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(UNKNOWN, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(UNKNOWN, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(UNKNOWN, STRING_OR_NULL, STRING_OR_NULL);
+ rule(UNKNOWN, jsStringOrNull, jsStringOrNull);
rule(UNKNOWN, NULL, NULL);
- rule(UNKNOWN, FIXED_ARRAY, FIXED_ARRAY);
+ rule(UNKNOWN, jsFixedArray, jsFixedArray);
rule(BOOLEAN, BOOLEAN, BOOLEAN);
rule(BOOLEAN, NUMBER, CONFLICTING);
rule(BOOLEAN, INTEGER, CONFLICTING);
rule(BOOLEAN, DOUBLE, CONFLICTING);
- rule(BOOLEAN, INDEXABLE_PRIMITIVE, CONFLICTING);
- rule(BOOLEAN, STRING, CONFLICTING);
- rule(BOOLEAN, READABLE_ARRAY, CONFLICTING);
- rule(BOOLEAN, MUTABLE_ARRAY, CONFLICTING);
- rule(BOOLEAN, EXTENDABLE_ARRAY, CONFLICTING);
+ rule(BOOLEAN, jsIndexable, CONFLICTING);
+ rule(BOOLEAN, jsString, CONFLICTING);
+ rule(BOOLEAN, jsReadableArray, CONFLICTING);
+ rule(BOOLEAN, jsMutableArray, CONFLICTING);
+ rule(BOOLEAN, jsExtendableArray, CONFLICTING);
rule(BOOLEAN, nonPrimitive1, CONFLICTING);
rule(BOOLEAN, nonPrimitive2, CONFLICTING);
rule(BOOLEAN, potentialArray, CONFLICTING);
@@ -449,18 +449,18 @@
rule(BOOLEAN, NUMBER_OR_NULL, CONFLICTING);
rule(BOOLEAN, INTEGER_OR_NULL, CONFLICTING);
rule(BOOLEAN, DOUBLE_OR_NULL, CONFLICTING);
- rule(BOOLEAN, STRING_OR_NULL, CONFLICTING);
+ rule(BOOLEAN, jsStringOrNull, CONFLICTING);
rule(BOOLEAN, NULL, CONFLICTING);
- rule(BOOLEAN, FIXED_ARRAY, CONFLICTING);
+ rule(BOOLEAN, jsFixedArray, CONFLICTING);
rule(NUMBER, NUMBER, NUMBER);
rule(NUMBER, INTEGER, INTEGER);
rule(NUMBER, DOUBLE, DOUBLE);
- rule(NUMBER, INDEXABLE_PRIMITIVE, CONFLICTING);
- rule(NUMBER, STRING, CONFLICTING);
- rule(NUMBER, READABLE_ARRAY, CONFLICTING);
- rule(NUMBER, MUTABLE_ARRAY, CONFLICTING);
- rule(NUMBER, EXTENDABLE_ARRAY, CONFLICTING);
+ rule(NUMBER, jsIndexable, CONFLICTING);
+ rule(NUMBER, jsString, CONFLICTING);
+ rule(NUMBER, jsReadableArray, CONFLICTING);
+ rule(NUMBER, jsMutableArray, CONFLICTING);
+ rule(NUMBER, jsExtendableArray, CONFLICTING);
rule(NUMBER, nonPrimitive1, CONFLICTING);
rule(NUMBER, nonPrimitive2, CONFLICTING);
rule(NUMBER, potentialArray, CONFLICTING);
@@ -469,17 +469,17 @@
rule(NUMBER, NUMBER_OR_NULL, NUMBER);
rule(NUMBER, INTEGER_OR_NULL, INTEGER);
rule(NUMBER, DOUBLE_OR_NULL, DOUBLE);
- rule(NUMBER, STRING_OR_NULL, CONFLICTING);
+ rule(NUMBER, jsStringOrNull, CONFLICTING);
rule(NUMBER, NULL, CONFLICTING);
- rule(NUMBER, FIXED_ARRAY, CONFLICTING);
+ rule(NUMBER, jsFixedArray, CONFLICTING);
rule(INTEGER, INTEGER, INTEGER);
rule(INTEGER, DOUBLE, CONFLICTING);
- rule(INTEGER, INDEXABLE_PRIMITIVE, CONFLICTING);
- rule(INTEGER, STRING, CONFLICTING);
- rule(INTEGER, READABLE_ARRAY, CONFLICTING);
- rule(INTEGER, MUTABLE_ARRAY, CONFLICTING);
- rule(INTEGER, EXTENDABLE_ARRAY, CONFLICTING);
+ rule(INTEGER, jsIndexable, CONFLICTING);
+ rule(INTEGER, jsString, CONFLICTING);
+ rule(INTEGER, jsReadableArray, CONFLICTING);
+ rule(INTEGER, jsMutableArray, CONFLICTING);
+ rule(INTEGER, jsExtendableArray, CONFLICTING);
rule(INTEGER, nonPrimitive1, CONFLICTING);
rule(INTEGER, nonPrimitive2, CONFLICTING);
rule(INTEGER, potentialArray, CONFLICTING);
@@ -488,16 +488,16 @@
rule(INTEGER, NUMBER_OR_NULL, INTEGER);
rule(INTEGER, INTEGER_OR_NULL, INTEGER);
rule(INTEGER, DOUBLE_OR_NULL, CONFLICTING);
- rule(INTEGER, STRING_OR_NULL, CONFLICTING);
+ rule(INTEGER, jsStringOrNull, CONFLICTING);
rule(INTEGER, NULL, CONFLICTING);
- rule(INTEGER, FIXED_ARRAY, CONFLICTING);
+ rule(INTEGER, jsFixedArray, CONFLICTING);
rule(DOUBLE, DOUBLE, DOUBLE);
- rule(DOUBLE, INDEXABLE_PRIMITIVE, CONFLICTING);
- rule(DOUBLE, STRING, CONFLICTING);
- rule(DOUBLE, READABLE_ARRAY, CONFLICTING);
- rule(DOUBLE, MUTABLE_ARRAY, CONFLICTING);
- rule(DOUBLE, EXTENDABLE_ARRAY, CONFLICTING);
+ rule(DOUBLE, jsIndexable, CONFLICTING);
+ rule(DOUBLE, jsString, CONFLICTING);
+ rule(DOUBLE, jsReadableArray, CONFLICTING);
+ rule(DOUBLE, jsMutableArray, CONFLICTING);
+ rule(DOUBLE, jsExtendableArray, CONFLICTING);
rule(DOUBLE, nonPrimitive1, CONFLICTING);
rule(DOUBLE, nonPrimitive2, CONFLICTING);
rule(DOUBLE, potentialArray, CONFLICTING);
@@ -506,84 +506,85 @@
rule(DOUBLE, NUMBER_OR_NULL, DOUBLE);
rule(DOUBLE, INTEGER_OR_NULL, CONFLICTING);
rule(DOUBLE, DOUBLE_OR_NULL, DOUBLE);
- rule(DOUBLE, STRING_OR_NULL, CONFLICTING);
+ rule(DOUBLE, jsStringOrNull, CONFLICTING);
rule(DOUBLE, NULL, CONFLICTING);
- rule(DOUBLE, FIXED_ARRAY, CONFLICTING);
+ rule(DOUBLE, jsFixedArray, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE, INDEXABLE_PRIMITIVE);
- rule(INDEXABLE_PRIMITIVE, STRING, STRING);
- rule(INDEXABLE_PRIMITIVE, READABLE_ARRAY, READABLE_ARRAY);
- rule(INDEXABLE_PRIMITIVE, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(INDEXABLE_PRIMITIVE, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
- rule(INDEXABLE_PRIMITIVE, nonPrimitive1, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, nonPrimitive2, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, potentialArray, READABLE_ARRAY);
- rule(INDEXABLE_PRIMITIVE, potentialString, STRING);
- rule(INDEXABLE_PRIMITIVE, BOOLEAN_OR_NULL, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, NUMBER_OR_NULL, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, INTEGER_OR_NULL, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, DOUBLE_OR_NULL, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, STRING_OR_NULL, STRING);
- rule(INDEXABLE_PRIMITIVE, NULL, CONFLICTING);
- rule(INDEXABLE_PRIMITIVE, FIXED_ARRAY, FIXED_ARRAY);
+ rule(jsIndexable, jsIndexable, jsIndexable);
+ rule(jsIndexable, jsString, jsString);
+ rule(jsIndexable, jsReadableArray, jsReadableArray);
+ rule(jsIndexable, jsMutableArray, jsMutableArray);
+ rule(jsIndexable, jsExtendableArray, jsExtendableArray);
+ rule(jsIndexable, nonPrimitive1, CONFLICTING);
+ rule(jsIndexable, nonPrimitive2, CONFLICTING);
+ rule(jsIndexable, potentialArray, new HType.nonNullSubtype(
+ compiler.backend.jsArrayClass.computeType(compiler), compiler));
+ rule(jsIndexable, potentialString, jsString);
+ rule(jsIndexable, BOOLEAN_OR_NULL, CONFLICTING);
+ rule(jsIndexable, NUMBER_OR_NULL, CONFLICTING);
+ rule(jsIndexable, INTEGER_OR_NULL, CONFLICTING);
+ rule(jsIndexable, DOUBLE_OR_NULL, CONFLICTING);
+ rule(jsIndexable, jsStringOrNull, jsString);
+ rule(jsIndexable, NULL, CONFLICTING);
+ rule(jsIndexable, jsFixedArray, jsFixedArray);
- rule(STRING, STRING, STRING);
- rule(STRING, READABLE_ARRAY, CONFLICTING);
- rule(STRING, MUTABLE_ARRAY, CONFLICTING);
- rule(STRING, EXTENDABLE_ARRAY, CONFLICTING);
- rule(STRING, nonPrimitive1, CONFLICTING);
- rule(STRING, nonPrimitive2, CONFLICTING);
- rule(STRING, potentialArray, CONFLICTING);
- rule(STRING, potentialString, STRING);
- rule(STRING, BOOLEAN_OR_NULL, CONFLICTING);
- rule(STRING, NUMBER_OR_NULL, CONFLICTING);
- rule(STRING, INTEGER_OR_NULL, CONFLICTING);
- rule(STRING, DOUBLE_OR_NULL, CONFLICTING);
- rule(STRING, STRING_OR_NULL, STRING);
- rule(STRING, NULL, CONFLICTING);
- rule(STRING, FIXED_ARRAY, CONFLICTING);
+ rule(jsString, jsString, jsString);
+ rule(jsString, jsReadableArray, CONFLICTING);
+ rule(jsString, jsMutableArray, CONFLICTING);
+ rule(jsString, jsExtendableArray, CONFLICTING);
+ rule(jsString, nonPrimitive1, CONFLICTING);
+ rule(jsString, nonPrimitive2, CONFLICTING);
+ rule(jsString, potentialArray, CONFLICTING);
+ rule(jsString, potentialString, jsString);
+ rule(jsString, BOOLEAN_OR_NULL, CONFLICTING);
+ rule(jsString, NUMBER_OR_NULL, CONFLICTING);
+ rule(jsString, INTEGER_OR_NULL, CONFLICTING);
+ rule(jsString, DOUBLE_OR_NULL, CONFLICTING);
+ rule(jsString, jsStringOrNull, jsString);
+ rule(jsString, NULL, CONFLICTING);
+ rule(jsString, jsFixedArray, CONFLICTING);
- rule(READABLE_ARRAY, READABLE_ARRAY, READABLE_ARRAY);
- rule(READABLE_ARRAY, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(READABLE_ARRAY, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
- rule(READABLE_ARRAY, nonPrimitive1, CONFLICTING);
- rule(READABLE_ARRAY, nonPrimitive2, CONFLICTING);
- rule(READABLE_ARRAY, potentialArray, READABLE_ARRAY);
- rule(READABLE_ARRAY, potentialString, CONFLICTING);
- rule(READABLE_ARRAY, BOOLEAN_OR_NULL, CONFLICTING);
- rule(READABLE_ARRAY, NUMBER_OR_NULL, CONFLICTING);
- rule(READABLE_ARRAY, INTEGER_OR_NULL, CONFLICTING);
- rule(READABLE_ARRAY, DOUBLE_OR_NULL, CONFLICTING);
- rule(READABLE_ARRAY, STRING_OR_NULL, CONFLICTING);
- rule(READABLE_ARRAY, NULL, CONFLICTING);
- rule(READABLE_ARRAY, FIXED_ARRAY, FIXED_ARRAY);
+ rule(jsReadableArray, jsReadableArray, jsReadableArray);
+ rule(jsReadableArray, jsMutableArray, jsMutableArray);
+ rule(jsReadableArray, jsExtendableArray, jsExtendableArray);
+ rule(jsReadableArray, nonPrimitive1, CONFLICTING);
+ rule(jsReadableArray, nonPrimitive2, CONFLICTING);
+ rule(jsReadableArray, potentialArray, jsReadableArray);
+ rule(jsReadableArray, potentialString, CONFLICTING);
+ rule(jsReadableArray, BOOLEAN_OR_NULL, CONFLICTING);
+ rule(jsReadableArray, NUMBER_OR_NULL, CONFLICTING);
+ rule(jsReadableArray, INTEGER_OR_NULL, CONFLICTING);
+ rule(jsReadableArray, DOUBLE_OR_NULL, CONFLICTING);
+ rule(jsReadableArray, jsStringOrNull, CONFLICTING);
+ rule(jsReadableArray, NULL, CONFLICTING);
+ rule(jsReadableArray, jsFixedArray, jsFixedArray);
- rule(MUTABLE_ARRAY, MUTABLE_ARRAY, MUTABLE_ARRAY);
- rule(MUTABLE_ARRAY, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
- rule(MUTABLE_ARRAY, nonPrimitive1, CONFLICTING);
- rule(MUTABLE_ARRAY, nonPrimitive2, CONFLICTING);
- rule(MUTABLE_ARRAY, potentialArray, MUTABLE_ARRAY);
- rule(MUTABLE_ARRAY, potentialString, CONFLICTING);
- rule(MUTABLE_ARRAY, BOOLEAN_OR_NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, NUMBER_OR_NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, INTEGER_OR_NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, DOUBLE_OR_NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, STRING_OR_NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, NULL, CONFLICTING);
- rule(MUTABLE_ARRAY, FIXED_ARRAY, FIXED_ARRAY);
+ rule(jsMutableArray, jsMutableArray, jsMutableArray);
+ rule(jsMutableArray, jsExtendableArray, jsExtendableArray);
+ rule(jsMutableArray, nonPrimitive1, CONFLICTING);
+ rule(jsMutableArray, nonPrimitive2, CONFLICTING);
+ rule(jsMutableArray, potentialArray, jsMutableArray);
+ rule(jsMutableArray, potentialString, CONFLICTING);
+ rule(jsMutableArray, BOOLEAN_OR_NULL, CONFLICTING);
+ rule(jsMutableArray, NUMBER_OR_NULL, CONFLICTING);
+ rule(jsMutableArray, INTEGER_OR_NULL, CONFLICTING);
+ rule(jsMutableArray, DOUBLE_OR_NULL, CONFLICTING);
+ rule(jsMutableArray, jsStringOrNull, CONFLICTING);
+ rule(jsMutableArray, NULL, CONFLICTING);
+ rule(jsMutableArray, jsFixedArray, jsFixedArray);
- rule(EXTENDABLE_ARRAY, EXTENDABLE_ARRAY, EXTENDABLE_ARRAY);
- rule(EXTENDABLE_ARRAY, nonPrimitive1, CONFLICTING);
- rule(EXTENDABLE_ARRAY, nonPrimitive2, CONFLICTING);
- rule(EXTENDABLE_ARRAY, potentialArray, EXTENDABLE_ARRAY);
- rule(EXTENDABLE_ARRAY, potentialString, CONFLICTING);
- rule(EXTENDABLE_ARRAY, BOOLEAN_OR_NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, NUMBER_OR_NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, INTEGER_OR_NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, DOUBLE_OR_NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, STRING_OR_NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, NULL, CONFLICTING);
- rule(EXTENDABLE_ARRAY, FIXED_ARRAY, CONFLICTING);
+ rule(jsExtendableArray, jsExtendableArray, jsExtendableArray);
+ rule(jsExtendableArray, nonPrimitive1, CONFLICTING);
+ rule(jsExtendableArray, nonPrimitive2, CONFLICTING);
+ rule(jsExtendableArray, potentialArray, jsExtendableArray);
+ rule(jsExtendableArray, potentialString, CONFLICTING);
+ rule(jsExtendableArray, BOOLEAN_OR_NULL, CONFLICTING);
+ rule(jsExtendableArray, NUMBER_OR_NULL, CONFLICTING);
+ rule(jsExtendableArray, INTEGER_OR_NULL, CONFLICTING);
+ rule(jsExtendableArray, DOUBLE_OR_NULL, CONFLICTING);
+ rule(jsExtendableArray, jsStringOrNull, CONFLICTING);
+ rule(jsExtendableArray, NULL, CONFLICTING);
+ rule(jsExtendableArray, jsFixedArray, CONFLICTING);
rule(nonPrimitive1, nonPrimitive1, nonPrimitive1);
rule(nonPrimitive1, nonPrimitive2, CONFLICTING);
@@ -593,9 +594,9 @@
rule(nonPrimitive1, NUMBER_OR_NULL, CONFLICTING);
rule(nonPrimitive1, INTEGER_OR_NULL, CONFLICTING);
rule(nonPrimitive1, DOUBLE_OR_NULL, CONFLICTING);
- rule(nonPrimitive1, STRING_OR_NULL, CONFLICTING);
+ rule(nonPrimitive1, jsStringOrNull, CONFLICTING);
rule(nonPrimitive1, NULL, CONFLICTING);
- rule(nonPrimitive1, FIXED_ARRAY, CONFLICTING);
+ rule(nonPrimitive1, jsFixedArray, CONFLICTING);
rule(nonPrimitive2, nonPrimitive2, nonPrimitive2);
rule(nonPrimitive2, potentialArray, CONFLICTING);
@@ -604,9 +605,9 @@
rule(nonPrimitive2, NUMBER_OR_NULL, CONFLICTING);
rule(nonPrimitive2, INTEGER_OR_NULL, CONFLICTING);
rule(nonPrimitive2, DOUBLE_OR_NULL, CONFLICTING);
- rule(nonPrimitive2, STRING_OR_NULL, CONFLICTING);
+ rule(nonPrimitive2, jsStringOrNull, CONFLICTING);
rule(nonPrimitive2, NULL, CONFLICTING);
- rule(nonPrimitive2, FIXED_ARRAY, CONFLICTING);
+ rule(nonPrimitive2, jsFixedArray, CONFLICTING);
rule(potentialArray, potentialArray, potentialArray);
rule(potentialArray, potentialString, NULL);
@@ -614,53 +615,53 @@
rule(potentialArray, NUMBER_OR_NULL, NULL);
rule(potentialArray, INTEGER_OR_NULL, NULL);
rule(potentialArray, DOUBLE_OR_NULL, NULL);
- rule(potentialArray, STRING_OR_NULL, NULL);
+ rule(potentialArray, jsStringOrNull, NULL);
rule(potentialArray, NULL, NULL);
- rule(potentialArray, FIXED_ARRAY, FIXED_ARRAY);
+ rule(potentialArray, jsFixedArray, jsFixedArray);
rule(potentialString, potentialString, potentialString);
rule(potentialString, BOOLEAN_OR_NULL, NULL);
rule(potentialString, NUMBER_OR_NULL, NULL);
rule(potentialString, INTEGER_OR_NULL, NULL);
rule(potentialString, DOUBLE_OR_NULL, NULL);
- rule(potentialString, STRING_OR_NULL, STRING_OR_NULL);
+ rule(potentialString, jsStringOrNull, jsStringOrNull);
rule(potentialString, NULL, NULL);
- rule(potentialString, FIXED_ARRAY, CONFLICTING);
+ rule(potentialString, jsFixedArray, CONFLICTING);
rule(BOOLEAN_OR_NULL, BOOLEAN_OR_NULL, BOOLEAN_OR_NULL);
rule(BOOLEAN_OR_NULL, NUMBER_OR_NULL, NULL);
rule(BOOLEAN_OR_NULL, INTEGER_OR_NULL, NULL);
rule(BOOLEAN_OR_NULL, DOUBLE_OR_NULL, NULL);
- rule(BOOLEAN_OR_NULL, STRING_OR_NULL, NULL);
+ rule(BOOLEAN_OR_NULL, jsStringOrNull, NULL);
rule(BOOLEAN_OR_NULL, NULL, NULL);
- rule(BOOLEAN_OR_NULL, FIXED_ARRAY, CONFLICTING);
+ rule(BOOLEAN_OR_NULL, jsFixedArray, CONFLICTING);
rule(NUMBER_OR_NULL, NUMBER_OR_NULL, NUMBER_OR_NULL);
rule(NUMBER_OR_NULL, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(NUMBER_OR_NULL, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(NUMBER_OR_NULL, STRING_OR_NULL, NULL);
+ rule(NUMBER_OR_NULL, jsStringOrNull, NULL);
rule(NUMBER_OR_NULL, NULL, NULL);
- rule(NUMBER_OR_NULL, FIXED_ARRAY, CONFLICTING);
+ rule(NUMBER_OR_NULL, jsFixedArray, CONFLICTING);
rule(INTEGER_OR_NULL, INTEGER_OR_NULL, INTEGER_OR_NULL);
rule(INTEGER_OR_NULL, DOUBLE_OR_NULL, NULL);
- rule(INTEGER_OR_NULL, STRING_OR_NULL, NULL);
+ rule(INTEGER_OR_NULL, jsStringOrNull, NULL);
rule(INTEGER_OR_NULL, NULL, NULL);
- rule(INTEGER_OR_NULL, FIXED_ARRAY, CONFLICTING);
+ rule(INTEGER_OR_NULL, jsFixedArray, CONFLICTING);
rule(DOUBLE_OR_NULL, DOUBLE_OR_NULL, DOUBLE_OR_NULL);
- rule(DOUBLE_OR_NULL, STRING_OR_NULL, NULL);
+ rule(DOUBLE_OR_NULL, jsStringOrNull, NULL);
rule(DOUBLE_OR_NULL, NULL, NULL);
- rule(DOUBLE_OR_NULL, FIXED_ARRAY, CONFLICTING);
+ rule(DOUBLE_OR_NULL, jsFixedArray, CONFLICTING);
- rule(STRING_OR_NULL, STRING_OR_NULL, STRING_OR_NULL);
- rule(STRING_OR_NULL, NULL, NULL);
- rule(STRING_OR_NULL, FIXED_ARRAY, CONFLICTING);
+ rule(jsStringOrNull, jsStringOrNull, jsStringOrNull);
+ rule(jsStringOrNull, NULL, NULL);
+ rule(jsStringOrNull, jsFixedArray, CONFLICTING);
rule(NULL, NULL, NULL);
- rule(NULL, FIXED_ARRAY, CONFLICTING);
+ rule(NULL, jsFixedArray, CONFLICTING);
- rule(FIXED_ARRAY, FIXED_ARRAY, FIXED_ARRAY);
+ rule(jsFixedArray, jsFixedArray, jsFixedArray);
ruleSet.validateCoverage();
}
@@ -669,7 +670,7 @@
HType nonNullPotentialString = new HType.nonNullSubtype(
patternClass.computeType(compiler), compiler);
Expect.equals(
- potentialString, STRING_OR_NULL.union(nonNullPotentialString, compiler));
+ potentialString, jsStringOrNull.union(nonNullPotentialString, compiler));
}
void main() {
@@ -700,16 +701,30 @@
compiler.backend.jsInterceptorClass.computeType(compiler), compiler);
jsArrayOrNull = new HType.subclass(
compiler.backend.jsArrayClass.computeType(compiler), compiler);
+ jsReadableArray = new HType.nonNullSubclass(
+ compiler.backend.jsArrayClass.computeType(compiler), compiler);
jsMutableArrayOrNull = new HType.subclass(
compiler.backend.jsMutableArrayClass.computeType(compiler), compiler);
+ jsMutableArray = new HType.nonNullSubclass(
+ compiler.backend.jsMutableArrayClass.computeType(compiler), compiler);
jsFixedArrayOrNull = new HType.exact(
compiler.backend.jsFixedArrayClass.computeType(compiler), compiler);
+ jsFixedArray = new HType.nonNullExact(
+ compiler.backend.jsFixedArrayClass.computeType(compiler), compiler);
jsExtendableArrayOrNull = new HType.exact(
compiler.backend.jsExtendableArrayClass.computeType(compiler), compiler);
+ jsExtendableArray = new HType.nonNullExact(
+ compiler.backend.jsExtendableArrayClass.computeType(compiler), compiler);
jsIndexableOrNull = new HType.subtype(
compiler.backend.jsIndexableClass.computeType(compiler), compiler);
+ jsIndexable = new HType.nonNullSubtype(
+ compiler.backend.jsIndexableClass.computeType(compiler), compiler);
jsInterceptorOrNull = new HType.subclass(
compiler.backend.jsInterceptorClass.computeType(compiler), compiler);
+ jsStringOrNull = new HType.exact(
+ compiler.backend.jsStringClass.computeType(compiler), compiler);
+ jsString = new HType.nonNullExact(
+ compiler.backend.jsStringClass.computeType(compiler), compiler);
testUnion(compiler);
testIntersection(compiler);
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index c155d64..6e91831 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -104,8 +104,8 @@
list_insert_test: fail
list_removeat_test: fail
-[ $arch == simarm ]
-*: Skip
+[ $arch == simarm && $mode == debug ]
+collection_to_string_test: Crash # Issue: 11207
[ $arch == mips ]
*: Skip
diff --git a/tests/corelib/hidden_library2_test.dart b/tests/corelib/hidden_library2_test.dart
index d47aca7..277ed54 100644
--- a/tests/corelib/hidden_library2_test.dart
+++ b/tests/corelib/hidden_library2_test.dart
@@ -1,6 +1,7 @@
// 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.
+
// Test that the internal hidden library doesn't make problems with taking
// stack-traces.
@@ -8,7 +9,7 @@
print(['x'].where((_) {
// We actually don't really care for the successful case. We just want to
// make sure that the test doesn't crash when it is negative.
- throw 'fisk'; /// 1: runtime error
+ throw 'fisk'; /// 01: runtime error
return true;
- }));
+ }).toList());
}
diff --git a/tests/corelib/string_pattern_test.dart b/tests/corelib/string_pattern_test.dart
index 46b4e75..25e12e7 100644
--- a/tests/corelib/string_pattern_test.dart
+++ b/tests/corelib/string_pattern_test.dart
@@ -14,6 +14,7 @@
testEmptyPattern();
testEmptyString();
testEmptyPatternAndString();
+ testMatchAsPrefix();
}
testNoMatch() {
@@ -77,3 +78,22 @@
Iterable<Match> matches = pattern.allMatches(str);
Expect.isTrue(matches.iterator.moveNext());
}
+
+testMatchAsPrefix() {
+ String pattern = "an";
+ String str = "banana";
+ Expect.isNull(pattern.matchAsPrefix(str));
+ Expect.isNull(pattern.matchAsPrefix(str, 0));
+ var m = pattern.matchAsPrefix(str, 1);
+ Expect.equals("an", m[0]);
+ Expect.equals(1, m.start);
+ Expect.isNull(pattern.matchAsPrefix(str, 2));
+ m = pattern.matchAsPrefix(str, 3);
+ Expect.equals("an", m[0]);
+ Expect.equals(3, m.start);
+ Expect.isNull(pattern.matchAsPrefix(str, 4));
+ Expect.isNull(pattern.matchAsPrefix(str, 5));
+ Expect.isNull(pattern.matchAsPrefix(str, 6));
+ Expect.throws(() => pattern.matchAsPrefix(str, -1));
+ Expect.throws(() => pattern.matchAsPrefix(str, 7));
+}
diff --git a/tests/corelib/string_test.dart b/tests/corelib/string_test.dart
index dbcd630..4519733 100644
--- a/tests/corelib/string_test.dart
+++ b/tests/corelib/string_test.dart
@@ -40,7 +40,7 @@
} on RangeError catch (e) {
exception_caught = true;
}
- Expect.equals(true, exception_caught);
+ Expect.isTrue(exception_caught);
}
static testIllegalArgument() {
@@ -48,19 +48,19 @@
bool exception_caught = false;
try {
var c = a[2.2]; // Throw exception.
- Expect.equals(true, false);
+ Expect.fail("Accepting double as index");
} on ArgumentError catch (e) {
exception_caught = true;
} on TypeError catch (e) { // Thrown in checked mode only.
exception_caught = true;
}
- Expect.equals(true, exception_caught);
+ Expect.isTrue(exception_caught);
}
static testIndex() {
String str = "string";
for (int i = 0; i < str.length; i++) {
- Expect.equals(true, str[i] is String);
+ Expect.isTrue(str[i] is String);
testStringLength(1, str[i]);
}
}
@@ -68,7 +68,7 @@
static testCodeUnitAt() {
String str = "string";
for (int i = 0; i < str.length; i++) {
- Expect.equals(true, str.codeUnitAt(i) is int);
+ Expect.isTrue(str.codeUnitAt(i) is int);
}
}
@@ -86,46 +86,60 @@
Expect.equals("str", "s" + "t" + "r");
Expect.equals("s" + "t" + "r", "str");
- Expect.equals(false, "str" == "s");
- Expect.equals(false, "str" == "r");
- Expect.equals(false, "str" == "st");
- Expect.equals(false, "str" == "tr");
+ Expect.isFalse("str" == "s");
+ Expect.isFalse("str" == "r");
+ Expect.isFalse("str" == "st");
+ Expect.isFalse("str" == "tr");
- Expect.equals(false, "s" == "str");
- Expect.equals(false, "r" == "str");
- Expect.equals(false, "st" == "str");
- Expect.equals(false, "tr" == "str");
+ Expect.isFalse("s" == "str");
+ Expect.isFalse("r" == "str");
+ Expect.isFalse("st" == "str");
+ Expect.isFalse("tr" == "str");
- Expect.equals(false, "" == "s");
+ Expect.isFalse("" == "s");
Expect.equals("", "");
}
static testEndsWith() {
- Expect.equals(true, "str".endsWith("r"));
- Expect.equals(true, "str".endsWith("tr"));
- Expect.equals(true, "str".endsWith("str"));
+ Expect.isTrue("str".endsWith("r"));
+ Expect.isTrue("str".endsWith("tr"));
+ Expect.isTrue("str".endsWith("str"));
- Expect.equals(false, "str".endsWith("stri"));
- Expect.equals(false, "str".endsWith("t"));
- Expect.equals(false, "str".endsWith("st"));
- Expect.equals(false, "str".endsWith("s"));
+ Expect.isFalse("str".endsWith("stri"));
+ Expect.isFalse("str".endsWith("t"));
+ Expect.isFalse("str".endsWith("st"));
+ Expect.isFalse("str".endsWith("s"));
- Expect.equals(true, "".endsWith(""));
- Expect.equals(false, "".endsWith("s"));
+ Expect.isTrue("".endsWith(""));
+ Expect.isFalse("".endsWith("s"));
}
static testStartsWith() {
- Expect.equals(true, "str".startsWith("s"));
- Expect.equals(true, "str".startsWith("st"));
- Expect.equals(true, "str".startsWith("str"));
+ Expect.isTrue("str".startsWith("s"));
+ Expect.isTrue("str".startsWith("st"));
+ Expect.isTrue("str".startsWith("str"));
- Expect.equals(false, "str".startsWith("stri"));
- Expect.equals(false, "str".startsWith("r"));
- Expect.equals(false, "str".startsWith("tr"));
- Expect.equals(false, "str".startsWith("t"));
+ Expect.isFalse("str".startsWith("stri"));
+ Expect.isFalse("str".startsWith("r"));
+ Expect.isFalse("str".startsWith("tr"));
+ Expect.isFalse("str".startsWith("t"));
- Expect.equals(true, "".startsWith(""));
- Expect.equals(false, "".startsWith("s"));
+ Expect.isTrue("".startsWith(""));
+ Expect.isFalse("".startsWith("s"));
+
+ var regexp = new RegExp("s(?:tr?)?");
+ Expect.isTrue("s".startsWith(regexp));
+ Expect.isTrue("st".startsWith(regexp));
+ Expect.isTrue("str".startsWith(regexp));
+ Expect.isTrue("sX".startsWith(regexp));
+ Expect.isTrue("stX".startsWith(regexp));
+ Expect.isTrue("strX".startsWith(regexp));
+
+ Expect.isFalse("".startsWith(regexp));
+ Expect.isFalse("astr".startsWith(regexp));
+
+ Expect.isTrue("".startsWith(new RegExp("")));
+ Expect.isTrue("".startsWith(new RegExp("a?")));
}
static testIndexOf() {
@@ -162,13 +176,29 @@
String str = "hello";
for (int i = 0; i < 10; i++) {
- int result = str.indexOf("", i);
if (i > str.length) {
- Expect.equals(str.length, result);
+ Expect.throws(() => str.indexOf("", i));
} else {
+ int result = str.indexOf("", i);
Expect.equals(i, result);
}
}
+
+ var re = new RegExp("an?");
+ Expect.equals(1, "banana".indexOf(re));
+ Expect.equals(1, "banana".indexOf(re, 0));
+ Expect.equals(1, "banana".indexOf(re, 1));
+ Expect.equals(3, "banana".indexOf(re, 2));
+ Expect.equals(3, "banana".indexOf(re, 3));
+ Expect.equals(5, "banana".indexOf(re, 4));
+ Expect.equals(5, "banana".indexOf(re, 5));
+ Expect.equals(-1, "banana".indexOf(re, 6));
+ Expect.throws(() => "banana".indexOf(re, -1));
+ Expect.throws(() => "banana".indexOf(re, 7));
+ re = new RegExp("x?");
+ for (int i = 0; i <= str.length; i++) {
+ Expect.equals(i, str.indexOf(re, i));
+ }
}
static testLastIndexOf() {
@@ -190,8 +220,9 @@
Expect.equals(3, "strstr".lastIndexOf("st", 5));
Expect.equals(3, "strstr".lastIndexOf("s", 5));
Expect.equals(5, "strstr".lastIndexOf("r", 5));
- Expect.equals(-1, "str".lastIndexOf("string", 5));
-
+ Expect.throws(() {
+ "str".lastIndexOf("string", 5);
+ });
Expect.equals(4, "strstr".lastIndexOf("t", 5));
Expect.equals(4, "strstr".lastIndexOf("tr", 5));
Expect.equals(3, "strstr".lastIndexOf("str", 5));
@@ -203,33 +234,49 @@
Expect.equals(2, "strstr".lastIndexOf("r", 4));
Expect.equals(2, "strstr".lastIndexOf("r", 3));
Expect.equals(5, "strstr".lastIndexOf("r"));
- Expect.equals(5, "strstr".lastIndexOf("r"), null);
+ Expect.equals(5, "strstr".lastIndexOf("r", null));
String str = "hello";
for (int i = 0; i < 10; i++) {
- int result = str.lastIndexOf("", i);
if (i > str.length) {
- Expect.equals(str.length, result);
+ Expect.throws(() => str.indexOf("", i));
} else {
+ int result = str.lastIndexOf("", i);
Expect.equals(i, result);
}
}
+
+ var re = new RegExp("an?");
+ Expect.equals(5, "banana".lastIndexOf(re));
+ Expect.equals(5, "banana".lastIndexOf(re, 6));
+ Expect.equals(5, "banana".lastIndexOf(re, 5));
+ Expect.equals(3, "banana".lastIndexOf(re, 4));
+ Expect.equals(3, "banana".lastIndexOf(re, 3));
+ Expect.equals(1, "banana".lastIndexOf(re, 2));
+ Expect.equals(1, "banana".lastIndexOf(re, 1));
+ Expect.equals(-1, "banana".lastIndexOf(re, 0));
+ Expect.throws(() => "banana".lastIndexOf(re, -1));
+ Expect.throws(() => "banana".lastIndexOf(re, 7));
+ re = new RegExp("x?");
+ for (int i = 0; i <= str.length; i++) {
+ Expect.equals(i, str.indexOf(re, i));
+ }
}
static testContains() {
- Expect.equals(true, "str".contains("s", 0));
- Expect.equals(true, "str".contains("st", 0));
- Expect.equals(true, "str".contains("str", 0));
- Expect.equals(true, "str".contains("t", 0));
- Expect.equals(true, "str".contains("r", 0));
- Expect.equals(true, "str".contains("tr", 0));
+ Expect.isTrue("str".contains("s", 0));
+ Expect.isTrue("str".contains("st", 0));
+ Expect.isTrue("str".contains("str", 0));
+ Expect.isTrue("str".contains("t", 0));
+ Expect.isTrue("str".contains("r", 0));
+ Expect.isTrue("str".contains("tr", 0));
- Expect.equals(false, "str".contains("sr", 0));
- Expect.equals(false, "str".contains("string", 0));
+ Expect.isFalse("str".contains("sr", 0));
+ Expect.isFalse("str".contains("string", 0));
- Expect.equals(true, "str".contains("", 0));
- Expect.equals(true, "".contains("", 0));
- Expect.equals(false, "".contains("s", 0));
+ Expect.isTrue("str".contains("", 0));
+ Expect.isTrue("".contains("", 0));
+ Expect.isFalse("".contains("s", 0));
}
static testReplaceAll() {
diff --git a/tests/corelib/uri_query_test.dart b/tests/corelib/uri_query_test.dart
index 03c9aba..bb21f9b 100644
--- a/tests/corelib/uri_query_test.dart
+++ b/tests/corelib/uri_query_test.dart
@@ -29,6 +29,9 @@
Expect.equals("?$normalizedQuery", uri.toString());
}
if (parameters.containsValue(null)) {
+ var map = new Map.from(parameters);
+ map.forEach((k, v) { if (v == null) map[k] = ""; });
+ Expect.mapEquals(map, uri.queryParameters);
} else {
Expect.mapEquals(parameters, uri.queryParameters);
}
@@ -42,6 +45,13 @@
check(uri3);
Expect.equals(uri1, uri3);
Expect.equals(uri2, uri3);
+ if (parameters.containsValue(null)) {
+ var map = new Map.from(parameters);
+ map.forEach((k, v) { if (v == null) map[k] = ""; });
+ Expect.mapEquals(map, Uri.splitQueryString(query));
+ } else {
+ Expect.mapEquals(parameters, Uri.splitQueryString(query));
+ }
}
test("", {});
diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart
index 9a9feac3e..03a0fd4 100644
--- a/tests/html/indexeddb_2_test.dart
+++ b/tests/html/indexeddb_2_test.dart
@@ -46,6 +46,14 @@
});
}
+List<String> get nonNativeListData {
+ var list = new List<String>();
+ list.add("data");
+ list.add("clone");
+ list.add("error");
+ list.add("test");
+ return list;
+}
main() {
useHtmlConfiguration();
@@ -93,5 +101,6 @@
go('array_deferred_copy', [1,2,3, obj3, obj3, 6]);
go('array_deferred_copy_2', [1,2,3, [4, 5, obj3], [obj3, 6]]);
go('cyclic_list', cyclic_list);
+ go('non-native lists', nonNativeListData);
}
}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index e001f6d..527f220 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -138,20 +138,33 @@
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari ) ]
isolate_stress_test: Pass, Timeout # http://dartbug.com/10697
-[ $arch == simarm ]
-*: Skip
+[ $arch == simarm && $mode == debug ]
+message_test: Crash # Issue: 11207
+unresolved_ports_test: Pass, Crash # Issue: 11207
-[ $arch == arm ]
-count_stream_test: Crash # Issue: 11207
+[ ($arch == arm || $arch == simarm) && $checked ]
+count_test: Pass, Crash # Issue: 11207
+isolate_complex_messages_test: Pass, Crash # Issue: 11207
+mandel_isolate_test: Pass, Crash # Issue 11207
+cross_isolate_message_test: Pass, Crash # Issue: 11207
+nested_spawn_test: Pass, Crash # Issue: 11207
+
+[ $arch == arm || $arch == simarm ]
+request_reply_test: Pass, Crash # Issue: 11207
+nested_spawn_test: Pass, Crash # Issue: 11207
+nested_spawn2_test: Pass, Crash # Issue: 11207
+count_stream_test: Pass, Crash # Issue: 11207
cross_isolate_message_stream_test: Crash # Issue: 11207
mandel_isolate_stream_test: Crash # Issue: 11207
-message2_test: Crash # Issue: 11207
+message2_test: Pass, Crash # Issue: 11207
message_stream2_test: Crash # Issue: 11207
-nested_spawn_stream2_test: Crash # Issue: 11207
-nested_spawn_stream_test: Crash # Issue: 11207
-spawn_function_negative_test: Crash # Issue: 11207
-spawn_uri_vm_negative_test: Crash # Issue: 11207
+nested_spawn_stream_test: Crash, Pass # Issue: 11207
+nested_spawn_stream2_test: Pass, Crash # Issue: 11207
+spawn_function_negative_test: Pass, Crash # Issue: 11207
+spawn_uri_vm_negative_test: Crash, Pass # Issue: 11207 (Pass on Mac)
stream_mangling_test: Crash # Issue: 11207
+message_test: Pass, Crash # Issue: 11207
+mint_maker_test: Pass, Crash # Issue: 11207
[ $arch == mips ]
*: Skip
diff --git a/tests/language/aborting_switch_case_test.dart b/tests/language/aborting_switch_case_test.dart
new file mode 100644
index 0000000..69037ad
--- /dev/null
+++ b/tests/language/aborting_switch_case_test.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// Regression test for dart2js that used to be confused when inlining
+// method that always aborts in a switch case.
+
+import "package:expect/expect.dart";
+
+foo() { throw 42; }
+
+main() {
+ var exception;
+ try {
+ switch (42) {
+ case 42:
+ foo();
+ foo();
+ break;
+ }
+ } catch (e) {
+ exception = e;
+ }
+ Expect.equals(42, exception);
+}
diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart
index e28ab716..bde573d 100644
--- a/tests/language/arithmetic_test.dart
+++ b/tests/language/arithmetic_test.dart
@@ -435,11 +435,24 @@
Expect.throws(() => mySqrt("abc"));
}
+ static self_equality(x) {
+ return x == x;
+ }
+
+ static testDoubleEquality() {
+ Expect.isFalse(self_equality(double.NAN));
+ for (int i = 0; i < 2000; i++) {
+ self_equality(3.0);
+ }
+ Expect.isFalse(self_equality(double.NAN));
+ }
+
static testMain() {
for (int i = 0; i < 1500; i++) {
runOne();
testSmiDivDeopt();
testSqrtDeopt();
+ testDoubleEquality();
}
}
}
diff --git a/tests/language/canonical_const3_test.dart b/tests/language/canonical_const3_test.dart
new file mode 100644
index 0000000..7dad367
--- /dev/null
+++ b/tests/language/canonical_const3_test.dart
@@ -0,0 +1,31 @@
+// 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.
+//
+// Check proper canonicalization (fields must be canonicalized as well).
+
+import "package:expect/expect.dart";
+
+
+main() {
+ Expect.isFalse(identical(new Duration(days: 1), new Duration(days: 1)));
+ Expect.isTrue(identical(const Duration(days: 2), const Duration(days: 2)));
+ Expect.isTrue(identical(const B(3.0), const B(3.0)));
+ Expect.isTrue(identical(const F(main), const F(main)));
+}
+
+
+class A {
+ final a;
+ const A(v) : a = v + 3.4;
+}
+
+class B extends A {
+ final b;
+ const B(v) : super(v), b = v + 1.0;
+}
+
+class F {
+ final f;
+ const F(v) : f = v;
+}
diff --git a/tests/language/generic_test.dart b/tests/language/generic_test.dart
index 55c6d41..7e7c56c 100644
--- a/tests/language/generic_test.dart
+++ b/tests/language/generic_test.dart
@@ -63,7 +63,7 @@
String subs = error.url.substring(pos + 1, error.url.length);
Expect.equals("generic_test.dart", subs);
Expect.equals(31, error.line); // new B<T>(t); AX does not extend A.
- Expect.equals(17, error.column);
+ Expect.equals(21, error.column);
}
return result;
}
diff --git a/tests/language/language.status b/tests/language/language.status
index 305a45a..7554f25 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -347,7 +347,6 @@
# Mixins fail on the VM.
mixin_mixin_test: Fail # VM issue
mixin_issue10216_2_test: Fail # VM issue
-mixin_illegal_constructor_test/none: Fail # VM issue
# Malformed types not handled as unresolved:
@@ -528,17 +527,16 @@
super_call4_test: Fail, OK # hardcoded names.
[ $arch == simarm || $arch == arm ]
-arithmetic_test: Fail, Crash
bit_operations_test: Crash, Fail
-char_escape_test: Pass, Crash
deopt_smi_op_test: Fail
-div_with_power_of_two_test: Fail
gc_test: Crash
invocation_mirror_test: Fail
load_to_load_forwarding_vm_test: Fail
named_parameters_with_conversions_test: Pass, Crash
-positive_bit_operations_test: Pass, Fail, Crash
-left_shift_test: Pass, Fail
+arithmetic_test: Pass, Crash, Fail # Fails on Mac
+left_shift_test: Pass, Fail # Fails on Mac
+positive_bit_operations_test: Pass, Fail, Crash # Fails and crashes on Mac
+
# large_implicit_getter_test Passes on ReleaseARM, Crashes in SIMARM and
# DebugARM. Should crash on ReleaseARM, but there is no exception on an
@@ -548,6 +546,9 @@
stack_overflow_test: Crash, Pass
stack_overflow_stacktrace_test: Crash, Pass
+[ ($arch == simarm || $arch == arm) && $mode == debug ]
+char_escape_test: Pass, Crash
+
[ $arch == mips ]
*: Skip
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index ebaff6e..456c164 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -104,7 +104,6 @@
list_literal_syntax_test/03: fail
map_literal1_negative_test: fail
map_literal3_test: fail
-method_override2_test/03: fail
mixin_illegal_constructor_test/13: fail
mixin_illegal_constructor_test/14: fail
mixin_illegal_constructor_test/15: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 31cf098..be8fb29 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -104,7 +104,6 @@
list_literal_syntax_test/03: fail
map_literal1_negative_test: fail
map_literal3_test: fail
-method_override2_test/03: fail
mixin_illegal_constructor_test/13: fail
mixin_illegal_constructor_test/14: fail
mixin_illegal_constructor_test/15: fail
diff --git a/tests/language/licm3_test.dart b/tests/language/licm3_test.dart
new file mode 100644
index 0000000..99e93b1
--- /dev/null
+++ b/tests/language/licm3_test.dart
@@ -0,0 +1,31 @@
+// 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.
+
+// Test that a loop invariant code motion optimization correctly hoists
+// instructions that may cause deoptimization.
+
+import "package:expect/expect.dart";
+
+foo(o) {
+ var r = 0;
+ for (var i = 0; i < 3; i++) {
+ r += o.z;
+ }
+ return r;
+}
+
+
+class A {
+ var z = 3;
+}
+
+main() {
+ var a = new A();
+ for(var i = 0; i < 10000; i++) foo(a);
+ Expect.equals(9, foo(a));
+ Expect.throws(() => foo(42));
+ for(var i = 0; i < 10000; i++) foo(a);
+ Expect.throws(() => foo(42));
+}
+
diff --git a/tests/language/reg_exp_test.dart b/tests/language/reg_exp_test.dart
index 26826a9..c51663c 100644
--- a/tests/language/reg_exp_test.dart
+++ b/tests/language/reg_exp_test.dart
@@ -25,4 +25,40 @@
exp = new RegExp("^", multiLine: true); // Any zero-length match will work.
str = "foo\nbar\nbaz";
Expect.equals(" foo\n bar\n baz", str.replaceAll(exp, " "));
+
+ exp = new RegExp(r"(\w+)");
+ Expect.isNull(exp.matchAsPrefix(" xyz ab"));
+ Expect.isNull(exp.matchAsPrefix(" xyz ab", 0));
+
+ var m = exp.matchAsPrefix(" xyz ab", 1);
+ Expect.equals("xyz", m[0]);
+ Expect.equals("xyz", m[1]);
+ Expect.equals(1, m.groupCount);
+
+ m = exp.matchAsPrefix(" xyz ab", 2);
+ Expect.equals("yz", m[0]);
+ Expect.equals("yz", m[1]);
+ Expect.equals(1, m.groupCount);
+
+ m = exp.matchAsPrefix(" xyz ab", 3);
+ Expect.equals("z", m[0]);
+ Expect.equals("z", m[1]);
+ Expect.equals(1, m.groupCount);
+
+ Expect.isNull(exp.matchAsPrefix(" xyz ab", 4));
+
+ m = exp.matchAsPrefix(" xyz ab", 5);
+ Expect.equals("ab", m[0]);
+ Expect.equals("ab", m[1]);
+ Expect.equals(1, m.groupCount);
+
+ m = exp.matchAsPrefix(" xyz ab", 6);
+ Expect.equals("b", m[0]);
+ Expect.equals("b", m[1]);
+ Expect.equals(1, m.groupCount);
+
+ Expect.isNull(exp.matchAsPrefix(" xyz ab", 7));
+
+ Expect.throws(() => exp.matchAsPrefix(" xyz ab", -1));
+ Expect.throws(() => exp.matchAsPrefix(" xyz ab", 8));
}
diff --git a/tests/lib/analyzer/analyze_tests.status b/tests/lib/analyzer/analyze_tests.status
index 3406d43..fb163a8 100644
--- a/tests/lib/analyzer/analyze_tests.status
+++ b/tests/lib/analyzer/analyze_tests.status
@@ -28,9 +28,8 @@
standalone/typed_data_view_test: Fail
# Tests using fake "part" and/or "part of" directive.
-standalone/crypto/base64_test: Fail
standalone/typed_data_test: Fail
-standalone/io/http_date_test: Fail
+standalone/io/http_cookie_date_test: Fail
standalone/io/http_headers_test: Fail
standalone/io/http_parser_test: Fail
standalone/io/web_socket_protocol_processor_test: Fail
diff --git a/tests/lib/collection/linked_list_test.dart b/tests/lib/collection/linked_list_test.dart
new file mode 100644
index 0000000..3ed06b7
--- /dev/null
+++ b/tests/lib/collection/linked_list_test.dart
@@ -0,0 +1,175 @@
+// 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.
+
+import 'dart:collection';
+import "package:expect/expect.dart";
+
+class MyEntry extends LinkedListEntry<MyEntry> {
+ final int value;
+
+ MyEntry(int this.value);
+
+ String toString() => value.toString();
+}
+
+
+testInsert() {
+ // Insert last.
+ var list = new LinkedList<MyEntry>();
+ for (int i = 0; i < 10; i++) {
+ list.add(new MyEntry(i));
+ }
+
+ Expect.equals(10, list.length);
+
+ int i = 0;
+ for (var entry in list) {
+ Expect.equals(i, entry.value);
+ i++;
+ }
+
+ Expect.equals(10, i);
+
+ list.clear();
+
+ // Insert first.
+ for (int i = 0; i < 10; i++) {
+ list.addFirst(new MyEntry(i));
+ }
+
+ Expect.equals(10, list.length);
+
+ i = 10;
+ for (var entry in list) {
+ Expect.equals(--i, entry.value);
+ }
+ Expect.equals(0, i);
+
+ list.clear();
+
+ // Insert after.
+ list.addFirst(new MyEntry(0));
+ for (int i = 1; i < 10; i++) {
+ list.last.insertAfter(new MyEntry(i));
+ }
+
+ Expect.equals(10, list.length);
+
+ i = 0;
+ for (var entry in list) {
+ Expect.equals(i, entry.value);
+ i++;
+ }
+
+ Expect.equals(10, i);
+
+ list.clear();
+
+ // Insert before.
+ list.addFirst(new MyEntry(0));
+ for (int i = 1; i < 10; i++) {
+ list.first.insertBefore(new MyEntry(i));
+ }
+
+ Expect.equals(10, list.length);
+
+ i = 10;
+ for (var entry in list) {
+ Expect.equals(--i, entry.value);
+ }
+ Expect.equals(0, i);
+
+ list.clear();
+}
+
+
+testRemove() {
+ var list = new LinkedList<MyEntry>();
+ for (int i = 0; i < 10; i++) {
+ list.add(new MyEntry(i));
+ }
+
+ Expect.equals(10, list.length);
+
+ list.remove(list.skip(5).first);
+
+ Expect.equals(9, list.length);
+
+ int i = 0;
+ for (var entry in list) {
+ if (i == 5) i++;
+ Expect.equals(i, entry.value);
+ i++;
+ }
+
+ Expect.listEquals([0, 1, 2, 3, 4, 6, 7, 8, 9],
+ list.map((e) => e.value).toList());
+
+ for (int i = 0; i < 9; i++) {
+ list.first.unlink();
+ }
+
+ Expect.throws(() => list.first);
+
+ Expect.equals(0, list.length);
+}
+
+
+testBadAdd() {
+ var list1 = new LinkedList<MyEntry>();
+ list1.addFirst(new MyEntry(0));
+
+ var list2 = new LinkedList<MyEntry>();
+ Expect.throws(() => list2.addFirst(list1.first));
+
+ Expect.throws(() => new MyEntry(0).unlink());
+}
+
+testConcurrentModificationError() {
+
+ test(function(LinkedList ll)) {
+ var ll = new LinkedList<MyEntry>();
+ for (int i = 0; i < 10; i++) {
+ ll.add(new MyEntry(i));
+ }
+ Expect.throws(() => function(ll), (e) => e is ConcurrentModificationError);
+ }
+ test((ll) { for(var x in ll) { ll.remove(x); } });
+ test((ll) { ll.forEach((x) { ll.remove(x); }); });
+ test((ll) { ll.any((x) { ll.remove(x); return false; }); });
+ test((ll) { ll.every((x) { ll.remove(x); return true; }); });
+ test((ll) { ll.fold(0, (x, y) { ll.remove(y); return x; }); });
+ test((ll) { ll.reduce((x, y) { ll.remove(y); return x; }); });
+ test((ll) { ll.where((x) { ll.remove(x); return true; }).forEach((_) {}); });
+ test((ll) { ll.map((x) { ll.remove(x); return x; }).forEach((_) {}); });
+ test((ll) { ll.expand((x) { ll.remove(x); return[x];}).forEach((_) {}); });
+ test((ll) { ll.takeWhile((x) {
+ ll.remove(x); return true;}).forEach((_) {}); });
+ test((ll) { ll.skipWhile((x) {
+ ll.remove(x); return true;}).forEach((_) {}); });
+ test((ll) {
+ bool first = true;
+ ll.firstWhere((x) {
+ ll.remove(x);
+ if (!first) return true;
+ return first = false;
+ });
+ });
+ test((ll) { ll.lastWhere((x) { ll.remove(x); return true;}); });
+ test((ll) {
+ bool first = true;
+ ll.singleWhere((x) {
+ ll.remove(x);
+ if (!first) return false;
+ return !(first = false);
+ });
+ });
+}
+
+main() {
+ testInsert();
+ testRemove();
+ testBadAdd();
+ testConcurrentModificationError();
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 093283e..cdf2a9d 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -21,13 +21,16 @@
[ $compiler == dart2js && $minified ]
mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
+mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # Issue 6490
mirrors/disable_tree_shaking_test: Fail # Issue 6490
+mirrors/reflect_model_test: Fail # Issue 6490
[ $csp ]
mirrors/metadata_test: Fail # Issue 6490
mirrors/reflect_runtime_type_test: Fail # Issue 6490
mirrors/reflect_uninstantiated_class_test: Fail # Issue 6490
mirrors/superclass_test: Fail # Issue 6490
+mirrors/reflect_model_test: Fail # Issue 6490
[ $compiler == dart2js && $checked ]
async/stream_event_transform_test: Fail # Issue 7733.
@@ -62,6 +65,7 @@
mirrors/mirrors_test: Fail # Issue 10957
mirrors/library_uri_package_test: Fail # Issue 10957
async/run_async6_test: Fail # Issue 10957 - may be related to issue 10910
+mirrors/reflect_model_test: Fail # http://dartbug.com/11219
[ $compiler == dart2dart && $minified ]
json/json_test: Fail # Issue 10961
@@ -99,6 +103,8 @@
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
mirrors/metadata_test: Fail # http://dartbug.com/10906
mirrors/superclass_test: Fail # http://dartbug.com/11142
+mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # http://dartbug.com/11187
+mirrors/reflect_model_test: Fail # http://dartbug.com/11219
[ $compiler == none && $runtime == drt ]
async/timer_isolate_test: Skip # See Issue 4997
@@ -111,24 +117,31 @@
async/multiple_timer_test: Fail, Pass # See Issue 10982
async/timer_test: Fail, Pass # See Issue 10982
-[ $arch == simarm ]
-*: Skip
-[ $arch == arm ]
-async/slow_consumer2_test: Crash # Issue: 11207
-async/slow_consumer3_test: Crash # Issue: 11207
-async/slow_consumer_test: Crash # Issue: 11207
-async/stream_controller_async_test: Crash # Issue: 11207
-async/stream_from_iterable_test: Crash # Issue: 11207
-async/stream_periodic3_test: Crash # Issue: 11207
-async/stream_periodic4_test: Crash # Issue: 11207
-async/stream_periodic5_test: Crash # Issue: 11207
-async/stream_state_nonzero_timer_test: Crash # Issue: 11207
-async/stream_state_test: Crash # Issue: 11207
-async/stream_subscription_as_future_test: Crash # Issue: 11207
-async/stream_transform_test: Crash # Issue: 11207
-math/pi_test: Fail # Issue: 11207
+[ $arch == arm || $arch == simarm ]
+async/future_test: Pass, Crash # Issue: 11207
+async/run_async6_test: Pass, Fail # Issue: 11207
+async/run_async_test: Pass, Crash # Issue: 11207
+async/slow_consumer2_test: Pass, Crash # Issue: 11207
+async/slow_consumer3_test: Pass, Crash # Issue: 11207
+async/slow_consumer_test: Pass, Crash # Issue: 11207
+async/stream_controller_async_test: Pass, Crash # Issue: 11207
+async/stream_controller_test: Timeout, Pass, Crash # Issue: 11207
+async/stream_from_iterable_test: Pass, Crash # Issue: 11207
+async/stream_periodic2_test: Pass, Crash # Issue: 11207
+async/stream_periodic3_test: Pass, Crash # Issue: 11207
+async/stream_periodic4_test: Pass, Crash # Issue: 11207
+async/stream_periodic5_test: Pass, Crash # Issue: 11207
+async/stream_single_to_multi_subscriber_test: Pass, Crash # Issue: 11207
+async/stream_state_nonzero_timer_test: Pass, Crash # Issue: 11207
+async/stream_state_test: Pass, Crash # Issue: 11207
+async/stream_subscription_as_future_test: Pass, Crash # Issue: 11207
+async/stream_transform_test: Pass, Crash # Issue: 11207
+async/timer_cancel1_test: Pass, Crash # Issue: 11207
+async/timer_cancel2_test: Pass, Crash # Issue: 11207
+math/pi_test: Crash, Fail # Issue: 11207
math/random_test: Fail # Issue: 11207
+mirrors/reflect_model_test: Pass, Crash # Issue: 11207
typed_data/float32x4_list_test: Crash # Issue: 11207
typed_data/float32x4_test: Crash # Issue: 11207
typed_data/float32x4_unbox_phi_test: Crash # Issue: 11207
diff --git a/tests/lib/mirrors/model.dart b/tests/lib/mirrors/model.dart
new file mode 100644
index 0000000..a06c757
--- /dev/null
+++ b/tests/lib/mirrors/model.dart
@@ -0,0 +1,45 @@
+// 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.
+
+library test.model;
+
+var accessorA;
+
+var accessorB;
+
+var accessorC;
+
+var fieldC;
+
+class A {
+ var field;
+ instanceMethod(x) => 'A:instanceMethod($x)';
+ get accessor => 'A:get accessor';
+ set accessor(x) {
+ accessorA = x;
+ }
+ aMethod() => 'aMethod';
+}
+
+class B extends A {
+ get field => 'B:get field';
+ instanceMethod(x) => 'B:instanceMethod($x)';
+ get accessor => 'B:get accessor';
+ set accessor(x) {
+ accessorB = x;
+ }
+ bMethod() => 'bMethod';
+}
+
+class C extends B {
+ set field(x) {
+ fieldC = x;
+ }
+ instanceMethod(x) => 'C:instanceMethod($x)';
+ get accessor => 'C:get accessor';
+ set accessor(x) {
+ accessorC = x;
+ }
+ cMethod() => 'cMethod';
+}
diff --git a/tests/lib/mirrors/model_test.dart b/tests/lib/mirrors/model_test.dart
new file mode 100644
index 0000000..1e3c292
--- /dev/null
+++ b/tests/lib/mirrors/model_test.dart
@@ -0,0 +1,57 @@
+// 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.
+
+library test.model_test;
+
+import 'package:expect/expect.dart';
+
+import 'model.dart';
+
+isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+main() {
+ var a = new A();
+ var b = new B();
+ var c = new C();
+
+ Expect.isNull(a.field);
+ Expect.equals('B:get field', b.field);
+ Expect.equals('B:get field', c.field);
+
+ a.field = 42;
+ b.field = 87;
+ c.field = 89;
+ Expect.equals(42, a.field);
+ Expect.equals('B:get field', b.field);
+ Expect.equals('B:get field', c.field);
+ Expect.equals(89, fieldC);
+
+ Expect.equals('A:instanceMethod(7)', a.instanceMethod(7));
+ Expect.equals('B:instanceMethod(9)', b.instanceMethod(9));
+ Expect.equals('C:instanceMethod(13)', c.instanceMethod(13));
+
+ Expect.equals('A:get accessor', a.accessor);
+ Expect.equals('B:get accessor', b.accessor);
+ Expect.equals('C:get accessor', c.accessor);
+
+ a.accessor = 'foo';
+ b.accessor = 'bar';
+ c.accessor = 'baz';
+
+ Expect.equals('foo', accessorA);
+ Expect.equals('bar', accessorB);
+ Expect.equals('baz', accessorC);
+
+ Expect.equals('aMethod', a.aMethod());
+ Expect.equals('aMethod', b.aMethod());
+ Expect.equals('aMethod', c.aMethod());
+
+ Expect.throws(() { a.bMethod(); }, isNoSuchMethodError);
+ Expect.equals('bMethod', b.bMethod());
+ Expect.equals('bMethod', c.bMethod());
+
+ Expect.throws(() { a.cMethod(); }, isNoSuchMethodError);
+ Expect.throws(() { b.cMethod(); }, isNoSuchMethodError);
+ Expect.equals('cMethod', c.cMethod());
+}
diff --git a/tests/lib/mirrors/reflect_model_test.dart b/tests/lib/mirrors/reflect_model_test.dart
new file mode 100644
index 0000000..e96124a
--- /dev/null
+++ b/tests/lib/mirrors/reflect_model_test.dart
@@ -0,0 +1,169 @@
+// 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.
+
+library test.reflect_model_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+import 'model.dart';
+
+isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+name(DeclarationMirror mirror) {
+ return (mirror == null) ? '<null>' : stringify(mirror.simpleName);
+}
+
+stringifyMap(Map map) {
+ var buffer = new StringBuffer('{');
+ bool first = true;
+ for (String key in map.keys.map(MirrorSystem.getName).toList()..sort()) {
+ if (!first) buffer.write(', ');
+ first = false;
+ buffer.write(key);
+ buffer.write(': ');
+ buffer.write(stringify(map[new Symbol(key)]));
+ }
+ return (buffer..write('}')).toString();
+}
+
+stringifySymbol(Symbol symbol) => 's(${MirrorSystem.getName(symbol)})';
+
+writeDeclarationOn(DeclarationMirror mirror, StringBuffer buffer) {
+ buffer.write(stringify(mirror.simpleName));
+ if (mirror.owner != null) {
+ buffer.write(' in ');
+ buffer.write(name(mirror.owner));
+ }
+ if (mirror.isPrivate) buffer.write(', private');
+ if (mirror.isTopLevel) buffer.write(', top-level');
+}
+
+stringifyVariable(VariableMirror variable) {
+ var buffer = new StringBuffer('Variable(');
+ writeDeclarationOn(variable, buffer);
+ if (variable.isStatic) buffer.write(', static');
+ if (variable.isFinal) buffer.write(', final');
+ return (buffer..write(')')).toString();
+}
+
+stringifyMethod(MethodMirror method) {
+ var buffer = new StringBuffer('Method(');
+ writeDeclarationOn(method, buffer);
+ if (method.isStatic) buffer.write(', static');
+ if (method.isGetter) buffer.write(', getter');
+ if (method.isSetter) buffer.write(', setter');
+ return (buffer..write(')')).toString();
+}
+
+stringify(value) {
+ if (value is Map) return stringifyMap(value);
+ if (value is VariableMirror) return stringifyVariable(value);
+ if (value is MethodMirror) return stringifyMethod(value);
+ if (value is Symbol) return stringifySymbol(value);
+ if (value == null) return '<null>';
+ throw 'Unexpected value: $value';
+}
+
+expect(expected, actual) => Expect.stringEquals(expected, stringify(actual));
+
+main() {
+ var unnamed = new Symbol('');
+ var field = new Symbol('field');
+ var instanceMethod = new Symbol('instanceMethod');
+ var accessor = new Symbol('accessor');
+ var aMethod = new Symbol('aMethod');
+ var bMethod = new Symbol('bMethod');
+ var cMethod = new Symbol('cMethod');
+
+ var aClass = reflectClass(A);
+ var bClass = reflectClass(B);
+ var cClass = reflectClass(C);
+ var a = aClass.newInstance(unnamed, []);
+ var b = bClass.newInstance(unnamed, []);
+ var c = cClass.newInstance(unnamed, []);
+
+ expect('{field: Variable(s(field) in s(A))}', aClass.variables);
+ expect('{}', bClass.variables);
+ expect('{}', cClass.variables);
+
+ Expect.isNull(a.getField(field).reflectee);
+ Expect.equals('B:get field', b.getField(field).reflectee);
+ Expect.equals('B:get field', c.getField(field).reflectee);
+
+ Expect.equals(42, a.setField(field, 42).reflectee);
+ Expect.equals(87, b.setField(field, 87).reflectee);
+ Expect.equals(89, c.setField(field, 89).reflectee);
+
+ Expect.equals(42, a.getField(field).reflectee);
+ Expect.equals('B:get field', b.getField(field).reflectee);
+ Expect.equals('B:get field', c.getField(field).reflectee);
+ Expect.equals(89, fieldC);
+
+ expect('{accessor: Method(s(accessor) in s(A), getter)'
+ // TODO(ahe): Include instance field getters?
+ ', field: Method(s(field) in s(A), getter)'
+ '}',
+ aClass.getters);
+ expect('{accessor: Method(s(accessor) in s(B), getter)'
+ ', field: Method(s(field) in s(B), getter)}',
+ bClass.getters);
+ expect('{accessor: Method(s(accessor) in s(C), getter)}',
+ cClass.getters);
+
+ expect('{accessor=: Method(s(accessor=) in s(A), setter)'
+ // TODO(ahe): Include instance field setters?
+ ', field=: Method(s(field=) in s(A), setter)'
+ '}',
+ aClass.setters);
+ expect('{accessor=: Method(s(accessor=) in s(B), setter)}',
+ bClass.setters);
+ expect('{accessor=: Method(s(accessor=) in s(C), setter)'
+ ', field=: Method(s(field=) in s(C), setter)}',
+ cClass.setters);
+
+ Expect.equals('A:instanceMethod(7)', a.invoke(instanceMethod, [7]).reflectee);
+ Expect.equals('B:instanceMethod(9)', b.invoke(instanceMethod, [9]).reflectee);
+ Expect.equals(
+ 'C:instanceMethod(13)', c.invoke(instanceMethod, [13]).reflectee);
+
+ expect(
+ '{aMethod: Method(s(aMethod) in s(A))'
+ ', instanceMethod: Method(s(instanceMethod) in s(A))}',
+ aClass.methods);
+
+ expect(
+ '{bMethod: Method(s(bMethod) in s(B))'
+ ', instanceMethod: Method(s(instanceMethod) in s(B))}',
+ bClass.methods);
+ expect(
+ '{cMethod: Method(s(cMethod) in s(C))'
+ ', instanceMethod: Method(s(instanceMethod) in s(C))}',
+ cClass.methods);
+
+ Expect.equals('A:get accessor', a.getField(accessor).reflectee);
+ Expect.equals('B:get accessor', b.getField(accessor).reflectee);
+ Expect.equals('C:get accessor', c.getField(accessor).reflectee);
+
+ Expect.equals('foo', a.setField(accessor, 'foo').reflectee);
+ Expect.equals('bar', b.setField(accessor, 'bar').reflectee);
+ Expect.equals('baz', c.setField(accessor, 'baz').reflectee);
+
+ Expect.equals('foo', accessorA);
+ Expect.equals('bar', accessorB);
+ Expect.equals('baz', accessorC);
+
+ Expect.equals('aMethod', a.invoke(aMethod, []).reflectee);
+ Expect.equals('aMethod', b.invoke(aMethod, []).reflectee);
+ Expect.equals('aMethod', c.invoke(aMethod, []).reflectee);
+
+ Expect.throws(() { a.invoke(bMethod, []); }, isNoSuchMethodError);
+ Expect.equals('bMethod', b.invoke(bMethod, []).reflectee);
+ Expect.equals('bMethod', c.invoke(bMethod, []).reflectee);
+
+ Expect.throws(() { a.invoke(cMethod, []); }, isNoSuchMethodError);
+ Expect.throws(() { b.invoke(cMethod, []); }, isNoSuchMethodError);
+ Expect.equals('cMethod', c.invoke(cMethod, []).reflectee);
+}
diff --git a/tests/lib/mirrors/reflectively_instantiate_uninstantiated_class_test.dart b/tests/lib/mirrors/reflectively_instantiate_uninstantiated_class_test.dart
new file mode 100644
index 0000000..4d18126
--- /dev/null
+++ b/tests/lib/mirrors/reflectively_instantiate_uninstantiated_class_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+// Ensure that otherwise uninstantiated classes can be instantiated
+// reflectively.
+
+import "dart:mirrors";
+
+class Foo {
+ int a;
+}
+
+main() {
+ // Do NOT instantiate Foo.
+ var m = reflectClass(Foo);
+ var instance = m.newInstance(const Symbol(''), []);
+ print(instance);
+ bool threw = false;
+ try {
+ m.newInstance(const Symbol('noSuchConstructor'), []);
+ throw 'Expected an exception';
+ } on NoSuchMethodError catch (e) {
+ print(e);
+ threw = true;
+ }
+ if (!threw) throw 'Expected a NoSuchMethodError';
+}
diff --git a/tests/standalone/io/http_cookie_date_test.dart b/tests/standalone/io/http_cookie_date_test.dart
new file mode 100644
index 0000000..b9c76ea
--- /dev/null
+++ b/tests/standalone/io/http_cookie_date_test.dart
@@ -0,0 +1,41 @@
+// 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.
+
+import "package:expect/expect.dart";
+import "dart:async";
+import "dart:math";
+import "dart:collection";
+
+part "../../../sdk/lib/io/common.dart";
+part "../../../sdk/lib/io/io_sink.dart";
+part "../../../sdk/lib/io/http.dart";
+part "../../../sdk/lib/io/http_impl.dart";
+part "../../../sdk/lib/io/http_parser.dart";
+part "../../../sdk/lib/io/http_utils.dart";
+part "../../../sdk/lib/io/socket.dart";
+
+void testParseHttpCookieDate() {
+ Expect.throws(() => _HttpUtils.parseCookieDate(""));
+
+ test(int year,
+ int month,
+ int day,
+ int hours,
+ int minutes,
+ int seconds,
+ String formatted) {
+ DateTime date = new DateTime.utc(year, month, day, hours, minutes, seconds, 0);
+ Expect.equals(date, _HttpUtils.parseCookieDate(formatted));
+ }
+
+ test(2012, DateTime.JUNE, 19, 14, 15, 01, "tue, 19-jun-12 14:15:01 gmt");
+ test(2021, DateTime.JUNE, 09, 10, 18, 14, "Wed, 09-Jun-2021 10:18:14 GMT");
+ test(2021, DateTime.JANUARY, 13, 22, 23, 01, "Wed, 13-Jan-2021 22:23:01 GMT");
+ test(2013, DateTime.JANUARY, 15, 21, 47, 38, "Tue, 15-Jan-2013 21:47:38 GMT");
+ test(1970, DateTime.JANUARY, 01, 00, 00, 01, "Thu, 01-Jan-1970 00:00:01 GMT");
+}
+
+void main() {
+ testParseHttpCookieDate();
+}
diff --git a/tests/standalone/io/http_date_test.dart b/tests/standalone/io/http_date_test.dart
index f3205ab..960ff82 100644
--- a/tests/standalone/io/http_date_test.dart
+++ b/tests/standalone/io/http_date_test.dart
@@ -5,32 +5,25 @@
import "package:expect/expect.dart";
import "dart:async";
import "dart:math";
-
-part '../../../sdk/lib/io/common.dart';
-part "../../../sdk/lib/io/io_sink.dart";
-part "../../../sdk/lib/io/http.dart";
-part "../../../sdk/lib/io/http_impl.dart";
-part "../../../sdk/lib/io/http_parser.dart";
-part "../../../sdk/lib/io/http_utils.dart";
-part "../../../sdk/lib/io/socket.dart";
+import "dart:io";
void testParseHttpDate() {
DateTime date;
date = new DateTime.utc(1999, DateTime.JUNE, 11, 18, 46, 53, 0);
- Expect.equals(date, _HttpUtils.parseDate("Fri, 11 Jun 1999 18:46:53 GMT"));
- Expect.equals(date, _HttpUtils.parseDate("Friday, 11-Jun-1999 18:46:53 GMT"));
- Expect.equals(date, _HttpUtils.parseDate("Fri Jun 11 18:46:53 1999"));
+ Expect.equals(date, HttpDate.parse("Fri, 11 Jun 1999 18:46:53 GMT"));
+ Expect.equals(date, HttpDate.parse("Friday, 11-Jun-1999 18:46:53 GMT"));
+ Expect.equals(date, HttpDate.parse("Fri Jun 11 18:46:53 1999"));
date = new DateTime.utc(1970, DateTime.JANUARY, 1, 0, 0, 0, 0);
- Expect.equals(date, _HttpUtils.parseDate("Thu, 1 Jan 1970 00:00:00 GMT"));
+ Expect.equals(date, HttpDate.parse("Thu, 1 Jan 1970 00:00:00 GMT"));
Expect.equals(date,
- _HttpUtils.parseDate("Thursday, 1-Jan-1970 00:00:00 GMT"));
- Expect.equals(date, _HttpUtils.parseDate("Thu Jan 1 00:00:00 1970"));
+ HttpDate.parse("Thursday, 1-Jan-1970 00:00:00 GMT"));
+ Expect.equals(date, HttpDate.parse("Thu Jan 1 00:00:00 1970"));
date = new DateTime.utc(2012, DateTime.MARCH, 5, 23, 59, 59, 0);
- Expect.equals(date, _HttpUtils.parseDate("Mon, 5 Mar 2012 23:59:59 GMT"));
- Expect.equals(date, _HttpUtils.parseDate("Monday, 5-Mar-2012 23:59:59 GMT"));
- Expect.equals(date, _HttpUtils.parseDate("Mon Mar 5 23:59:59 2012"));
+ Expect.equals(date, HttpDate.parse("Mon, 5 Mar 2012 23:59:59 GMT"));
+ Expect.equals(date, HttpDate.parse("Monday, 5-Mar-2012 23:59:59 GMT"));
+ Expect.equals(date, HttpDate.parse("Mon Mar 5 23:59:59 2012"));
}
void testFormatParseHttpDate() {
@@ -44,9 +37,9 @@
DateTime date;
String formatted;
date = new DateTime.utc(year, month, day, hours, minutes, seconds, 0);
- formatted = _HttpUtils.formatDate(date);
+ formatted = HttpDate.format(date);
Expect.equals(expectedFormatted, formatted);
- Expect.equals(date, _HttpUtils.parseDate(formatted));
+ Expect.equals(date, HttpDate.parse(formatted));
}
test(1999, DateTime.JUNE, 11, 18, 46, 53, "Fri, 11 Jun 1999 18:46:53 GMT");
@@ -56,59 +49,37 @@
void testParseHttpDateFailures() {
Expect.throws(() {
- _HttpUtils.parseDate("");
+ HttpDate.parse("");
});
String valid = "Mon, 5 Mar 2012 23:59:59 GMT";
for (int i = 1; i < valid.length - 1; i++) {
String tmp = valid.substring(0, i);
Expect.throws(() {
- _HttpUtils.parseDate(tmp);
+ HttpDate.parse(tmp);
});
Expect.throws(() {
- _HttpUtils.parseDate(" $tmp");
+ HttpDate.parse(" $tmp");
});
Expect.throws(() {
- _HttpUtils.parseDate(" $tmp ");
+ HttpDate.parse(" $tmp ");
});
Expect.throws(() {
- _HttpUtils.parseDate("$tmp ");
+ HttpDate.parse("$tmp ");
});
}
Expect.throws(() {
- _HttpUtils.parseDate(" $valid");
+ HttpDate.parse(" $valid");
});
Expect.throws(() {
- _HttpUtils.parseDate(" $valid ");
+ HttpDate.parse(" $valid ");
});
Expect.throws(() {
- _HttpUtils.parseDate("$valid ");
+ HttpDate.parse("$valid ");
});
}
-void testParseHttpCookieDate() {
- Expect.throws(() => _HttpUtils.parseCookieDate(""));
-
- test(int year,
- int month,
- int day,
- int hours,
- int minutes,
- int seconds,
- String formatted) {
- DateTime date = new DateTime.utc(year, month, day, hours, minutes, seconds, 0);
- Expect.equals(date, _HttpUtils.parseCookieDate(formatted));
- }
-
- test(2012, DateTime.JUNE, 19, 14, 15, 01, "tue, 19-jun-12 14:15:01 gmt");
- test(2021, DateTime.JUNE, 09, 10, 18, 14, "Wed, 09-Jun-2021 10:18:14 GMT");
- test(2021, DateTime.JANUARY, 13, 22, 23, 01, "Wed, 13-Jan-2021 22:23:01 GMT");
- test(2013, DateTime.JANUARY, 15, 21, 47, 38, "Tue, 15-Jan-2013 21:47:38 GMT");
- test(1970, DateTime.JANUARY, 01, 00, 00, 01, "Thu, 01-Jan-1970 00:00:01 GMT");
-}
-
void main() {
testParseHttpDate();
testFormatParseHttpDate();
testParseHttpDateFailures();
- testParseHttpCookieDate();
}
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index a6cca81..14ae21e 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -5,6 +5,7 @@
import "package:expect/expect.dart";
import 'dart:async';
import 'dart:math';
+import 'dart:collection';
part '../../../sdk/lib/io/common.dart';
part "../../../sdk/lib/io/io_sink.dart";
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index 8ff7713..6757633 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -7,6 +7,7 @@
import 'dart:math';
import 'dart:typed_data';
import 'dart:isolate';
+import 'dart:collection';
part '../../../sdk/lib/io/common.dart';
part '../../../sdk/lib/io/io_sink.dart';
diff --git a/tests/standalone/io/process_run_output_test.dart b/tests/standalone/io/process_run_output_test.dart
index 6bdbf44..f8b06d4 100644
--- a/tests/standalone/io/process_run_output_test.dart
+++ b/tests/standalone/io/process_run_output_test.dart
@@ -16,6 +16,9 @@
Expect.equals(output, 'æøå');
} else if (encoding == 'utf8') {
Expect.listEquals(output.codeUnits, [955]);
+ } else if (encoding == 'binary') {
+ print(output);
+ Expect.listEquals(output, [0, 1, 2]);
}
}
@@ -27,6 +30,8 @@
enc = Encoding.ISO_8859_1;
} else if (encoding == 'utf8') {
enc = Encoding.UTF_8;
+ } else if (encoding == 'binary') {
+ enc = null;
}
if (stream == 'stdout') {
@@ -61,5 +66,6 @@
test(scriptFile.path, 'latin1', 'stderr');
test(scriptFile.path, 'utf8', 'stdout');
test(scriptFile.path, 'utf8', 'stderr');
-
+ test(scriptFile.path, 'binary', 'stdout');
+ test(scriptFile.path, 'binary', 'stderr');
}
diff --git a/tests/standalone/io/process_std_io_script2.dart b/tests/standalone/io/process_std_io_script2.dart
index b6ff026..db57929 100644
--- a/tests/standalone/io/process_std_io_script2.dart
+++ b/tests/standalone/io/process_std_io_script2.dart
@@ -9,11 +9,19 @@
writeData(data, encoding, stream) {
if (stream == "stdout") {
- stdout.encoding = encoding;
- stdout.write(data);
+ if (encoding == null) {
+ stdout.add(data);
+ } else {
+ stdout.encoding = encoding;
+ stdout.write(data);
+ }
} else if (stream == "stderr") {
- stderr.encoding = encoding;
- stderr.write(data);
+ if (encoding == null) {
+ stderr.add(data);
+ } else {
+ stderr.encoding = encoding;
+ stderr.write(data);
+ }
}
}
@@ -21,6 +29,7 @@
var asciiString = 'abc';
var latin1String = 'æøå';
var utf8String = new String.fromCharCodes([955]);
+ var binary = [0, 1, 2];
var options = new Options();
if (options.arguments.length > 1) {
var stream = options.arguments[1];
@@ -30,6 +39,8 @@
writeData(latin1String, Encoding.ISO_8859_1, stream);
} else if (options.arguments[0] == "utf8") {
writeData(utf8String, Encoding.UTF_8, stream);
+ } else if (options.arguments[0] == "binary") {
+ writeData(binary, null, stream);
}
}
}
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.da